Compare commits
165 Commits
libssh2-1.
...
libssh2-1.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c889058cb3 | ||
![]() |
69c876e210 | ||
![]() |
10f5c70ac0 | ||
![]() |
ea914c8b72 | ||
![]() |
64a6c255ec | ||
![]() |
e09d6ac653 | ||
![]() |
91841731af | ||
![]() |
a190437c4a | ||
![]() |
68a900d27a | ||
![]() |
e4b7baa885 | ||
![]() |
2622bbaf33 | ||
![]() |
d3dbe4c81e | ||
![]() |
095ccbf825 | ||
![]() |
8eafded280 | ||
![]() |
6df87e64b7 | ||
![]() |
3ddac8ac66 | ||
![]() |
6c543545fe | ||
![]() |
abd9bd0bbe | ||
![]() |
5dd4005ace | ||
![]() |
8f102b8f56 | ||
![]() |
7d71f92a9c | ||
![]() |
f6fab0d9ea | ||
![]() |
cc7f90f1d4 | ||
![]() |
6d55714ab5 | ||
![]() |
6b23f640f8 | ||
![]() |
2cb8866f0a | ||
![]() |
3b3e13366e | ||
![]() |
9f4292433a | ||
![]() |
f077984394 | ||
![]() |
44eba0c993 | ||
![]() |
474e38119b | ||
![]() |
7f27b0822d | ||
![]() |
e3d8c1cfed | ||
![]() |
11a114ee7c | ||
![]() |
e48907ee05 | ||
![]() |
3f6bc287f9 | ||
![]() |
e84fe88526 | ||
![]() |
73e37b3b49 | ||
![]() |
7926c9cfaa | ||
![]() |
63457dfa6c | ||
![]() |
d00e97a7f1 | ||
![]() |
8436e45ea6 | ||
![]() |
0b6e37872d | ||
![]() |
1b3b7b2214 | ||
![]() |
6a249d7b6c | ||
![]() |
87e32272f9 | ||
![]() |
bd0505d6b9 | ||
![]() |
f70dbfa3e6 | ||
![]() |
a2452d7eee | ||
![]() |
bbb2f29037 | ||
![]() |
3138b5891f | ||
![]() |
c573af83de | ||
![]() |
ea8babf6d1 | ||
![]() |
db26c4eace | ||
![]() |
7b351eed36 | ||
![]() |
58abc7e30b | ||
![]() |
0a3b350012 | ||
![]() |
b5e358618b | ||
![]() |
dd81bda112 | ||
![]() |
12433b4511 | ||
![]() |
39cbd17e19 | ||
![]() |
1f91ab049f | ||
![]() |
f2e5b49904 | ||
![]() |
b4c0821332 | ||
![]() |
70b199f476 | ||
![]() |
d142f385da | ||
![]() |
1a491c6f00 | ||
![]() |
1256c61815 | ||
![]() |
95f559a926 | ||
![]() |
052a68db30 | ||
![]() |
1aba38cd7d | ||
![]() |
7317edab61 | ||
![]() |
e642e2c202 | ||
![]() |
f07cf3afd3 | ||
![]() |
1e350754f6 | ||
![]() |
55031fa320 | ||
![]() |
355fbf4d5b | ||
![]() |
74c63852d7 | ||
![]() |
ebbd7c879b | ||
![]() |
b78f854d8b | ||
![]() |
1f0d47fa92 | ||
![]() |
463e09e55f | ||
![]() |
82bf39dbfa | ||
![]() |
e5f170bae2 | ||
![]() |
fc60563840 | ||
![]() |
b38b4fb859 | ||
![]() |
3182045c2d | ||
![]() |
60d73d5663 | ||
![]() |
1e80194b97 | ||
![]() |
0c13f7beda | ||
![]() |
b859f4d9d2 | ||
![]() |
13092c5a5e | ||
![]() |
22b73235d3 | ||
![]() |
55034294e8 | ||
![]() |
5e80055d22 | ||
![]() |
11ca8d5583 | ||
![]() |
9162fd7e61 | ||
![]() |
7208e8d0d9 | ||
![]() |
e1bb074287 | ||
![]() |
e887ffca4c | ||
![]() |
65d1cb8107 | ||
![]() |
4ed82f0e78 | ||
![]() |
3cc2f143c1 | ||
![]() |
683aa0f6b5 | ||
![]() |
7a9d36903a | ||
![]() |
c2375dbfa4 | ||
![]() |
906a7d8866 | ||
![]() |
1418993a0f | ||
![]() |
c4b7f0394b | ||
![]() |
9e84b999a5 | ||
![]() |
3fda91d725 | ||
![]() |
7c32c84d0e | ||
![]() |
766127ad57 | ||
![]() |
a9e7f87e31 | ||
![]() |
a04a0b6c69 | ||
![]() |
1f8d58a4ce | ||
![]() |
4b482eddbe | ||
![]() |
05eb612f8e | ||
![]() |
d48ee98ecf | ||
![]() |
536443246e | ||
![]() |
b728b1018f | ||
![]() |
3f5a6662d0 | ||
![]() |
33f4e0f250 | ||
![]() |
8dabb1c5eb | ||
![]() |
0d6aaa1f56 | ||
![]() |
00fac145ba | ||
![]() |
f65f71a156 | ||
![]() |
3142e8df7e | ||
![]() |
bffefb12ea | ||
![]() |
feadd5f321 | ||
![]() |
7c139633a1 | ||
![]() |
692401633a | ||
![]() |
5bb1fb5cbc | ||
![]() |
5e5ead00b4 | ||
![]() |
06278728e2 | ||
![]() |
0357befa42 | ||
![]() |
85198c1cdb | ||
![]() |
face4750ca | ||
![]() |
a1365916c7 | ||
![]() |
f64a84a909 | ||
![]() |
fba3877ed8 | ||
![]() |
f1e010f5d4 | ||
![]() |
9e96acf86e | ||
![]() |
1a157d27cc | ||
![]() |
b3418bb1eb | ||
![]() |
08be841b4d | ||
![]() |
e39128df52 | ||
![]() |
5c6b8166c7 | ||
![]() |
dcb9625473 | ||
![]() |
c1b687c9e4 | ||
![]() |
13e920d4ef | ||
![]() |
314e61e545 | ||
![]() |
13c16db3bc | ||
![]() |
82c3f0ba72 | ||
![]() |
9e099fb88a | ||
![]() |
415efe10ac | ||
![]() |
4b1cb4e95e | ||
![]() |
d8b6f3c7b8 | ||
![]() |
a871f0b214 | ||
![]() |
08cad8e14c | ||
![]() |
46178378f2 | ||
![]() |
28b179ecf2 | ||
![]() |
7b4d6b2868 | ||
![]() |
fbe4737719 | ||
![]() |
ce4ad0d086 |
28
.cvsignore
28
.cvsignore
@@ -1,28 +0,0 @@
|
||||
.deps
|
||||
.libs
|
||||
*.lib
|
||||
*.pdb
|
||||
*.dll
|
||||
*.exe
|
||||
*.obj
|
||||
.*.swp
|
||||
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
|
||||
libssh2-*.tar.gz
|
||||
INSTALL
|
||||
install-sh
|
11
.cvsusers
11
.cvsusers
@@ -1,11 +0,0 @@
|
||||
jas4711:Simon Josefsson <simon@josefsson.org>
|
||||
bagder:Daniel Stenberg
|
||||
sarag:Sara Golemon <pollita@libssh2.org>
|
||||
gusarov:Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
wez:Wez Furlong
|
||||
edink:Edink Kadribasic
|
||||
jehousley: James Housley
|
||||
gknauf: Guenter Knauf
|
||||
dfandrich: Dan Fandrich
|
||||
yangtse: Yang Tse
|
||||
thomaspu: Paul Thomas
|
2
.gitattribute
Normal file
2
.gitattribute
Normal file
@@ -0,0 +1,2 @@
|
||||
win32/msvcproj.head -crlf
|
||||
win32/msvcproj.foot -crlf
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -30,3 +30,5 @@ install-sh
|
||||
*.lo
|
||||
*.la
|
||||
mkinstalldirs
|
||||
tags
|
||||
libssh2.pc
|
||||
|
7
AUTHORS
7
AUTHORS
@@ -6,6 +6,7 @@
|
||||
Adam Gobiowski
|
||||
Alexander Holyapin
|
||||
Alexander Lamaison
|
||||
Ben Kibbey
|
||||
Bjorn Stenborg
|
||||
Carlo Bramini
|
||||
Dan Casey
|
||||
@@ -15,15 +16,19 @@ David J Sullivan
|
||||
David Robins
|
||||
Edink Kadribasic
|
||||
Erik Brossler
|
||||
Francois Dupoux
|
||||
Guenter Knauf
|
||||
Heiner Steven
|
||||
James Housleys
|
||||
Jean-Louis Charton
|
||||
Jussi Mononen
|
||||
Mark McPherson
|
||||
Markus Moeller
|
||||
Mike Protts
|
||||
Mikhail Gusarov
|
||||
Neil Gierman
|
||||
Olivier Hervieu
|
||||
Paul Veldkamp
|
||||
Peter O'Gorman
|
||||
Peter Stuge
|
||||
Romain Bondue
|
||||
@@ -34,6 +39,8 @@ Selcuk Gueney
|
||||
Simon Hart
|
||||
Simon Josefsson
|
||||
Steven Ayre
|
||||
Steven Van Ingelgem
|
||||
Tor Arntsen
|
||||
Vincent Jaulin
|
||||
Vlad Grachov
|
||||
Wez Furlong
|
||||
|
1
COPYING
1
COPYING
@@ -1,6 +1,7 @@
|
||||
/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2006-2007 The Written Word, Inc.
|
||||
* Copyright (c) 2009 Daniel Stenberg
|
||||
* Copyright (C) 2008, 2009 Simon Josefsson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
|
11
HACKING
11
HACKING
@@ -9,14 +9,5 @@ libssh2 source code style guide:
|
||||
go_nuts();
|
||||
}
|
||||
|
||||
- write both braces on the else line:
|
||||
|
||||
if (banana) {
|
||||
go_nuts();
|
||||
} else {
|
||||
stay_calm();
|
||||
}
|
||||
|
||||
- use braces even for single-statement blocks
|
||||
|
||||
- keep source lines shorter than 80 columns
|
||||
- See libssh2-style.el for how to achieve this within Emacs
|
||||
|
95
Makefile.am
95
Makefile.am
@@ -2,6 +2,9 @@ AUTOMAKE_OPTIONS = foreign nostdinc
|
||||
|
||||
SUBDIRS = src example tests docs
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libssh2.pc
|
||||
|
||||
include_HEADERS = \
|
||||
include/libssh2.h \
|
||||
include/libssh2_publickey.h \
|
||||
@@ -16,8 +19,7 @@ NETWAREFILES = nw/keepscreen.c \
|
||||
DSP = win32/libssh2.dsp
|
||||
VCPROJ = win32/libssh2.vcproj
|
||||
|
||||
#Need to include $(VCPROJ) to CLEANFILES and WIN32FILES when I get a proper vc8proj.head|foot
|
||||
CLEANFILES = $(DSP)
|
||||
DISTCLEANFILES = $(DSP)
|
||||
|
||||
WIN32FILES = win32/Makefile.win32 win32/libssh2.dsw \
|
||||
win32/config.mk win32/Makefile win32/test/Makefile.win32 \
|
||||
@@ -25,14 +27,14 @@ win32/libssh2_config.h win32/tests.dsp win32/rules.mk $(DSP) \
|
||||
win32/msvcproj.head win32/msvcproj.foot
|
||||
|
||||
EXTRA_DIST = $(WIN32FILES) buildconf $(NETWAREFILES) get_ver.awk HACKING \
|
||||
maketgz NMakefile TODO RELEASE-NOTES
|
||||
maketgz NMakefile TODO RELEASE-NOTES libssh2.pc.in
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
.PHONY: ChangeLog
|
||||
ChangeLog:
|
||||
echo "see NEWS" > ./ChangeLog
|
||||
CLEANFILES += ChangeLog
|
||||
DISTCLEANFILES += ChangeLog
|
||||
|
||||
dist-hook:
|
||||
rm -rf $(top_builddir)/tests/log
|
||||
@@ -73,55 +75,54 @@ include Makefile.inc
|
||||
WIN32SOURCES = $(CSOURCES)
|
||||
WIN32HEADERS = $(HHEADERS) libssh2_config.h
|
||||
|
||||
DSPOUT = | awk '{printf("%s\r\n", $$0)}' >> $(DSP)
|
||||
VCPROJOUT = | awk '{printf("%s\r\n", $$0)}' >> $(VCPROJ)
|
||||
|
||||
$(DSP): win32/msvcproj.head win32/msvcproj.foot Makefile.am
|
||||
echo "creating $(DSP)"
|
||||
@(cp $(srcdir)/win32/msvcproj.head $(DSP); \
|
||||
echo "# Begin Group \"Source Files\"" $(DSPOUT); \
|
||||
echo "" $(DSPOUT); \
|
||||
echo "# PROP Default_Filter \"cpp;c;cxx\"" $(DSPOUT); \
|
||||
win32_srcs='$(WIN32SOURCES)'; \
|
||||
sorted_srcs=`for file in $$win32_srcs; do echo $$file; done | sort`; \
|
||||
for file in $$sorted_srcs; do \
|
||||
echo "# Begin Source File" $(DSPOUT); \
|
||||
echo "" $(DSPOUT); \
|
||||
echo "SOURCE=..\\src\\"$$file $(DSPOUT); \
|
||||
echo "# End Source File" $(DSPOUT); \
|
||||
@( (cat $(srcdir)/win32/msvcproj.head; \
|
||||
echo "# Begin Group \"Source Files\""; \
|
||||
echo ""; \
|
||||
echo "# PROP Default_Filter \"cpp;c;cxx\""; \
|
||||
win32_srcs='$(WIN32SOURCES)'; \
|
||||
sorted_srcs=`for file in $$win32_srcs; do echo $$file; done | sort`; \
|
||||
for file in $$sorted_srcs; do \
|
||||
echo "# Begin Source File"; \
|
||||
echo ""; \
|
||||
echo "SOURCE=..\\src\\"$$file; \
|
||||
echo "# End Source File"; \
|
||||
done; \
|
||||
echo "# End Group" $(DSPOUT); \
|
||||
echo "# Begin Group \"Header Files\"" $(DSPOUT); \
|
||||
echo "" $(DSPOUT); \
|
||||
echo "# PROP Default_Filter \"h;hpp;hxx\"" $(DSPOUT); \
|
||||
win32_hdrs='$(WIN32HEADERS)'; \
|
||||
sorted_hdrs=`for file in $$win32_hdrs; do echo $$file; done | sort`; \
|
||||
for file in $$sorted_hdrs; do \
|
||||
echo "# Begin Source File" $(DSPOUT); \
|
||||
echo "" $(DSPOUT); \
|
||||
if [ "$$file" == "libssh2_config.h" ]; \
|
||||
then \
|
||||
echo "SOURCE=.\\"$$file $(DSPOUT); \
|
||||
else \
|
||||
echo "SOURCE=..\\src\\"$$file $(DSPOUT); \
|
||||
fi; \
|
||||
echo "# End Source File" $(DSPOUT); \
|
||||
echo "# End Group"; \
|
||||
echo "# Begin Group \"Header Files\""; \
|
||||
echo ""; \
|
||||
echo "# PROP Default_Filter \"h;hpp;hxx\""; \
|
||||
win32_hdrs='$(WIN32HEADERS)'; \
|
||||
sorted_hdrs=`for file in $$win32_hdrs; do echo $$file; done | sort`; \
|
||||
for file in $$sorted_hdrs; do \
|
||||
echo "# Begin Source File"; \
|
||||
echo ""; \
|
||||
if [ "$$file" == "libssh2_config.h" ]; \
|
||||
then \
|
||||
echo "SOURCE=.\\"$$file; \
|
||||
else \
|
||||
echo "SOURCE=..\\src\\"$$file; \
|
||||
fi; \
|
||||
echo "# End Source File"; \
|
||||
done; \
|
||||
echo "# End Group" $(DSPOUT); \
|
||||
cat $(srcdir)/win32/msvcproj.foot $(DSPOUT) )
|
||||
echo "# End Group"; \
|
||||
cat $(srcdir)/win32/msvcproj.foot) | \
|
||||
awk '{printf("%s\r\n", gensub("\r", "", "g"))}' > $@ )
|
||||
|
||||
$(VCPROJ): win32/vc8proj.head win32/vc8proj.foot Makefile.am
|
||||
echo "creating $(VCPROJ)"
|
||||
@(cp $(srcdir)/vc8proj.head $(VCPROJ); \
|
||||
win32_srcs='$(WIN32SOURCES)'; \
|
||||
sorted_srcs=`for file in $$win32_srcs; do echo $$file; done | sort`; \
|
||||
for file in $$sorted_srcs; do \
|
||||
echo "<File RelativePath=\""..\src\$$file"\"></File>" $(VCPROJOUT); \
|
||||
@( (cat $(srcdir)/vc8proj.head; \
|
||||
win32_srcs='$(WIN32SOURCES)'; \
|
||||
sorted_srcs=`for file in $$win32_srcs; do echo $$file; done | sort`; \
|
||||
for file in $$sorted_srcs; do \
|
||||
echo "<File RelativePath=\""..\src\$$file"\"></File>"; \
|
||||
done; \
|
||||
echo "</Filter><Filter Name=\"Header Files\">" $(VCPROJOUT); \
|
||||
win32_hdrs='$(WIN32HEADERS)'; \
|
||||
sorted_hdrs=`for file in $$win32_hdrs; do echo $$file; done | sort`; \
|
||||
for file in $$sorted_hdrs; do \
|
||||
echo "<File RelativePath=\""..\src\$$file"\"></File>" $(VCPROJOUT); \
|
||||
echo "</Filter><Filter Name=\"Header Files\">"; \
|
||||
win32_hdrs='$(WIN32HEADERS)'; \
|
||||
sorted_hdrs=`for file in $$win32_hdrs; do echo $$file; done | sort`; \
|
||||
for file in $$sorted_hdrs; do \
|
||||
echo "<File RelativePath=\""..\src\$$file"\"></File>"; \
|
||||
done; \
|
||||
cat $(srcdir)/vc8proj.foot $(VCPROJOUT) )
|
||||
cat $(srcdir)/vc8proj.foot) | \
|
||||
awk '{printf("%s\r\n", gensub("\r", "", "g"))}' > $@ )
|
||||
|
@@ -1,11 +1,5 @@
|
||||
CSOURCES = 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 transport.c \
|
||||
version.c knownhost.c
|
||||
|
||||
if LIBGCRYPT
|
||||
CSOURCES += libgcrypt.c pem.c
|
||||
else
|
||||
CSOURCES += openssl.c
|
||||
endif
|
||||
version.c knownhost.c agent.c openssl.c libgcrypt.c pem.c
|
||||
|
||||
HHEADERS = libssh2_priv.h openssl.h libgcrypt.h transport.h channel.h comp.h mac.h misc.h
|
80
NEWS
80
NEWS
@@ -1,3 +1,83 @@
|
||||
Version 1.2.4 (February 13, 2010)
|
||||
|
||||
o Resolve compile issues on Solaris x64 and UltraSPARC
|
||||
o Allow compiling with OpenSSL when AES isn't available
|
||||
o Fix Tru64 socklen_t compile issue with example/direct_tcpip.c
|
||||
|
||||
Version 1.2.3 (February 3, 2010)
|
||||
|
||||
o Added libssh2_trace_sethandler()
|
||||
o Added the direct_tcpip.c example
|
||||
o Fixed memory leak in userauth_publickey
|
||||
o Added support for authentication via SSH-Agent. By Daiki Ueno.
|
||||
|
||||
o Respond to unknown SSH_MSG_GLOBAL_REQUEST/SSH_MSG_CHANNEL_REQUEST
|
||||
with SSH_MSG_REQUEST_FAILURE/SSH_MSG_CHANNEL_FAILURE in order to
|
||||
make (at least) OpenSSH server keepalive work. Before OpenSSH
|
||||
servers (configured with a positive ClientAliveInterval) would
|
||||
terminate connections against libssh2 clients because libssh2 did
|
||||
not respond properly to the request. By Simon Josefsson.
|
||||
|
||||
Version 1.2.2 (November 16, 2009)
|
||||
|
||||
* This release includes the following changes:
|
||||
|
||||
o Fix crash when server sends an invalid SSH_MSG_IGNORE message.
|
||||
Reported by Bob Alexander <balexander@expressor-software.com> in
|
||||
<http://thread.gmane.org/gmane.network.ssh.libssh2.devel/2530>.
|
||||
By Simon Josefsson.
|
||||
|
||||
o Support for the "aes128-ctr", "aes192-ctr", "aes256-ctr" ciphers
|
||||
as per RFC 4344 for libgcrypt and OpenSSL. They are now the
|
||||
preferred ciphers. By Simon Josefsson.
|
||||
|
||||
o Support for the "arcfour128" cipher as per RFC 4345 for libgcrypt
|
||||
and OpenSSL. It is preferred over the normal "arcfour" cipher
|
||||
which is somewhat broken. By Simon Josefsson.
|
||||
|
||||
o Add support for GCC visibility features. By Cristian Rodr<64>guez.
|
||||
|
||||
o Fix libssh2_channel_forward_accept. By Juzna.
|
||||
|
||||
o Generate Win32 files correctly. By Peter Stuge.
|
||||
|
||||
o Fix permission issue in ssh2 self test. By Dan Fandrich.
|
||||
|
||||
o Use memmove instead of memcpy in one place which copies
|
||||
overlapping memory areas.
|
||||
|
||||
o Cleanup hard coding of cipher modes in libgcrypt backend. By Simon.
|
||||
|
||||
o Added man page for libssh2_knownhost_free. By Daniel.
|
||||
|
||||
Version 1.2.1 (September 28, 2009)
|
||||
|
||||
* This release includes the following changes:
|
||||
|
||||
o generate and install libssh2.pc
|
||||
|
||||
... and the following bugfixes:
|
||||
|
||||
o proper return codes returned from several functions
|
||||
o return EAGAIN internal cleanup
|
||||
o added knownhost.c to windows makefiles
|
||||
o pass private-key to OpenSSL as a filename with BIO_new_file().
|
||||
o make libssh2_scp_send/recv do blocking mode correctly
|
||||
o libssh2_channel_wait_closed() could hang
|
||||
o libssh2_channel_read_ex() must return 0 when closed
|
||||
o added gettimeofday() function for win32 for the debug trace outputs
|
||||
o transport layer bug causing invalid -39 (LIBSSH2_ERROR_BAD_USE) errors
|
||||
o scp examples now loop correctly over libssh2_channel_write()
|
||||
|
||||
* (August 29 2009) Daniel Stenberg:
|
||||
|
||||
- I fixed all code to use the recently added dedicated linked list functions
|
||||
instead of doing the same stuff spread out all over.
|
||||
|
||||
- I also fixed a few cases where local variables where used to keep memory
|
||||
but was used to keep state for re-invokes due to non-blocking situations
|
||||
which would lead to segfaults.
|
||||
|
||||
Version 1.2 (August 10, 2009)
|
||||
-----------------------------
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
!include "win32/config.mk"
|
||||
|
||||
# SUBDIRS=src example\simple
|
||||
# SUBDIRS=src example
|
||||
SUBDIRS=src
|
||||
|
||||
all-sub:
|
||||
|
@@ -1,40 +1,18 @@
|
||||
libssh2 1.2
|
||||
libssh2 1.2.4
|
||||
|
||||
This release includes the following changes:
|
||||
|
||||
o we've switched to using git for source code control
|
||||
o we're offering an alternative web site at http://libssh2.haxx.se/
|
||||
o the libssh2-devel mailing list moved to http://cool.haxx.se/
|
||||
o libssh2_poll() and libssh2_poll_channel_read() are now deprecated
|
||||
o a range of libssh2_knownhost_*() functions were added to the API to work
|
||||
with OpenSSH style known_hosts files etc
|
||||
o added libssh2_session_hostkey()
|
||||
o added an X11 forwarding example
|
||||
o the makefile now generate MSVS project files
|
||||
o
|
||||
|
||||
This release includes the following bugfixes:
|
||||
|
||||
o bad 0-return from libssh2_channel_read
|
||||
o failure to "drain" the transport data caused badness
|
||||
o memory leak in libssh2_sftp_shutdown()
|
||||
o fixed stroll() #if condition
|
||||
o build thread-safe on Solaris
|
||||
o error when including libssh2.h in two files on Windows fixed
|
||||
o custom memory function extra argument was wrong
|
||||
o transport now checks for and bail out on packets claing to be zero sized
|
||||
o fixed a number of compiler warnings
|
||||
o buildconf runs on Mac OS X
|
||||
o public headers includable on their own
|
||||
o bad debugdump() caused SIGSEGV at times (when libssh2_trace() was used)
|
||||
o possible data loss when send_existing() failed to send its buffer
|
||||
o passing FILE*s across DLL boundaries (OpenSSL) caused crashes on Windows
|
||||
o Resolve compile issues on Solaris x64 and UltraSPARC
|
||||
o Allow compiling with OpenSSL when AES isn't available
|
||||
o Fix Tru64 socklen_t compile issue with example/direct_tcpip.c
|
||||
|
||||
This release would not have looked like this without help, code, reports and
|
||||
advice from friends like these:
|
||||
|
||||
Simon Josefsson, Neil Gierman, Alexander Lamaison, Peter Stuge,
|
||||
Steven Van Ingelgem, Ben Kibbey, Francois Dupoux, Mark McPherson,
|
||||
Guenter Knauf, Yang Tse, Tor Arntsen, Jussi Mononen, Olivier Hervieu,
|
||||
Paul Veldkamp
|
||||
Dan Fandrich, Dave McCaldon, Peter Stuge
|
||||
|
||||
Thanks! (and sorry if I forgot to mention someone)
|
||||
|
5
TODO
5
TODO
@@ -8,9 +8,6 @@ Things TODO
|
||||
|
||||
* Provide a libssh2_scp_send() API for files larger than 4GB (32bit size)
|
||||
|
||||
* Convert the linked list code used all over to use the (new) generic linked
|
||||
list code. See the _libssh2_list_*() functions in src/misc.c
|
||||
|
||||
* Add more info to the man pages.
|
||||
|
||||
* Decrease the number of mallocs. Everywhere.
|
||||
@@ -21,6 +18,8 @@ Things TODO
|
||||
|
||||
* Fix all compiler warnings (some can't be done without API changes)
|
||||
|
||||
* Expose error messages sent by the server
|
||||
|
||||
At next SONAME bump
|
||||
===================
|
||||
|
||||
|
@@ -297,7 +297,7 @@ dnl Internal macro for CURL_CONFIGURE_REENTRANT.
|
||||
|
||||
AC_DEFUN([CURL_CHECK_NEED_REENTRANT_SYSTEM], [
|
||||
case $host in
|
||||
*-*-solaris*)
|
||||
*-*-solaris* | *-*-hpux*)
|
||||
tmp_need_reentrant="yes"
|
||||
;;
|
||||
*)
|
||||
|
@@ -22,6 +22,6 @@ ${AUTOHEADER:-autoheader}
|
||||
# copy the private libssh2_config.h.in to the examples dir so that
|
||||
# it can be included without pointing the include path to the private
|
||||
# source dir
|
||||
cp src/libssh2_config.h.in example/simple/config.h.in
|
||||
cp src/libssh2_config.h.in example/libssh2_config.h.in
|
||||
${AUTOCONF:-autoconf}
|
||||
${AUTOMAKE:-automake} --add-missing --copy
|
||||
|
@@ -1,8 +1,8 @@
|
||||
# AC_PREREQ(2.57)
|
||||
AC_INIT(libssh2, [-], libssh2-devel@lists.sourceforge.net)
|
||||
AC_INIT(libssh2, [-], libssh2-devel@cool.haxx.se)
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_SRCDIR([src])
|
||||
AC_CONFIG_HEADER([src/libssh2_config.h])
|
||||
AM_CONFIG_HEADER([src/libssh2_config.h example/libssh2_config.h])
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
dnl SED is needed by some of the tools
|
||||
@@ -41,6 +41,9 @@ case "$host" in
|
||||
;;
|
||||
*hpux*)
|
||||
;;
|
||||
*osf*)
|
||||
CFLAGS="$CFLAGS -D_POSIX_PII_SOCKET"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
@@ -162,11 +165,51 @@ AC_HELP_STRING([--disable-debug],[Disable debug options]),
|
||||
AC_MSG_RESULT(no)
|
||||
)
|
||||
|
||||
dnl ************************************************************
|
||||
dnl Enable hiding of internal symbols in library to reduce its size and
|
||||
dnl speed dynamic linking of applications. This currently is only supported
|
||||
dnl on gcc >= 4.0 and SunPro C.
|
||||
dnl
|
||||
AC_MSG_CHECKING([whether to enable hidden symbols in the library])
|
||||
AC_ARG_ENABLE(hidden-symbols,
|
||||
AC_HELP_STRING([--enable-hidden-symbols],[Hide internal symbols in library])
|
||||
AC_HELP_STRING([--disable-hidden-symbols],[Leave all symbols with default visibility in library]),
|
||||
[ case "$enableval" in
|
||||
no)
|
||||
AC_MSG_RESULT(no)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_CHECKING([whether $CC supports it])
|
||||
if test "$GCC" = yes ; then
|
||||
if $CC --help --verbose 2>&1 | grep fvisibility= > /dev/null ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(LIBSSH2_API, [__attribute__ ((visibility ("default")))], [to make a symbol visible])
|
||||
CFLAGS="$CFLAGS -fvisibility=hidden"
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
else
|
||||
dnl Test for SunPro cc
|
||||
if $CC 2>&1 | grep flags >/dev/null && $CC -flags | grep xldscope= >/dev/null ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(LIBSSH2_API, [__global], [to make a symbol visible])
|
||||
CFLAGS="$CFLAGS -xldscope=hidden"
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
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 sys/uio.h])
|
||||
AC_CHECK_HEADERS([sys/select.h sys/socket.h sys/ioctl.h sys/time.h])
|
||||
AC_CHECK_HEADERS([arpa/inet.h netinet/in.h])
|
||||
AC_CHECK_HEADERS([sys/un.h])
|
||||
|
||||
case $host in
|
||||
*-*-cygwin* | *-*-cegcc*)
|
||||
@@ -213,6 +256,6 @@ AC_CONFIG_FILES([Makefile
|
||||
src/Makefile
|
||||
tests/Makefile
|
||||
example/Makefile
|
||||
example/simple/Makefile
|
||||
docs/Makefile])
|
||||
docs/Makefile
|
||||
libssh2.pc])
|
||||
AC_OUTPUT
|
0
docs/.cvsignore → docs/.gitignore
vendored
0
docs/.cvsignore → docs/.gitignore
vendored
@@ -3,6 +3,13 @@
|
||||
EXTRA_DIST = template.3
|
||||
|
||||
dist_man_MANS = \
|
||||
libssh2_agent_connect.3 \
|
||||
libssh2_agent_disconnect.3 \
|
||||
libssh2_agent_free.3 \
|
||||
libssh2_agent_get_identity.3 \
|
||||
libssh2_agent_init.3 \
|
||||
libssh2_agent_list_identities.3 \
|
||||
libssh2_agent_userauth.3 \
|
||||
libssh2_banner_set.3 \
|
||||
libssh2_base64_decode.3 \
|
||||
libssh2_channel_close.3 \
|
||||
@@ -40,6 +47,7 @@ dist_man_MANS = \
|
||||
libssh2_knownhost_del.3 \
|
||||
libssh2_knownhost_get.3 \
|
||||
libssh2_knownhost_init.3 \
|
||||
libssh2_knownhost_free.3 \
|
||||
libssh2_knownhost_readfile.3 \
|
||||
libssh2_knownhost_readline.3 \
|
||||
libssh2_knownhost_writefile.3 \
|
||||
@@ -89,6 +97,7 @@ dist_man_MANS = \
|
||||
libssh2_sftp_unlink_ex.3 \
|
||||
libssh2_sftp_write.3 \
|
||||
libssh2_trace.3 \
|
||||
libssh2_trace_sethandler.3 \
|
||||
libssh2_userauth_authenticated.3 \
|
||||
libssh2_userauth_hostbased_fromfile_ex.3 \
|
||||
libssh2_userauth_keyboard_interactive_ex.3 \
|
||||
|
23
docs/libssh2_agent_connect.3
Normal file
23
docs/libssh2_agent_connect.3
Normal file
@@ -0,0 +1,23 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2009 by Daiki Ueno
|
||||
.\"
|
||||
.TH libssh2_agent_connect 3 "23 Dec 2009" "libssh2 1.2" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_agent_connect - connect to an ssh-agent
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int libssh2_agent_connect(LIBSSH2_AGENT *agent);
|
||||
.SH DESCRIPTION
|
||||
Connect to an ssh-agent running on the system.
|
||||
|
||||
Call \fBlibssh2_agent_disconnect(3)\fP to close the connection after
|
||||
you're doing using it.
|
||||
.SH RETURN VALUE
|
||||
Returns 0 if succeeded, or a negative value for error.
|
||||
.SH AVAILABILITY
|
||||
Added in libssh2 1.2
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_agent_init(3)
|
||||
.BR libssh2_agent_disconnect(3)
|
||||
|
20
docs/libssh2_agent_disconnect.3
Normal file
20
docs/libssh2_agent_disconnect.3
Normal file
@@ -0,0 +1,20 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2009 by Daiki Ueno
|
||||
.\"
|
||||
.TH libssh2_agent_disconnect 3 "23 Dec 2009" "libssh2 1.2" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_agent_disconnect - close a connection to an ssh-agent
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int libssh2_agent_disconnect(LIBSSH2_AGENT *agent);
|
||||
.SH DESCRIPTION
|
||||
Close a connection to an ssh-agent.
|
||||
|
||||
.SH RETURN VALUE
|
||||
Returns 0 if succeeded, or a negative value for error.
|
||||
.SH AVAILABILITY
|
||||
Added in libssh2 1.2
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_agent_connect(3)
|
||||
.BR libssh2_agent_free(3)
|
20
docs/libssh2_agent_free.3
Normal file
20
docs/libssh2_agent_free.3
Normal file
@@ -0,0 +1,20 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2009 by Daiki Ueno
|
||||
.\"
|
||||
.TH libssh2_agent_free 3 "28 May 2009" "libssh2 1.2" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_agent_free - free an ssh-agent handle
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
void libssh2_agent_free(LIBSSH2_AGENT *agent);
|
||||
.SH DESCRIPTION
|
||||
Free an ssh-agent handle. This function also frees the internal
|
||||
collection of public keys.
|
||||
.SH RETURN VALUE
|
||||
None.
|
||||
.SH AVAILABILITY
|
||||
Added in libssh2 1.2
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_agent_init(3)
|
||||
.BR libssh2_agent_disconnect(3)
|
34
docs/libssh2_agent_get_identity.3
Normal file
34
docs/libssh2_agent_get_identity.3
Normal file
@@ -0,0 +1,34 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2009 by Daiki Ueno
|
||||
.\"
|
||||
.TH libssh2_agent_get_identity 3 "23 Dec 2009" "libssh2 1.2" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_agent_get_identity - get a public key off the collection of public keys managed by ssh-agent
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int libssh2_agent_get_identity(LIBSSH2_AGENT *agent,
|
||||
struct libssh2_agent_publickey **store,
|
||||
struct libssh2_agent_publickey *prev);
|
||||
.SH DESCRIPTION
|
||||
\fIlibssh2_agent_get_identity(3)\fP allows an application to iterate
|
||||
over all public keys in the collection managed by ssh-agent.
|
||||
|
||||
\fIstore\fP should point to a pointer that gets filled in to point to the
|
||||
public key data.
|
||||
|
||||
\fIprev\fP is a pointer to a previous 'struct libssh2_agent_publickey'
|
||||
as returned by a previous invoke of this function, or NULL to get the
|
||||
first entry in the internal collection.
|
||||
.SH RETURN VALUE
|
||||
Returns 0 if everything is fine and information about a host was stored in
|
||||
the \fIstore\fP struct.
|
||||
|
||||
Returns 1 if it reached the end of public keys.
|
||||
|
||||
Returns negative values for error
|
||||
.SH AVAILABILITY
|
||||
Added in libssh2 1.2
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_agent_list_identities(3)
|
||||
.BR libssh2_agent_userauth(3)
|
26
docs/libssh2_agent_init.3
Normal file
26
docs/libssh2_agent_init.3
Normal file
@@ -0,0 +1,26 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2009 by Daiki Ueno
|
||||
.\"
|
||||
.TH libssh2_agent_init 3 "23 Dec 2009" "libssh2 1.2" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_agent_init - init an ssh-agent handle
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
LIBSSH2_AGENT *libssh2_agent_init(LIBSSH2_SESSION *session);
|
||||
.SH DESCRIPTION
|
||||
Init an ssh-agent handle. Returns the handle to an internal
|
||||
representation of an ssh-agent connection. After the successful
|
||||
initialization, an application can call \fBlibssh2_agent_connect(3)\fP
|
||||
to connect to a running ssh-agent.
|
||||
|
||||
Call \fBlibssh2_agent_free(3)\fP to free the handle again after you're
|
||||
doing using it.
|
||||
.SH RETURN VALUE
|
||||
Returns a handle pointer or NULL if something went wrong. The returned handle
|
||||
is used as input to all other ssh-agent related functions libssh2 provides.
|
||||
.SH AVAILABILITY
|
||||
Added in libssh2 1.2
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_agent_connect(3)
|
||||
.BR libssh2_agent_free(3)
|
24
docs/libssh2_agent_list_identities.3
Normal file
24
docs/libssh2_agent_list_identities.3
Normal file
@@ -0,0 +1,24 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2009 by Daiki Ueno
|
||||
.\"
|
||||
.TH libssh2_agent_list_identities 3 "23 Dec 2009" "libssh2 1.2" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_agent_list_identities - request an ssh-agent to list of public keys.
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int libssh2_agent_list_identities(LIBSSH2_AGENT *agent);
|
||||
.SH DESCRIPTION
|
||||
Request an ssh-agent to list of public keys, and stores them in the
|
||||
internal collection of the handle. Call
|
||||
\fIlibssh2_agent_get_identity(3)\fP to get a public key off the
|
||||
collection.
|
||||
|
||||
.SH RETURN VALUE
|
||||
Returns 0 if succeeded, or a negative value for error.
|
||||
.SH AVAILABILITY
|
||||
Added in libssh2 1.2
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_agent_connect(3)
|
||||
.BR libssh2_agent_get_identity(3)
|
||||
|
29
docs/libssh2_agent_userauth.3
Normal file
29
docs/libssh2_agent_userauth.3
Normal file
@@ -0,0 +1,29 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2009 by Daiki Ueno
|
||||
.\"
|
||||
.TH libssh2_agent_userauth 3 "23 Dec 2009" "libssh2 1.2" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_agent_userauth - authenticate a session with a public key, with the help of ssh-agent
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int libssh2_agent_userauth(LIBSSH2_AGENT *agent,
|
||||
const char *username,
|
||||
struct libssh2_agent_publickey *identity);
|
||||
.SH DESCRIPTION
|
||||
\fIagent\fP - ssh-agent handle as returned by
|
||||
.BR libssh2_agent_init(3)
|
||||
|
||||
\fIusername\fP - Remote user name to authenticate as.
|
||||
|
||||
\fIidentity\fP - Public key to authenticate with, as returned by
|
||||
.BR libssh2_agent_get_identity(3)
|
||||
|
||||
Attempt public key authentication with the help of ssh-agent.
|
||||
.SH RETURN VALUE
|
||||
Returns 0 if succeeded, or a negative value for error.
|
||||
.SH AVAILABILITY
|
||||
Added in libssh2 1.2
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_agent_init(3)
|
||||
.BR libssh2_agent_get_identity(3)
|
@@ -35,6 +35,9 @@ macros.
|
||||
Actual number of bytes read or negative on failure. It returns
|
||||
LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
|
||||
LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
|
||||
Note that a return value of zero (0) can in fact be a legitimate value and
|
||||
only signals that no payload data was read. It is not an error.
|
||||
.SH ERRORS
|
||||
\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
|
||||
|
||||
|
20
docs/libssh2_knownhost_free.3
Normal file
20
docs/libssh2_knownhost_free.3
Normal file
@@ -0,0 +1,20 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2009 by Daniel Stenberg
|
||||
.\"
|
||||
.TH libssh2_knownhost_free 3 "28 May 2009" "libssh2 1.2" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_knownhost_free - free a collection of known hosts
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
void libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts);
|
||||
.SH DESCRIPTION
|
||||
Free a collection of known hosts.
|
||||
.SH RETURN VALUE
|
||||
None.
|
||||
.SH AVAILABILITY
|
||||
Added in libssh2 1.2
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_knownhost_init(3)
|
||||
.BR libssh2_knownhost_add(3)
|
||||
.BR libssh2_knownhost_check(3)
|
@@ -11,6 +11,9 @@ LIBSSH2_KNOWNHOSTS *libssh2_knownhost_init(LIBSSH2_SESSION *session);
|
||||
.SH DESCRIPTION
|
||||
Init a collection of known hosts for this session. Returns the handle to an
|
||||
internal representation of a known host collection.
|
||||
|
||||
Call \fBlibssh2_knownhost_free(3)\fP to free the collection again after you're
|
||||
doing using it.
|
||||
.SH RETURN VALUE
|
||||
Returns a handle pointer or NULL if something went wrong. The returned handle
|
||||
is used as input to all other known host related functions libssh2 provides.
|
||||
|
@@ -13,7 +13,8 @@ libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb);
|
||||
\fIsession\fP - Session instance as returned by
|
||||
.BR libssh2_session_init_ex(3)
|
||||
|
||||
\fIpath\fP - Full path and filename of file to transfer
|
||||
\fIpath\fP - Full path and filename of file to transfer. That is the remote
|
||||
file name.
|
||||
|
||||
\fIsb\fP - Populated with remote file's size, mode, mtime, and atime
|
||||
|
||||
|
@@ -12,7 +12,8 @@ libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t
|
||||
\fIsession\fP - Session instance as returned by
|
||||
.BR libssh2_session_init_ex(3)
|
||||
|
||||
\fIpath\fP - Full path and filename of file to transfer
|
||||
\fIpath\fP - Full path and filename of file to transfer to. That is the remote
|
||||
file name.
|
||||
|
||||
\fImode\fP - File access mode to create file with
|
||||
|
||||
|
@@ -11,21 +11,26 @@ ssize_t
|
||||
libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, size_t count);
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fIhandle\fP - SFTP File Handle as returned by
|
||||
.BR libssh2_sftp_open_ex(3)
|
||||
\fIhandle\fP - SFTP file handle as returned by \fIlibssh2_sftp_open_ex(3)\fP.
|
||||
|
||||
\fIbuffer\fP - Pre-initialized data buffer to write to the LIBSSH2_SFTP_HANDLE.
|
||||
\fIbuffer\fP - points to the data to send off
|
||||
|
||||
\fIcount\fP - Number of bytes from buffer to write. Note that it may not
|
||||
be possible to write all bytes as requested.
|
||||
|
||||
Write a block of data to a LIBSSH2_SFTP_HANDLE. This method is modeled after the POSIX write() function and uses the same calling semantics.
|
||||
\fIcount\fP - Number of bytes from 'buffer' to write. Note that it may not be
|
||||
possible to write all bytes as requested.
|
||||
|
||||
\fBlibssh2_sftp_write(3)\fP writes a block of data to the SFTP server. This
|
||||
method is modeled after the POSIX write() function and uses the same calling
|
||||
semantics.
|
||||
.SH RETURN VALUE
|
||||
Actual number of bytes written or negative on failure. It returns
|
||||
LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
|
||||
LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
Actual number of bytes written or negative on failure.
|
||||
|
||||
If used in non-blocking mode, it returns LIBSSH2_ERROR_EAGAIN when it would
|
||||
otherwise block. While LIBSSH2_ERROR_EAGAIN is a negative number, it isn't
|
||||
really a failure per se.
|
||||
|
||||
If this function returns 0 (zero) it should not be considered an error, but
|
||||
simply that there was no error but yet no payload data got sent to the other
|
||||
end.
|
||||
.SH ERRORS
|
||||
\fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed.
|
||||
|
||||
@@ -36,6 +41,5 @@ LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was
|
||||
received on the socket, or an SFTP operation caused an errorcode to
|
||||
be returned by the server.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_sftp_open_ex(3)
|
||||
|
@@ -6,16 +6,18 @@ libssh2_trace - enable debug info from inside libssh2
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
void libssh2_trace(int bitmask);
|
||||
void libssh2_trace(LIBSSH2_SESSION *session, int bitmask);
|
||||
|
||||
.SH DESCRIPTION
|
||||
This is a function present in the library that can be used to get debug info
|
||||
from within libssh2 when it is running. Helpful when trying to trace or debug
|
||||
behaviors. This function has no effect unless libssh2 was built to support
|
||||
this option, and a typical "release build" might not.
|
||||
behaviors. Note that this function has no effect unless libssh2 was built to
|
||||
support tracing! It is usually disabled in release builds.
|
||||
|
||||
\fBbitmask\fP can be set to none, one or more of these bits:
|
||||
\fBbitmask\fP can be set to the logical OR of none, one or more of these:
|
||||
.RS
|
||||
.IP LIBSSH2_TRACE_SOCKET
|
||||
Socket low-level debugging
|
||||
.IP LIBSSH2_TRACE_TRANS
|
||||
Transport layer debugging
|
||||
.IP LIBSSH2_TRACE_KEX
|
||||
|
30
docs/libssh2_trace_sethandler.3
Normal file
30
docs/libssh2_trace_sethandler.3
Normal file
@@ -0,0 +1,30 @@
|
||||
.\" $Id: libssh2_trace_sethandler.3,v 1.1 2008/12/26 07:46:45 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_trace_sethandler 3 "15 Jan 2010" "libssh2 1.2.3" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_trace_sethandler - set a trace output handler
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
#include <libssh2.h>
|
||||
|
||||
typedef void (*libssh2_trace_handler_func)(LIBSSH2_SESSION *session,
|
||||
void* context,
|
||||
const char *data,
|
||||
size_t length);
|
||||
|
||||
int libssh2_trace_sethandler(LIBSSH2_SESSION *session,
|
||||
void* context,
|
||||
libssh2_trace_handler_func callback);
|
||||
.SH DESCRIPTION
|
||||
libssh2_trace_sethandler installs a trace output handler for your application.
|
||||
By default, when tracing has been switched on via a call to libssh2_trace(),
|
||||
all output is written to stderr. By calling this method and passing a
|
||||
function pointer that matches the libssh2_trace_handler_func prototype,
|
||||
libssh2 will call back as it generates trace output. This can be used to
|
||||
capture the trace output and put it into a log file or diagnostic window.
|
||||
This function has no effect unless libssh2 was built to support this option,
|
||||
and a typical "release build" might not.
|
||||
|
||||
\fBcontext\fP can be used to pass arbitrary user defined data back into the callback when invoked.
|
||||
.SH AVAILABILITY
|
||||
Added in libssh2 version 1.2.3
|
@@ -39,5 +39,7 @@ LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
|
||||
\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
|
||||
|
||||
\fLIBSSH2_ERROR_AUTHENTICATION_FAILED\fP - failed, invalid username/password or public/private key.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_session_init_ex(3)
|
||||
|
@@ -46,5 +46,7 @@ LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
|
||||
\fILIBSSH2_ERROR_PASSWORD_EXPIRED\fP -
|
||||
|
||||
\fLIBSSH2_ERROR_AUTHENTICATION_FAILED\fP - failed, invalid username/password or public/private key.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_session_init_ex(3)
|
||||
|
@@ -40,12 +40,11 @@ LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
|
||||
\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP -
|
||||
|
||||
\fILIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED\fP - >The username/public key
|
||||
\fILIBSSH2_ERROR_PUBLICKEY_UNVERIFIED\fP - The username/public key
|
||||
combination was invalid.
|
||||
|
||||
\fILIBSSH2_ERROR_PUBLICKEY_UNVERIFIED\fP - The username/public key
|
||||
combination was invalid, or the signature for the supplied public
|
||||
key was invalid.
|
||||
\fILIBSSH2_ERROR_AUTHENTICATION_FAILED\fP - Authentication using the supplied
|
||||
public key was not accepted.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_session_init_ex(3)
|
||||
|
@@ -1,2 +0,0 @@
|
||||
Makefile
|
||||
Makefile.in
|
@@ -1,5 +1,8 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
*.gcno
|
||||
*.gcda
|
||||
direct_tcpip
|
||||
scp
|
||||
scp_nonblock
|
||||
scp_write
|
||||
@@ -16,3 +19,7 @@ sftp_write
|
||||
sftp_write_nonblock
|
||||
config.h.in
|
||||
ssh2_exec
|
||||
ssh2_agent
|
||||
libssh2_config.h
|
||||
libssh2_config.h.in
|
||||
stamp-h2
|
@@ -1,2 +1,16 @@
|
||||
AUTOMAKE_OPTIONS = foreign nostdinc
|
||||
SUBDIRS = simple
|
||||
|
||||
EXTRA_DIST = libssh2_config.h.in
|
||||
|
||||
# samples
|
||||
noinst_PROGRAMS = direct_tcpip ssh2 \
|
||||
scp scp_nonblock \
|
||||
scp_write scp_write_nonblock \
|
||||
sftp sftp_nonblock \
|
||||
sftp_write sftp_write_nonblock \
|
||||
sftp_mkdir sftp_mkdir_nonblock \
|
||||
sftp_RW_nonblock \
|
||||
sftpdir sftpdir_nonblock ssh2_exec ssh2_agent
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/example
|
||||
LDADD = $(top_builddir)/src/libssh2.la
|
||||
|
275
example/direct_tcpip.c
Normal file
275
example/direct_tcpip.c
Normal file
@@ -0,0 +1,275 @@
|
||||
#include <libssh2.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef INADDR_NONE
|
||||
#define INADDR_NONE (in_addr_t)-1
|
||||
#endif
|
||||
|
||||
const char *keyfile1 = "/home/username/.ssh/id_rsa.pub";
|
||||
const char *keyfile2 = "/home/username/.ssh/id_rsa";
|
||||
const char *username = "username";
|
||||
const char *password = "";
|
||||
|
||||
const char *server_ip = "127.0.0.1";
|
||||
|
||||
const char *local_listenip = "127.0.0.1";
|
||||
unsigned int local_listenport = 2222;
|
||||
|
||||
const char *remote_desthost = "localhost"; /* resolved by the server */
|
||||
unsigned int remote_destport = 22;
|
||||
|
||||
enum {
|
||||
AUTH_NONE = 0,
|
||||
AUTH_PASSWORD,
|
||||
AUTH_PUBLICKEY
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int rc, sock = -1, listensock = -1, forwardsock = -1, i, auth = AUTH_NONE;
|
||||
struct sockaddr_in sin;
|
||||
socklen_t sinlen;
|
||||
const char *fingerprint;
|
||||
char *userauthlist;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel = NULL;
|
||||
const char *shost;
|
||||
unsigned int sport;
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
ssize_t len, wr;
|
||||
char buf[16384];
|
||||
|
||||
#ifdef WIN32
|
||||
char sockopt;
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(MAKEWORD(2,0), &wsadata);
|
||||
#else
|
||||
int sockopt;
|
||||
#endif
|
||||
|
||||
if (argc > 1)
|
||||
server_ip = argv[1];
|
||||
if (argc > 2)
|
||||
username = argv[2];
|
||||
if (argc > 3)
|
||||
password = argv[3];
|
||||
if (argc > 4)
|
||||
local_listenip = argv[4];
|
||||
if (argc > 5)
|
||||
local_listenport = atoi(argv[5]);
|
||||
if (argc > 6)
|
||||
remote_desthost = argv[6];
|
||||
if (argc > 7)
|
||||
remote_destport = atoi(argv[7]);
|
||||
|
||||
/* Connect to SSH server */
|
||||
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
sin.sin_family = AF_INET;
|
||||
if (INADDR_NONE == (sin.sin_addr.s_addr = inet_addr(server_ip))) {
|
||||
perror("inet_addr");
|
||||
return -1;
|
||||
}
|
||||
sin.sin_port = htons(22);
|
||||
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) {
|
||||
fprintf(stderr, "Could not initialize SSH session!\n");
|
||||
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, "Error when starting up 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_SHA1);
|
||||
fprintf(stderr, "Fingerprint: ");
|
||||
for(i = 0; i < 20; i++)
|
||||
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
/* check what authentication methods are available */
|
||||
userauthlist = libssh2_userauth_list(session, username, strlen(username));
|
||||
printf("Authentication methods: %s\n", userauthlist);
|
||||
if (strstr(userauthlist, "password"))
|
||||
auth |= AUTH_PASSWORD;
|
||||
if (strstr(userauthlist, "publickey"))
|
||||
auth |= AUTH_PUBLICKEY;
|
||||
|
||||
/* check for options */
|
||||
if(argc > 8) {
|
||||
if ((auth & AUTH_PASSWORD) && !strcasecmp(argv[8], "-p"))
|
||||
auth = AUTH_PASSWORD;
|
||||
if ((auth & AUTH_PUBLICKEY) && !strcasecmp(argv[8], "-k"))
|
||||
auth = AUTH_PUBLICKEY;
|
||||
}
|
||||
|
||||
if (auth & AUTH_PASSWORD) {
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
fprintf(stderr, "Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else if (auth & AUTH_PUBLICKEY) {
|
||||
if (libssh2_userauth_publickey_fromfile(session, username, keyfile1, keyfile2, password)) {
|
||||
printf("\tAuthentication by public key failed!\n");
|
||||
goto shutdown;
|
||||
}
|
||||
printf("\tAuthentication by public key succeeded.\n");
|
||||
} else {
|
||||
printf("No supported authentication methods found!\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
listensock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(local_listenport);
|
||||
if (INADDR_NONE == (sin.sin_addr.s_addr = inet_addr(local_listenip))) {
|
||||
perror("inet_addr");
|
||||
goto shutdown;
|
||||
}
|
||||
sockopt = 1;
|
||||
setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
|
||||
sinlen=sizeof(sin);
|
||||
if (-1 == bind(listensock, (struct sockaddr *)&sin, sinlen)) {
|
||||
perror("bind");
|
||||
goto shutdown;
|
||||
}
|
||||
if (-1 == listen(listensock, 2)) {
|
||||
perror("listen");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
printf("Waiting for TCP connection on %s:%d...\n",
|
||||
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
|
||||
|
||||
forwardsock = accept(listensock, (struct sockaddr *)&sin, &sinlen);
|
||||
if (-1 == forwardsock) {
|
||||
perror("accept");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
shost = inet_ntoa(sin.sin_addr);
|
||||
sport = ntohs(sin.sin_port);
|
||||
|
||||
printf("Forwarding connection from %s:%d here to remote %s:%d\n", shost,
|
||||
sport, remote_desthost, remote_destport);
|
||||
|
||||
channel = libssh2_channel_direct_tcpip_ex(session, remote_desthost,
|
||||
remote_destport, shost, sport);
|
||||
if (!channel) {
|
||||
fprintf(stderr, "Could not open the direct-tcpip channel!\n");
|
||||
fprintf(stderr, "(Note that this can be a problem at the server! Please review the server logs.)\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/* Must use non-blocking IO hereafter due to the current libssh2 API */
|
||||
libssh2_session_set_blocking(session, 0);
|
||||
|
||||
while (1) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(forwardsock, &fds);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 100000;
|
||||
rc = select(forwardsock + 1, &fds, NULL, NULL, &tv);
|
||||
if (-1 == rc) {
|
||||
perror("select");
|
||||
goto shutdown;
|
||||
}
|
||||
if (rc && FD_ISSET(forwardsock, &fds)) {
|
||||
len = recv(forwardsock, buf, sizeof(buf), 0);
|
||||
if (len < 0) {
|
||||
perror("read");
|
||||
goto shutdown;
|
||||
} else if (0 == len) {
|
||||
printf("The client at %s:%d disconnected!\n", shost, sport);
|
||||
goto shutdown;
|
||||
}
|
||||
wr = 0;
|
||||
do {
|
||||
i = libssh2_channel_write(channel, buf, len);
|
||||
if (i < 0) {
|
||||
fprintf(stderr, "libssh2_channel_write: %d\n", i);
|
||||
goto shutdown;
|
||||
}
|
||||
wr += i;
|
||||
} while(i > 0 && wr < len);
|
||||
}
|
||||
while (1) {
|
||||
len = libssh2_channel_read(channel, buf, sizeof(buf));
|
||||
if (LIBSSH2_ERROR_EAGAIN == len)
|
||||
break;
|
||||
else if (len < 0) {
|
||||
fprintf(stderr, "libssh2_channel_read: %d", (int)len);
|
||||
goto shutdown;
|
||||
}
|
||||
wr = 0;
|
||||
while (wr < len) {
|
||||
i = send(forwardsock, buf + wr, len - wr, 0);
|
||||
if (i <= 0) {
|
||||
perror("write");
|
||||
goto shutdown;
|
||||
}
|
||||
wr += i;
|
||||
}
|
||||
if (libssh2_channel_eof(channel)) {
|
||||
printf("The server at %s:%d disconnected!\n",
|
||||
remote_desthost, remote_destport);
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shutdown:
|
||||
#ifdef WIN32
|
||||
closesocket(forwardsock);
|
||||
closesocket(listensock);
|
||||
#else
|
||||
close(forwardsock);
|
||||
close(listensock);
|
||||
#endif
|
||||
if (channel)
|
||||
libssh2_channel_free(channel);
|
||||
libssh2_session_disconnect(session, "Client disconnecting normally");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
closesocket(sock);
|
||||
#else
|
||||
close(sock);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
@@ -10,12 +10,12 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -103,9 +103,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
fprintf(stderr, "Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
@@ -15,11 +15,14 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
@@ -157,9 +160,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
fprintf(stderr, "Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
@@ -10,12 +10,12 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -47,7 +47,7 @@ int main(int argc, char *argv[])
|
||||
FILE *local;
|
||||
int rc;
|
||||
char mem[1024];
|
||||
size_t nread;
|
||||
size_t nread, sent;
|
||||
char *ptr;
|
||||
struct stat fileinfo;
|
||||
|
||||
@@ -118,9 +118,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
fprintf(stderr, "Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
@@ -142,8 +142,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
/* Request a file via SCP */
|
||||
channel = libssh2_scp_send(session, scppath, 0x1FF & fileinfo.st_mode,
|
||||
/* Send a file via scp. The mode parameter must only have permissions! */
|
||||
channel = libssh2_scp_send(session, scppath, fileinfo.st_mode & 0777,
|
||||
(unsigned long)fileinfo.st_size);
|
||||
|
||||
if (!channel) {
|
||||
@@ -159,13 +159,20 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
ptr = mem;
|
||||
sent = 0;
|
||||
|
||||
do {
|
||||
/* write data in a loop until we block */
|
||||
/* write the same data over and over, until error or completion */
|
||||
rc = libssh2_channel_write(channel, ptr, nread);
|
||||
ptr += rc;
|
||||
nread -= nread;
|
||||
} while (rc > 0);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "ERROR %d\n", rc);
|
||||
} else {
|
||||
/* rc indicates how many bytes were written this time */
|
||||
sent += rc;
|
||||
}
|
||||
} while (rc > 0 && sent < nread);
|
||||
ptr += sent;
|
||||
nread -= sent;
|
||||
} while (1);
|
||||
|
||||
fprintf(stderr, "Sending EOF\n");
|
@@ -11,12 +11,12 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -51,7 +51,7 @@ int main(int argc, char *argv[])
|
||||
long flag = 1;
|
||||
#endif
|
||||
char mem[1024];
|
||||
size_t nread;
|
||||
size_t nread, sent;
|
||||
char *ptr;
|
||||
struct stat fileinfo;
|
||||
|
||||
@@ -126,9 +126,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
fprintf(stderr, "Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
@@ -153,9 +153,9 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
/* Request a file via SCP */
|
||||
/* Send a file via scp. The mode parameter must only have permissions! */
|
||||
do {
|
||||
channel = libssh2_scp_send(session, scppath, 0x1FF & fileinfo.st_mode,
|
||||
channel = libssh2_scp_send(session, scppath, fileinfo.st_mode & 0777,
|
||||
(unsigned long)fileinfo.st_size);
|
||||
|
||||
if ((!channel) && (libssh2_session_last_errno(session) !=
|
||||
@@ -176,17 +176,22 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
ptr = mem;
|
||||
sent = 0;
|
||||
|
||||
do {
|
||||
/* write data in a loop until we block */
|
||||
while ((rc = libssh2_channel_write(channel, ptr, nread)) ==
|
||||
LIBSSH2_ERROR_EAGAIN);
|
||||
if (rc < 0) {
|
||||
/* write the same data over and over, until error or completion */
|
||||
rc = libssh2_channel_write(channel, ptr, nread);
|
||||
if (LIBSSH2_ERROR_EAGAIN == rc) { /* must loop around */
|
||||
continue;
|
||||
} else if (rc < 0) {
|
||||
fprintf(stderr, "ERROR %d\n", rc);
|
||||
} else {
|
||||
/* rc indicates how many bytes were written this time */
|
||||
sent += rc;
|
||||
}
|
||||
ptr += rc;
|
||||
nread -= rc;
|
||||
} while (nread > 0);
|
||||
} while (rc > 0 && sent < nread);
|
||||
ptr += sent;
|
||||
nread -= sent;
|
||||
} while (1);
|
||||
|
||||
fprintf(stderr, "Sending EOF\n");
|
@@ -16,12 +16,12 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -136,9 +136,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
fprintf(stderr, "Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
@@ -16,11 +16,14 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
@@ -106,9 +109,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
@@ -16,12 +16,12 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -105,9 +105,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
@@ -16,12 +16,12 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -108,9 +108,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
@@ -16,11 +16,14 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
@@ -158,9 +161,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
fprintf(stderr, "Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
@@ -16,12 +16,12 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -123,9 +123,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
@@ -16,12 +16,12 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -127,9 +127,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
@@ -16,12 +16,12 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -105,9 +105,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
@@ -16,12 +16,12 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -111,9 +111,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
@@ -1,21 +0,0 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
.deps
|
||||
.libs
|
||||
*.gcno
|
||||
*.gcda
|
||||
scp
|
||||
scp_nonblock
|
||||
scp_write
|
||||
scp_write_nonblock
|
||||
sftp
|
||||
sftp_nonblock
|
||||
sftpdir
|
||||
sftpdir_nonblock
|
||||
ssh2
|
||||
sftp_RW_nonblock
|
||||
sftp_mkdir
|
||||
sftp_mkdir_nonblock
|
||||
sftp_write
|
||||
sftp_write_nonblock
|
||||
|
@@ -1,16 +0,0 @@
|
||||
AUTOMAKE_OPTIONS = foreign nostdinc
|
||||
|
||||
# samples
|
||||
noinst_PROGRAMS = ssh2 \
|
||||
scp scp_nonblock \
|
||||
scp_write scp_write_nonblock \
|
||||
sftp sftp_nonblock \
|
||||
sftp_write sftp_write_nonblock \
|
||||
sftp_mkdir sftp_mkdir_nonblock \
|
||||
sftp_RW_nonblock \
|
||||
sftpdir sftpdir_nonblock ssh2_exec
|
||||
|
||||
# the examples need the $(top_builddir)/src since when building outside of the
|
||||
# source dir they still need to reach the libssh2_config.h header
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include -I$(top_builddir)/src
|
||||
LDADD = $(top_builddir)/src/libssh2.la
|
@@ -19,12 +19,12 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -121,9 +121,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
229
example/ssh2_agent.c
Normal file
229
example/ssh2_agent.c
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Sample showing how to do SSH2 connect using ssh-agent.
|
||||
*
|
||||
* The sample code has default values for host name, user name:
|
||||
*
|
||||
* "ssh2_agent host user"
|
||||
*/
|
||||
|
||||
#include "libssh2_config.h"
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
# include <windows.h>
|
||||
#endif
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
# ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
const char *username="username";
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned long hostaddr;
|
||||
int sock = -1, i, j, rc;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
char *userauthlist;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
LIBSSH2_AGENT *agent = NULL;
|
||||
struct libssh2_agent_publickey *identity, *prev_identity = NULL;
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(MAKEWORD(2,0), &wsadata);
|
||||
#endif
|
||||
|
||||
if (argc > 1) {
|
||||
hostaddr = inet_addr(argv[1]);
|
||||
} else {
|
||||
hostaddr = htonl(0x7F000001);
|
||||
}
|
||||
|
||||
if(argc > 2) {
|
||||
username = argv[2];
|
||||
}
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost". Your code is
|
||||
* responsible for creating the socket establishing the connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock == -1) {
|
||||
fprintf(stderr, "failed to create socket!\n");
|
||||
rc = 1;
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = hostaddr;
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* check what authentication methods are available */
|
||||
userauthlist = libssh2_userauth_list(session, username, strlen(username));
|
||||
printf("Authentication methods: %s\n", userauthlist);
|
||||
if (strstr(userauthlist, "publickey") == NULL) {
|
||||
fprintf(stderr, "\"publickey\" authentication is not supported\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/* Connect to the ssh-agent */
|
||||
agent = libssh2_agent_init(session);
|
||||
if (!agent) {
|
||||
fprintf(stderr, "Failure initializing ssh-agent support\n");
|
||||
rc = 1;
|
||||
goto shutdown;
|
||||
}
|
||||
if (libssh2_agent_connect(agent)) {
|
||||
fprintf(stderr, "Failure connecting to ssh-agent\n");
|
||||
rc = 1;
|
||||
goto shutdown;
|
||||
}
|
||||
if (libssh2_agent_list_identities(agent)) {
|
||||
fprintf(stderr, "Failure requesting identities to ssh-agent\n");
|
||||
rc = 1;
|
||||
goto shutdown;
|
||||
}
|
||||
while (1) {
|
||||
rc = libssh2_agent_get_identity(agent, &identity, prev_identity);
|
||||
if (rc == 1)
|
||||
break;
|
||||
if (rc < 0) {
|
||||
fprintf(stderr,
|
||||
"Failure obtaining identity from ssh-agent support\n");
|
||||
rc = 1;
|
||||
goto shutdown;
|
||||
}
|
||||
if (libssh2_agent_userauth(agent, username, identity)) {
|
||||
printf("\tAuthentication with username %s and "
|
||||
"public key %s failed!\n",
|
||||
username, identity->comment);
|
||||
} else {
|
||||
printf("\tAuthentication with username %s and "
|
||||
"public key %s succeeded!\n",
|
||||
username, identity->comment);
|
||||
break;
|
||||
}
|
||||
prev_identity = identity;
|
||||
}
|
||||
if (rc) {
|
||||
fprintf(stderr, "Couldn't continue authentication\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/* 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_SHA1);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 20; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* 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, "FOO", "bar");
|
||||
|
||||
/* Request a terminal with 'vanilla' terminal emulation
|
||||
* See /etc/termcap for more options
|
||||
*/
|
||||
if (libssh2_channel_request_pty(channel, "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_agent_disconnect(agent);
|
||||
libssh2_agent_free(agent);
|
||||
|
||||
libssh2_session_disconnect(session,
|
||||
"Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
if (sock != -1) {
|
||||
#ifdef WIN32
|
||||
closesocket(sock);
|
||||
#else
|
||||
close(sock);
|
||||
#endif
|
||||
}
|
||||
|
||||
printf("all done!\n");
|
||||
return rc;
|
||||
}
|
@@ -18,11 +18,14 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
@@ -84,17 +84,17 @@ typedef unsigned long long libssh2_uint64_t;
|
||||
typedef long long libssh2_int64_t;
|
||||
#endif
|
||||
|
||||
/* We use underscore instead of dash when appending CVS in dev versions just
|
||||
/* We use underscore instead of dash when appending DEV in dev versions just
|
||||
to make the BANNER define (used by src/session.c) be a valid SSH
|
||||
banner. Release versions have no appended strings and may of course not
|
||||
have dashes either. */
|
||||
#define LIBSSH2_VERSION "1.1.1_CVS"
|
||||
#define LIBSSH2_VERSION "1.2.4_DEV"
|
||||
|
||||
/* The numeric version number is also available "in parts" by using these
|
||||
defines: */
|
||||
#define LIBSSH2_VERSION_MAJOR 1
|
||||
#define LIBSSH2_VERSION_MINOR 1
|
||||
#define LIBSSH2_VERSION_PATCH 1
|
||||
#define LIBSSH2_VERSION_MINOR 2
|
||||
#define LIBSSH2_VERSION_PATCH 4
|
||||
|
||||
/* This is the numeric version of the libssh2 version number, meant for easier
|
||||
parsing and comparions by programs. The LIBSSH2_VERSION_NUM define will
|
||||
@@ -111,18 +111,18 @@ typedef long long libssh2_int64_t;
|
||||
and it is always a greater number in a more recent release. It makes
|
||||
comparisons with greater than and less than work.
|
||||
*/
|
||||
#define LIBSSH2_VERSION_NUM 0x010101
|
||||
#define LIBSSH2_VERSION_NUM 0x010204
|
||||
|
||||
/*
|
||||
* This is the date and time when the full source package was created. The
|
||||
* timestamp is not stored in CVS, as the timestamp is properly set in the
|
||||
* tarballs by the maketgz script.
|
||||
* timestamp is not stored in the source code repo, as the timestamp is
|
||||
* properly set in the tarballs by the maketgz script.
|
||||
*
|
||||
* The format of the date should follow this template:
|
||||
*
|
||||
* "Mon Feb 12 11:35:33 UTC 2007"
|
||||
*/
|
||||
#define LIBSSH2_TIMESTAMP "CVS"
|
||||
#define LIBSSH2_TIMESTAMP "DEV"
|
||||
|
||||
/* Part of every banner, user specified or not */
|
||||
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
|
||||
@@ -178,6 +178,11 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
|
||||
unsigned int length;
|
||||
} LIBSSH2_USERAUTH_KBDINT_RESPONSE;
|
||||
|
||||
/* 'publickey' authentication callback */
|
||||
#define LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC(name) \
|
||||
int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, \
|
||||
const unsigned char *data, size_t data_len, void **abstract)
|
||||
|
||||
/* 'keyboard-interactive' authentication callback */
|
||||
#define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) \
|
||||
void name_(const char* name, int name_len, const char* instruction, \
|
||||
@@ -242,6 +247,7 @@ typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
|
||||
typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
|
||||
typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER;
|
||||
typedef struct _LIBSSH2_KNOWNHOSTS LIBSSH2_KNOWNHOSTS;
|
||||
typedef struct _LIBSSH2_AGENT LIBSSH2_AGENT;
|
||||
|
||||
typedef struct _LIBSSH2_POLLFD {
|
||||
unsigned char type; /* LIBSSH2_POLLFD_* below */
|
||||
@@ -335,7 +341,8 @@ typedef struct _LIBSSH2_POLLFD {
|
||||
#define LIBSSH2_ERROR_PASSWORD_EXPIRED -15
|
||||
#define LIBSSH2_ERROR_FILE -16
|
||||
#define LIBSSH2_ERROR_METHOD_NONE -17
|
||||
#define LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED -18
|
||||
#define LIBSSH2_ERROR_AUTHENTICATION_FAILED -18
|
||||
#define LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED LIBSSH2_ERROR_AUTHENTICATION_FAILED
|
||||
#define LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED -19
|
||||
#define LIBSSH2_ERROR_CHANNEL_OUTOFORDER -20
|
||||
#define LIBSSH2_ERROR_CHANNEL_FAILURE -21
|
||||
@@ -356,6 +363,10 @@ typedef struct _LIBSSH2_POLLFD {
|
||||
#define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL -36
|
||||
#define LIBSSH2_ERROR_EAGAIN -37
|
||||
#define LIBSSH2_ERROR_BUFFER_TOO_SMALL -38
|
||||
#define LIBSSH2_ERROR_BAD_USE -39
|
||||
#define LIBSSH2_ERROR_COMPRESS -40
|
||||
#define LIBSSH2_ERROR_OUT_OF_BOUNDARY -41
|
||||
#define LIBSSH2_ERROR_AGENT_PROTOCOL -42
|
||||
|
||||
/* Session API */
|
||||
LIBSSH2_API LIBSSH2_SESSION *
|
||||
@@ -433,6 +444,14 @@ libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
strlen(username), (publickey), \
|
||||
(privatekey), (passphrase))
|
||||
|
||||
LIBSSH2_API int
|
||||
libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
const unsigned char *pubkeydata,
|
||||
size_t pubkeydata_len,
|
||||
LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)),
|
||||
void **abstract);
|
||||
|
||||
LIBSSH2_API int
|
||||
libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
@@ -675,6 +694,7 @@ LIBSSH2_API
|
||||
const char *libssh2_version(int req_version_num);
|
||||
|
||||
#define HAVE_LIBSSH2_KNOWNHOST_API 0x010101 /* since 1.1.1 */
|
||||
#define HAVE_LIBSSH2_VERSION_API 0x010100 /* libssh2_version since 1.1 */
|
||||
|
||||
struct libssh2_knownhost {
|
||||
unsigned int magic; /* magic stored by the library */
|
||||
@@ -866,6 +886,93 @@ libssh2_knownhost_get(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
struct libssh2_knownhost **store,
|
||||
struct libssh2_knownhost *prev);
|
||||
|
||||
#define HAVE_LIBSSH2_AGENT_API 0x010202 /* since 1.2.2 */
|
||||
|
||||
struct libssh2_agent_publickey {
|
||||
unsigned int magic; /* magic stored by the library */
|
||||
void *node; /* handle to the internal representation of key */
|
||||
unsigned char *blob; /* public key blob */
|
||||
size_t blob_len; /* length of the public key blob */
|
||||
char *comment; /* comment in printable format */
|
||||
};
|
||||
|
||||
/*
|
||||
* libssh2_agent_init
|
||||
*
|
||||
* Init an ssh-agent handle. Returns the pointer to the handle.
|
||||
*
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_AGENT *
|
||||
libssh2_agent_init(LIBSSH2_SESSION *session);
|
||||
|
||||
/*
|
||||
* libssh2_agent_connect()
|
||||
*
|
||||
* Connect to an ssh-agent.
|
||||
*
|
||||
* Returns 0 if succeeded, or a negative value for error.
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_agent_connect(LIBSSH2_AGENT *agent);
|
||||
|
||||
/*
|
||||
* libssh2_agent_list_identities()
|
||||
*
|
||||
* Request an ssh-agent to list identities.
|
||||
*
|
||||
* Returns 0 if succeeded, or a negative value for error.
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_agent_list_identities(LIBSSH2_AGENT *agent);
|
||||
|
||||
/*
|
||||
* libssh2_agent_get_identity()
|
||||
*
|
||||
* Traverse the internal list of public keys. Pass NULL to 'prev' to get
|
||||
* the first one. Or pass a poiner to the previously returned one to get the
|
||||
* next.
|
||||
*
|
||||
* Returns:
|
||||
* 0 if a fine public key was stored in 'store'
|
||||
* 1 if end of public keys
|
||||
* [negative] on errors
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_agent_get_identity(LIBSSH2_AGENT *agent,
|
||||
struct libssh2_agent_publickey **store,
|
||||
struct libssh2_agent_publickey *prev);
|
||||
|
||||
/*
|
||||
* libssh2_agent_userauth()
|
||||
*
|
||||
* Do publickey user authentication with the help of ssh-agent.
|
||||
*
|
||||
* Returns 0 if succeeded, or a negative value for error.
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_agent_userauth(LIBSSH2_AGENT *agent,
|
||||
const char *username,
|
||||
struct libssh2_agent_publickey *identity);
|
||||
|
||||
/*
|
||||
* libssh2_agent_disconnect()
|
||||
*
|
||||
* Close a connection to an ssh-agent.
|
||||
*
|
||||
* Returns 0 if succeeded, or a negative value for error.
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_agent_disconnect(LIBSSH2_AGENT *agent);
|
||||
|
||||
/*
|
||||
* libssh2_agent_free()
|
||||
*
|
||||
* Free an ssh-agent handle. This function also frees the internal
|
||||
* collection of public keys.
|
||||
*/
|
||||
LIBSSH2_API void
|
||||
libssh2_agent_free(LIBSSH2_AGENT *agent);
|
||||
|
||||
/* NOTE NOTE NOTE
|
||||
libssh2_trace() has no function in builds that aren't built with debug
|
||||
enabled
|
||||
@@ -879,6 +986,15 @@ LIBSSH2_API int libssh2_trace(LIBSSH2_SESSION *session, int bitmask);
|
||||
#define LIBSSH2_TRACE_SFTP (1<<6)
|
||||
#define LIBSSH2_TRACE_ERROR (1<<7)
|
||||
#define LIBSSH2_TRACE_PUBLICKEY (1<<8)
|
||||
#define LIBSSH2_TRACE_SOCKET (1<<9)
|
||||
|
||||
typedef void (*libssh2_trace_handler_func)(LIBSSH2_SESSION*,
|
||||
void*,
|
||||
const char *,
|
||||
size_t);
|
||||
LIBSSH2_API int libssh2_trace_sethandler(LIBSSH2_SESSION *session,
|
||||
void* context,
|
||||
libssh2_trace_handler_func callback);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
16
libssh2.pc.in
Normal file
16
libssh2.pc.in
Normal file
@@ -0,0 +1,16 @@
|
||||
###########################################################################
|
||||
# libssh2 installation details
|
||||
###########################################################################
|
||||
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: libssh2
|
||||
URL: http://www.libssh2.org/
|
||||
Description: Library for SSH based connunication
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lssh2 @LDFLAGS@ @LIBS@
|
||||
Libs.private: @LIBS@
|
||||
Cflags: -I${includedir}
|
@@ -1,5 +0,0 @@
|
||||
libtool.m4
|
||||
ltoptions.m4
|
||||
ltsugar.m4
|
||||
ltversion.m4
|
||||
lt~obsolete.m4
|
@@ -96,7 +96,7 @@ LIBARCH_L = $(shell $(AWK) 'BEGIN {print tolower(ARGV[1])}' $(LIBARCH))
|
||||
-include $(OBJDIR)/version.inc
|
||||
|
||||
# Global flags for all compilers
|
||||
CFLAGS = $(OPT) -D$(DB) -DNETWARE -nostdinc
|
||||
CFLAGS += $(OPT) -D$(DB) -DNETWARE -nostdinc
|
||||
#CFLAGS += -DHAVE_CONFIG_H
|
||||
|
||||
ifeq ($(CC),mwccnlm)
|
||||
@@ -184,8 +184,7 @@ ifdef XDCOPT
|
||||
XDCDATA = $(OBJDIR)/$(TARGET).xdc
|
||||
endif
|
||||
|
||||
ifeq ($(findstring linux,$(OSTYPE)),linux)
|
||||
#-include $(NDKBASE)/nlmconv/ncpfs.inc
|
||||
ifeq ($(findstring /sh,$(SHELL)),/sh)
|
||||
DL = '
|
||||
DS = /
|
||||
else
|
||||
@@ -194,24 +193,10 @@ endif
|
||||
|
||||
vpath %.c . ../src
|
||||
|
||||
OBJECTS = \
|
||||
channel.o \
|
||||
comp.o \
|
||||
crypt.o \
|
||||
hostkey.o \
|
||||
kex.o \
|
||||
mac.o \
|
||||
misc.o \
|
||||
openssl.o \
|
||||
packet.o \
|
||||
pem.o \
|
||||
publickey.o \
|
||||
scp.o \
|
||||
session.o \
|
||||
sftp.o \
|
||||
transport.o \
|
||||
userauth.o
|
||||
# include Makefile.inc to get CSOURCES define
|
||||
include ../Makefile.inc
|
||||
|
||||
OBJECTS := $(patsubst %.c,%.o,$(CSOURCES))
|
||||
ifeq ($(LIBARCH),CLIB)
|
||||
# CLIB lacks of snprint() function - here's a replacement:
|
||||
# http://www.ijs.si/software/snprintf/
|
||||
@@ -220,7 +205,6 @@ vpath %.c $(SNPRINTF)
|
||||
endif
|
||||
|
||||
OBJS := $(addprefix $(OBJDIR)/,$(OBJECTS))
|
||||
|
||||
OBJL = $(OBJS) $(OBJDIR)/nwlib.o $(LDLIBS)
|
||||
|
||||
all: lib nlm
|
||||
@@ -382,6 +366,8 @@ ifeq ($(LIBARCH),CLIB)
|
||||
@echo $(DL)#define HAVE_STRICMP 1$(DL) >> $@
|
||||
@echo $(DL)#define socklen_t int$(DL) >> $@
|
||||
@echo $(DL)#define sleep(s) delay(1000 * s)$(DL) >> $@
|
||||
@echo $(DL)#define strcasecmp stricmp$(DL) >> $@
|
||||
@echo $(DL)#define strncasecmp strnicmp$(DL) >> $@
|
||||
else
|
||||
@echo $(DL)#define OS "i586-pc-libc-NetWare"$(DL) >> $@
|
||||
@echo $(DL)#define HAVE_DLFCN_H 1$(DL) >> $@
|
||||
@@ -508,6 +494,7 @@ endif
|
||||
@echo $(DL) libssh2_channel_eof,$(DL) >> $@
|
||||
@echo $(DL) libssh2_channel_flush_ex,$(DL) >> $@
|
||||
@echo $(DL) libssh2_channel_free,$(DL) >> $@
|
||||
@echo $(DL) libssh2_channel_get_exit_status,$(DL) >> $@
|
||||
@echo $(DL) libssh2_channel_open_ex,$(DL) >> $@
|
||||
@echo $(DL) libssh2_channel_process_startup,$(DL) >> $@
|
||||
@echo $(DL) libssh2_channel_read_ex,$(DL) >> $@
|
||||
@@ -521,11 +508,18 @@ endif
|
||||
@echo $(DL) libssh2_hostkey_hash,$(DL) >> $@
|
||||
@echo $(DL) libssh2_scp_recv,$(DL) >> $@
|
||||
@echo $(DL) libssh2_scp_send_ex,$(DL) >> $@
|
||||
@echo $(DL) libssh2_knownhost_add,$(DL) >> $@
|
||||
@echo $(DL) libssh2_knownhost_check,$(DL) >> $@
|
||||
@echo $(DL) libssh2_knownhost_free,$(DL) >> $@
|
||||
@echo $(DL) libssh2_knownhost_init,$(DL) >> $@
|
||||
@echo $(DL) libssh2_knownhost_readfile,$(DL) >> $@
|
||||
@echo $(DL) libssh2_knownhost_writefile,$(DL) >> $@
|
||||
@echo $(DL) libssh2_session_abstract,$(DL) >> $@
|
||||
@echo $(DL) libssh2_session_block_directions,$(DL) >> $@
|
||||
@echo $(DL) libssh2_session_callback_set,$(DL) >> $@
|
||||
@echo $(DL) libssh2_session_disconnect_ex,$(DL) >> $@
|
||||
@echo $(DL) libssh2_session_free,$(DL) >> $@
|
||||
@echo $(DL) libssh2_session_hostkey,$(DL) >> $@
|
||||
@echo $(DL) libssh2_session_init_ex,$(DL) >> $@
|
||||
@echo $(DL) libssh2_session_last_errno,$(DL) >> $@
|
||||
@echo $(DL) libssh2_session_last_error,$(DL) >> $@
|
||||
|
@@ -28,8 +28,8 @@ endif
|
||||
LINK_STATIC = 1
|
||||
|
||||
# Edit the vars below to change NLM target settings.
|
||||
SAMPLES = ../../example/simple
|
||||
TARGETS := $(patsubst $(SAMPLES)/%.c,%.nlm,$(strip $(wildcard $(SAMPLES)/*.c)))
|
||||
SAMPLES = ../../example
|
||||
TARGETS := $(filter-out x11.nlm,$(patsubst $(SAMPLES)/%.c,%.nlm,$(strip $(wildcard $(SAMPLES)/*.c))))
|
||||
VERSION = $(LIBSSH2_VERSION)
|
||||
COPYR = Copyright (c) 2004-2009, Sara Golemon <sarag@libssh2.org>
|
||||
WWWURL = http://www.libssh2.org/
|
||||
@@ -89,7 +89,7 @@ LIBARCH_L = $(shell $(AWK) 'BEGIN {print tolower(ARGV[1])}' $(LIBARCH))
|
||||
-include $(OBJDIR)/version.inc
|
||||
|
||||
# Global flags for all compilers
|
||||
CFLAGS = $(OPT) -D$(DB) -DNETWARE -nostdinc
|
||||
CFLAGS += $(OPT) -D$(DB) -DNETWARE -nostdinc
|
||||
|
||||
ifeq ($(CC),mwccnlm)
|
||||
LD = mwldnlm
|
||||
@@ -116,12 +116,15 @@ LDFLAGS = -T
|
||||
AR = ar
|
||||
ARFLAGS = -cq
|
||||
LIBEXT = a
|
||||
CFLAGS += -fno-builtin -fpack-struct -fpcc-struct-return -fno-strict-aliasing
|
||||
CFLAGS += -Wall,no-unused # -pedantic
|
||||
CFLAGS += -fno-builtin -fpcc-struct-return -fno-strict-aliasing
|
||||
CFLAGS += -Wall # -pedantic
|
||||
ifeq ($(LIBARCH),LIBC)
|
||||
PRELUDE = $(SDK_LIBC)/imports/libcpre.gcc.o
|
||||
else
|
||||
PRELUDE = $(SDK_CLIB)/imports/clibpre.gcc.o
|
||||
# PRELUDE = $(SDK_CLIB)/imports/clibpre.gcc.o
|
||||
# to avoid the __init_* / __deinit_* whoes dont use prelude from NDK
|
||||
# http://www.gknw.net/development/mk_nlm/gcc_pre.zip
|
||||
PRELUDE = $(NDK_ROOT)/pre/prelude.o
|
||||
CFLAGS += -include $(NDKBASE)/nlmconv/genlm.h
|
||||
endif
|
||||
endif
|
||||
@@ -135,6 +138,13 @@ INCLUDES = -I.. -I../../include
|
||||
|
||||
LDLIBS =
|
||||
|
||||
ifdef LINK_STATIC
|
||||
LDLIBS += ../libssh2.$(LIBEXT)
|
||||
else
|
||||
IMPORTS += @../libssh2.imp
|
||||
MODULES += libssh2.nlm
|
||||
endif
|
||||
|
||||
INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L) -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L)/openssl
|
||||
LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/ssl.$(LIBEXT)
|
||||
LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/crypto.$(LIBEXT)
|
||||
@@ -150,13 +160,6 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef LINK_STATIC
|
||||
LDLIBS += ../libssh2.$(LIBEXT)
|
||||
else
|
||||
IMPORTS += @../libssh2.imp
|
||||
MODULES += libssh2.nlm
|
||||
endif
|
||||
|
||||
ifeq ($(LIBARCH),LIBC)
|
||||
INCLUDES += -I$(SDK_LIBC)/include
|
||||
# INCLUDES += -I$(SDK_LIBC)/include/nks
|
||||
@@ -177,8 +180,11 @@ ifeq ($(MTSAFE),NO)
|
||||
XDCOPT = -u
|
||||
endif
|
||||
|
||||
ifeq ($(findstring linux,$(OSTYPE)),linux)
|
||||
DL = '
|
||||
ifeq ($(findstring /sh,$(SHELL)),/sh)
|
||||
DL = '
|
||||
DS = /
|
||||
else
|
||||
DS = \\
|
||||
endif
|
||||
|
||||
vpath %.c $(SAMPLES)
|
||||
@@ -188,7 +194,7 @@ vpath %.c $(SAMPLES)
|
||||
|
||||
all: prebuild $(TARGETS)
|
||||
|
||||
prebuild: $(OBJDIR) $(OBJDIR)/version.inc config.h
|
||||
prebuild: $(OBJDIR) $(OBJDIR)/version.inc
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
# @echo Compiling $<
|
||||
@@ -276,7 +282,7 @@ ifdef IMPORTS
|
||||
@echo $(DL)import $(IMPORTS)$(DL) >> $@
|
||||
endif
|
||||
ifeq ($(LD),nlmconv)
|
||||
@echo $(DL)input $(<:.def=.o)$(DL) >> $@
|
||||
@echo $(DL)input $(@:.def=.o)$(DL) >> $@
|
||||
@echo $(DL)input $(PRELUDE)$(DL) >> $@
|
||||
ifdef LDLIBS
|
||||
@echo $(DL)input $(LDLIBS)$(DL) >> $@
|
||||
@@ -284,7 +290,7 @@ endif
|
||||
@echo $(DL)output $(notdir $(@:.def=.nlm))$(DL) >> $@
|
||||
endif
|
||||
|
||||
config.h: Makefile.netware
|
||||
ssh2_config.h: Makefile.netware
|
||||
@echo Creating $@
|
||||
@echo $(DL)/* $@ for NetWare target.$(DL) > $@
|
||||
@echo $(DL)** Do not edit this file - it is created by make!$(DL) >> $@
|
||||
|
@@ -1,20 +0,0 @@
|
||||
.deps
|
||||
.libs
|
||||
*.lib
|
||||
*.pdb
|
||||
*.dll
|
||||
*.exe
|
||||
*.obj
|
||||
*.gcno
|
||||
*.gcda
|
||||
.*.swp
|
||||
Debug
|
||||
Release
|
||||
*.exp
|
||||
Makefile
|
||||
Makefile.in
|
||||
*.lo
|
||||
libssh2.la
|
||||
libssh2_config.h
|
||||
libssh2_config.h.in
|
||||
stamp-h1
|
759
src/agent.c
Normal file
759
src/agent.c
Normal file
@@ -0,0 +1,759 @@
|
||||
/*
|
||||
* Copyright (c) 2009 by Daiki Ueno
|
||||
* 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 "misc.h"
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#else
|
||||
/* Use the existence of sys/un.h as a test if Unix domain socket is
|
||||
supported. winsock*.h define PF_UNIX/AF_UNIX but do not actually
|
||||
support them. */
|
||||
#undef PF_UNIX
|
||||
#endif
|
||||
|
||||
/* Requests from client to agent for protocol 1 key operations */
|
||||
#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
|
||||
#define SSH_AGENTC_RSA_CHALLENGE 3
|
||||
#define SSH_AGENTC_ADD_RSA_IDENTITY 7
|
||||
#define SSH_AGENTC_REMOVE_RSA_IDENTITY 8
|
||||
#define SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9
|
||||
#define SSH_AGENTC_ADD_RSA_ID_CONSTRAINED 24
|
||||
|
||||
/* Requests from client to agent for protocol 2 key operations */
|
||||
#define SSH2_AGENTC_REQUEST_IDENTITIES 11
|
||||
#define SSH2_AGENTC_SIGN_REQUEST 13
|
||||
#define SSH2_AGENTC_ADD_IDENTITY 17
|
||||
#define SSH2_AGENTC_REMOVE_IDENTITY 18
|
||||
#define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19
|
||||
#define SSH2_AGENTC_ADD_ID_CONSTRAINED 25
|
||||
|
||||
/* Key-type independent requests from client to agent */
|
||||
#define SSH_AGENTC_ADD_SMARTCARD_KEY 20
|
||||
#define SSH_AGENTC_REMOVE_SMARTCARD_KEY 21
|
||||
#define SSH_AGENTC_LOCK 22
|
||||
#define SSH_AGENTC_UNLOCK 23
|
||||
#define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26
|
||||
|
||||
/* Generic replies from agent to client */
|
||||
#define SSH_AGENT_FAILURE 5
|
||||
#define SSH_AGENT_SUCCESS 6
|
||||
|
||||
/* Replies from agent to client for protocol 1 key operations */
|
||||
#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2
|
||||
#define SSH_AGENT_RSA_RESPONSE 4
|
||||
|
||||
/* Replies from agent to client for protocol 2 key operations */
|
||||
#define SSH2_AGENT_IDENTITIES_ANSWER 12
|
||||
#define SSH2_AGENT_SIGN_RESPONSE 14
|
||||
|
||||
/* Key constraint identifiers */
|
||||
#define SSH_AGENT_CONSTRAIN_LIFETIME 1
|
||||
#define SSH_AGENT_CONSTRAIN_CONFIRM 2
|
||||
|
||||
/* non-blocking mode on agent connection is not yet implemented, but
|
||||
for future use. */
|
||||
typedef enum {
|
||||
agent_NB_state_init = 0,
|
||||
agent_NB_state_request_created,
|
||||
agent_NB_state_request_length_sent,
|
||||
agent_NB_state_request_sent,
|
||||
agent_NB_state_response_length_received,
|
||||
agent_NB_state_response_received
|
||||
} agent_nonblocking_states;
|
||||
|
||||
typedef struct agent_transaction_ctx {
|
||||
unsigned char *request;
|
||||
size_t request_len;
|
||||
unsigned char *response;
|
||||
size_t response_len;
|
||||
agent_nonblocking_states state;
|
||||
} *agent_transaction_ctx_t;
|
||||
|
||||
typedef int (*agent_connect_func)(LIBSSH2_AGENT *agent);
|
||||
typedef int (*agent_transact_func)(LIBSSH2_AGENT *agent,
|
||||
agent_transaction_ctx_t transctx);
|
||||
typedef int (*agent_disconnect_func)(LIBSSH2_AGENT *agent);
|
||||
|
||||
struct agent_publickey {
|
||||
struct list_node node;
|
||||
|
||||
/* this is the struct we expose externally */
|
||||
struct libssh2_agent_publickey external;
|
||||
};
|
||||
|
||||
struct agent_ops {
|
||||
agent_connect_func connect;
|
||||
agent_transact_func transact;
|
||||
agent_disconnect_func disconnect;
|
||||
};
|
||||
|
||||
struct _LIBSSH2_AGENT
|
||||
{
|
||||
LIBSSH2_SESSION *session; /* the session this "belongs to" */
|
||||
|
||||
libssh2_socket_t fd;
|
||||
|
||||
struct agent_ops *ops;
|
||||
|
||||
struct agent_transaction_ctx transctx;
|
||||
struct agent_publickey *identity;
|
||||
struct list_head head; /* list of public keys */
|
||||
};
|
||||
|
||||
#ifdef PF_UNIX
|
||||
static int
|
||||
agent_connect_unix(LIBSSH2_AGENT *agent)
|
||||
{
|
||||
const char *path;
|
||||
struct sockaddr_un s_un;
|
||||
|
||||
path = getenv("SSH_AUTH_SOCK");
|
||||
if (!path) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
agent->fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (agent->fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s_un.sun_family = AF_UNIX;
|
||||
strncpy (s_un.sun_path, path, sizeof s_un.sun_path);
|
||||
if (connect(agent->fd, (struct sockaddr*)(&s_un), sizeof s_un) != 0) {
|
||||
close (agent->fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
||||
{
|
||||
unsigned char buf[4], *s;
|
||||
int rc;
|
||||
|
||||
/* Send the length of the request */
|
||||
if (transctx->state == agent_NB_state_request_created) {
|
||||
_libssh2_htonu32(buf, transctx->request_len);
|
||||
rc = send(agent->fd, buf, sizeof buf, 0);
|
||||
if (rc < 0) {
|
||||
if (errno == EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
transctx->state = agent_NB_state_request_length_sent;
|
||||
}
|
||||
|
||||
/* Send the request body */
|
||||
if (transctx->state == agent_NB_state_request_length_sent) {
|
||||
rc = send(agent->fd, transctx->request,
|
||||
transctx->request_len, 0);
|
||||
if (rc < 0) {
|
||||
if (errno == EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
transctx->state = agent_NB_state_request_sent;
|
||||
}
|
||||
|
||||
/* Receive the length of a response */
|
||||
if (transctx->state == agent_NB_state_request_sent) {
|
||||
rc = recv(agent->fd, buf, sizeof buf, 0);
|
||||
if (rc < 0) {
|
||||
if (errno == EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
transctx->response_len = _libssh2_ntohu32(buf);
|
||||
s = transctx->response = LIBSSH2_ALLOC(agent->session,
|
||||
transctx->response_len);
|
||||
if (!transctx->response) {
|
||||
return LIBSSH2_ERROR_ALLOC;
|
||||
}
|
||||
transctx->state = agent_NB_state_response_length_received;
|
||||
}
|
||||
|
||||
/* Receive the response body */
|
||||
if (transctx->state == agent_NB_state_response_length_received) {
|
||||
rc = recv(agent->fd, transctx->response, transctx->response_len, 0);
|
||||
if (rc < 0) {
|
||||
if (errno == EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
transctx->state = agent_NB_state_response_received;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agent_disconnect_unix(LIBSSH2_AGENT *agent)
|
||||
{
|
||||
return close(agent->fd);
|
||||
}
|
||||
|
||||
struct agent_ops agent_ops_unix = {
|
||||
agent_connect_unix,
|
||||
agent_transact_unix,
|
||||
agent_disconnect_unix
|
||||
};
|
||||
#endif /* PF_UNIX */
|
||||
|
||||
#ifdef WIN32
|
||||
/* Code to talk to Pageant was taken from PuTTY.
|
||||
*
|
||||
* Portions copyright Robert de Bath, Joris van Rantwijk, Delian
|
||||
* Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas
|
||||
* Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa,
|
||||
* Markus Kuhn, Colin Watson, and CORE SDI S.A.
|
||||
*/
|
||||
#define PAGEANT_COPYDATA_ID 0x804e50ba /* random goop */
|
||||
#define PAGEANT_MAX_MSGLEN 8192
|
||||
|
||||
static int
|
||||
agent_connect_pageant(LIBSSH2_AGENT *agent)
|
||||
{
|
||||
HWND hwnd;
|
||||
hwnd = FindWindow("Pageant", "Pageant");
|
||||
if (!hwnd)
|
||||
return -1;
|
||||
agent->fd = 0; /* Mark as the connection has been established */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
||||
{
|
||||
HWND hwnd;
|
||||
char mapname[23];
|
||||
HANDLE filemap;
|
||||
unsigned char *p;
|
||||
int id;
|
||||
COPYDATASTRUCT cds;
|
||||
|
||||
if (!transctx || 4 + transctx->request_len > PAGEANT_MAX_MSGLEN) {
|
||||
return LIBSSH2_ERROR_INVAL;
|
||||
}
|
||||
hwnd = FindWindow("Pageant", "Pageant");
|
||||
if (!hwnd) {
|
||||
return -1;
|
||||
}
|
||||
sprintf(mapname, "PageantRequest%08x", (unsigned)GetCurrentThreadId());
|
||||
filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
|
||||
0, PAGEANT_MAX_MSGLEN, mapname);
|
||||
if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) {
|
||||
return -1;
|
||||
}
|
||||
p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
|
||||
_libssh2_htonu32(p, transctx->request_len);
|
||||
memcpy(p + 4, transctx->request, transctx->request_len);
|
||||
cds.dwData = PAGEANT_COPYDATA_ID;
|
||||
cds.cbData = 1 + strlen(mapname);
|
||||
cds.lpData = mapname;
|
||||
|
||||
id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds);
|
||||
if (id > 0) {
|
||||
transctx->response_len = _libssh2_ntohu32(p);
|
||||
if (transctx->response_len > PAGEANT_MAX_MSGLEN) {
|
||||
UnmapViewOfFile(p);
|
||||
CloseHandle(filemap);
|
||||
return LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
}
|
||||
transctx->response = LIBSSH2_ALLOC(agent->session,
|
||||
transctx->response_len);
|
||||
if (!transctx->response) {
|
||||
UnmapViewOfFile(p);
|
||||
CloseHandle(filemap);
|
||||
return LIBSSH2_ERROR_ALLOC;
|
||||
}
|
||||
memcpy(transctx->response, p + 4, transctx->response_len);
|
||||
}
|
||||
|
||||
UnmapViewOfFile(p);
|
||||
CloseHandle(filemap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agent_disconnect_pageant(LIBSSH2_AGENT *agent)
|
||||
{
|
||||
agent->fd = INVALID_SOCKET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct agent_ops agent_ops_pageant = {
|
||||
agent_connect_pageant,
|
||||
agent_transact_pageant,
|
||||
agent_disconnect_pageant
|
||||
};
|
||||
#endif /* WIN32 */
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
struct agent_ops *ops;
|
||||
} supported_backends[] = {
|
||||
#ifdef WIN32
|
||||
{"Pageant", &agent_ops_pageant},
|
||||
#endif /* WIN32 */
|
||||
#ifdef PF_UNIX
|
||||
{"Unix", &agent_ops_unix},
|
||||
#endif /* PF_UNIX */
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static int
|
||||
agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
|
||||
const unsigned char *data, size_t data_len, void **abstract)
|
||||
{
|
||||
LIBSSH2_AGENT *agent = (LIBSSH2_AGENT *) (*abstract);
|
||||
agent_transaction_ctx_t transctx = &agent->transctx;
|
||||
struct agent_publickey *identity = agent->identity;
|
||||
ssize_t len = 1 + 4 + identity->external.blob_len + 4 + data_len + 4;
|
||||
ssize_t method_len;
|
||||
unsigned char *s;
|
||||
int rc;
|
||||
|
||||
/* Create a request to sign the data */
|
||||
if (transctx->state == agent_NB_state_init) {
|
||||
s = transctx->request = LIBSSH2_ALLOC(session, len);
|
||||
if (!transctx->request) {
|
||||
return LIBSSH2_ERROR_ALLOC;
|
||||
}
|
||||
|
||||
*s++ = SSH2_AGENTC_SIGN_REQUEST;
|
||||
/* key blob */
|
||||
_libssh2_htonu32(s, identity->external.blob_len);
|
||||
s += 4;
|
||||
memcpy(s, identity->external.blob, identity->external.blob_len);
|
||||
s += identity->external.blob_len;
|
||||
/* data */
|
||||
_libssh2_htonu32(s, data_len);
|
||||
s += 4;
|
||||
memcpy(s, data, data_len);
|
||||
s += data_len;
|
||||
/* flags */
|
||||
_libssh2_htonu32(s, 0);
|
||||
s += 4;
|
||||
transctx->request_len = s - transctx->request;
|
||||
transctx->state = agent_NB_state_request_created;
|
||||
}
|
||||
|
||||
/* Make sure to be re-called as a result of EAGAIN. */
|
||||
if (*transctx->request != SSH2_AGENTC_SIGN_REQUEST) {
|
||||
return LIBSSH2_ERROR_BAD_USE;
|
||||
}
|
||||
|
||||
rc = agent->ops->transact(agent, transctx);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
LIBSSH2_FREE(session, transctx->request);
|
||||
transctx->request = NULL;
|
||||
|
||||
len = transctx->response_len;
|
||||
s = transctx->response;
|
||||
len--;
|
||||
if (len < 0) {
|
||||
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
goto error;
|
||||
}
|
||||
if (*s != SSH2_AGENT_SIGN_RESPONSE) {
|
||||
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
goto error;
|
||||
}
|
||||
s++;
|
||||
|
||||
/* Skip the entire length of the signature */
|
||||
len -= 4;
|
||||
if (len < 0) {
|
||||
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
goto error;
|
||||
}
|
||||
s += 4;
|
||||
|
||||
/* Skip signing method */
|
||||
len -= 4;
|
||||
if (len < 0) {
|
||||
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
goto error;
|
||||
}
|
||||
method_len = _libssh2_ntohu32(s);
|
||||
s += 4;
|
||||
len -= method_len;
|
||||
if (len < 0) {
|
||||
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
goto error;
|
||||
}
|
||||
s += method_len;
|
||||
|
||||
/* Read the signature */
|
||||
len -= 4;
|
||||
if (len < 0) {
|
||||
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
goto error;
|
||||
}
|
||||
*sig_len = _libssh2_ntohu32(s);
|
||||
s += 4;
|
||||
len -= *sig_len;
|
||||
if (len < 0) {
|
||||
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
*sig = LIBSSH2_ALLOC(session, *sig_len);
|
||||
if (!*sig) {
|
||||
rc = LIBSSH2_ERROR_ALLOC;
|
||||
goto error;
|
||||
}
|
||||
memcpy(*sig, s, *sig_len);
|
||||
|
||||
error:
|
||||
LIBSSH2_FREE(session, transctx->request);
|
||||
transctx->request = NULL;
|
||||
|
||||
LIBSSH2_FREE(session, transctx->response);
|
||||
transctx->response = NULL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
agent_list_identities(LIBSSH2_AGENT *agent)
|
||||
{
|
||||
agent_transaction_ctx_t transctx = &agent->transctx;
|
||||
ssize_t len, num_identities;
|
||||
unsigned char *s;
|
||||
int rc;
|
||||
|
||||
/* Create a request to list identities */
|
||||
if (transctx->state == agent_NB_state_init) {
|
||||
unsigned char c = SSH2_AGENTC_REQUEST_IDENTITIES;
|
||||
transctx->request = &c;
|
||||
transctx->request_len = 1;
|
||||
transctx->state = agent_NB_state_request_created;
|
||||
}
|
||||
|
||||
/* Make sure to be re-called as a result of EAGAIN. */
|
||||
if (*transctx->request != SSH2_AGENTC_REQUEST_IDENTITIES) {
|
||||
return LIBSSH2_ERROR_BAD_USE;
|
||||
}
|
||||
|
||||
rc = agent->ops->transact(agent, transctx);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
transctx->request = NULL;
|
||||
|
||||
len = transctx->response_len;
|
||||
s = transctx->response;
|
||||
len--;
|
||||
if (len < 0) {
|
||||
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
goto error;
|
||||
}
|
||||
if (*s != SSH2_AGENT_IDENTITIES_ANSWER) {
|
||||
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
goto error;
|
||||
}
|
||||
s++;
|
||||
|
||||
/* Read the length of identities */
|
||||
len -= 4;
|
||||
if (len < 0) {
|
||||
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
goto error;
|
||||
}
|
||||
num_identities = _libssh2_ntohu32(s);
|
||||
s += 4;
|
||||
|
||||
while (num_identities--) {
|
||||
struct agent_publickey *identity;
|
||||
ssize_t comment_len;
|
||||
|
||||
identity = LIBSSH2_ALLOC(agent->session, sizeof *identity);
|
||||
if (!identity) {
|
||||
rc = LIBSSH2_ERROR_ALLOC;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Read the length of the blob */
|
||||
len -= 4;
|
||||
if (len < 0) {
|
||||
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
goto error;
|
||||
}
|
||||
identity->external.blob_len = _libssh2_ntohu32(s);
|
||||
s += 4;
|
||||
|
||||
/* Read the blob */
|
||||
len -= identity->external.blob_len;
|
||||
if (len < 0) {
|
||||
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
goto error;
|
||||
}
|
||||
identity->external.blob = LIBSSH2_ALLOC(agent->session,
|
||||
identity->external.blob_len);
|
||||
if (!identity->external.blob) {
|
||||
rc = LIBSSH2_ERROR_ALLOC;
|
||||
goto error;
|
||||
}
|
||||
memcpy(identity->external.blob, s, identity->external.blob_len);
|
||||
s += identity->external.blob_len;
|
||||
|
||||
/* Read the length of the comment */
|
||||
len -= 4;
|
||||
if (len < 0) {
|
||||
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
goto error;
|
||||
}
|
||||
comment_len = _libssh2_ntohu32(s);
|
||||
s += 4;
|
||||
|
||||
/* Read the comment */
|
||||
len -= comment_len;
|
||||
if (len < 0) {
|
||||
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
|
||||
goto error;
|
||||
}
|
||||
identity->external.comment = LIBSSH2_ALLOC(agent->session,
|
||||
comment_len + 1);
|
||||
if (!identity->external.comment) {
|
||||
rc = LIBSSH2_ERROR_ALLOC;
|
||||
goto error;
|
||||
}
|
||||
identity->external.comment[comment_len] = '\0';
|
||||
memcpy(identity->external.comment, s, comment_len);
|
||||
s += comment_len;
|
||||
|
||||
_libssh2_list_add(&agent->head, &identity->node);
|
||||
}
|
||||
error:
|
||||
LIBSSH2_FREE(agent->session, transctx->response);
|
||||
transctx->response = NULL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
agent_free_identities(LIBSSH2_AGENT *agent) {
|
||||
struct agent_publickey *node;
|
||||
struct agent_publickey *next;
|
||||
|
||||
for (node = _libssh2_list_first(&agent->head); node; node = next) {
|
||||
next = _libssh2_list_next(&node->node);
|
||||
LIBSSH2_FREE(agent->session, node->external.blob);
|
||||
LIBSSH2_FREE(agent->session, node->external.comment);
|
||||
LIBSSH2_FREE(agent->session, node);
|
||||
}
|
||||
_libssh2_list_init(&agent->head);
|
||||
}
|
||||
|
||||
#define AGENT_PUBLICKEY_MAGIC 0x3bdefed2
|
||||
/*
|
||||
* agent_publickey_to_external()
|
||||
*
|
||||
* Copies data from the internal to the external representation struct.
|
||||
*
|
||||
*/
|
||||
static struct libssh2_agent_publickey *
|
||||
agent_publickey_to_external(struct agent_publickey *node)
|
||||
{
|
||||
struct libssh2_agent_publickey *ext = &node->external;
|
||||
|
||||
ext->magic = AGENT_PUBLICKEY_MAGIC;
|
||||
ext->node = node;
|
||||
|
||||
return ext;
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_agent_init
|
||||
*
|
||||
* Init an ssh-agent handle. Returns the pointer to the handle.
|
||||
*
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_AGENT *
|
||||
libssh2_agent_init(LIBSSH2_SESSION *session)
|
||||
{
|
||||
LIBSSH2_AGENT *agent;
|
||||
|
||||
agent = LIBSSH2_ALLOC(session, sizeof *agent);
|
||||
if (!agent) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate space for agent connection", 0);
|
||||
return NULL;
|
||||
}
|
||||
memset(agent, 0, sizeof *agent);
|
||||
agent->session = session;
|
||||
_libssh2_list_init(&agent->head);
|
||||
|
||||
return agent;
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_agent_connect()
|
||||
*
|
||||
* Connect to an ssh-agent.
|
||||
*
|
||||
* Returns 0 if succeeded, or a negative value for error.
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_agent_connect(LIBSSH2_AGENT *agent)
|
||||
{
|
||||
int i, rc = -1;
|
||||
for (i = 0; supported_backends[i].name; i++) {
|
||||
agent->ops = supported_backends[i].ops;
|
||||
rc = agent->ops->connect(agent);
|
||||
if (!rc)
|
||||
return 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_agent_list_identities()
|
||||
*
|
||||
* Request ssh-agent to list identities.
|
||||
*
|
||||
* Returns 0 if succeeded, or a negative value for error.
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_agent_list_identities(LIBSSH2_AGENT *agent)
|
||||
{
|
||||
memset(&agent->transctx, 0, sizeof agent->transctx);
|
||||
/* Abondon the last fetched identities */
|
||||
agent_free_identities(agent);
|
||||
return agent_list_identities(agent);
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_agent_get_identity()
|
||||
*
|
||||
* Traverse the internal list of public keys. Pass NULL to 'prev' to get
|
||||
* the first one. Or pass a poiner to the previously returned one to get the
|
||||
* next.
|
||||
*
|
||||
* Returns:
|
||||
* 0 if a fine public key was stored in 'store'
|
||||
* 1 if end of public keys
|
||||
* [negative] on errors
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_agent_get_identity(LIBSSH2_AGENT *agent,
|
||||
struct libssh2_agent_publickey **ext,
|
||||
struct libssh2_agent_publickey *oprev)
|
||||
{
|
||||
struct agent_publickey *node;
|
||||
if (oprev && oprev->node) {
|
||||
/* we have a starting point */
|
||||
struct agent_publickey *prev = oprev->node;
|
||||
|
||||
/* get the next node in the list */
|
||||
node = _libssh2_list_next(&prev->node);
|
||||
}
|
||||
else
|
||||
node = _libssh2_list_first(&agent->head);
|
||||
|
||||
if (!node)
|
||||
/* no (more) node */
|
||||
return 1;
|
||||
|
||||
*ext = agent_publickey_to_external(node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_agent_userauth()
|
||||
*
|
||||
* Do publickey user authentication with the help of ssh-agent.
|
||||
*
|
||||
* Returns 0 if succeeded, or a negative value for error.
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_agent_userauth(LIBSSH2_AGENT *agent,
|
||||
const char *username,
|
||||
struct libssh2_agent_publickey *identity)
|
||||
{
|
||||
void *abstract = agent;
|
||||
|
||||
if (agent->session->userauth_pblc_state == libssh2_NB_state_idle) {
|
||||
memset(&agent->transctx, 0, sizeof agent->transctx);
|
||||
agent->identity = identity->node;
|
||||
}
|
||||
return libssh2_userauth_publickey(agent->session, username,
|
||||
identity->blob,
|
||||
identity->blob_len,
|
||||
agent_sign,
|
||||
&abstract);
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_agent_disconnect()
|
||||
*
|
||||
* Close a connection to an ssh-agent.
|
||||
*
|
||||
* Returns 0 if succeeded, or a negative value for error.
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_agent_disconnect(LIBSSH2_AGENT *agent)
|
||||
{
|
||||
if (agent->ops && agent->fd != INVALID_SOCKET)
|
||||
return agent->ops->disconnect(agent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_agent_free()
|
||||
*
|
||||
* Free an ssh-agent handle. This function also frees the internal
|
||||
* collection of public keys.
|
||||
*/
|
||||
LIBSSH2_API void
|
||||
libssh2_agent_free(LIBSSH2_AGENT *agent) {
|
||||
/* Allow connection freeing when the socket has lost its connection */
|
||||
if (agent->fd != INVALID_SOCKET) {
|
||||
libssh2_agent_disconnect(agent);
|
||||
}
|
||||
agent_free_identities(agent);
|
||||
LIBSSH2_FREE(agent->session, agent);
|
||||
}
|
487
src/channel.c
487
src/channel.c
File diff suppressed because it is too large
Load Diff
@@ -104,5 +104,17 @@ _libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
|
||||
const char *request, unsigned int request_len,
|
||||
const char *message, unsigned int message_len);
|
||||
|
||||
|
||||
/*
|
||||
* _libssh2_channel_read
|
||||
*
|
||||
* Read data from a channel
|
||||
*
|
||||
* It is important to not return 0 until the currently read channel is
|
||||
* complete. If we read stuff from the wire but it was no payload data to fill
|
||||
* in the buffer with, we MUST make sure to return PACKET_EAGAIN.
|
||||
*/
|
||||
ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
char *buf, size_t buflen);
|
||||
#endif /* __LIBSSH2_CHANNEL_H */
|
||||
|
||||
|
81
src/crypt.c
81
src/crypt.c
@@ -1,4 +1,5 @@
|
||||
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2009 Simon Josefsson <simon@josefsson.org>
|
||||
* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -114,6 +115,44 @@ crypt_dtor(LIBSSH2_SESSION * session, void **abstract)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LIBSSH2_AES_CTR
|
||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_ctr = {
|
||||
"aes128-ctr",
|
||||
16, /* blocksize */
|
||||
16, /* initial value length */
|
||||
16, /* secret length -- 16*8 == 128bit */
|
||||
0, /* flags */
|
||||
&crypt_init,
|
||||
&crypt_encrypt,
|
||||
&crypt_dtor,
|
||||
_libssh2_cipher_aes128ctr
|
||||
};
|
||||
|
||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_ctr = {
|
||||
"aes192-ctr",
|
||||
16, /* blocksize */
|
||||
16, /* initial value length */
|
||||
24, /* secret length -- 24*8 == 192bit */
|
||||
0, /* flags */
|
||||
&crypt_init,
|
||||
&crypt_encrypt,
|
||||
&crypt_dtor,
|
||||
_libssh2_cipher_aes192ctr
|
||||
};
|
||||
|
||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_ctr = {
|
||||
"aes256-ctr",
|
||||
16, /* blocksize */
|
||||
16, /* initial value length */
|
||||
32, /* secret length -- 32*8 == 256bit */
|
||||
0, /* flags */
|
||||
&crypt_init,
|
||||
&crypt_encrypt,
|
||||
&crypt_dtor,
|
||||
_libssh2_cipher_aes256ctr
|
||||
};
|
||||
#endif
|
||||
|
||||
#if LIBSSH2_AES
|
||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = {
|
||||
"aes128-cbc",
|
||||
@@ -192,6 +231,40 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = {
|
||||
&crypt_dtor,
|
||||
_libssh2_cipher_arcfour
|
||||
};
|
||||
|
||||
static int
|
||||
crypt_init_arcfour128(LIBSSH2_SESSION * session,
|
||||
const LIBSSH2_CRYPT_METHOD * method,
|
||||
unsigned char *iv, int *free_iv,
|
||||
unsigned char *secret, int *free_secret,
|
||||
int encrypt, void **abstract)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = crypt_init (session, method, iv, free_iv, secret, free_secret,
|
||||
encrypt, abstract);
|
||||
if (rc == 0) {
|
||||
struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract;
|
||||
unsigned char block[8];
|
||||
size_t discard = 1536;
|
||||
for (; discard; discard -= 8)
|
||||
_libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour128 = {
|
||||
"arcfour128",
|
||||
8, /* blocksize */
|
||||
8, /* initial value length */
|
||||
16, /* secret length */
|
||||
0, /* flags */
|
||||
&crypt_init_arcfour128,
|
||||
&crypt_encrypt,
|
||||
&crypt_dtor,
|
||||
_libssh2_cipher_arcfour
|
||||
};
|
||||
#endif /* LIBSSH2_RC4 */
|
||||
|
||||
#if LIBSSH2_CAST
|
||||
@@ -223,6 +296,11 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = {
|
||||
#endif
|
||||
|
||||
static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = {
|
||||
#if LIBSSH2_AES_CTR
|
||||
&libssh2_crypt_method_aes128_ctr,
|
||||
&libssh2_crypt_method_aes192_ctr,
|
||||
&libssh2_crypt_method_aes256_ctr,
|
||||
#endif /* LIBSSH2_AES */
|
||||
#if LIBSSH2_AES
|
||||
&libssh2_crypt_method_aes256_cbc,
|
||||
&libssh2_crypt_method_rijndael_cbc_lysator_liu_se, /* == aes256-cbc */
|
||||
@@ -233,6 +311,7 @@ static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = {
|
||||
&libssh2_crypt_method_blowfish_cbc,
|
||||
#endif /* LIBSSH2_BLOWFISH */
|
||||
#if LIBSSH2_RC4
|
||||
&libssh2_crypt_method_arcfour128,
|
||||
&libssh2_crypt_method_arcfour,
|
||||
#endif /* LIBSSH2_RC4 */
|
||||
#if LIBSSH2_CAST
|
||||
|
@@ -114,7 +114,6 @@ hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session,
|
||||
void **abstract)
|
||||
{
|
||||
libssh2_rsa_ctx *rsactx;
|
||||
FILE *fp;
|
||||
int ret;
|
||||
|
||||
if (*abstract) {
|
||||
@@ -122,13 +121,7 @@ hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session,
|
||||
*abstract = NULL;
|
||||
}
|
||||
|
||||
fp = fopen(privkeyfile, "r");
|
||||
if (!fp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = _libssh2_rsa_new_private(&rsactx, session, fp, passphrase);
|
||||
fclose(fp);
|
||||
ret = _libssh2_rsa_new_private(&rsactx, session, privkeyfile, passphrase);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
@@ -296,7 +289,6 @@ hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session,
|
||||
void **abstract)
|
||||
{
|
||||
libssh2_dsa_ctx *dsactx;
|
||||
FILE *fp;
|
||||
int ret;
|
||||
|
||||
if (*abstract) {
|
||||
@@ -304,13 +296,7 @@ hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session,
|
||||
*abstract = NULL;
|
||||
}
|
||||
|
||||
fp = fopen(privkeyfile, "r");
|
||||
if (!fp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = _libssh2_dsa_new_private(&dsactx, session, fp, passphrase);
|
||||
fclose(fp);
|
||||
ret = _libssh2_dsa_new_private(&dsactx, session, privkeyfile, passphrase);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
|
242
src/kex.c
242
src/kex.c
@@ -69,22 +69,20 @@
|
||||
} \
|
||||
}
|
||||
|
||||
/* kex_method_diffie_hellman_groupGP_sha1_key_exchange
|
||||
/*
|
||||
* diffie_hellman_sha1
|
||||
*
|
||||
* Diffie Hellman Key Exchange, Group Agnostic
|
||||
*/
|
||||
static int
|
||||
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,
|
||||
kmdhgGPsha1kex_state_t
|
||||
* exchange_state)
|
||||
static int diffie_hellman_sha1(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,
|
||||
kmdhgGPsha1kex_state_t *exchange_state)
|
||||
{
|
||||
int ret = 0;
|
||||
int rc;
|
||||
@@ -122,7 +120,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
if (!exchange_state->e_packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Out of memory error",
|
||||
0);
|
||||
ret = -1;
|
||||
ret = LIBSSH2_ERROR_ALLOC;
|
||||
goto clean_exit;
|
||||
}
|
||||
exchange_state->e_packet[0] = packet_type_init;
|
||||
@@ -137,7 +135,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
exchange_state->e_packet + 6);
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending KEX packet %d",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending KEX packet %d",
|
||||
(int) packet_type_init);
|
||||
exchange_state->state = libssh2_NB_state_created;
|
||||
}
|
||||
@@ -146,11 +144,11 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
rc = _libssh2_transport_write(session, exchange_state->e_packet,
|
||||
exchange_state->e_packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
libssh2_error(session, rc,
|
||||
"Unable to send KEX init message", 0);
|
||||
ret = -1;
|
||||
ret = rc;
|
||||
goto clean_exit;
|
||||
}
|
||||
exchange_state->state = libssh2_NB_state_sent;
|
||||
@@ -163,20 +161,20 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
* need to silently ignore it */
|
||||
int burn_type;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||
"Waiting for badly guessed KEX packet (to be ignored)");
|
||||
burn_type =
|
||||
_libssh2_packet_burn(session, &exchange_state->burn_state);
|
||||
if (burn_type == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return burn_type;
|
||||
} else if (burn_type <= 0) {
|
||||
/* Failed to receive a packet */
|
||||
ret = -1;
|
||||
ret = burn_type;
|
||||
goto clean_exit;
|
||||
}
|
||||
session->burn_optimistic_kexinit = 0;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||
"Burnt packet of type: %02x",
|
||||
(unsigned int) burn_type);
|
||||
}
|
||||
@@ -191,12 +189,12 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
&exchange_state->s_packet_len, 0, NULL,
|
||||
0, &exchange_state->req_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
|
||||
"Timed out waiting for KEX reply", 0);
|
||||
ret = -1;
|
||||
ret = rc;
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
@@ -211,7 +209,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for a copy of the host key",
|
||||
0);
|
||||
ret = -1;
|
||||
ret = LIBSSH2_ERROR_ALLOC;
|
||||
goto clean_exit;
|
||||
}
|
||||
memcpy(session->server_hostkey, exchange_state->s,
|
||||
@@ -235,7 +233,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]);
|
||||
}
|
||||
*(--fprint) = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||
"Server's MD5 Fingerprint: %s", fingerprint);
|
||||
}
|
||||
#endif /* LIBSSH2DEBUG */
|
||||
@@ -258,17 +256,17 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]);
|
||||
}
|
||||
*(--fprint) = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||
"Server's SHA1 Fingerprint: %s", fingerprint);
|
||||
}
|
||||
#endif /* LIBSSH2DEBUG */
|
||||
|
||||
if (session->hostkey->
|
||||
init(session, session->server_hostkey, session->server_hostkey_len,
|
||||
&session->server_hostkey_abstract)) {
|
||||
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);
|
||||
ret = -1;
|
||||
ret = LIBSSH2_ERROR_HOSTKEY_INIT;
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
@@ -296,7 +294,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
if (!exchange_state->k_value) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate buffer for K", 0);
|
||||
ret = -1;
|
||||
ret = LIBSSH2_ERROR_ALLOC;
|
||||
goto clean_exit;
|
||||
}
|
||||
_libssh2_htonu32(exchange_state->k_value,
|
||||
@@ -412,7 +410,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending NEWKEYS message");
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending NEWKEYS message");
|
||||
exchange_state->c = SSH_MSG_NEWKEYS;
|
||||
|
||||
exchange_state->state = libssh2_NB_state_sent2;
|
||||
@@ -421,11 +419,10 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
if (exchange_state->state == libssh2_NB_state_sent2) {
|
||||
rc = _libssh2_transport_write(session, &exchange_state->c, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send NEWKEYS message", 0);
|
||||
ret = -1;
|
||||
libssh2_error(session, rc, "Unable to send NEWKEYS message", 0);
|
||||
ret = rc;
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
@@ -438,17 +435,16 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
&exchange_state->tmp_len, 0, NULL, 0,
|
||||
&exchange_state->req_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
|
||||
"Timed out waiting for NEWKEYS", 0);
|
||||
ret = -1;
|
||||
libssh2_error(session, rc, "Timed out waiting for NEWKEYS", 0);
|
||||
ret = rc;
|
||||
goto clean_exit;
|
||||
}
|
||||
/* The first key exchange has been performed,
|
||||
switch to active crypt/comp/mac mode */
|
||||
session->state |= LIBSSH2_STATE_NEWKEYS;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Received NEWKEYS message");
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message");
|
||||
|
||||
/* This will actually end up being just packet_type(1)
|
||||
for this packet type anyway */
|
||||
@@ -457,13 +453,15 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
if (!session->session_id) {
|
||||
session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH);
|
||||
if (!session->session_id) {
|
||||
ret = -1;
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate buffer for SHA digest", 0);
|
||||
ret = LIBSSH2_ERROR_ALLOC;
|
||||
goto clean_exit;
|
||||
}
|
||||
memcpy(session->session_id, exchange_state->h_sig_comp,
|
||||
SHA_DIGEST_LENGTH);
|
||||
session->session_id_len = SHA_DIGEST_LENGTH;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "session_id calculated");
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "session_id calculated");
|
||||
}
|
||||
|
||||
/* Cleanup any existing cipher */
|
||||
@@ -489,7 +487,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
secret_len, "C");
|
||||
if (!secret) {
|
||||
LIBSSH2_FREE(session, iv);
|
||||
ret = -1;
|
||||
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||
goto clean_exit;
|
||||
}
|
||||
if (session->local.crypt->
|
||||
@@ -497,7 +495,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
&free_secret, 1, &session->local.crypt_abstract)) {
|
||||
LIBSSH2_FREE(session, iv);
|
||||
LIBSSH2_FREE(session, secret);
|
||||
ret = -1;
|
||||
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
@@ -511,7 +509,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
LIBSSH2_FREE(session, secret);
|
||||
}
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||
"Client to Server IV and Key calculated");
|
||||
|
||||
if (session->remote.crypt->dtor) {
|
||||
@@ -528,7 +526,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
session->remote.crypt->
|
||||
iv_len, "B");
|
||||
if (!iv) {
|
||||
ret = -1;
|
||||
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||
goto clean_exit;
|
||||
}
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret,
|
||||
@@ -536,7 +534,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
secret_len, "D");
|
||||
if (!secret) {
|
||||
LIBSSH2_FREE(session, iv);
|
||||
ret = -1;
|
||||
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||
goto clean_exit;
|
||||
}
|
||||
if (session->remote.crypt->
|
||||
@@ -544,7 +542,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
&free_secret, 0, &session->remote.crypt_abstract)) {
|
||||
LIBSSH2_FREE(session, iv);
|
||||
LIBSSH2_FREE(session, secret);
|
||||
ret = -1;
|
||||
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
@@ -558,7 +556,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
LIBSSH2_FREE(session, secret);
|
||||
}
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||
"Server to Client IV and Key calculated");
|
||||
|
||||
if (session->local.mac->dtor) {
|
||||
@@ -573,7 +571,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
session->local.mac->
|
||||
key_len, "E");
|
||||
if (!key) {
|
||||
ret = -1;
|
||||
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||
goto clean_exit;
|
||||
}
|
||||
session->local.mac->init(session, key, &free_key,
|
||||
@@ -584,7 +582,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
LIBSSH2_FREE(session, key);
|
||||
}
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||
"Client to Server HMAC Key calculated");
|
||||
|
||||
if (session->remote.mac->dtor) {
|
||||
@@ -599,7 +597,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
session->remote.mac->
|
||||
key_len, "F");
|
||||
if (!key) {
|
||||
ret = -1;
|
||||
ret = LIBSSH2_ERROR_KEX_FAILURE;
|
||||
goto clean_exit;
|
||||
}
|
||||
session->remote.mac->init(session, key, &free_key,
|
||||
@@ -610,7 +608,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
LIBSSH2_FREE(session, key);
|
||||
}
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||
"Server to Client HMAC Key calculated");
|
||||
}
|
||||
|
||||
@@ -686,23 +684,16 @@ kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
_libssh2_bn_set_word(key_state->g, 2);
|
||||
_libssh2_bn_from_bin(key_state->p, 128, p_value);
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||
"Initiating Diffie-Hellman Group1 Key Exchange");
|
||||
|
||||
key_state->state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
ret =
|
||||
kex_method_diffie_hellman_groupGP_sha1_key_exchange(session,
|
||||
key_state->g,
|
||||
key_state->p, 128,
|
||||
SSH_MSG_KEXDH_INIT,
|
||||
SSH_MSG_KEXDH_REPLY,
|
||||
NULL, 0,
|
||||
&key_state->
|
||||
exchange_state);
|
||||
ret = diffie_hellman_sha1(session, key_state->g, key_state->p, 128,
|
||||
SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY,
|
||||
NULL, 0, &key_state->exchange_state);
|
||||
if (ret == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return ret;
|
||||
}
|
||||
|
||||
_libssh2_bn_free(key_state->p);
|
||||
@@ -769,23 +760,16 @@ kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
_libssh2_bn_set_word(key_state->g, 2);
|
||||
_libssh2_bn_from_bin(key_state->p, 256, p_value);
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||
"Initiating Diffie-Hellman Group14 Key Exchange");
|
||||
|
||||
key_state->state = libssh2_NB_state_created;
|
||||
}
|
||||
ret =
|
||||
kex_method_diffie_hellman_groupGP_sha1_key_exchange(session,
|
||||
key_state->g,
|
||||
key_state->p,
|
||||
256,
|
||||
SSH_MSG_KEXDH_INIT,
|
||||
SSH_MSG_KEXDH_REPLY,
|
||||
NULL, 0,
|
||||
&key_state->
|
||||
exchange_state);
|
||||
ret = diffie_hellman_sha1(session, key_state->g, key_state->p,
|
||||
256, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY,
|
||||
NULL, 0, &key_state->exchange_state);
|
||||
if (ret == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return ret;
|
||||
}
|
||||
|
||||
key_state->state = libssh2_NB_state_idle;
|
||||
@@ -822,13 +806,13 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange
|
||||
_libssh2_htonu32(key_state->request + 5, LIBSSH2_DH_GEX_OPTGROUP);
|
||||
_libssh2_htonu32(key_state->request + 9, LIBSSH2_DH_GEX_MAXGROUP);
|
||||
key_state->request_len = 13;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||
"Initiating Diffie-Hellman Group-Exchange (New Method)");
|
||||
#else
|
||||
key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD;
|
||||
_libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_OPTGROUP);
|
||||
key_state->request_len = 5;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX,
|
||||
"Initiating Diffie-Hellman Group-Exchange (Old Method)");
|
||||
#endif
|
||||
|
||||
@@ -839,11 +823,11 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange
|
||||
rc = _libssh2_transport_write(session, key_state->request,
|
||||
key_state->request_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
libssh2_error(session, rc,
|
||||
"Unable to send Group Exchange Request", 0);
|
||||
ret = -1;
|
||||
ret = rc;
|
||||
goto dh_gex_clean_exit;
|
||||
}
|
||||
|
||||
@@ -855,11 +839,11 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange
|
||||
&key_state->data, &key_state->data_len,
|
||||
0, NULL, 0, &key_state->req_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
|
||||
libssh2_error(session, rc,
|
||||
"Timeout waiting for GEX_GROUP reply", 0);
|
||||
ret = -1;
|
||||
ret = rc;
|
||||
goto dh_gex_clean_exit;
|
||||
}
|
||||
|
||||
@@ -878,14 +862,14 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange
|
||||
_libssh2_bn_from_bin(key_state->g, g_len, s);
|
||||
s += g_len;
|
||||
|
||||
ret =
|
||||
kex_method_diffie_hellman_groupGP_sha1_key_exchange
|
||||
(session, key_state->g, key_state->p, p_len,
|
||||
SSH_MSG_KEX_DH_GEX_INIT, SSH_MSG_KEX_DH_GEX_REPLY,
|
||||
key_state->data + 1, key_state->data_len - 1,
|
||||
&key_state->exchange_state);
|
||||
ret = diffie_hellman_sha1(session, key_state->g, key_state->p, p_len,
|
||||
SSH_MSG_KEX_DH_GEX_INIT,
|
||||
SSH_MSG_KEX_DH_GEX_REPLY,
|
||||
key_state->data + 1,
|
||||
key_state->data_len - 1,
|
||||
&key_state->exchange_state);
|
||||
if (ret == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return ret;
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, key_state->data);
|
||||
@@ -1056,7 +1040,7 @@ static int kexinit(LIBSSH2_SESSION * session)
|
||||
if (!data) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory", 0);
|
||||
return -1;
|
||||
return LIBSSH2_ERROR_ALLOC;
|
||||
}
|
||||
|
||||
*(s++) = SSH_MSG_KEXINIT;
|
||||
@@ -1106,25 +1090,25 @@ static int kexinit(LIBSSH2_SESSION * session)
|
||||
/* Funnily enough, they'll all "appear" to be '\0' terminated */
|
||||
unsigned char *p = data + 21; /* type(1) + cookie(16) + len(4) */
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent KEX: %s", p);
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent KEX: %s", p);
|
||||
p += kex_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent HOSTKEY: %s", p);
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent HOSTKEY: %s", p);
|
||||
p += hostkey_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_CS: %s", p);
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent CRYPT_CS: %s", p);
|
||||
p += crypt_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_SC: %s", p);
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent CRYPT_SC: %s", p);
|
||||
p += crypt_sc_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_CS: %s", p);
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent MAC_CS: %s", p);
|
||||
p += mac_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_SC: %s", p);
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent MAC_SC: %s", p);
|
||||
p += mac_sc_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_CS: %s", p);
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent COMP_CS: %s", p);
|
||||
p += comp_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_SC: %s", p);
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent COMP_SC: %s", p);
|
||||
p += comp_sc_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_CS: %s", p);
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent LANG_CS: %s", p);
|
||||
p += lang_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_SC: %s", p);
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent LANG_SC: %s", p);
|
||||
p += lang_sc_len + 4;
|
||||
}
|
||||
#endif /* LIBSSH2DEBUG */
|
||||
@@ -1139,14 +1123,14 @@ static int kexinit(LIBSSH2_SESSION * session)
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
session->kexinit_data = data;
|
||||
session->kexinit_data_len = data_len;
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
else if (rc) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
libssh2_error(session, rc,
|
||||
"Unable to send KEXINIT packet to remote host", 0);
|
||||
session->kexinit_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (session->local.kexinit) {
|
||||
@@ -1623,24 +1607,24 @@ static int kex_agree_methods(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
return -1;
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on KEX method: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on KEX method: %s",
|
||||
session->kex->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on HOSTKEY method: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on HOSTKEY method: %s",
|
||||
session->hostkey->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_CS method: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on CRYPT_CS method: %s",
|
||||
session->local.crypt->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_SC method: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on CRYPT_SC method: %s",
|
||||
session->remote.crypt->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_CS method: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on MAC_CS method: %s",
|
||||
session->local.mac->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_SC method: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on MAC_SC method: %s",
|
||||
session->remote.mac->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_CS method: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on COMP_CS method: %s",
|
||||
session->local.comp->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_SC method: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_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 */
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on LANG_CS method:"); /* None yet */
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on LANG_SC method:"); /* None yet */
|
||||
|
||||
/* Initialize compression layer */
|
||||
if (session->local.comp && session->local.comp->init &&
|
||||
@@ -1662,6 +1646,8 @@ static int kex_agree_methods(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
/* libssh2_kex_exchange
|
||||
* Exchange keys
|
||||
* Returns 0 on success, non-zero on failure
|
||||
*
|
||||
* Returns some errors without libssh2_error()
|
||||
*/
|
||||
int
|
||||
libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
|
||||
@@ -1704,7 +1690,7 @@ libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
|
||||
retcode = kexinit(session);
|
||||
if (retcode == PACKET_EAGAIN) {
|
||||
session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
|
||||
return PACKET_EAGAIN;
|
||||
return retcode;
|
||||
} else if (retcode) {
|
||||
session->local.kexinit = key_state->oldlocal;
|
||||
session->local.kexinit_len = key_state->oldlocal_len;
|
||||
@@ -1725,7 +1711,7 @@ libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
|
||||
&key_state->req_state);
|
||||
if (retcode == PACKET_EAGAIN) {
|
||||
session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
|
||||
return PACKET_EAGAIN;
|
||||
return retcode;
|
||||
}
|
||||
else if (retcode) {
|
||||
if (session->local.kexinit) {
|
||||
@@ -1746,9 +1732,8 @@ libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
|
||||
session->remote.kexinit_len = key_state->data_len;
|
||||
|
||||
if (kex_agree_methods(session, key_state->data,
|
||||
key_state->data_len)) {
|
||||
rc = -1;
|
||||
}
|
||||
key_state->data_len))
|
||||
rc = LIBSSH2_ERROR_KEX_FAILURE;
|
||||
|
||||
key_state->state = libssh2_NB_state_sent2;
|
||||
}
|
||||
@@ -1758,16 +1743,15 @@ libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
|
||||
|
||||
if (rc == 0) {
|
||||
if (key_state->state == libssh2_NB_state_sent2) {
|
||||
retcode =
|
||||
session->kex->exchange_keys(session,
|
||||
&key_state->key_state_low);
|
||||
retcode = session->kex->exchange_keys(session,
|
||||
&key_state->key_state_low);
|
||||
if (retcode == PACKET_EAGAIN) {
|
||||
session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
|
||||
return PACKET_EAGAIN;
|
||||
return retcode;
|
||||
} else if (retcode) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE,
|
||||
"Unrecoverable error exchanging keys", 0);
|
||||
rc = -1;
|
||||
rc = retcode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
101
src/libgcrypt.c
101
src/libgcrypt.c
@@ -1,5 +1,5 @@
|
||||
/* Copyright (C) 2006, 2007, The Written Word, Inc.
|
||||
* Copyright (C) 2008, Simon Josefsson
|
||||
/* Copyright (C) 2008, 2009, Simon Josefsson
|
||||
* Copyright (C) 2006, 2007, The Written Word, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -37,6 +37,9 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
|
||||
#ifdef LIBSSH2_LIBGCRYPT /* compile only if we build with libgcrypt */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
int
|
||||
@@ -149,8 +152,9 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx,
|
||||
int
|
||||
_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
||||
LIBSSH2_SESSION * session,
|
||||
FILE * fp, unsigned const char *passphrase)
|
||||
const char *filename, unsigned const char *passphrase)
|
||||
{
|
||||
FILE *fp;
|
||||
unsigned char *data, *save_data;
|
||||
unsigned int datalen;
|
||||
int ret;
|
||||
@@ -159,10 +163,16 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
||||
|
||||
(void) passphrase;
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
if (!fp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_parse(session,
|
||||
"-----BEGIN RSA PRIVATE KEY-----",
|
||||
"-----END RSA PRIVATE KEY-----",
|
||||
fp, &data, &datalen);
|
||||
fclose(fp);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
@@ -244,8 +254,9 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
||||
int
|
||||
_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
|
||||
LIBSSH2_SESSION * session,
|
||||
FILE * fp, unsigned const char *passphrase)
|
||||
const char *filename, unsigned const char *passphrase)
|
||||
{
|
||||
FILE *fp;
|
||||
unsigned char *data, *save_data;
|
||||
unsigned int datalen;
|
||||
int ret;
|
||||
@@ -254,10 +265,16 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
|
||||
|
||||
(void) passphrase;
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
if (!fp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_parse(session,
|
||||
"-----BEGIN DSA PRIVATE KEY-----",
|
||||
"-----END DSA PRIVATE KEY-----",
|
||||
fp, &data, &datalen);
|
||||
fclose(fp);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
@@ -407,61 +424,54 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(sig, 0, 40);
|
||||
|
||||
/* Extract R. */
|
||||
|
||||
data = gcry_sexp_find_token(sig_sexp, "r", 0);
|
||||
if (!data) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
if (!data)
|
||||
goto err;
|
||||
|
||||
tmp = gcry_sexp_nth_data(data, 1, &size);
|
||||
if (!tmp) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
if (!tmp)
|
||||
goto err;
|
||||
|
||||
if (tmp[0] == '\0') {
|
||||
tmp++;
|
||||
size--;
|
||||
}
|
||||
|
||||
if (size != 20) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
if (size < 1 || size > 20)
|
||||
goto err;
|
||||
|
||||
memcpy(sig, tmp, 20);
|
||||
memcpy(sig + (20 - size), tmp, size);
|
||||
|
||||
gcry_sexp_release(data);
|
||||
|
||||
/* Extract S. */
|
||||
|
||||
data = gcry_sexp_find_token(sig_sexp, "s", 0);
|
||||
if (!data) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
if (!data)
|
||||
goto err;
|
||||
|
||||
tmp = gcry_sexp_nth_data(data, 1, &size);
|
||||
if (!tmp) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
if (!tmp)
|
||||
goto err;
|
||||
|
||||
if (tmp[0] == '\0') {
|
||||
tmp++;
|
||||
size--;
|
||||
}
|
||||
|
||||
if (size != 20) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
if (size < 1 || size > 20)
|
||||
goto err;
|
||||
|
||||
memcpy(sig + 20, tmp, 20);
|
||||
memcpy(sig + 20 + (20 - size), tmp, size);
|
||||
goto out;
|
||||
|
||||
err:
|
||||
ret = -1;
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
if (sig_sexp) {
|
||||
gcry_sexp_release(sig_sexp);
|
||||
@@ -507,16 +517,14 @@ _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);
|
||||
int ret;
|
||||
int cipher = _libssh2_gcry_cipher (algo);
|
||||
int mode = _libssh2_gcry_mode (algo);
|
||||
int keylen = gcry_cipher_get_algo_keylen(cipher);
|
||||
|
||||
(void) encrypt;
|
||||
|
||||
if (algo != GCRY_CIPHER_ARCFOUR) {
|
||||
mode = GCRY_CIPHER_MODE_CBC;
|
||||
}
|
||||
|
||||
ret = gcry_cipher_open(h, algo, mode, 0);
|
||||
ret = gcry_cipher_open(h, cipher, mode, 0);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
@@ -527,10 +535,13 @@ _libssh2_cipher_init(_libssh2_cipher_ctx * 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) {
|
||||
if (mode != GCRY_CIPHER_MODE_STREAM) {
|
||||
int blklen = gcry_cipher_get_algo_blklen(cipher);
|
||||
if (mode == GCRY_CIPHER_MODE_CTR)
|
||||
ret = gcry_cipher_setctr(*h, iv, blklen);
|
||||
else
|
||||
ret = gcry_cipher_setiv(*h, iv, blklen);
|
||||
if (ret) {
|
||||
gcry_cipher_close(*h);
|
||||
return -1;
|
||||
}
|
||||
@@ -544,8 +555,10 @@ _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 cipher = _libssh2_gcry_cipher (algo);
|
||||
size_t blklen = gcry_cipher_get_algo_blklen(cipher);
|
||||
int ret;
|
||||
|
||||
if (blklen == 1) {
|
||||
/* Hack for arcfour. */
|
||||
blklen = 8;
|
||||
@@ -558,3 +571,5 @@ _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_LIBGCRYPT */
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/* Copyright (C) 2006, 2007, The Written Word, Inc.
|
||||
* Copyright (C) 2008, Simon Josefsson
|
||||
/*
|
||||
* Copyright (C) 2008, 2009 Simon Josefsson
|
||||
* Copyright (C) 2006, 2007, The Written Word, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -43,6 +44,7 @@
|
||||
#define LIBSSH2_HMAC_RIPEMD 1
|
||||
|
||||
#define LIBSSH2_AES 1
|
||||
#define LIBSSH2_AES_CTR 1
|
||||
#define LIBSSH2_BLOWFISH 1
|
||||
#define LIBSSH2_RC4 1
|
||||
#define LIBSSH2_CAST 1
|
||||
@@ -112,7 +114,8 @@ int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
|
||||
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);
|
||||
const char *filename,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
@@ -140,7 +143,8 @@ int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
|
||||
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);
|
||||
const char *filename,
|
||||
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);
|
||||
@@ -153,13 +157,30 @@ int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * 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
|
||||
#define _libssh2_gcry_ciphermode(c,m) ((c << 8) | m)
|
||||
#define _libssh2_gcry_cipher(c) (c >> 8)
|
||||
#define _libssh2_gcry_mode(m) (m & 0xFF)
|
||||
|
||||
#define _libssh2_cipher_aes256ctr \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR)
|
||||
#define _libssh2_cipher_aes192ctr \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR)
|
||||
#define _libssh2_cipher_aes128ctr \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR)
|
||||
#define _libssh2_cipher_aes256 \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC)
|
||||
#define _libssh2_cipher_aes192 \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC)
|
||||
#define _libssh2_cipher_aes128 \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC)
|
||||
#define _libssh2_cipher_blowfish \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC)
|
||||
#define _libssh2_cipher_arcfour \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM)
|
||||
#define _libssh2_cipher_cast5 \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC)
|
||||
#define _libssh2_cipher_3des \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC)
|
||||
|
||||
int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
|
||||
_libssh2_cipher_type(algo),
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2009 by Daniel Stenberg
|
||||
* Copyright (c) 2010 Simon Josefsson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -85,6 +86,7 @@
|
||||
#include "libssh2.h"
|
||||
#include "libssh2_publickey.h"
|
||||
#include "libssh2_sftp.h"
|
||||
#include "misc.h" /* for the linked list stuff */
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
@@ -96,10 +98,9 @@
|
||||
/* Provide iovec / writev on WIN32 platform. */
|
||||
#ifdef WIN32
|
||||
|
||||
/* same as WSABUF */
|
||||
struct iovec {
|
||||
u_long iov_len;
|
||||
char *iov_base;
|
||||
size_t iov_len;
|
||||
void * iov_base;
|
||||
};
|
||||
|
||||
#define inline __inline
|
||||
@@ -149,6 +150,13 @@ static inline int writev(int sock, struct iovec *iov, int nvecs)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
typedef SOCKET libssh2_socket_t;
|
||||
#else /* !WIN32 */
|
||||
typedef int libssh2_socket_t;
|
||||
#define INVALID_SOCKET -1
|
||||
#endif /* WIN32 */
|
||||
|
||||
/* RFC4253 section 6.1 Maximum Packet Length says:
|
||||
*
|
||||
* "All implementations MUST be able to process packets with
|
||||
@@ -187,10 +195,6 @@ typedef struct _LIBSSH2_CRYPT_METHOD LIBSSH2_CRYPT_METHOD;
|
||||
typedef struct _LIBSSH2_COMP_METHOD LIBSSH2_COMP_METHOD;
|
||||
|
||||
typedef struct _LIBSSH2_PACKET LIBSSH2_PACKET;
|
||||
typedef struct _LIBSSH2_PACKET_BRIGADE LIBSSH2_PACKET_BRIGADE;
|
||||
typedef struct _LIBSSH2_CHANNEL_BRIGADE LIBSSH2_CHANNEL_BRIGADE;
|
||||
|
||||
typedef int libssh2pack_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -207,7 +211,9 @@ typedef enum
|
||||
libssh2_NB_state_sent7,
|
||||
libssh2_NB_state_jump1,
|
||||
libssh2_NB_state_jump2,
|
||||
libssh2_NB_state_jump3
|
||||
libssh2_NB_state_jump3,
|
||||
libssh2_NB_state_jump4,
|
||||
libssh2_NB_state_jump5
|
||||
} libssh2_nonblocking_states;
|
||||
|
||||
typedef struct packet_require_state_t
|
||||
@@ -288,6 +294,7 @@ typedef struct packet_queue_listener_state_t
|
||||
uint32_t sport;
|
||||
uint32_t host_len;
|
||||
uint32_t shost_len;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
} packet_queue_listener_state_t;
|
||||
|
||||
#define X11FwdUnAvil "X11 Forward Unavailable"
|
||||
@@ -302,10 +309,13 @@ typedef struct packet_x11_open_state_t
|
||||
uint32_t packet_size;
|
||||
uint32_t sport;
|
||||
uint32_t shost_len;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
} packet_x11_open_state_t;
|
||||
|
||||
struct _LIBSSH2_PACKET
|
||||
{
|
||||
struct list_node node; /* linked list header */
|
||||
|
||||
unsigned char type;
|
||||
|
||||
/* Unencrypted Payload (no type byte, no padding, just the facts ma'am) */
|
||||
@@ -318,15 +328,6 @@ struct _LIBSSH2_PACKET
|
||||
|
||||
/* Can the message be confirmed? */
|
||||
int mac;
|
||||
|
||||
LIBSSH2_PACKET_BRIGADE *brigade;
|
||||
|
||||
LIBSSH2_PACKET *next, *prev;
|
||||
};
|
||||
|
||||
struct _LIBSSH2_PACKET_BRIGADE
|
||||
{
|
||||
LIBSSH2_PACKET *head, *tail;
|
||||
};
|
||||
|
||||
typedef struct _libssh2_channel_data
|
||||
@@ -343,6 +344,8 @@ typedef struct _libssh2_channel_data
|
||||
|
||||
struct _LIBSSH2_CHANNEL
|
||||
{
|
||||
struct list_node node;
|
||||
|
||||
unsigned char *channel_type;
|
||||
unsigned channel_type_len;
|
||||
|
||||
@@ -355,8 +358,6 @@ struct _LIBSSH2_CHANNEL
|
||||
|
||||
LIBSSH2_SESSION *session;
|
||||
|
||||
LIBSSH2_CHANNEL *next, *prev;
|
||||
|
||||
void *abstract;
|
||||
LIBSSH2_CHANNEL_CLOSE_FUNC((*close_cb));
|
||||
|
||||
@@ -399,8 +400,6 @@ struct _LIBSSH2_CHANNEL
|
||||
|
||||
/* State variables used in libssh2_channel_read_ex() */
|
||||
libssh2_nonblocking_states read_state;
|
||||
LIBSSH2_PACKET *read_packet;
|
||||
LIBSSH2_PACKET *read_next;
|
||||
|
||||
uint32_t read_local_id;
|
||||
|
||||
@@ -429,24 +428,21 @@ struct _LIBSSH2_CHANNEL
|
||||
libssh2_nonblocking_states extData2_state;
|
||||
};
|
||||
|
||||
struct _LIBSSH2_CHANNEL_BRIGADE
|
||||
{
|
||||
LIBSSH2_CHANNEL *head, *tail;
|
||||
};
|
||||
|
||||
struct _LIBSSH2_LISTENER
|
||||
{
|
||||
struct list_node node; /* linked list header */
|
||||
|
||||
LIBSSH2_SESSION *session;
|
||||
|
||||
char *host;
|
||||
int port;
|
||||
|
||||
LIBSSH2_CHANNEL *queue;
|
||||
/* a list of CHANNELs for this listener */
|
||||
struct list_head queue;
|
||||
|
||||
int queue_size;
|
||||
int queue_maxsize;
|
||||
|
||||
LIBSSH2_LISTENER *prev, *next;
|
||||
|
||||
/* State variables used in libssh2_channel_forward_cancel() */
|
||||
libssh2_nonblocking_states chanFwdCncl_state;
|
||||
unsigned char *chanFwdCncl_data;
|
||||
@@ -547,8 +543,9 @@ struct _LIBSSH2_PUBLICKEY
|
||||
|
||||
struct _LIBSSH2_SFTP_HANDLE
|
||||
{
|
||||
struct list_node node;
|
||||
|
||||
LIBSSH2_SFTP *sftp;
|
||||
LIBSSH2_SFTP_HANDLE *prev, *next;
|
||||
|
||||
/* This is a pre-allocated buffer used for sending SFTP requests as the
|
||||
whole thing might not get sent in one go. This buffer is used for read,
|
||||
@@ -586,9 +583,10 @@ struct _LIBSSH2_SFTP
|
||||
|
||||
unsigned long request_id, version;
|
||||
|
||||
LIBSSH2_PACKET_BRIGADE packets;
|
||||
struct list_head packets;
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *handles;
|
||||
/* a list of _LIBSSH2_SFTP_HANDLE structs */
|
||||
struct list_head sftp_handles;
|
||||
|
||||
unsigned long last_errno;
|
||||
|
||||
@@ -713,18 +711,19 @@ struct _LIBSSH2_SESSION
|
||||
/* (local as source of data -- packet_write ) */
|
||||
libssh2_endpoint_data local;
|
||||
|
||||
/* Inbound Data buffer -- Sometimes the packet that comes in isn't the
|
||||
/* Inbound Data linked list -- Sometimes the packet that comes in isn't the
|
||||
packet we're ready for */
|
||||
LIBSSH2_PACKET_BRIGADE packets;
|
||||
struct list_head packets;
|
||||
|
||||
/* Active connection channels */
|
||||
LIBSSH2_CHANNEL_BRIGADE channels;
|
||||
struct list_head channels;
|
||||
|
||||
unsigned long next_channel;
|
||||
|
||||
LIBSSH2_LISTENER *listeners;
|
||||
struct list_head listeners; /* list of LIBSSH2_LISTENER structs */
|
||||
|
||||
/* Actual I/O socket */
|
||||
int socket_fd;
|
||||
libssh2_socket_t socket_fd;
|
||||
int socket_state;
|
||||
int socket_block_directions;
|
||||
int socket_prev_blockstate; /* stores the state of the socket blockiness
|
||||
@@ -740,6 +739,8 @@ struct _LIBSSH2_SESSION
|
||||
struct transportpacket packet;
|
||||
#ifdef LIBSSH2DEBUG
|
||||
int showmask; /* what debug/trace messages to display */
|
||||
libssh2_trace_handler_func tracehandler; /* callback to display trace messages */
|
||||
void* tracehandler_context; /* context for the trace handler */
|
||||
#endif
|
||||
|
||||
/* State variables used in libssh2_banner_send() */
|
||||
@@ -811,7 +812,7 @@ struct _LIBSSH2_SESSION
|
||||
unsigned char *userauth_pblc_b;
|
||||
packet_requirev_state_t userauth_pblc_packet_requirev_state;
|
||||
|
||||
/* State variables used in llibssh2_userauth_keyboard_interactive_ex() */
|
||||
/* State variables used in libssh2_userauth_keyboard_interactive_ex() */
|
||||
libssh2_nonblocking_states userauth_kybd_state;
|
||||
unsigned char *userauth_kybd_data;
|
||||
unsigned long userauth_kybd_data_len;
|
||||
@@ -860,7 +861,6 @@ struct _LIBSSH2_SESSION
|
||||
|
||||
/* State variables used in libssh2_packet_add() */
|
||||
libssh2_nonblocking_states packAdd_state;
|
||||
LIBSSH2_PACKET *packAdd_packet;
|
||||
LIBSSH2_CHANNEL *packAdd_channel;
|
||||
unsigned long packAdd_data_head;
|
||||
key_exchange_state_t packAdd_key_state;
|
||||
@@ -871,7 +871,7 @@ struct _LIBSSH2_SESSION
|
||||
libssh2_nonblocking_states fullpacket_state;
|
||||
int fullpacket_macstate;
|
||||
int fullpacket_payload_len;
|
||||
libssh2pack_t fullpacket_packet_type;
|
||||
int fullpacket_packet_type;
|
||||
|
||||
/* State variables used in libssh2_sftp_init() */
|
||||
libssh2_nonblocking_states sftpInit_state;
|
||||
@@ -928,22 +928,6 @@ struct _LIBSSH2_SESSION
|
||||
#define LIBSSH2_SOCKET_RECV_FLAGS(session) 0
|
||||
#endif
|
||||
|
||||
/* -------- */
|
||||
|
||||
/* First take towards a generic linked list handling code for libssh2
|
||||
internals */
|
||||
|
||||
struct list_head {
|
||||
struct list_node *last;
|
||||
struct list_node *first;
|
||||
};
|
||||
|
||||
struct list_node {
|
||||
struct list_node *next;
|
||||
struct list_node *prev;
|
||||
struct list_head *head;
|
||||
};
|
||||
|
||||
/* --------- */
|
||||
|
||||
/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional
|
||||
@@ -1036,14 +1020,6 @@ struct _LIBSSH2_MAC_METHOD
|
||||
int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
|
||||
};
|
||||
|
||||
#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
|
||||
#ifdef LIBSSH2DEBUG
|
||||
void _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format,
|
||||
...);
|
||||
@@ -1070,7 +1046,7 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
|
||||
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); \
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_ERROR, "%d - %s", session->err_code, session->err_msg); \
|
||||
}
|
||||
|
||||
#else /* ! LIBSSH2DEBUG */
|
||||
@@ -1161,8 +1137,8 @@ libssh2_uint64_t _libssh2_ntohu64(const unsigned char *buf);
|
||||
void _libssh2_htonu32(unsigned char *buf, unsigned int val);
|
||||
|
||||
#ifdef WIN32
|
||||
ssize_t _libssh2_recv(int socket, void *buffer, size_t length, int flags);
|
||||
ssize_t _libssh2_send(int socket, const void *buffer, size_t length, int flags);
|
||||
ssize_t _libssh2_recv(libssh2_socket_t socket, void *buffer, size_t length, int flags);
|
||||
ssize_t _libssh2_send(libssh2_socket_t socket, const void *buffer, size_t length, int flags);
|
||||
#else
|
||||
#define _libssh2_recv(a,b,c,d) recv(a,b,c,d)
|
||||
#define _libssh2_send(a,b,c,d) send(a,b,c,d)
|
||||
@@ -1174,20 +1150,21 @@ ssize_t _libssh2_send(int socket, const void *buffer, size_t length, int flags);
|
||||
int _libssh2_wait_socket(LIBSSH2_SESSION *session);
|
||||
|
||||
|
||||
/* CAUTION: some of these error codes are returned in the public API and is
|
||||
there known with other #defined names from the public header file. They
|
||||
should not be changed. */
|
||||
/* These started out as private return codes for the transport layer, but was
|
||||
converted to using the library-wide return codes to easy propagation of the
|
||||
error reasons all over etc without risking mixups. The PACKET_* names are
|
||||
left only to reduce the impact of changing the code all over.*/
|
||||
|
||||
#define PACKET_TIMEOUT -7
|
||||
#define PACKET_BADUSE -6
|
||||
#define PACKET_COMPRESS -5
|
||||
#define PACKET_TOOBIG -4
|
||||
#define PACKET_ENOMEM -3
|
||||
#define PACKET_TIMEOUT LIBSSH2_ERROR_TIMEOUT
|
||||
#define PACKET_BADUSE LIBSSH2_ERROR_BAD_USE
|
||||
#define PACKET_COMPRESS LIBSSH2_ERROR_COMPRESS
|
||||
#define PACKET_TOOBIG LIBSSH2_ERROR_OUT_OF_BOUNDARY
|
||||
#define PACKET_ENOMEM LIBSSH2_ERROR_ALLOC
|
||||
#define PACKET_EAGAIN LIBSSH2_ERROR_EAGAIN
|
||||
#define PACKET_FAIL -1
|
||||
#define PACKET_NONE 0
|
||||
#define PACKET_FAIL LIBSSH2_ERROR_SOCKET_NONE
|
||||
#define PACKET_NONE LIBSSH2_ERROR_NONE
|
||||
|
||||
libssh2pack_t _libssh2_packet_read(LIBSSH2_SESSION * session);
|
||||
int _libssh2_packet_read(LIBSSH2_SESSION * session);
|
||||
|
||||
int _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type,
|
||||
unsigned char **data, unsigned long *data_len,
|
||||
@@ -1292,4 +1269,7 @@ int _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
|
||||
} while(1)
|
||||
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof ((a)) / sizeof ((a)[0]))
|
||||
|
||||
|
||||
#endif /* LIBSSH2_H */
|
||||
|
@@ -167,6 +167,7 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1_96 = {
|
||||
mac_method_common_dtor,
|
||||
};
|
||||
|
||||
#if LIBSSH2_MD5
|
||||
/* mac_method_hmac_md5_hash
|
||||
* Calculate hash using full md5 value
|
||||
*/
|
||||
@@ -235,6 +236,7 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_md5_96 = {
|
||||
mac_method_hmac_md5_96_hash,
|
||||
mac_method_common_dtor,
|
||||
};
|
||||
#endif /* LIBSSH2_MD5 */
|
||||
|
||||
#if LIBSSH2_HMAC_RIPEMD
|
||||
/* mac_method_hmac_ripemd160_hash
|
||||
@@ -291,8 +293,10 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160_openssh_com = {
|
||||
static const LIBSSH2_MAC_METHOD *mac_methods[] = {
|
||||
&mac_method_hmac_sha1,
|
||||
&mac_method_hmac_sha1_96,
|
||||
#if LIBSSH2_MD5
|
||||
&mac_method_hmac_md5,
|
||||
&mac_method_hmac_md5_96,
|
||||
#endif
|
||||
#if LIBSSH2_HMAC_RIPEMD
|
||||
&mac_method_hmac_ripemd160,
|
||||
&mac_method_hmac_ripemd160_openssh_com,
|
||||
|
130
src/misc.c
130
src/misc.c
@@ -78,7 +78,7 @@ static int wsa2errno(void)
|
||||
* to set errno
|
||||
*/
|
||||
ssize_t
|
||||
_libssh2_recv(int socket, void *buffer, size_t length, int flags)
|
||||
_libssh2_recv(libssh2_socket_t socket, void *buffer, size_t length, int flags)
|
||||
{
|
||||
ssize_t rc = recv(socket, buffer, length, flags);
|
||||
#ifdef WIN32
|
||||
@@ -97,7 +97,7 @@ _libssh2_recv(int socket, void *buffer, size_t length, int flags)
|
||||
* to set errno
|
||||
*/
|
||||
ssize_t
|
||||
_libssh2_send(int socket, const void *buffer, size_t length, int flags)
|
||||
_libssh2_send(libssh2_socket_t socket, const void *buffer, size_t length, int flags)
|
||||
{
|
||||
ssize_t rc = send(socket, buffer, length, flags);
|
||||
#ifdef WIN32
|
||||
@@ -312,6 +312,14 @@ libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBSSH2_API int
|
||||
libssh2_trace_sethandler(LIBSSH2_SESSION *session, void* handler_context, libssh2_trace_handler_func callback)
|
||||
{
|
||||
session->tracehandler = callback;
|
||||
session->tracehandler_context = handler_context;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
|
||||
{
|
||||
@@ -320,7 +328,7 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
|
||||
va_list vargs;
|
||||
struct timeval now;
|
||||
static int firstsec;
|
||||
static const char *const contexts[9] = {
|
||||
static const char *const contexts[] = {
|
||||
"Unknown",
|
||||
"Transport",
|
||||
"Key Ex",
|
||||
@@ -330,15 +338,24 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
|
||||
"SFTP",
|
||||
"Failure Event",
|
||||
"Publickey",
|
||||
"Socket",
|
||||
};
|
||||
const char* contexttext = contexts[0];
|
||||
unsigned int contextindex;
|
||||
|
||||
if (context < 1 || context > 8) {
|
||||
context = 0;
|
||||
}
|
||||
if (!(session->showmask & (1 << context))) {
|
||||
if (!(session->showmask & context)) {
|
||||
/* no such output asked for */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find the first matching context string for this message */
|
||||
for (contextindex = 0; contextindex < ARRAY_SIZE(contexts); contextindex++) {
|
||||
if ((context & (1 << contextindex)) != 0) {
|
||||
contexttext = contexts[contextindex];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
if(!firstsec) {
|
||||
firstsec = now.tv_sec;
|
||||
@@ -346,14 +363,18 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
|
||||
now.tv_sec -= firstsec;
|
||||
|
||||
len = snprintf(buffer, sizeof(buffer), "[libssh2] %d.%06d %s: ",
|
||||
(int)now.tv_sec, (int)now.tv_usec, contexts[context]);
|
||||
(int)now.tv_sec, (int)now.tv_usec, contexttext);
|
||||
|
||||
va_start(vargs, format);
|
||||
len += vsnprintf(buffer + len, 1535 - len, format, vargs);
|
||||
buffer[len] = '\n';
|
||||
va_end(vargs);
|
||||
write(2, buffer, len + 1);
|
||||
|
||||
if (session->tracehandler) {
|
||||
(session->tracehandler)(session, session->tracehandler_context, buffer, len + 1);
|
||||
} else {
|
||||
write(2, buffer, len + 1);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -364,6 +385,15 @@ libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
|
||||
(void) bitmask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBSSH2_API int
|
||||
libssh2_trace_sethandler(LIBSSH2_SESSION *session, void* handler_context, libssh2_trace_handler_func callback)
|
||||
{
|
||||
(void) session;
|
||||
(void) handler_context;
|
||||
(void) callback;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* init the list head */
|
||||
@@ -426,3 +456,85 @@ void _libssh2_list_remove(struct list_node *entry)
|
||||
else
|
||||
entry->head->last = entry->prev;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* insert a node before the given 'after' entry */
|
||||
void _libssh2_list_insert(struct list_node *after, /* insert before this */
|
||||
struct list_node *entry)
|
||||
{
|
||||
/* 'after' is next to 'entry' */
|
||||
bentry->next = after;
|
||||
|
||||
/* entry's prev is then made to be the prev after current has */
|
||||
entry->prev = after->prev;
|
||||
|
||||
/* the node that is now before 'entry' was previously before 'after'
|
||||
and must be made to point to 'entry' correctly */
|
||||
if(entry->prev)
|
||||
entry->prev->next = entry;
|
||||
else
|
||||
/* there was no node before this, so we make sure we point the head
|
||||
pointer to this node */
|
||||
after->head->first = entry;
|
||||
|
||||
/* after's prev entry points back to entry */
|
||||
after->prev = entry;
|
||||
|
||||
/* after's next entry is still the same as before */
|
||||
|
||||
/* entry's head is the same as after's */
|
||||
entry->head = after->head;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
/*
|
||||
* gettimeofday
|
||||
* Implementation according to:
|
||||
* The Open Group Base Specifications Issue 6
|
||||
* IEEE Std 1003.1, 2004 Edition
|
||||
*/
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS NOT COPYRIGHTED
|
||||
*
|
||||
* This source code is offered for use in the public domain. You may
|
||||
* use, modify or distribute it freely.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful but
|
||||
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
|
||||
* DISCLAIMED. This includes but is not limited to warranties of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Contributed by:
|
||||
* Danny Smith <dannysmith@users.sourceforge.net>
|
||||
*/
|
||||
|
||||
/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
|
||||
#define _W32_FT_OFFSET (116444736000000000ULL)
|
||||
|
||||
|
||||
int __cdecl gettimeofday(struct timeval *tp,
|
||||
void *tzp)
|
||||
{
|
||||
union {
|
||||
unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
|
||||
FILETIME ft;
|
||||
} _now;
|
||||
|
||||
if(tp)
|
||||
{
|
||||
GetSystemTimeAsFileTime (&_now.ft);
|
||||
tp->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL );
|
||||
tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL);
|
||||
}
|
||||
/* Always return 0 as per Open Group Base Specifications Issue 6.
|
||||
Do not set errno on error. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
15
src/misc.h
15
src/misc.h
@@ -38,11 +38,20 @@
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
struct list_head {
|
||||
struct list_node *last;
|
||||
struct list_node *first;
|
||||
};
|
||||
|
||||
struct list_node {
|
||||
struct list_node *next;
|
||||
struct list_node *prev;
|
||||
struct list_head *head;
|
||||
};
|
||||
|
||||
void _libssh2_list_init(struct list_head *head);
|
||||
|
||||
/* add a node first in the list */
|
||||
/* add a node last in the list */
|
||||
void _libssh2_list_add(struct list_head *head,
|
||||
struct list_node *entry);
|
||||
|
||||
@@ -58,6 +67,6 @@ void *_libssh2_list_prev(struct list_node *node);
|
||||
/* remove this node from the list */
|
||||
void _libssh2_list_remove(struct list_node *entry);
|
||||
|
||||
size_t _libssh2_base64_encode(LIBSSH2_SESSION *session,
|
||||
size_t _libssh2_base64_encode(struct _LIBSSH2_SESSION *session,
|
||||
const char *inp, size_t insize, char **outptr);
|
||||
#endif /* _LIBSSH2_MISC_H */
|
||||
|
198
src/openssl.c
198
src/openssl.c
@@ -1,7 +1,9 @@
|
||||
/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
* Author: Simon Josefsson
|
||||
/* Copyright (C) 2009 Simon Josefsson
|
||||
* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
*
|
||||
* Author: Simon Josefsson
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
@@ -37,15 +39,15 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
|
||||
#ifndef LIBSSH2_LIBGCRYPT /* compile only if we build with OpenSSL */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef EVP_MAX_BLOCK_LENGTH
|
||||
#define EVP_MAX_BLOCK_LENGTH 32
|
||||
#endif
|
||||
|
||||
/* Ridiculously large key-file size cap (512KB) */
|
||||
#define MAX_KEY_FILE_LENGTH 524288
|
||||
|
||||
int
|
||||
_libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
|
||||
const unsigned char *edata,
|
||||
@@ -197,6 +199,110 @@ _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
|
||||
return ret == 1 ? 0 : 1;
|
||||
}
|
||||
|
||||
#if LIBSSH2_AES_CTR
|
||||
#include <openssl/aes.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
AES_KEY key;
|
||||
unsigned char ctr[AES_BLOCK_SIZE];
|
||||
} aes_ctr_ctx;
|
||||
|
||||
static int
|
||||
aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc) /* init key */
|
||||
{
|
||||
aes_ctr_ctx *c = malloc(sizeof(*c));
|
||||
(void) enc;
|
||||
|
||||
if (c == NULL)
|
||||
return 0;
|
||||
|
||||
AES_set_encrypt_key(key, 8 * ctx->key_len, &c->key);
|
||||
memcpy(c->ctr, iv, AES_BLOCK_SIZE);
|
||||
|
||||
EVP_CIPHER_CTX_set_app_data(ctx, c);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in,
|
||||
unsigned int inl) /* encrypt/decrypt data */
|
||||
{
|
||||
aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx);
|
||||
unsigned char b1[AES_BLOCK_SIZE];
|
||||
size_t i;
|
||||
|
||||
if (inl != 16) /* libssh2 only ever encrypt one block */
|
||||
return 0;
|
||||
|
||||
/*
|
||||
To encrypt a packet P=P1||P2||...||Pn (where P1, P2, ..., Pn are each
|
||||
blocks of length L), the encryptor first encrypts <X> with <cipher>
|
||||
to obtain a block B1. The block B1 is then XORed with P1 to generate
|
||||
the ciphertext block C1. The counter X is then incremented
|
||||
*/
|
||||
|
||||
AES_encrypt(c->ctr, b1, &c->key);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
*out++ = *in++ ^ b1[i];
|
||||
|
||||
i = 15;
|
||||
while (c->ctr[i]++ == 0xFF) {
|
||||
if (i == 0)
|
||||
break;
|
||||
i--;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) /* cleanup ctx */
|
||||
{
|
||||
free(EVP_CIPHER_CTX_get_app_data(ctx));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const EVP_CIPHER *
|
||||
make_ctr_evp (size_t keylen)
|
||||
{
|
||||
static EVP_CIPHER aes_ctr_cipher;
|
||||
|
||||
memset(&aes_ctr_cipher, 0, sizeof(aes_ctr_cipher));
|
||||
|
||||
aes_ctr_cipher.block_size = 16;
|
||||
aes_ctr_cipher.key_len = keylen;
|
||||
aes_ctr_cipher.iv_len = 16;
|
||||
aes_ctr_cipher.init = aes_ctr_init;
|
||||
aes_ctr_cipher.do_cipher = aes_ctr_do_cipher;
|
||||
aes_ctr_cipher.cleanup = aes_ctr_cleanup;
|
||||
|
||||
return &aes_ctr_cipher;
|
||||
}
|
||||
|
||||
const EVP_CIPHER *
|
||||
_libssh2_EVP_aes_128_ctr(void)
|
||||
{
|
||||
return make_ctr_evp (16);
|
||||
}
|
||||
|
||||
const EVP_CIPHER *
|
||||
_libssh2_EVP_aes_192_ctr(void)
|
||||
{
|
||||
return make_ctr_evp (24);
|
||||
}
|
||||
|
||||
const EVP_CIPHER *
|
||||
_libssh2_EVP_aes_256_ctr(void)
|
||||
{
|
||||
return make_ctr_evp (32);
|
||||
}
|
||||
#endif /* LIBSSH2_AES_CTR */
|
||||
|
||||
/* TODO: Optionally call a passphrase callback specified by the
|
||||
* calling program
|
||||
*/
|
||||
@@ -215,79 +321,39 @@ passphrase_cb(char *buf, int size, int rwflag, char *passphrase)
|
||||
return passphrase_len;
|
||||
}
|
||||
|
||||
static int
|
||||
read_file_into_string(char ** key, LIBSSH2_SESSION * session, FILE * fp)
|
||||
{
|
||||
long size;
|
||||
size_t read;
|
||||
|
||||
*key = NULL;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size = ftell(fp);
|
||||
if (size < 0) {
|
||||
return -1;
|
||||
}
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
size *= sizeof(char);
|
||||
if (size > MAX_KEY_FILE_LENGTH) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*key = LIBSSH2_ALLOC(session, size + 1);
|
||||
if (!*key) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
read = fread(*key, 1, size, fp);
|
||||
if (read != size) {
|
||||
LIBSSH2_FREE(session, *key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*key)[size] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef void * (*pem_read_bio_func)(BIO *, void **, pem_password_cb *,
|
||||
void * u);
|
||||
|
||||
static int
|
||||
read_private_key_from_file(void ** key_ctx, LIBSSH2_SESSION * session,
|
||||
read_private_key_from_file(void ** key_ctx,
|
||||
pem_read_bio_func read_private_key,
|
||||
FILE * fp, unsigned const char *passphrase)
|
||||
const char * filename,
|
||||
unsigned const char *passphrase)
|
||||
{
|
||||
char * key;
|
||||
BIO * bp;
|
||||
|
||||
*key_ctx = NULL;
|
||||
|
||||
if(read_file_into_string(&key, session, fp)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bp = BIO_new_mem_buf(key, -1);
|
||||
bp = BIO_new_file(filename, "r");
|
||||
if (!bp) {
|
||||
LIBSSH2_FREE(session, key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*key_ctx = read_private_key(bp, NULL, (void *) passphrase_cb,
|
||||
*key_ctx = read_private_key(bp, NULL, (pem_password_cb *) passphrase_cb,
|
||||
(void *) passphrase);
|
||||
|
||||
BIO_free(bp);
|
||||
LIBSSH2_FREE(session, key);
|
||||
return (*key_ctx) ? 0 : -1;
|
||||
}
|
||||
|
||||
int
|
||||
_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
||||
LIBSSH2_SESSION * session,
|
||||
FILE * fp, unsigned const char *passphrase)
|
||||
const char *filename, unsigned const char *passphrase)
|
||||
{
|
||||
pem_read_bio_func read_rsa =
|
||||
(pem_read_bio_func) &PEM_read_bio_RSAPrivateKey;
|
||||
(void) session;
|
||||
|
||||
if (!EVP_get_cipherbyname("des")) {
|
||||
/* If this cipher isn't loaded it's a pretty good indication that none are.
|
||||
@@ -297,17 +363,18 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
||||
OpenSSL_add_all_ciphers();
|
||||
}
|
||||
|
||||
return read_private_key_from_file((void **) rsa, session, read_rsa, fp,
|
||||
passphrase);
|
||||
return read_private_key_from_file((void **) rsa, read_rsa,
|
||||
filename, passphrase);
|
||||
}
|
||||
|
||||
int
|
||||
_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
|
||||
LIBSSH2_SESSION * session,
|
||||
FILE * fp, unsigned const char *passphrase)
|
||||
const char *filename, unsigned const char *passphrase)
|
||||
{
|
||||
pem_read_bio_func read_dsa =
|
||||
(pem_read_bio_func) &PEM_read_bio_DSAPrivateKey;
|
||||
(void) session;
|
||||
|
||||
if (!EVP_get_cipherbyname("des")) {
|
||||
/* If this cipher isn't loaded it's a pretty good indication that none are.
|
||||
@@ -317,8 +384,8 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
|
||||
OpenSSL_add_all_ciphers();
|
||||
}
|
||||
|
||||
return read_private_key_from_file((void **) dsa, session, read_dsa, fp,
|
||||
passphrase);
|
||||
return read_private_key_from_file((void **) dsa, read_dsa,
|
||||
filename, passphrase);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -358,7 +425,7 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
|
||||
unsigned long hash_len, unsigned char *signature)
|
||||
{
|
||||
DSA_SIG *sig;
|
||||
int r_len, s_len, rs_pad;
|
||||
int r_len, s_len;
|
||||
(void) hash_len;
|
||||
|
||||
sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
|
||||
@@ -367,17 +434,24 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
|
||||
}
|
||||
|
||||
r_len = BN_num_bytes(sig->r);
|
||||
if (r_len < 1 || r_len > 20) {
|
||||
DSA_SIG_free(sig);
|
||||
return -1;
|
||||
}
|
||||
s_len = BN_num_bytes(sig->s);
|
||||
rs_pad = (2 * SHA_DIGEST_LENGTH) - (r_len + s_len);
|
||||
if (rs_pad < 0) {
|
||||
if (s_len < 1 || s_len > 20) {
|
||||
DSA_SIG_free(sig);
|
||||
return -1;
|
||||
}
|
||||
|
||||
BN_bn2bin(sig->r, signature + rs_pad);
|
||||
BN_bn2bin(sig->s, signature + rs_pad + r_len);
|
||||
memset(signature, 0, 40);
|
||||
|
||||
BN_bn2bin(sig->r, signature + (20 - r_len));
|
||||
BN_bn2bin(sig->s, signature + 20 + (20 - s_len));
|
||||
|
||||
DSA_SIG_free(sig);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !LIBSSH2_LIBGCRYPT */
|
||||
|
@@ -1,4 +1,6 @@
|
||||
/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
/* Copyright (C) 2009 Simon Josefsson
|
||||
* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
*
|
||||
* Author: Simon Josefsson
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -71,6 +73,7 @@
|
||||
#endif
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)
|
||||
# define LIBSSH2_AES_CTR 1
|
||||
# define LIBSSH2_AES 1
|
||||
#else
|
||||
# define LIBSSH2_AES 0
|
||||
@@ -148,7 +151,8 @@ int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
|
||||
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);
|
||||
const char *filename,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
@@ -176,7 +180,8 @@ int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
|
||||
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);
|
||||
const char *filename,
|
||||
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);
|
||||
@@ -192,6 +197,9 @@ int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
|
||||
#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_aes128ctr _libssh2_EVP_aes_128_ctr
|
||||
#define _libssh2_cipher_aes192ctr _libssh2_EVP_aes_192_ctr
|
||||
#define _libssh2_cipher_aes256ctr _libssh2_EVP_aes_256_ctr
|
||||
#define _libssh2_cipher_blowfish EVP_bf_cbc
|
||||
#define _libssh2_cipher_arcfour EVP_rc4
|
||||
#define _libssh2_cipher_cast5 EVP_cast5_cbc
|
||||
@@ -221,3 +229,7 @@ int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
|
||||
#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)
|
||||
|
||||
const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void);
|
||||
const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void);
|
||||
const EVP_CIPHER *_libssh2_EVP_aes_256_ctr(void);
|
||||
|
467
src/packet.c
467
src/packet.c
@@ -1,5 +1,6 @@
|
||||
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2009 by Daniel Stenberg
|
||||
* Copyright (c) 2010 Simon Josefsson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -60,6 +61,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "transport.h"
|
||||
#include "channel.h"
|
||||
|
||||
/*
|
||||
* libssh2_packet_queue_listener
|
||||
@@ -69,7 +71,7 @@
|
||||
static inline int
|
||||
packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
unsigned long datalen,
|
||||
packet_queue_listener_state_t * listen_state)
|
||||
packet_queue_listener_state_t *listen_state)
|
||||
{
|
||||
/*
|
||||
* Look for a matching listener
|
||||
@@ -78,7 +80,7 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
/* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
|
||||
unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1);
|
||||
unsigned char *p;
|
||||
LIBSSH2_LISTENER *listen = session->listeners;
|
||||
LIBSSH2_LISTENER *listen = _libssh2_list_first(&session->listeners);
|
||||
char failure_code = 1; /* SSH_OPEN_ADMINISTRATIVELY_PROHIBITED */
|
||||
int rc;
|
||||
|
||||
@@ -107,7 +109,7 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
listen_state->sport = _libssh2_ntohu32(s);
|
||||
s += 4;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"Remote received connection from %s:%ld to %s:%ld",
|
||||
listen_state->shost, listen_state->sport,
|
||||
listen_state->host, listen_state->port);
|
||||
@@ -119,19 +121,18 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
while (listen) {
|
||||
if ((listen->port == (int) listen_state->port) &&
|
||||
(strlen(listen->host) == listen_state->host_len) &&
|
||||
(memcmp
|
||||
(listen->host, listen_state->host,
|
||||
listen_state->host_len) == 0)) {
|
||||
(memcmp (listen->host, listen_state->host,
|
||||
listen_state->host_len) == 0)) {
|
||||
/* This is our listener */
|
||||
LIBSSH2_CHANNEL *channel = NULL, *last_queued = listen->queue;
|
||||
LIBSSH2_CHANNEL *channel = NULL;
|
||||
listen_state->channel = NULL;
|
||||
|
||||
last_queued = listen->queue;
|
||||
if (listen_state->state == libssh2_NB_state_allocated) {
|
||||
if (listen->queue_maxsize &&
|
||||
(listen->queue_maxsize <= listen->queue_size)) {
|
||||
/* Queue is full */
|
||||
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"Listener queue full, ignoring");
|
||||
listen_state->state = libssh2_NB_state_sent;
|
||||
break;
|
||||
@@ -146,6 +147,8 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
listen_state->state = libssh2_NB_state_sent;
|
||||
break;
|
||||
}
|
||||
listen_state->channel = channel;
|
||||
|
||||
memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
|
||||
|
||||
channel->session = session;
|
||||
@@ -181,7 +184,7 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
listen_state->initial_window_size;
|
||||
channel->local.packet_size = listen_state->packet_size;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"Connection queued: channel %lu/%lu win %lu/%lu packet %lu/%lu",
|
||||
channel->local.id, channel->remote.id,
|
||||
channel->local.window_size,
|
||||
@@ -206,31 +209,19 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
if (listen_state->state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, listen_state->packet,
|
||||
17);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send channel open confirmation",
|
||||
0);
|
||||
if (rc == PACKET_EAGAIN)
|
||||
return rc;
|
||||
else if (rc) {
|
||||
libssh2_error(session, rc,
|
||||
"Unable to send channel "
|
||||
"open confirmation", 0);
|
||||
listen_state->state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Link the channel into the end of the queue list */
|
||||
|
||||
if (!last_queued) {
|
||||
listen->queue = channel;
|
||||
listen_state->state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (last_queued->next) {
|
||||
last_queued = last_queued->next;
|
||||
}
|
||||
|
||||
last_queued->next = channel;
|
||||
channel->prev = last_queued;
|
||||
|
||||
_libssh2_list_add(&listen->queue,
|
||||
&listen_state->channel->node);
|
||||
listen->queue_size++;
|
||||
|
||||
listen_state->state = libssh2_NB_state_idle;
|
||||
@@ -238,39 +229,36 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
}
|
||||
}
|
||||
|
||||
listen = listen->next;
|
||||
listen = _libssh2_list_next(&listen->node);
|
||||
}
|
||||
|
||||
listen_state->state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
/* We're not listening to you */
|
||||
{
|
||||
p = listen_state->packet;
|
||||
*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
|
||||
_libssh2_htonu32(p, listen_state->sender_channel);
|
||||
p += 4;
|
||||
_libssh2_htonu32(p, failure_code);
|
||||
p += 4;
|
||||
_libssh2_htonu32(p, sizeof(FwdNotReq) - 1);
|
||||
p += 4;
|
||||
memcpy(s, FwdNotReq, sizeof(FwdNotReq) - 1);
|
||||
p += sizeof(FwdNotReq) - 1;
|
||||
_libssh2_htonu32(p, 0);
|
||||
p = listen_state->packet;
|
||||
*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
|
||||
_libssh2_htonu32(p, listen_state->sender_channel);
|
||||
p += 4;
|
||||
_libssh2_htonu32(p, failure_code);
|
||||
p += 4;
|
||||
_libssh2_htonu32(p, sizeof(FwdNotReq) - 1);
|
||||
p += 4;
|
||||
memcpy(s, FwdNotReq, sizeof(FwdNotReq) - 1);
|
||||
p += sizeof(FwdNotReq) - 1;
|
||||
_libssh2_htonu32(p, 0);
|
||||
|
||||
rc = _libssh2_transport_write(session, listen_state->packet,
|
||||
packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send open failure", 0);
|
||||
listen_state->state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
}
|
||||
rc = _libssh2_transport_write(session, listen_state->packet,
|
||||
packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, rc, "Unable to send open failure", 0);
|
||||
listen_state->state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
listen_state->state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -281,14 +269,14 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
static inline int
|
||||
packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
unsigned long datalen,
|
||||
packet_x11_open_state_t * x11open_state)
|
||||
packet_x11_open_state_t *x11open_state)
|
||||
{
|
||||
int failure_code = 2; /* SSH_OPEN_CONNECT_FAILED */
|
||||
unsigned char *s = data + (sizeof("x11") - 1) + 5;
|
||||
/* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
|
||||
unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1);
|
||||
unsigned char *p;
|
||||
LIBSSH2_CHANNEL *channel = NULL;
|
||||
LIBSSH2_CHANNEL *channel = x11open_state->channel;
|
||||
int rc;
|
||||
|
||||
(void) datalen;
|
||||
@@ -307,7 +295,7 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
x11open_state->sport = _libssh2_ntohu32(s);
|
||||
s += 4;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"X11 Connection Received from %s:%ld on channel %lu",
|
||||
x11open_state->shost, x11open_state->sport,
|
||||
x11open_state->sender_channel);
|
||||
@@ -355,7 +343,7 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
channel->local.window_size = x11open_state->initial_window_size;
|
||||
channel->local.packet_size = x11open_state->packet_size;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"X11 Connection established: channel %lu/%lu win %lu/%lu packet %lu/%lu",
|
||||
channel->local.id, channel->remote.id,
|
||||
channel->local.window_size,
|
||||
@@ -379,7 +367,7 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
if (x11open_state->state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, x11open_state->packet, 17);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send channel open confirmation", 0);
|
||||
@@ -388,21 +376,13 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
}
|
||||
|
||||
/* Link the channel into the session */
|
||||
if (session->channels.tail) {
|
||||
session->channels.tail->next = channel;
|
||||
channel->prev = session->channels.tail;
|
||||
} else {
|
||||
session->channels.head = channel;
|
||||
channel->prev = NULL;
|
||||
}
|
||||
channel->next = NULL;
|
||||
session->channels.tail = channel;
|
||||
_libssh2_list_add(&session->channels, &channel->node);
|
||||
|
||||
/*
|
||||
* Pass control to the callback, they may turn right around and
|
||||
* free the channel, or actually use it
|
||||
*/
|
||||
LIBSSH2_X11_OPEN(channel, (char *) x11open_state->shost,
|
||||
LIBSSH2_X11_OPEN(channel, (char *)x11open_state->shost,
|
||||
x11open_state->sport);
|
||||
|
||||
x11open_state->state = libssh2_NB_state_idle;
|
||||
@@ -427,12 +407,11 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
|
||||
rc = _libssh2_transport_write(session, x11open_state->packet, packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send open failure", 0);
|
||||
libssh2_error(session, rc, "Unable to send open failure", 0);
|
||||
x11open_state->state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
return rc;
|
||||
}
|
||||
x11open_state->state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
@@ -442,7 +421,10 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
* _libssh2_packet_add
|
||||
*
|
||||
* Create a new packet and attach it to the brigade. Called from the transport
|
||||
* layer when it as received a packet.
|
||||
* layer when it has received a packet.
|
||||
*
|
||||
* The input pointer 'data' is pointing to allocated data that this function
|
||||
* is asked to deal with so on failure OR success, it must be freed fine.
|
||||
*/
|
||||
int
|
||||
_libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
@@ -465,27 +447,14 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
memset(&session->packAdd_x11open_state, 0,
|
||||
sizeof(session->packAdd_x11open_state));
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||
"Packet type %d received, length=%d",
|
||||
(int) data[0], (int) datalen);
|
||||
if (macstate == LIBSSH2_MAC_INVALID) {
|
||||
if (session->macerror) {
|
||||
if (LIBSSH2_MACERROR(session, (char *) data, datalen) == 0) {
|
||||
/* Calling app has given the OK, Process it anyway */
|
||||
macstate = LIBSSH2_MAC_CONFIRMED;
|
||||
} else {
|
||||
libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
|
||||
"Invalid Message Authentication Code received",
|
||||
0);
|
||||
if (session->ssh_msg_disconnect) {
|
||||
LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR,
|
||||
"Invalid MAC received",
|
||||
sizeof("Invalid MAC received") - 1,
|
||||
"", 0);
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
if (session->macerror &&
|
||||
LIBSSH2_MACERROR(session, (char *) data, datalen) == 0) {
|
||||
/* Calling app has given the OK, Process it anyway */
|
||||
macstate = LIBSSH2_MAC_CONFIRMED;
|
||||
} else {
|
||||
libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
|
||||
"Invalid Message Authentication Code received",
|
||||
@@ -497,7 +466,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
"", 0);
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
return LIBSSH2_ERROR_INVALID_MAC;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,8 +484,16 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
goto libssh2_packet_add_jump_point2;
|
||||
} else if (session->packAdd_state == libssh2_NB_state_jump3) {
|
||||
goto libssh2_packet_add_jump_point3;
|
||||
} else if (session->packAdd_state == libssh2_NB_state_jump4) {
|
||||
goto libssh2_packet_add_jump_point4;
|
||||
} else if (session->packAdd_state == libssh2_NB_state_jump5) {
|
||||
goto libssh2_packet_add_jump_point5;
|
||||
}
|
||||
|
||||
/* FIXME: I've noticed that DATA is accessed without proper
|
||||
* out-of-bounds checking (i.e., DATALEN) in many places
|
||||
* below. --simon */
|
||||
|
||||
if (session->packAdd_state == libssh2_NB_state_allocated) {
|
||||
/* A couple exceptions to the packet adding rule: */
|
||||
switch (data[0]) {
|
||||
@@ -544,7 +521,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
message[message_len] = '\0';
|
||||
language = (char *) data + 9 + message_len + 3;
|
||||
if (language_len) {
|
||||
memcpy(language, language + 1, language_len);
|
||||
memmove(language, language + 1, language_len);
|
||||
}
|
||||
language[language_len] = '\0';
|
||||
|
||||
@@ -552,27 +529,32 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
LIBSSH2_DISCONNECT(session, reason, message,
|
||||
message_len, language, language_len);
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||
"Disconnect(%d): %s(%s)", reason,
|
||||
message, language);
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
|
||||
"socket disconnect", 0);
|
||||
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
|
||||
}
|
||||
break;
|
||||
|
||||
case SSH_MSG_IGNORE:
|
||||
/* As with disconnect, back it up one and add a trailing NULL */
|
||||
memcpy(data + 4, data + 5, datalen - 5);
|
||||
data[datalen] = '\0';
|
||||
if (session->ssh_msg_ignore) {
|
||||
LIBSSH2_IGNORE(session, (char *) data + 4, datalen - 5);
|
||||
if (datalen >= 5) {
|
||||
/* Back it up one and add a trailing NULL */
|
||||
memmove(data, data + 1, datalen - 1);
|
||||
data[datalen] = '\0';
|
||||
if (session->ssh_msg_ignore) {
|
||||
LIBSSH2_IGNORE(session, (char *) data + 4, datalen - 1);
|
||||
}
|
||||
} else if (session->ssh_msg_ignore) {
|
||||
LIBSSH2_IGNORE(session, "", 0);
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SSH_MSG_DEBUG:
|
||||
{
|
||||
@@ -598,7 +580,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
message[message_len] = '\0';
|
||||
language = (char *) data + 6 + message_len + 3;
|
||||
if (language_len) {
|
||||
memcpy(language, language + 1, language_len);
|
||||
memmove(language, language + 1, language_len);
|
||||
}
|
||||
language[language_len] = '\0';
|
||||
|
||||
@@ -610,7 +592,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
* _libssh2_debug will actually truncate this for us so
|
||||
* that it's not an inordinate about of data
|
||||
*/
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||
"Debug Packet: %s", message);
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
@@ -618,6 +600,30 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
}
|
||||
break;
|
||||
|
||||
case SSH_MSG_GLOBAL_REQUEST:
|
||||
{
|
||||
uint32_t strlen = _libssh2_ntohu32(data + 1);
|
||||
unsigned char want_reply = data[5 + strlen];
|
||||
|
||||
_libssh2_debug(session,
|
||||
LIBSSH2_TRACE_CONN,
|
||||
"Received global request type %.*s (wr %X)",
|
||||
strlen, data + 5, want_reply);
|
||||
|
||||
if (want_reply) {
|
||||
libssh2_packet_add_jump_point5:
|
||||
session->packAdd_state = libssh2_NB_state_jump5;
|
||||
data[0] = SSH_MSG_REQUEST_FAILURE;
|
||||
rc = _libssh2_transport_write(session, data, 1);
|
||||
if (rc == PACKET_EAGAIN)
|
||||
return rc;
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_EXTENDED_DATA:
|
||||
/* streamid(4) */
|
||||
session->packAdd_data_head += 4;
|
||||
@@ -643,7 +649,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
stream_id = _libssh2_ntohu32(data + 5);
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"%d bytes packet_add() for %lu/%lu/%lu",
|
||||
(int) (datalen - session->packAdd_data_head),
|
||||
session->packAdd_channel->local.id,
|
||||
@@ -657,21 +663,19 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
/* Pretend we didn't receive this */
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"Ignoring extended data and refunding %d bytes",
|
||||
(int) (datalen - 13));
|
||||
/* Adjust the window based on the block we just freed */
|
||||
libssh2_packet_add_jump_point1:
|
||||
session->packAdd_state = libssh2_NB_state_jump1;
|
||||
rc = libssh2_channel_receive_window_adjust(session->
|
||||
packAdd_channel,
|
||||
datalen - 13,
|
||||
0);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
session->socket_block_directions =
|
||||
LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
rc = _libssh2_channel_receive_window_adjust(session->
|
||||
packAdd_channel,
|
||||
datalen - 13,
|
||||
0, NULL);
|
||||
if (rc == PACKET_EAGAIN)
|
||||
return rc;
|
||||
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
}
|
||||
@@ -731,101 +735,110 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_EOF:
|
||||
{
|
||||
session->packAdd_channel =
|
||||
_libssh2_channel_locate(session, _libssh2_ntohu32(data + 1));
|
||||
|
||||
if (!session->packAdd_channel) {
|
||||
/* We may have freed already, just quietly ignore this... */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_libssh2_debug(session,
|
||||
LIBSSH2_DBG_CONN,
|
||||
"EOF received for channel %lu/%lu",
|
||||
session->packAdd_channel->local.id,
|
||||
session->packAdd_channel->remote.id);
|
||||
session->packAdd_channel->remote.eof = 1;
|
||||
session->packAdd_channel =
|
||||
_libssh2_channel_locate(session, _libssh2_ntohu32(data + 1));
|
||||
|
||||
if (!session->packAdd_channel) {
|
||||
/* We may have freed already, just quietly ignore this... */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
_libssh2_debug(session,
|
||||
LIBSSH2_TRACE_CONN,
|
||||
"EOF received for channel %lu/%lu",
|
||||
session->packAdd_channel->local.id,
|
||||
session->packAdd_channel->remote.id);
|
||||
session->packAdd_channel->remote.eof = 1;
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
|
||||
case SSH_MSG_CHANNEL_REQUEST:
|
||||
{
|
||||
if (_libssh2_ntohu32(data + 5) == sizeof("exit-status") - 1
|
||||
&& !memcmp("exit-status", data + 9,
|
||||
sizeof("exit-status") - 1)) {
|
||||
{
|
||||
uint32_t channel = _libssh2_ntohu32(data + 1);
|
||||
uint32_t strlen = _libssh2_ntohu32(data + 5);
|
||||
unsigned char want_reply = data[9 + strlen];
|
||||
|
||||
/* we've got "exit-status" packet. Set the session value */
|
||||
session->packAdd_channel =
|
||||
_libssh2_channel_locate(session,
|
||||
_libssh2_ntohu32(data + 1));
|
||||
_libssh2_debug(session,
|
||||
LIBSSH2_TRACE_CONN,
|
||||
"Channel %d received request type %.*s (wr %X)",
|
||||
channel, strlen, data + 9, want_reply);
|
||||
|
||||
if (session->packAdd_channel) {
|
||||
session->packAdd_channel->exit_status =
|
||||
_libssh2_ntohu32(data + 9 + sizeof("exit-status"));
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN,
|
||||
"Exit status %lu received for channel %lu/%lu",
|
||||
session->packAdd_channel->exit_status,
|
||||
session->packAdd_channel->local.id,
|
||||
session->packAdd_channel->remote.id);
|
||||
}
|
||||
if (strlen == sizeof("exit-status") - 1
|
||||
&& !memcmp("exit-status", data + 9,
|
||||
sizeof("exit-status") - 1)) {
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_CLOSE:
|
||||
{
|
||||
/* we've got "exit-status" packet. Set the session value */
|
||||
session->packAdd_channel =
|
||||
_libssh2_channel_locate(session, _libssh2_ntohu32(data + 1));
|
||||
_libssh2_channel_locate(session, channel);
|
||||
|
||||
if (!session->packAdd_channel) {
|
||||
/* We may have freed already, just quietly ignore this... */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
if (session->packAdd_channel) {
|
||||
session->packAdd_channel->exit_status =
|
||||
_libssh2_ntohu32(data + 9 + sizeof("exit-status"));
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"Exit status %lu received for channel %lu/%lu",
|
||||
session->packAdd_channel->exit_status,
|
||||
session->packAdd_channel->local.id,
|
||||
session->packAdd_channel->remote.id);
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN,
|
||||
"Close received for channel %lu/%lu",
|
||||
session->packAdd_channel->local.id,
|
||||
session->packAdd_channel->remote.id);
|
||||
|
||||
session->packAdd_channel->remote.close = 1;
|
||||
session->packAdd_channel->remote.eof = 1;
|
||||
/* TODO: Add a callback for this */
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (want_reply) {
|
||||
libssh2_packet_add_jump_point4:
|
||||
session->packAdd_state = libssh2_NB_state_jump4;
|
||||
data[0] = SSH_MSG_CHANNEL_FAILURE;
|
||||
rc = _libssh2_transport_write(session, data, 5);
|
||||
if (rc == PACKET_EAGAIN)
|
||||
return rc;
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SSH_MSG_CHANNEL_CLOSE:
|
||||
session->packAdd_channel =
|
||||
_libssh2_channel_locate(session, _libssh2_ntohu32(data + 1));
|
||||
|
||||
if (!session->packAdd_channel) {
|
||||
/* We may have freed already, just quietly ignore this... */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"Close received for channel %lu/%lu",
|
||||
session->packAdd_channel->local.id,
|
||||
session->packAdd_channel->remote.id);
|
||||
|
||||
session->packAdd_channel->remote.close = 1;
|
||||
session->packAdd_channel->remote.eof = 1;
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
|
||||
case SSH_MSG_CHANNEL_OPEN:
|
||||
if ((datalen >= (sizeof("forwarded-tcpip") + 4)) &&
|
||||
((sizeof("forwarded-tcpip") - 1) == _libssh2_ntohu32(data + 1))
|
||||
&&
|
||||
(memcmp
|
||||
(data + 5, "forwarded-tcpip",
|
||||
sizeof("forwarded-tcpip") - 1) == 0)) {
|
||||
(memcmp(data + 5, "forwarded-tcpip",
|
||||
sizeof("forwarded-tcpip") - 1) == 0)) {
|
||||
|
||||
libssh2_packet_add_jump_point2:
|
||||
session->packAdd_state = libssh2_NB_state_jump2;
|
||||
rc = packet_queue_listener(session, data, datalen,
|
||||
&session->packAdd_Qlstn_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
session->socket_block_directions =
|
||||
LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
if (rc == PACKET_EAGAIN)
|
||||
return rc;
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
@@ -839,11 +852,8 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
session->packAdd_state = libssh2_NB_state_jump3;
|
||||
rc = packet_x11_open(session, data, datalen,
|
||||
&session->packAdd_x11open_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
session->socket_block_directions =
|
||||
LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
if (rc == PACKET_EAGAIN)
|
||||
return rc;
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
@@ -861,7 +871,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
if (session->packAdd_channel && bytestoadd) {
|
||||
session->packAdd_channel->local.window_size += bytestoadd;
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"Window adjust received for channel %lu/%lu, adding %lu bytes, new window_size=%lu",
|
||||
session->packAdd_channel->local.id,
|
||||
session->packAdd_channel->remote.id,
|
||||
@@ -879,33 +889,23 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
}
|
||||
|
||||
if (session->packAdd_state == libssh2_NB_state_sent) {
|
||||
session->packAdd_packet =
|
||||
LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
|
||||
if (!session->packAdd_packet) {
|
||||
LIBSSH2_PACKET *packAdd_packet;
|
||||
packAdd_packet =
|
||||
LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
|
||||
if (!packAdd_packet) {
|
||||
_libssh2_debug(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for LIBSSH2_PACKET");
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->packAdd_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
}
|
||||
memset(session->packAdd_packet, 0, sizeof(LIBSSH2_PACKET));
|
||||
memset(packAdd_packet, 0, sizeof(LIBSSH2_PACKET));
|
||||
|
||||
session->packAdd_packet->data = data;
|
||||
session->packAdd_packet->data_len = datalen;
|
||||
session->packAdd_packet->data_head = session->packAdd_data_head;
|
||||
session->packAdd_packet->mac = macstate;
|
||||
session->packAdd_packet->brigade = &session->packets;
|
||||
session->packAdd_packet->next = NULL;
|
||||
packAdd_packet->data = data;
|
||||
packAdd_packet->data_len = datalen;
|
||||
packAdd_packet->data_head = session->packAdd_data_head;
|
||||
packAdd_packet->mac = macstate;
|
||||
|
||||
if (session->packets.tail) {
|
||||
session->packAdd_packet->prev = session->packets.tail;
|
||||
session->packAdd_packet->prev->next = session->packAdd_packet;
|
||||
session->packets.tail = session->packAdd_packet;
|
||||
} else {
|
||||
session->packets.head = session->packAdd_packet;
|
||||
session->packets.tail = session->packAdd_packet;
|
||||
session->packAdd_packet->prev = NULL;
|
||||
}
|
||||
_libssh2_list_add(&session->packets, &packAdd_packet->node);
|
||||
|
||||
session->packAdd_state = libssh2_NB_state_sent1;
|
||||
}
|
||||
@@ -919,7 +919,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
* Well, it's already in the brigade,
|
||||
* let's just call back into ourselves
|
||||
*/
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Renegotiating Keys");
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Renegotiating Keys");
|
||||
|
||||
session->packAdd_state = libssh2_NB_state_sent2;
|
||||
}
|
||||
@@ -948,7 +948,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
*/
|
||||
rc = libssh2_kex_exchange(session, 1, &session->startup_key_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,9 +968,9 @@ _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type,
|
||||
unsigned long match_ofs, const unsigned char *match_buf,
|
||||
unsigned long match_len)
|
||||
{
|
||||
LIBSSH2_PACKET *packet = session->packets.head;
|
||||
LIBSSH2_PACKET *packet = _libssh2_list_first(&session->packets);
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||
"Looking for packet of type: %d", (int) packet_type);
|
||||
|
||||
while (packet) {
|
||||
@@ -982,24 +982,14 @@ _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type,
|
||||
*data = packet->data;
|
||||
*data_len = packet->data_len;
|
||||
|
||||
/* unlink struct */
|
||||
if (packet->prev) {
|
||||
packet->prev->next = packet->next;
|
||||
} else {
|
||||
session->packets.head = packet->next;
|
||||
}
|
||||
|
||||
if (packet->next) {
|
||||
packet->next->prev = packet->prev;
|
||||
} else {
|
||||
session->packets.tail = packet->prev;
|
||||
}
|
||||
/* unlink struct from session->packets */
|
||||
_libssh2_list_remove(&packet->node);
|
||||
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
return 0;
|
||||
}
|
||||
packet = packet->next;
|
||||
packet = _libssh2_list_next(&packet->node);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -1060,13 +1050,10 @@ _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type,
|
||||
}
|
||||
|
||||
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
||||
libssh2pack_t ret = _libssh2_transport_read(session);
|
||||
if (ret == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
} else if (ret == 0) {
|
||||
/* There is no data, return that. TODO: is this really correct? */
|
||||
return PACKET_EAGAIN;
|
||||
} else if (ret < 0) {
|
||||
int ret = _libssh2_transport_read(session);
|
||||
if (ret == PACKET_EAGAIN)
|
||||
return ret;
|
||||
else if (ret < 0) {
|
||||
state->start = 0;
|
||||
/* an error which is not just because of blocking */
|
||||
return ret;
|
||||
@@ -1084,11 +1071,12 @@ _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type,
|
||||
state->start = 0;
|
||||
return PACKET_TIMEOUT;
|
||||
}
|
||||
return -1; /* no packet available yet */
|
||||
}
|
||||
}
|
||||
|
||||
/* Only reached if the socket died */
|
||||
return -1;
|
||||
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1121,14 +1109,15 @@ _libssh2_packet_burn(LIBSSH2_SESSION * session,
|
||||
return i;
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||
"Blocking until packet becomes available to burn");
|
||||
*state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
||||
if ((ret = _libssh2_transport_read(session)) == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
ret = _libssh2_transport_read(session);
|
||||
if (ret == PACKET_EAGAIN) {
|
||||
return ret;
|
||||
} else if (ret < 0) {
|
||||
*state = libssh2_NB_state_idle;
|
||||
return ret;
|
||||
@@ -1148,7 +1137,7 @@ _libssh2_packet_burn(LIBSSH2_SESSION * session,
|
||||
}
|
||||
|
||||
/* Only reached if the socket died */
|
||||
return -1;
|
||||
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1194,7 +1183,7 @@ _libssh2_packet_requirev(LIBSSH2_SESSION * session,
|
||||
return PACKET_TIMEOUT;
|
||||
}
|
||||
else if (ret == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1208,6 +1197,6 @@ _libssh2_packet_requirev(LIBSSH2_SESSION * session,
|
||||
|
||||
/* Only reached if the socket died */
|
||||
state->start = 0;
|
||||
return -1;
|
||||
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
|
||||
}
|
||||
|
||||
|
@@ -38,6 +38,8 @@
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
|
||||
#ifdef LIBSSH2_LIBGCRYPT /* compile only if we build with libgcrypt */
|
||||
|
||||
static int
|
||||
readline(char *line, int line_size, FILE * fp)
|
||||
{
|
||||
@@ -207,3 +209,5 @@ _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_LIBGCRYPT */
|
||||
|
@@ -37,6 +37,7 @@
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include "libssh2_publickey.h"
|
||||
#include "channel.h"
|
||||
|
||||
#define LIBSSH2_PUBLICKEY_VERSION 2
|
||||
|
||||
@@ -168,9 +169,9 @@ publickey_packet_receive(LIBSSH2_PUBLICKEY * pkey,
|
||||
int rc;
|
||||
|
||||
if (pkey->receive_state == libssh2_NB_state_idle) {
|
||||
rc = libssh2_channel_read_ex(channel, 0, (char *) buffer, 4);
|
||||
rc = _libssh2_channel_read(channel, 0, (char *) buffer, 4);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc != 4) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
|
||||
"Invalid response from publickey subsystem", 0);
|
||||
@@ -190,10 +191,10 @@ publickey_packet_receive(LIBSSH2_PUBLICKEY * pkey,
|
||||
}
|
||||
|
||||
if (pkey->receive_state == libssh2_NB_state_sent) {
|
||||
rc = libssh2_channel_read_ex(channel, 0, (char *) pkey->receive_packet,
|
||||
pkey->receive_packet_len);
|
||||
rc = _libssh2_channel_read(channel, 0, (char *) pkey->receive_packet,
|
||||
pkey->receive_packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc != (int)pkey->receive_packet_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for publickey subsystem response packet",
|
||||
@@ -265,7 +266,7 @@ publickey_response_success(LIBSSH2_PUBLICKEY * pkey)
|
||||
while (1) {
|
||||
rc = publickey_packet_receive(pkey, &data, &data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for response from publickey subsystem",
|
||||
@@ -352,7 +353,7 @@ libssh2_publickey_init(LIBSSH2_SESSION * session)
|
||||
session->pkeyInit_pkey = NULL;
|
||||
session->pkeyInit_channel = NULL;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY,
|
||||
"Initializing publickey subsystem");
|
||||
|
||||
session->pkeyInit_state = libssh2_NB_state_allocated;
|
||||
@@ -433,7 +434,7 @@ libssh2_publickey_init(LIBSSH2_SESSION * session)
|
||||
_libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION);
|
||||
s += 4;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY,
|
||||
"Sending publickey version packet advertising version %d support",
|
||||
(int) LIBSSH2_PUBLICKEY_VERSION);
|
||||
|
||||
@@ -441,8 +442,8 @@ libssh2_publickey_init(LIBSSH2_SESSION * session)
|
||||
}
|
||||
|
||||
if (session->pkeyInit_state == libssh2_NB_state_sent2) {
|
||||
rc = libssh2_channel_write_ex(session->pkeyInit_channel, 0,
|
||||
(char *) buffer, (s - buffer));
|
||||
rc = _libssh2_channel_write(session->pkeyInit_channel, 0,
|
||||
(char *) buffer, (s - buffer));
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block sending publickey version packet", 0);
|
||||
@@ -518,13 +519,13 @@ libssh2_publickey_init(LIBSSH2_SESSION * session)
|
||||
session->pkeyInit_pkey->version = _libssh2_ntohu32(s);
|
||||
if (session->pkeyInit_pkey->version >
|
||||
LIBSSH2_PUBLICKEY_VERSION) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY,
|
||||
"Truncating remote publickey version from %lu",
|
||||
session->pkeyInit_pkey->version);
|
||||
session->pkeyInit_pkey->version =
|
||||
LIBSSH2_PUBLICKEY_VERSION;
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY,
|
||||
"Enabling publickey subsystem version %lu",
|
||||
session->pkeyInit_pkey->version);
|
||||
LIBSSH2_FREE(session, session->pkeyInit_data);
|
||||
@@ -589,7 +590,7 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY * pkey, const unsigned char *name,
|
||||
if (pkey->add_state == libssh2_NB_state_idle) {
|
||||
pkey->add_packet = NULL;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Adding %s publickey",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, "Adding %s publickey",
|
||||
name);
|
||||
|
||||
if (pkey->version == 1) {
|
||||
@@ -670,7 +671,7 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY * pkey, const unsigned char *name,
|
||||
}
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY,
|
||||
"Sending publickey \"add\" packet: type=%s blob_len=%ld num_attrs=%ld",
|
||||
name, blob_len, num_attrs);
|
||||
|
||||
@@ -678,10 +679,10 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY * pkey, const unsigned char *name,
|
||||
}
|
||||
|
||||
if (pkey->add_state == libssh2_NB_state_created) {
|
||||
rc = libssh2_channel_write_ex(channel, 0, (char *) pkey->add_packet,
|
||||
(pkey->add_s - pkey->add_packet));
|
||||
rc = _libssh2_channel_write(channel, 0, (char *) pkey->add_packet,
|
||||
(pkey->add_s - pkey->add_packet));
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if ((pkey->add_s - pkey->add_packet) != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send publickey add packet", 0);
|
||||
@@ -697,7 +698,7 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY * pkey, const unsigned char *name,
|
||||
|
||||
rc = publickey_response_success(pkey);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
|
||||
pkey->add_state = libssh2_NB_state_idle;
|
||||
@@ -746,7 +747,7 @@ libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY * pkey,
|
||||
memcpy(pkey->remove_s, blob, blob_len);
|
||||
pkey->remove_s += blob_len;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY,
|
||||
"Sending publickey \"remove\" packet: type=%s blob_len=%ld",
|
||||
name, blob_len);
|
||||
|
||||
@@ -754,10 +755,10 @@ libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY * pkey,
|
||||
}
|
||||
|
||||
if (pkey->remove_state == libssh2_NB_state_created) {
|
||||
rc = libssh2_channel_write_ex(channel, 0, (char *) pkey->remove_packet,
|
||||
(pkey->remove_s - pkey->remove_packet));
|
||||
rc = _libssh2_channel_write(channel, 0, (char *) pkey->remove_packet,
|
||||
(pkey->remove_s - pkey->remove_packet));
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if ((pkey->remove_s - pkey->remove_packet) != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send publickey remove packet", 0);
|
||||
@@ -774,7 +775,7 @@ libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY * pkey,
|
||||
|
||||
rc = publickey_response_success(pkey);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
|
||||
pkey->remove_state = libssh2_NB_state_idle;
|
||||
@@ -808,19 +809,19 @@ libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys,
|
||||
memcpy(pkey->listFetch_s, "list", sizeof("list") - 1);
|
||||
pkey->listFetch_s += sizeof("list") - 1;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY,
|
||||
"Sending publickey \"list\" packet");
|
||||
|
||||
pkey->listFetch_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
if (pkey->listFetch_state == libssh2_NB_state_created) {
|
||||
rc = libssh2_channel_write_ex(channel, 0,
|
||||
(char *) pkey->listFetch_buffer,
|
||||
(pkey->listFetch_s -
|
||||
pkey->listFetch_buffer));
|
||||
rc = _libssh2_channel_write(channel, 0,
|
||||
(char *) pkey->listFetch_buffer,
|
||||
(pkey->listFetch_s -
|
||||
pkey->listFetch_buffer));
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if ((pkey->listFetch_s - pkey->listFetch_buffer) != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send publickey list packet", 0);
|
||||
@@ -835,7 +836,7 @@ libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys,
|
||||
rc = publickey_packet_receive(pkey, &pkey->listFetch_data,
|
||||
&pkey->listFetch_data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for response from publickey subsystem",
|
||||
@@ -1040,6 +1041,7 @@ LIBSSH2_API int
|
||||
libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY * pkey)
|
||||
{
|
||||
LIBSSH2_SESSION *session = pkey->channel->session;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Make sure all memory used in the state variables are free
|
||||
@@ -1061,9 +1063,9 @@ libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY * pkey)
|
||||
pkey->listFetch_data = NULL;
|
||||
}
|
||||
|
||||
if (libssh2_channel_free(pkey->channel) == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
rc = libssh2_channel_free(pkey->channel);
|
||||
if (rc == PACKET_EAGAIN)
|
||||
return rc;
|
||||
|
||||
LIBSSH2_FREE(session, pkey);
|
||||
return 0;
|
||||
|
130
src/scp.c
130
src/scp.c
@@ -1,4 +1,5 @@
|
||||
/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2009 by Daniel Stenberg
|
||||
* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -39,6 +40,8 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "channel.h"
|
||||
|
||||
|
||||
/* Max. length of a quoted string after libssh2_shell_quotearg() processing */
|
||||
#define libssh2_shell_quotedsize(s) (3 * strlen(s) + 2)
|
||||
@@ -258,13 +261,13 @@ libssh2_shell_quotearg(const char *path, unsigned char *buf,
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_scp_recv
|
||||
* scp_recv
|
||||
*
|
||||
* Open a channel and request a remote file via SCP
|
||||
*
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *
|
||||
libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
static LIBSSH2_CHANNEL *
|
||||
scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
{
|
||||
int cmd_len;
|
||||
int rc;
|
||||
@@ -298,7 +301,7 @@ libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
session->scpRecv_command_len - cmd_len);
|
||||
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SCP,
|
||||
"Opening channel for SCP receive");
|
||||
|
||||
session->scpRecv_state = libssh2_NB_state_created;
|
||||
@@ -347,7 +350,7 @@ libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
LIBSSH2_FREE(session, session->scpRecv_command);
|
||||
session->scpRecv_command = NULL;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup");
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sending initial wakeup");
|
||||
/* SCP ACK */
|
||||
session->scpRecv_response[0] = '\0';
|
||||
|
||||
@@ -355,8 +358,8 @@ libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
}
|
||||
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent1) {
|
||||
rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
|
||||
(char *) session->scpRecv_response, 1);
|
||||
rc = _libssh2_channel_write(session->scpRecv_channel, 0,
|
||||
(char *) session->scpRecv_response, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block sending initial wakeup", 0);
|
||||
@@ -378,10 +381,10 @@ libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
unsigned char *s, *p;
|
||||
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent2) {
|
||||
rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
|
||||
(char *) session->
|
||||
scpRecv_response +
|
||||
session->scpRecv_response_len, 1);
|
||||
rc = _libssh2_channel_read(session->scpRecv_channel, 0,
|
||||
(char *) session->
|
||||
scpRecv_response +
|
||||
session->scpRecv_response_len, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting for SCP response", 0);
|
||||
@@ -415,9 +418,9 @@ libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
session->scpRecv_err_len + 1);
|
||||
|
||||
/* Read the remote error message */
|
||||
rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
|
||||
session->scpRecv_err_msg,
|
||||
session->scpRecv_err_len);
|
||||
rc = _libssh2_channel_read(session->scpRecv_channel, 0,
|
||||
session->scpRecv_err_msg,
|
||||
session->scpRecv_err_len);
|
||||
if (rc <= 0) {
|
||||
/*
|
||||
* Since we have alread started reading this packet,
|
||||
@@ -555,9 +558,9 @@ libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
}
|
||||
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent3) {
|
||||
rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
|
||||
(char *) session->
|
||||
scpRecv_response, 1);
|
||||
rc = _libssh2_channel_write(session->scpRecv_channel, 0,
|
||||
(char *) session->
|
||||
scpRecv_response, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting to send SCP ACK", 0);
|
||||
@@ -566,7 +569,7 @@ libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
goto scp_recv_error;
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SCP,
|
||||
"mtime = %ld, atime = %ld",
|
||||
session->scpRecv_mtime, session->scpRecv_atime);
|
||||
|
||||
@@ -591,10 +594,10 @@ libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
char *s, *p, *e = NULL;
|
||||
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent5) {
|
||||
rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
|
||||
(char *) session->
|
||||
scpRecv_response +
|
||||
session->scpRecv_response_len, 1);
|
||||
rc = _libssh2_channel_read(session->scpRecv_channel, 0,
|
||||
(char *) session->
|
||||
scpRecv_response +
|
||||
session->scpRecv_response_len, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting for SCP response", 0);
|
||||
@@ -718,9 +721,9 @@ libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
}
|
||||
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent6) {
|
||||
rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
|
||||
(char *) session->
|
||||
scpRecv_response, 1);
|
||||
rc = _libssh2_channel_write(session->scpRecv_channel, 0,
|
||||
(char *) session->
|
||||
scpRecv_response, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block sending SCP ACK", 0);
|
||||
@@ -728,7 +731,7 @@ libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
} else if (rc != 1) {
|
||||
goto scp_recv_error;
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SCP,
|
||||
"mode = 0%lo size = %ld", session->scpRecv_mode,
|
||||
session->scpRecv_size);
|
||||
|
||||
@@ -761,14 +764,28 @@ libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_scp_send_ex
|
||||
* libssh2_scp_recv
|
||||
*
|
||||
* Open a channel and request a remote file via SCP
|
||||
*
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *
|
||||
libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat * sb)
|
||||
{
|
||||
LIBSSH2_CHANNEL *ptr;
|
||||
BLOCK_ADJUST_ERRNO(ptr, session, scp_recv(session, path, sb));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* scp_send()
|
||||
*
|
||||
* Send a file using SCP
|
||||
*
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *
|
||||
libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
size_t size, long mtime, long atime)
|
||||
static LIBSSH2_CHANNEL *
|
||||
scp_send(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
size_t size, long mtime, long atime)
|
||||
{
|
||||
int cmd_len;
|
||||
unsigned const char *base;
|
||||
@@ -799,7 +816,7 @@ libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
|
||||
session->scpSend_command[session->scpSend_command_len - 1] = '\0';
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SCP,
|
||||
"Opening channel for SCP send");
|
||||
/* Allocate a channel */
|
||||
|
||||
@@ -857,8 +874,8 @@ libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
|
||||
if (session->scpSend_state == libssh2_NB_state_sent1) {
|
||||
/* Wait for ACK */
|
||||
rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
|
||||
(char *) session->scpSend_response, 1);
|
||||
rc = _libssh2_channel_read(session->scpSend_channel, 0,
|
||||
(char *) session->scpSend_response, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting for response from remote", 0);
|
||||
@@ -875,7 +892,7 @@ libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
snprintf((char *) session->scpSend_response,
|
||||
LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", mtime,
|
||||
atime);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s",
|
||||
session->scpSend_response);
|
||||
}
|
||||
|
||||
@@ -885,9 +902,9 @@ libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
/* Send mtime and atime to be used for file */
|
||||
if (mtime || atime) {
|
||||
if (session->scpSend_state == libssh2_NB_state_sent2) {
|
||||
rc = libssh2_channel_write_ex(session->scpSend_channel, 0,
|
||||
(char *) session->scpSend_response,
|
||||
session->scpSend_response_len);
|
||||
rc = _libssh2_channel_write(session->scpSend_channel, 0,
|
||||
(char *) session->scpSend_response,
|
||||
session->scpSend_response_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block sending time data for SCP file", 0);
|
||||
@@ -903,9 +920,8 @@ libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
|
||||
if (session->scpSend_state == libssh2_NB_state_sent3) {
|
||||
/* Wait for ACK */
|
||||
rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
|
||||
(char *) session->scpSend_response,
|
||||
1);
|
||||
rc = _libssh2_channel_read(session->scpSend_channel, 0,
|
||||
(char *) session->scpSend_response, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting for response", 0);
|
||||
@@ -937,16 +953,16 @@ libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
snprintf((char *) session->scpSend_response,
|
||||
LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %lu %s\n", mode,
|
||||
(unsigned long) size, base);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s",
|
||||
session->scpSend_response);
|
||||
|
||||
session->scpSend_state = libssh2_NB_state_sent5;
|
||||
}
|
||||
|
||||
if (session->scpSend_state == libssh2_NB_state_sent5) {
|
||||
rc = libssh2_channel_write_ex(session->scpSend_channel, 0,
|
||||
(char *) session->scpSend_response,
|
||||
session->scpSend_response_len);
|
||||
rc = _libssh2_channel_write(session->scpSend_channel, 0,
|
||||
(char *) session->scpSend_response,
|
||||
session->scpSend_response_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block send core file data for SCP file", 0);
|
||||
@@ -962,8 +978,8 @@ libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
|
||||
if (session->scpSend_state == libssh2_NB_state_sent6) {
|
||||
/* Wait for ACK */
|
||||
rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
|
||||
(char *) session->scpSend_response, 1);
|
||||
rc = _libssh2_channel_read(session->scpSend_channel, 0,
|
||||
(char *) session->scpSend_response, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting for response", 0);
|
||||
@@ -990,9 +1006,9 @@ libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
memset(session->scpSend_err_msg, 0, session->scpSend_err_len + 1);
|
||||
|
||||
/* Read the remote error message */
|
||||
rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
|
||||
session->scpSend_err_msg,
|
||||
session->scpSend_err_len);
|
||||
rc = _libssh2_channel_read(session->scpSend_channel, 0,
|
||||
session->scpSend_err_msg,
|
||||
session->scpSend_err_len);
|
||||
if (rc <= 0) {
|
||||
/*
|
||||
* Since we have alread started reading this packet, it is
|
||||
@@ -1021,3 +1037,17 @@ libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_scp_send_ex
|
||||
*
|
||||
* Send a file using SCP
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *
|
||||
libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode,
|
||||
size_t size, long mtime, long atime)
|
||||
{
|
||||
LIBSSH2_CHANNEL *ptr;
|
||||
BLOCK_ADJUST_ERRNO(ptr, session,
|
||||
scp_send(session, path, mode, size, mtime, atime));
|
||||
return ptr;
|
||||
}
|
||||
|
160
src/session.c
160
src/session.c
@@ -106,8 +106,17 @@ banner_receive(LIBSSH2_SESSION * session)
|
||||
|| (session->banner_TxRx_banner[banner_len - 1] != '\n'))) {
|
||||
char c = '\0';
|
||||
|
||||
/* no incoming block yet! */
|
||||
session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND;
|
||||
|
||||
ret = _libssh2_recv(session->socket_fd, &c, 1,
|
||||
LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
if (ret < 0)
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Error recving %d bytes to %p: %d", 1, &c, errno);
|
||||
else
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Recved %d bytes to %p", ret, &c);
|
||||
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
@@ -159,7 +168,7 @@ banner_receive(LIBSSH2_SESSION * session)
|
||||
}
|
||||
memcpy(session->remote.banner, session->banner_TxRx_banner, banner_len);
|
||||
session->remote.banner[banner_len] = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Received Banner: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Received Banner: %s",
|
||||
session->remote.banner);
|
||||
return 0;
|
||||
}
|
||||
@@ -200,17 +209,29 @@ banner_send(LIBSSH2_SESSION * session)
|
||||
banner[255] = '\0';
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending Banner: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Sending Banner: %s",
|
||||
banner_dup);
|
||||
#endif
|
||||
|
||||
session->banner_TxRx_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
/* no outgoing block yet! */
|
||||
session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||
|
||||
ret = _libssh2_send(session->socket_fd,
|
||||
banner + session->banner_TxRx_total_send,
|
||||
banner_len - session->banner_TxRx_total_send,
|
||||
LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||
if (ret < 0)
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Error sending %d bytes: %d",
|
||||
banner_len - session->banner_TxRx_total_send, errno);
|
||||
else
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Sent %d/%d bytes at %p+%d", ret,
|
||||
banner_len - session->banner_TxRx_total_send,
|
||||
banner, session->banner_TxRx_total_send);
|
||||
|
||||
if (ret != (banner_len - session->banner_TxRx_total_send)) {
|
||||
if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
|
||||
@@ -238,7 +259,7 @@ banner_send(LIBSSH2_SESSION * session)
|
||||
* is copied from the libcurl sources with permission.
|
||||
*/
|
||||
static int
|
||||
session_nonblock(int sockfd, /* operate on this */
|
||||
session_nonblock(libssh2_socket_t sockfd, /* operate on this */
|
||||
int nonblock /* TRUE or FALSE */ )
|
||||
{
|
||||
#undef SETBLOCK
|
||||
@@ -389,7 +410,7 @@ libssh2_banner_set(LIBSSH2_SESSION * session, const char *banner)
|
||||
|
||||
memcpy(session->local.banner, banner, banner_len);
|
||||
session->local.banner[banner_len] = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting local Banner: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Setting local Banner: %s",
|
||||
session->local.banner);
|
||||
session->local.banner[banner_len++] = '\r';
|
||||
session->local.banner[banner_len++] = '\n';
|
||||
@@ -435,7 +456,7 @@ libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)),
|
||||
session->realloc = local_realloc;
|
||||
session->abstract = abstract;
|
||||
session->api_block_mode = 1; /* blocking API by default */
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||
"New session resource allocated");
|
||||
libssh2_crypto_init();
|
||||
}
|
||||
@@ -484,7 +505,7 @@ libssh2_session_callback_set(LIBSSH2_SESSION * session,
|
||||
return oldcb;
|
||||
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting Callback %d", cbtype);
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Setting Callback %d", cbtype);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -529,15 +550,14 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session)
|
||||
}
|
||||
|
||||
static int
|
||||
session_startup(LIBSSH2_SESSION *session, int sock)
|
||||
session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (session->startup_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||
"session_startup for socket %d", sock);
|
||||
/* FIXME: on some platforms (like win32) sockets are unsigned */
|
||||
if (sock < 0) {
|
||||
if (INVALID_SOCKET == sock) {
|
||||
/* Did we forget something? */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE,
|
||||
"Bad socket provided", 0);
|
||||
@@ -556,35 +576,22 @@ session_startup(LIBSSH2_SESSION *session, int sock)
|
||||
session->startup_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
/* TODO: Liveness check */
|
||||
|
||||
if (session->startup_state == libssh2_NB_state_created) {
|
||||
rc = banner_send(session);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block sending banner to remote host", 0);
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
} else if (rc) {
|
||||
/* Unable to send banner? */
|
||||
libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND,
|
||||
"Error sending banner to remote host", 0);
|
||||
return LIBSSH2_ERROR_BANNER_SEND;
|
||||
if (rc) {
|
||||
libssh2_error(session, rc,
|
||||
"Failed sending banner", 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
session->startup_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
if (session->startup_state == libssh2_NB_state_sent) {
|
||||
rc = banner_receive(session);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting for banner", 0);
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
} else if (rc) {
|
||||
/* Unable to receive banner from remote */
|
||||
libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE,
|
||||
"Timeout waiting for banner", 0);
|
||||
return LIBSSH2_ERROR_BANNER_NONE;
|
||||
if (rc) {
|
||||
libssh2_error(session, rc,
|
||||
"Failed getting banner", 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
session->startup_state = libssh2_NB_state_sent1;
|
||||
@@ -592,21 +599,17 @@ session_startup(LIBSSH2_SESSION *session, int sock)
|
||||
|
||||
if (session->startup_state == libssh2_NB_state_sent1) {
|
||||
rc = libssh2_kex_exchange(session, 0, &session->startup_key_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block exchanging encryption keys", 0);
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
|
||||
if (rc) {
|
||||
libssh2_error(session, rc,
|
||||
"Unable to exchange encryption keys", 0);
|
||||
return LIBSSH2_ERROR_KEX_FAILURE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
session->startup_state = libssh2_NB_state_sent2;
|
||||
}
|
||||
|
||||
if (session->startup_state == libssh2_NB_state_sent2) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||
"Requesting userauth service");
|
||||
|
||||
/* Request the userauth service */
|
||||
@@ -622,15 +625,10 @@ session_startup(LIBSSH2_SESSION *session, int sock)
|
||||
if (session->startup_state == libssh2_NB_state_sent3) {
|
||||
rc = _libssh2_transport_write(session, session->startup_service,
|
||||
sizeof("ssh-userauth") + 5 - 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block asking for ssh-userauth service", 0);
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
if (rc) {
|
||||
libssh2_error(session, rc,
|
||||
"Unable to ask for ssh-userauth service", 0);
|
||||
return LIBSSH2_ERROR_SOCKET_SEND;
|
||||
return rc;
|
||||
}
|
||||
|
||||
session->startup_state = libssh2_NB_state_sent4;
|
||||
@@ -641,11 +639,9 @@ session_startup(LIBSSH2_SESSION *session, int sock)
|
||||
&session->startup_data,
|
||||
&session->startup_data_len, 0, NULL, 0,
|
||||
&session->startup_req_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
} else if (rc) {
|
||||
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
|
||||
}
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
session->startup_service_length =
|
||||
_libssh2_ntohu32(session->startup_data + 1);
|
||||
|
||||
@@ -699,22 +695,27 @@ static int
|
||||
session_free(LIBSSH2_SESSION *session)
|
||||
{
|
||||
int rc;
|
||||
LIBSSH2_PACKET *pkg;
|
||||
LIBSSH2_CHANNEL *ch;
|
||||
LIBSSH2_LISTENER *l;
|
||||
|
||||
if (session->free_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Freeing session resource",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Freeing session resource",
|
||||
session->remote.banner);
|
||||
|
||||
session->state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
if (session->free_state == libssh2_NB_state_created) {
|
||||
while (session->channels.head) {
|
||||
LIBSSH2_CHANNEL *tmp = session->channels.head;
|
||||
while ((ch = _libssh2_list_first(&session->channels))) {
|
||||
|
||||
rc = libssh2_channel_free(session->channels.head);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
rc = libssh2_channel_free(ch);
|
||||
if (rc == PACKET_EAGAIN)
|
||||
return rc;
|
||||
#if 0
|
||||
/* Daniel's note: I'm leaving this code here right now since it
|
||||
looks so weird I'm stumped. Why would libssh2_channel_free()
|
||||
fail and forces this to be done? */
|
||||
if (tmp == session->channels.head) {
|
||||
/* channel_free couldn't do it's job, perform a messy cleanup */
|
||||
tmp = session->channels.head;
|
||||
@@ -728,17 +729,17 @@ session_free(LIBSSH2_SESSION *session)
|
||||
/* reverse linking isn't important here, we're killing the
|
||||
* structure */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
session->state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
if (session->state == libssh2_NB_state_sent) {
|
||||
while (session->listeners) {
|
||||
rc = libssh2_channel_forward_cancel(session->listeners);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
while ((l = _libssh2_list_first(&session->listeners))) {
|
||||
rc = libssh2_channel_forward_cancel(l);
|
||||
if (rc == PACKET_EAGAIN)
|
||||
return rc;
|
||||
}
|
||||
|
||||
session->state = libssh2_NB_state_sent1;
|
||||
@@ -908,16 +909,14 @@ session_free(LIBSSH2_SESSION *session)
|
||||
LIBSSH2_FREE(session, session->err_msg);
|
||||
}
|
||||
|
||||
/* Cleanup any remaining packets */
|
||||
while (session->packets.head) {
|
||||
LIBSSH2_PACKET *tmp = session->packets.head;
|
||||
|
||||
/* unlink */
|
||||
session->packets.head = tmp->next;
|
||||
/* Cleanup all remaining packets */
|
||||
while ((pkg = _libssh2_list_first(&session->packets))) {
|
||||
/* unlink the node */
|
||||
_libssh2_list_remove(&pkg->node);
|
||||
|
||||
/* free */
|
||||
LIBSSH2_FREE(session, tmp->data);
|
||||
LIBSSH2_FREE(session, tmp);
|
||||
LIBSSH2_FREE(session, pkg->data);
|
||||
LIBSSH2_FREE(session, pkg);
|
||||
}
|
||||
|
||||
if(session->socket_prev_blockstate)
|
||||
@@ -961,7 +960,7 @@ session_disconnect(LIBSSH2_SESSION *session, int reason,
|
||||
int rc;
|
||||
|
||||
if (session->disconnect_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||
"Disconnecting: reason=%d, desc=%s, lang=%s", reason,
|
||||
description, lang);
|
||||
if (description) {
|
||||
@@ -1007,7 +1006,7 @@ session_disconnect(LIBSSH2_SESSION *session, int reason,
|
||||
rc = _libssh2_transport_write(session, session->disconnect_data,
|
||||
session->disconnect_data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, session->disconnect_data);
|
||||
@@ -1207,7 +1206,7 @@ int
|
||||
_libssh2_session_set_blocking(LIBSSH2_SESSION *session, int blocking)
|
||||
{
|
||||
int bl = session->api_block_mode;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"Setting blocking mode %s", blocking?"ON":"OFF");
|
||||
session->api_block_mode = blocking;
|
||||
|
||||
@@ -1245,7 +1244,7 @@ LIBSSH2_API int
|
||||
libssh2_poll_channel_read(LIBSSH2_CHANNEL * channel, int extended)
|
||||
{
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
LIBSSH2_PACKET *packet = session->packets.head;
|
||||
LIBSSH2_PACKET *packet = _libssh2_list_first(&session->packets);
|
||||
|
||||
while (packet) {
|
||||
if ( channel->local.id == _libssh2_ntohu32(packet->data + 1)) {
|
||||
@@ -1259,7 +1258,7 @@ libssh2_poll_channel_read(LIBSSH2_CHANNEL * channel, int extended)
|
||||
}
|
||||
/* else - no data of any type is ready to be read */
|
||||
}
|
||||
packet = packet->next;
|
||||
packet = _libssh2_list_next(&packet->node);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1285,7 +1284,7 @@ poll_channel_write(LIBSSH2_CHANNEL * channel)
|
||||
static inline int
|
||||
poll_listener_queued(LIBSSH2_LISTENER * listener)
|
||||
{
|
||||
return listener->queue ? 1 : 0;
|
||||
return _libssh2_list_first(&listener->queue) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1346,7 +1345,7 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
|
||||
}
|
||||
#elif defined(HAVE_SELECT)
|
||||
LIBSSH2_SESSION *session = NULL;
|
||||
int maxfd = 0;
|
||||
libssh2_socket_t maxfd = 0;
|
||||
fd_set rfds, wfds;
|
||||
struct timeval tv;
|
||||
|
||||
@@ -1456,8 +1455,7 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
|
||||
((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) {
|
||||
/* No connections known of yet */
|
||||
fds[i].revents |=
|
||||
poll_listener_queued(fds[i].fd.
|
||||
listener) ?
|
||||
poll_listener_queued(fds[i].fd. listener) ?
|
||||
LIBSSH2_POLLFD_POLLIN : 0;
|
||||
}
|
||||
if (fds[i].fd.listener->session->socket_state ==
|
||||
|
234
src/sftp.c
234
src/sftp.c
@@ -118,28 +118,21 @@ sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data,
|
||||
LIBSSH2_SESSION *session = sftp->channel->session;
|
||||
LIBSSH2_PACKET *packet;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Received packet %d (len %d)",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Received packet %d (len %d)",
|
||||
(int) data[0], data_len);
|
||||
packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate datablock for SFTP packet", 0);
|
||||
return -1;
|
||||
return LIBSSH2_ERROR_ALLOC;
|
||||
}
|
||||
memset(packet, 0, sizeof(LIBSSH2_PACKET));
|
||||
|
||||
packet->data = data;
|
||||
packet->data_len = data_len;
|
||||
packet->data_head = 5;
|
||||
packet->brigade = &sftp->packets;
|
||||
packet->next = NULL;
|
||||
packet->prev = sftp->packets.tail;
|
||||
if (packet->prev) {
|
||||
packet->prev->next = packet;
|
||||
} else {
|
||||
sftp->packets.head = packet;
|
||||
}
|
||||
sftp->packets.tail = packet;
|
||||
|
||||
_libssh2_list_add(&sftp->packets, &packet->node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -160,7 +153,7 @@ sftp_packet_read(LIBSSH2_SFTP *sftp)
|
||||
ssize_t bytes_received;
|
||||
int rc;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "recv packet");
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "recv packet");
|
||||
|
||||
/* If there was a previous partial, start using it */
|
||||
if (sftp->partial_packet) {
|
||||
@@ -170,37 +163,37 @@ sftp_packet_read(LIBSSH2_SFTP *sftp)
|
||||
packet_received = sftp->partial_received;
|
||||
sftp->partial_packet = NULL;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
|
||||
"partial read cont, len: %lu", packet_len);
|
||||
}
|
||||
else {
|
||||
rc = libssh2_channel_read_ex(channel, 0, (char *) buffer, 4);
|
||||
rc = _libssh2_channel_read(channel, 0, (char *) buffer, 4);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
else if (4 != rc) {
|
||||
/* TODO: this is stupid since we can in fact get 1-3 bytes in a
|
||||
legitimate working case as well if the connection happens to be
|
||||
super slow or something */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for FXP packet", 0);
|
||||
return -1;
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
|
||||
"Read part of packet", 0);
|
||||
return LIBSSH2_ERROR_CHANNEL_FAILURE;
|
||||
}
|
||||
|
||||
packet_len = _libssh2_ntohu32(buffer);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
|
||||
"Data begin - Packet Length: %lu", packet_len);
|
||||
if (packet_len > LIBSSH2_SFTP_PACKET_MAXLEN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
|
||||
"SFTP packet too large", 0);
|
||||
return -1;
|
||||
return LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED;
|
||||
}
|
||||
|
||||
packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate SFTP packet", 0);
|
||||
return -1;
|
||||
return LIBSSH2_ERROR_ALLOC;
|
||||
}
|
||||
|
||||
packet_received = 0;
|
||||
@@ -209,9 +202,9 @@ sftp_packet_read(LIBSSH2_SFTP *sftp)
|
||||
/* Read as much of the packet as we can */
|
||||
while (packet_len > packet_received) {
|
||||
bytes_received =
|
||||
libssh2_channel_read_ex(channel, 0,
|
||||
(char *) packet + packet_received,
|
||||
packet_len - packet_received);
|
||||
_libssh2_channel_read(channel, 0,
|
||||
(char *) packet + packet_received,
|
||||
packet_len - packet_received);
|
||||
|
||||
if (bytes_received == PACKET_EAGAIN) {
|
||||
/*
|
||||
@@ -223,20 +216,21 @@ sftp_packet_read(LIBSSH2_SFTP *sftp)
|
||||
sftp->partial_received = packet_received;
|
||||
packet = NULL;
|
||||
|
||||
return PACKET_EAGAIN;
|
||||
return bytes_received;
|
||||
}
|
||||
else if (bytes_received < 0) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Receive error waiting for SFTP packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
return bytes_received;
|
||||
}
|
||||
packet_received += bytes_received;
|
||||
}
|
||||
|
||||
if (sftp_packet_add(sftp, packet, packet_len)) {
|
||||
rc = sftp_packet_add(sftp, packet, packet_len);
|
||||
if (rc) {
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
return packet[0];
|
||||
@@ -253,11 +247,11 @@ sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type,
|
||||
unsigned long *data_len)
|
||||
{
|
||||
LIBSSH2_SESSION *session = sftp->channel->session;
|
||||
LIBSSH2_PACKET *packet = sftp->packets.head;
|
||||
LIBSSH2_PACKET *packet = _libssh2_list_first(&sftp->packets);
|
||||
unsigned char match_buf[5];
|
||||
int match_len;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Asking for %d packet",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Asking for %d packet",
|
||||
(int) packet_type);
|
||||
|
||||
match_buf[0] = packet_type;
|
||||
@@ -277,24 +271,13 @@ sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type,
|
||||
*data_len = packet->data_len;
|
||||
|
||||
/* unlink and free this struct */
|
||||
if (packet->prev) {
|
||||
packet->prev->next = packet->next;
|
||||
} else {
|
||||
sftp->packets.head = packet->next;
|
||||
}
|
||||
|
||||
if (packet->next) {
|
||||
packet->next->prev = packet->prev;
|
||||
} else {
|
||||
sftp->packets.tail = packet->prev;
|
||||
}
|
||||
|
||||
_libssh2_list_remove(&packet->node);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* check next struct in the list */
|
||||
packet = packet->next;
|
||||
packet = _libssh2_list_next(&packet->node);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -310,12 +293,12 @@ sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_type,
|
||||
LIBSSH2_SESSION *session = sftp->channel->session;
|
||||
int ret;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Requiring packet %d id %ld",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Requiring packet %d id %ld",
|
||||
(int) packet_type, request_id);
|
||||
|
||||
if (sftp_packet_ask(sftp, packet_type, request_id, data, data_len) == 0) {
|
||||
/* The right packet was available in the packet brigade */
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Got %d",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Got %d",
|
||||
(int) packet_type);
|
||||
return 0;
|
||||
}
|
||||
@@ -323,7 +306,7 @@ sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_type,
|
||||
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
||||
ret = sftp_packet_read(sftp);
|
||||
if (ret == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return ret;
|
||||
} else if (ret <= 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -331,14 +314,14 @@ sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_type,
|
||||
/* data was read, check the queue again */
|
||||
if (!sftp_packet_ask(sftp, packet_type, request_id, data, data_len)) {
|
||||
/* The right packet was available in the packet brigade */
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Got %d",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Got %d",
|
||||
(int) packet_type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only reached if the socket died */
|
||||
return -1;
|
||||
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
|
||||
}
|
||||
|
||||
/* sftp_packet_requirev
|
||||
@@ -385,7 +368,7 @@ sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses,
|
||||
return PACKET_TIMEOUT;
|
||||
}
|
||||
else if (ret == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -547,7 +530,7 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session)
|
||||
LIBSSH2_SFTP *sftp_handle;
|
||||
|
||||
if (session->sftpInit_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
|
||||
"Initializing SFTP subsystem");
|
||||
|
||||
/*
|
||||
@@ -556,8 +539,8 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session)
|
||||
* as the SFTP session is created they are cleared and can thus be
|
||||
* re-used again to allow any amount of SFTP handles per sessions.
|
||||
*
|
||||
* Note that you MUST NOT try to call libssh2_sftp_init() to get
|
||||
* another handle until the previous one has finished and either
|
||||
* Note that you MUST NOT try to call libssh2_sftp_init() again to get
|
||||
* another handle until the previous call has finished and either
|
||||
* succesffully made a handle or failed and returned error (not
|
||||
* including *EAGAIN).
|
||||
*/
|
||||
@@ -633,7 +616,7 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session)
|
||||
session->sftpInit_buffer[4] = SSH_FXP_INIT;
|
||||
_libssh2_htonu32(session->sftpInit_buffer + 5, LIBSSH2_SFTP_VERSION);
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
|
||||
"Sending FXP_INIT packet advertising version %d support",
|
||||
(int) LIBSSH2_SFTP_VERSION);
|
||||
|
||||
@@ -678,12 +661,12 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session)
|
||||
sftp_handle->version = _libssh2_ntohu32(s);
|
||||
s += 4;
|
||||
if (sftp_handle->version > LIBSSH2_SFTP_VERSION) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
|
||||
"Truncating remote SFTP version from %lu",
|
||||
sftp_handle->version);
|
||||
sftp_handle->version = LIBSSH2_SFTP_VERSION;
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
|
||||
"Enabling SFTP version %lu compatability",
|
||||
sftp_handle->version);
|
||||
while (s < (data + data_len)) {
|
||||
@@ -715,6 +698,8 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session)
|
||||
session->sftpInit_sftp = NULL;
|
||||
session->sftpInit_channel = NULL;
|
||||
|
||||
_libssh2_list_init(&sftp_handle->sftp_handles);
|
||||
|
||||
return sftp_handle;
|
||||
|
||||
sftp_init_error:
|
||||
@@ -798,6 +783,9 @@ sftp_shutdown(LIBSSH2_SFTP *sftp)
|
||||
sftp->symlink_packet = NULL;
|
||||
}
|
||||
|
||||
/* TODO: We should consider walking over the sftp_handles list and kill
|
||||
* any remaining sftp handles ... */
|
||||
|
||||
rc = _libssh2_channel_free(sftp->channel);
|
||||
|
||||
return rc;
|
||||
@@ -810,8 +798,7 @@ LIBSSH2_API int
|
||||
libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp)
|
||||
{
|
||||
int rc;
|
||||
BLOCK_ADJUST(rc, sftp->channel->session,
|
||||
sftp_shutdown(sftp));
|
||||
BLOCK_ADJUST(rc, sftp->channel->session, sftp_shutdown(sftp));
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -877,7 +864,7 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename,
|
||||
s += sftp_attr2bin(s, &attrs);
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending %s open request",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Sending %s open request",
|
||||
(open_type ==
|
||||
LIBSSH2_SFTP_OPENFILE) ? "file" : "directory");
|
||||
|
||||
@@ -920,7 +907,7 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename,
|
||||
return NULL;
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
libssh2_error(session, rc,
|
||||
"Timeout waiting for status message", 0);
|
||||
sftp->open_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
@@ -938,7 +925,7 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename,
|
||||
sftp->last_errno = _libssh2_ntohu32(data + 5);
|
||||
|
||||
if(LIBSSH2_FX_OK == sftp->last_errno) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "got HANDLE FXOK!");
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "got HANDLE FXOK!");
|
||||
|
||||
/* silly situation, but check for a HANDLE */
|
||||
rc = sftp_packet_require(sftp, SSH_FXP_HANDLE,
|
||||
@@ -956,7 +943,7 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename,
|
||||
if(badness) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
|
||||
"Failed opening remote file", 0);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "got FXP_STATUS %d",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "got FXP_STATUS %d",
|
||||
sftp->last_errno);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return NULL;
|
||||
@@ -985,16 +972,14 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename,
|
||||
memcpy(fp->handle, data + 9, fp->handle_len);
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
/* Link the file and the sftp session together */
|
||||
fp->next = sftp->handles;
|
||||
if (fp->next) {
|
||||
fp->next->prev = fp;
|
||||
}
|
||||
fp->sftp = sftp;
|
||||
/* add this file handle to the list kept in the sftp session */
|
||||
_libssh2_list_add(&sftp->sftp_handles, &fp->node);
|
||||
|
||||
fp->sftp = sftp; /* point to the parent struct */
|
||||
|
||||
fp->u.file.offset = 0;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Open command successful");
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Open command successful");
|
||||
return fp;
|
||||
}
|
||||
|
||||
@@ -1034,7 +1019,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
|
||||
int retcode;
|
||||
|
||||
if (sftp->read_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
|
||||
"Reading %lu bytes from SFTP handle",
|
||||
(unsigned long) buffer_maxlen);
|
||||
packet = handle->request_packet;
|
||||
@@ -1072,7 +1057,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
|
||||
bytes_requested = LIBSSH2_SFTP_PACKET_MAXLEN - 13;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
|
||||
"Requesting %lu bytes from SFTP handle",
|
||||
(unsigned long) bytes_requested);
|
||||
#endif
|
||||
@@ -1106,7 +1091,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
|
||||
sftp->read_packet = packet;
|
||||
sftp->read_request_id = request_id;
|
||||
sftp->read_total_read = total_read;
|
||||
return PACKET_EAGAIN;
|
||||
return retcode;
|
||||
} else if (packet_len != retcode) {
|
||||
/* TODO: a partial write is not a critical error when in
|
||||
non-blocking mode! */
|
||||
@@ -1127,9 +1112,11 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
|
||||
sftp_packet_requirev(sftp, 2, read_responses,
|
||||
request_id, &data, &data_len);
|
||||
if (retcode == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
libssh2_error(session, retcode,
|
||||
"Would block waiting for status message", 0);
|
||||
return retcode;
|
||||
} else if (retcode) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
libssh2_error(session, retcode,
|
||||
"Timeout waiting for status message", 0);
|
||||
sftp->read_packet = NULL;
|
||||
sftp->read_state = libssh2_NB_state_idle;
|
||||
@@ -1166,7 +1153,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
|
||||
return -1;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu bytes returned",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%lu bytes returned",
|
||||
(unsigned long) bytes_read);
|
||||
#endif
|
||||
memcpy(buffer + total_read, data + 9, bytes_read);
|
||||
@@ -1270,7 +1257,7 @@ static int sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
LIBSSH2_FREE(session, handle->u.dir.names_packet);
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
|
||||
"libssh2_sftp_readdir_ex() return %d",
|
||||
filename_len);
|
||||
return filename_len;
|
||||
@@ -1301,13 +1288,13 @@ static int sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
}
|
||||
|
||||
if (sftp->readdir_state == libssh2_NB_state_created) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
|
||||
"Reading entries from directory handle");
|
||||
retcode = _libssh2_channel_write(channel, 0,
|
||||
(char *) sftp->readdir_packet,
|
||||
packet_len);
|
||||
if (retcode == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return retcode;
|
||||
}
|
||||
else if (packet_len != retcode) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
@@ -1329,7 +1316,7 @@ static int sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
sftp->readdir_request_id, &data,
|
||||
&data_len);
|
||||
if (retcode == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return retcode;
|
||||
} else if (retcode) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for status message", 0);
|
||||
@@ -1353,7 +1340,7 @@ static int sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
}
|
||||
|
||||
num_names = _libssh2_ntohu32(data + 5);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu entries returned",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%lu entries returned",
|
||||
num_names);
|
||||
if (num_names <= 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
@@ -1418,7 +1405,8 @@ libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *hnd, char *buffer,
|
||||
/*
|
||||
* sftp_write
|
||||
*
|
||||
* Write data to an SFTP handle
|
||||
* Write data to an SFTP handle. Returns the number of bytes written, or
|
||||
* a negative error code.
|
||||
*/
|
||||
static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer,
|
||||
size_t count)
|
||||
@@ -1443,13 +1431,13 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer,
|
||||
packet_len = handle->handle_len + count + 25;
|
||||
|
||||
if (sftp->write_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Writing %lu bytes",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Writing %lu bytes",
|
||||
(unsigned long) count);
|
||||
s = sftp->write_packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!sftp->write_packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for FXP_WRITE", 0);
|
||||
return -1;
|
||||
return LIBSSH2_ERROR_ALLOC;
|
||||
}
|
||||
_libssh2_htonu32(s, packet_len - 4);
|
||||
s += 4;
|
||||
@@ -1474,17 +1462,13 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer,
|
||||
if (sftp->write_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_channel_write(channel, 0, (char *)sftp->write_packet,
|
||||
packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
else if(rc < 0) {
|
||||
/* an actual error */
|
||||
if(rc < 0) {
|
||||
/* error */
|
||||
return rc;
|
||||
}
|
||||
else if(0 == rc) {
|
||||
/* an actual error */
|
||||
fprintf(stderr, "WEIRDNESS\n");
|
||||
return -1;
|
||||
/* nothing sent is an error */
|
||||
return LIBSSH2_ERROR_SOCKET_SEND;
|
||||
}
|
||||
else if (packet_len != rc) {
|
||||
return rc;
|
||||
@@ -1497,12 +1481,13 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer,
|
||||
rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
|
||||
sftp->write_request_id, &data, &data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
return rc;
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, rc,
|
||||
"Timeout waiting for status message", 0);
|
||||
sftp->write_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
sftp->write_state = libssh2_NB_state_idle;
|
||||
@@ -1518,7 +1503,7 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer,
|
||||
0);
|
||||
sftp->last_errno = retcode;
|
||||
|
||||
return -1;
|
||||
return LIBSSH2_ERROR_SFTP_PROTOCOL;
|
||||
}
|
||||
|
||||
/* libssh2_sftp_write
|
||||
@@ -1556,7 +1541,7 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle,
|
||||
int rc;
|
||||
|
||||
if (sftp->fstat_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Issuing %s command",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Issuing %s command",
|
||||
setstat ? "set-stat" : "stat");
|
||||
s = sftp->fstat_packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!sftp->fstat_packet) {
|
||||
@@ -1587,7 +1572,7 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle,
|
||||
rc = _libssh2_channel_write(channel, 0, (char *) sftp->fstat_packet,
|
||||
packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
(setstat ? "Unable to send FXP_FSETSTAT"
|
||||
@@ -1607,7 +1592,7 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle,
|
||||
sftp->fstat_request_id, &data,
|
||||
&data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for status message", 0);
|
||||
@@ -1633,6 +1618,7 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle,
|
||||
}
|
||||
|
||||
sftp_bin2attr(attrs, data + 5);
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1707,7 +1693,7 @@ sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
|
||||
int rc;
|
||||
|
||||
if (handle->close_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Closing handle");
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Closing handle");
|
||||
s = handle->close_packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!handle->close_packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
@@ -1733,7 +1719,7 @@ sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
|
||||
rc = _libssh2_channel_write(channel, 0, (char *) handle->close_packet,
|
||||
packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send FXP_CLOSE command", 0);
|
||||
@@ -1753,7 +1739,7 @@ sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
|
||||
handle->close_request_id, &data,
|
||||
&data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for status message", 0);
|
||||
@@ -1775,12 +1761,8 @@ sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle == sftp->handles) {
|
||||
sftp->handles = handle->next;
|
||||
}
|
||||
if (handle->next) {
|
||||
handle->next->prev = NULL;
|
||||
}
|
||||
/* remove this handle from the parent's list */
|
||||
_libssh2_list_remove(&handle->node);
|
||||
|
||||
if ((handle->handle_type == LIBSSH2_SFTP_HANDLE_DIR)
|
||||
&& handle->u.dir.names_left) {
|
||||
@@ -1822,7 +1804,7 @@ static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename,
|
||||
int rc;
|
||||
|
||||
if (sftp->unlink_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Unlinking %s", filename);
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Unlinking %s", filename);
|
||||
s = sftp->unlink_packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!sftp->unlink_packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
@@ -1849,7 +1831,7 @@ static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename,
|
||||
rc = _libssh2_channel_write(channel, 0, (char *) sftp->unlink_packet,
|
||||
packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send FXP_REMOVE command", 0);
|
||||
@@ -1868,7 +1850,7 @@ static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename,
|
||||
sftp->unlink_request_id, &data,
|
||||
&data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
@@ -1934,7 +1916,7 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename,
|
||||
}
|
||||
|
||||
if (sftp->rename_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Renaming %s to %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Renaming %s to %s",
|
||||
source_filename, dest_filename);
|
||||
sftp->rename_s = sftp->rename_packet =
|
||||
LIBSSH2_ALLOC(session, packet_len);
|
||||
@@ -1972,7 +1954,7 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename,
|
||||
rc = _libssh2_channel_write(channel, 0, (char *) sftp->rename_packet,
|
||||
sftp->rename_s - sftp->rename_packet);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send FXP_RENAME command", 0);
|
||||
@@ -1991,7 +1973,7 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename,
|
||||
sftp->rename_request_id, &data,
|
||||
&data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for status message", 0);
|
||||
@@ -2070,7 +2052,7 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path,
|
||||
int rc;
|
||||
|
||||
if (sftp->mkdir_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
|
||||
"Creating directory %s with mode 0%lo", path, mode);
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
@@ -2103,7 +2085,7 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path,
|
||||
rc = _libssh2_channel_write(channel, 0, (char *) packet, packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
sftp->mkdir_packet = packet;
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
@@ -2120,7 +2102,7 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path,
|
||||
rc = sftp_packet_require(sftp, SSH_FXP_STATUS, sftp->mkdir_request_id,
|
||||
&data, &data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for status message", 0);
|
||||
@@ -2134,7 +2116,7 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path,
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
if (retcode == LIBSSH2_FX_OK) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "OK!");
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "OK!");
|
||||
return 0;
|
||||
} else {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
|
||||
@@ -2174,7 +2156,7 @@ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path,
|
||||
int rc;
|
||||
|
||||
if (sftp->rmdir_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Removing directory: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Removing directory: %s",
|
||||
path);
|
||||
s = sftp->rmdir_packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!sftp->rmdir_packet) {
|
||||
@@ -2201,7 +2183,7 @@ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path,
|
||||
rc = _libssh2_channel_write(channel, 0, (char *) sftp->rmdir_packet,
|
||||
packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send FXP_RMDIR command", 0);
|
||||
@@ -2219,7 +2201,7 @@ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path,
|
||||
rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
|
||||
sftp->rmdir_request_id, &data, &data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for status message", 0);
|
||||
@@ -2276,7 +2258,7 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path,
|
||||
int rc;
|
||||
|
||||
if (sftp->stat_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%s %s",
|
||||
(stat_type == LIBSSH2_SFTP_SETSTAT) ? "Set-statting" :
|
||||
(stat_type ==
|
||||
LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path);
|
||||
@@ -2320,7 +2302,7 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path,
|
||||
rc = _libssh2_channel_write(channel, 0, (char *) sftp->stat_packet,
|
||||
packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send STAT/LSTAT/SETSTAT command", 0);
|
||||
@@ -2338,7 +2320,7 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path,
|
||||
rc = sftp_packet_requirev(sftp, 2, stat_responses,
|
||||
sftp->stat_request_id, &data, &data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for status message", 0);
|
||||
@@ -2418,7 +2400,7 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path,
|
||||
return -1;
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s on %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%s %s on %s",
|
||||
(link_type ==
|
||||
LIBSSH2_SFTP_SYMLINK) ? "Creating" : "Reading",
|
||||
(link_type ==
|
||||
@@ -2460,7 +2442,7 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path,
|
||||
rc = _libssh2_channel_write(channel, 0, (char *) sftp->symlink_packet,
|
||||
packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send SYMLINK/READLINK command", 0);
|
||||
@@ -2479,7 +2461,7 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path,
|
||||
sftp->symlink_request_id, &data,
|
||||
&data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
|
139
src/transport.c
139
src/transport.c
@@ -41,6 +41,7 @@
|
||||
#include "libssh2_priv.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@@ -57,36 +58,58 @@ debugdump(LIBSSH2_SESSION * session,
|
||||
{
|
||||
size_t i;
|
||||
size_t c;
|
||||
FILE *stream = stderr;
|
||||
unsigned int width = 0x10;
|
||||
char buffer[256]; /* Must be enough for width*4 + about 30 or so */
|
||||
size_t used;
|
||||
static const char* hex_chars = "0123456789ABCDEF";
|
||||
|
||||
if (!(session->showmask & (1 << LIBSSH2_DBG_TRANS))) {
|
||||
if (!(session->showmask & LIBSSH2_TRACE_TRANS)) {
|
||||
/* not asked for, bail out */
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stream, "=> %s (%d bytes)\n", desc, (int) size);
|
||||
used = snprintf(buffer, sizeof(buffer), "=> %s (%d bytes)\n",
|
||||
desc, (int) size);
|
||||
if (session->tracehandler)
|
||||
(session->tracehandler)(session, session->tracehandler_context, buffer, used);
|
||||
else
|
||||
write(2 /* stderr */, buffer, used);
|
||||
|
||||
for(i = 0; i < size; i += width) {
|
||||
|
||||
fprintf(stream, "%04lx: ", (long)i);
|
||||
used = snprintf(buffer, sizeof(buffer), "%04lx: ", (long)i);
|
||||
|
||||
/* hex not disabled, show it */
|
||||
for(c = 0; c < width; c++) {
|
||||
if (i + c < size)
|
||||
fprintf(stream, "%02x ", ptr[i + c]);
|
||||
else
|
||||
fputs(" ", stream);
|
||||
if (i + c < size) {
|
||||
buffer[used++] = hex_chars[(ptr[i+c] >> 4) & 0xF];
|
||||
buffer[used++] = hex_chars[ptr[i+c] & 0xF];
|
||||
}
|
||||
else {
|
||||
buffer[used++] = ' ';
|
||||
buffer[used++] = ' ';
|
||||
}
|
||||
|
||||
buffer[used++] = ' ';
|
||||
if ((width/2) - 1 == c)
|
||||
buffer[used++] = ' ';
|
||||
}
|
||||
|
||||
buffer[used++] = ':';
|
||||
buffer[used++] = ' ';
|
||||
|
||||
for(c = 0; (c < width) && (i + c < size); c++) {
|
||||
fprintf(stream, "%c",
|
||||
(ptr[i + c] >= 0x20) &&
|
||||
(ptr[i + c] < 0x80) ? ptr[i + c] : UNPRINTABLE_CHAR);
|
||||
buffer[used++] = isprint(ptr[i + c]) ?
|
||||
ptr[i + c] : UNPRINTABLE_CHAR;
|
||||
}
|
||||
fputc('\n', stream); /* newline */
|
||||
buffer[used++] = '\n';
|
||||
buffer[used] = 0;
|
||||
|
||||
if (session->tracehandler)
|
||||
(session->tracehandler)(session, session->tracehandler_context, buffer, used);
|
||||
else
|
||||
write(2, buffer, used);
|
||||
}
|
||||
fflush(stream);
|
||||
}
|
||||
#else
|
||||
#define debugdump(a,x,y,z)
|
||||
@@ -95,10 +118,10 @@ debugdump(LIBSSH2_SESSION * session,
|
||||
|
||||
/* decrypt() decrypts 'len' bytes from 'source' to 'dest'.
|
||||
*
|
||||
* returns PACKET_NONE on success and PACKET_FAIL on failure
|
||||
* returns 0 on success and negative on failure
|
||||
*/
|
||||
|
||||
static libssh2pack_t
|
||||
static int
|
||||
decrypt(LIBSSH2_SESSION * session, unsigned char *source,
|
||||
unsigned char *dest, int len)
|
||||
{
|
||||
@@ -134,7 +157,7 @@ decrypt(LIBSSH2_SESSION * session, unsigned char *source,
|
||||
* fullpacket() gets called when a full packet has been received and properly
|
||||
* collected.
|
||||
*/
|
||||
static libssh2pack_t
|
||||
static int
|
||||
fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
|
||||
{
|
||||
unsigned char macbuf[MAX_MACSIZE];
|
||||
@@ -232,11 +255,8 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
|
||||
rc = _libssh2_packet_add(session, p->payload,
|
||||
session->fullpacket_payload_len,
|
||||
session->fullpacket_macstate);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
} else if (rc < 0) {
|
||||
return PACKET_FAIL;
|
||||
}
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
session->fullpacket_state = libssh2_NB_state_idle;
|
||||
@@ -248,22 +268,21 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
|
||||
/*
|
||||
* _libssh2_transport_read
|
||||
*
|
||||
* Collect a packet into the input brigade block only controls whether or not
|
||||
* to wait for a packet to start.
|
||||
* Collect a packet into the input queue.
|
||||
*
|
||||
* Returns packet type added to input brigade (PACKET_NONE if nothing added),
|
||||
* or PACKET_FAIL on failure and PACKET_EAGAIN if it couldn't process a full
|
||||
* packet.
|
||||
* Returns packet type added to input queue (0 if nothing added), or a
|
||||
* negative error number.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This function reads the binary stream as specified in chapter 6 of RFC4253
|
||||
* "The Secure Shell (SSH) Transport Layer Protocol"
|
||||
*
|
||||
* DOES NOT call libssh2_error() for ANY error case.
|
||||
*/
|
||||
libssh2pack_t
|
||||
_libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
int _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
{
|
||||
libssh2pack_t rc = -1;
|
||||
int rc = LIBSSH2_ERROR_SOCKET_NONE;
|
||||
struct transportpacket *p = &session->packet;
|
||||
int remainbuf;
|
||||
int remainpack;
|
||||
@@ -272,7 +291,6 @@ _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
unsigned char block[MAX_BLOCKSIZE];
|
||||
int blocksize;
|
||||
int encrypted = 1;
|
||||
int status;
|
||||
|
||||
/* default clear the bit */
|
||||
session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND;
|
||||
@@ -295,18 +313,11 @@ _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
/* Whoever wants a packet won't get anything until the key re-exchange
|
||||
* is done!
|
||||
*/
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Redirecting into the"
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the"
|
||||
" key re-exchange");
|
||||
status = libssh2_kex_exchange(session, 1, &session->startup_key_state);
|
||||
if (status == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block exchanging encryption keys", 0);
|
||||
return PACKET_EAGAIN;
|
||||
} else if (status) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
|
||||
"Unable to exchange encryption keys",0);
|
||||
return LIBSSH2_ERROR_KEX_FAILURE;
|
||||
}
|
||||
rc = libssh2_kex_exchange(session, 1, &session->startup_key_state);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -367,11 +378,20 @@ _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
_libssh2_recv(session->socket_fd, &p->buf[remainbuf],
|
||||
PACKETBUFSIZE - remainbuf,
|
||||
LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
if (nread < 0)
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Error recving %d bytes to %p+%d: %d",
|
||||
PACKETBUFSIZE - remainbuf, p->buf, remainbuf,
|
||||
errno);
|
||||
else
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Recved %d/%d bytes to %p+%d", nread,
|
||||
PACKETBUFSIZE - remainbuf, p->buf, remainbuf);
|
||||
if (nread <= 0) {
|
||||
/* check if this is due to EAGAIN and return the special
|
||||
return code if so, error out normally otherwise */
|
||||
if ((nread < 0) && (errno == EAGAIN)) {
|
||||
session->socket_block_directions =
|
||||
session->socket_block_directions |=
|
||||
LIBSSH2_SESSION_BLOCK_INBOUND;
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
@@ -400,6 +420,8 @@ _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
check is only done for the initial block since once we have
|
||||
got the start of a block we can in fact deal with fractions
|
||||
*/
|
||||
session->socket_block_directions |=
|
||||
LIBSSH2_SESSION_BLOCK_INBOUND;
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
|
||||
@@ -570,7 +592,7 @@ _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
session->readPack_state = libssh2_NB_state_jump1;
|
||||
}
|
||||
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
|
||||
p->total_num = 0; /* no packet buffer available */
|
||||
@@ -582,7 +604,7 @@ _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
return PACKET_FAIL; /* we never reach this point */
|
||||
}
|
||||
|
||||
static libssh2pack_t
|
||||
static int
|
||||
send_existing(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
unsigned long data_len, ssize_t * ret)
|
||||
{
|
||||
@@ -612,6 +634,13 @@ send_existing(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
|
||||
rc = _libssh2_send(session->socket_fd, &p->outbuf[p->osent], length,
|
||||
LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||
if (rc < 0)
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Error sending %d bytes: %d", length, errno);
|
||||
else
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Sent %d/%d bytes at %p+%d", rc, length, p->outbuf,
|
||||
p->osent);
|
||||
|
||||
if(rc > 0) {
|
||||
debugdump(session, "libssh2_transport_write send()",
|
||||
@@ -630,13 +659,13 @@ send_existing(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
/* send failure! */
|
||||
return PACKET_FAIL;
|
||||
}
|
||||
session->socket_block_directions = LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||
session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
|
||||
p->osent += rc; /* we sent away this much data */
|
||||
|
||||
return PACKET_NONE;
|
||||
return rc < length ? PACKET_EAGAIN : PACKET_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -653,6 +682,8 @@ send_existing(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
* NOTE: this function does not verify that 'data_len' is less than ~35000
|
||||
* which is what all implementations should support at least as packet size.
|
||||
* (RFC4253 section 6.1)
|
||||
*
|
||||
* This function DOES not call libssh2_error() on any errors.
|
||||
*/
|
||||
int
|
||||
_libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
@@ -673,21 +704,21 @@ _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
int encrypted;
|
||||
int i;
|
||||
ssize_t ret;
|
||||
libssh2pack_t rc;
|
||||
int rc;
|
||||
unsigned char *orgdata = data;
|
||||
unsigned long orgdata_len = data_len;
|
||||
|
||||
debugdump(session, "libssh2_transport_write plain", data, data_len);
|
||||
|
||||
/* default clear the bit */
|
||||
session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||
|
||||
/* FIRST, check if we have a pending write to complete */
|
||||
rc = send_existing(session, data, data_len, &ret);
|
||||
if (rc || ret) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* default clear the bit */
|
||||
session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||
|
||||
encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0;
|
||||
|
||||
/* check if we should compress */
|
||||
@@ -784,6 +815,12 @@ _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
|
||||
ret = _libssh2_send(session->socket_fd, p->outbuf, total_length,
|
||||
LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||
if (ret < 0)
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Error sending %d bytes: %d", total_length, errno);
|
||||
else
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET, "Sent %d/%d bytes at %p",
|
||||
ret, total_length, p->outbuf);
|
||||
|
||||
if (ret != -1) {
|
||||
debugdump(session, "libssh2_transport_write send()", p->outbuf, ret);
|
||||
@@ -791,7 +828,7 @@ _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
if (ret != total_length) {
|
||||
if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
|
||||
/* the whole packet could not be sent, save the rest */
|
||||
session->socket_block_directions = LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||
session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||
p->odata = orgdata;
|
||||
p->olen = orgdata_len;
|
||||
p->osent = (ret == -1) ? 0 : ret;
|
||||
|
@@ -75,6 +75,6 @@ int _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
* This function reads the binary stream as specified in chapter 6 of RFC4253
|
||||
* "The Secure Shell (SSH) Transport Layer Protocol"
|
||||
*/
|
||||
libssh2pack_t _libssh2_transport_read(LIBSSH2_SESSION * session);
|
||||
int _libssh2_transport_read(LIBSSH2_SESSION * session);
|
||||
|
||||
#endif /* __LIBSSH2_TRANSPORT_H */
|
||||
|
337
src/userauth.c
337
src/userauth.c
@@ -41,6 +41,8 @@
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* Needed for struct iovec on some platforms */
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
@@ -104,7 +106,7 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
|
||||
|
||||
if (session->userauth_list_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, session->userauth_list_data,
|
||||
session->userauth_list_data_len);
|
||||
session->userauth_list_data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block requesting userauth list", 0);
|
||||
@@ -155,7 +157,7 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
|
||||
memmove(session->userauth_list_data, session->userauth_list_data + 5,
|
||||
methods_len);
|
||||
session->userauth_list_data[methods_len] = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Permitted auth methods: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Permitted auth methods: %s",
|
||||
session->userauth_list_data);
|
||||
}
|
||||
|
||||
@@ -206,8 +208,8 @@ userauth_password(LIBSSH2_SESSION *session, const char *username,
|
||||
unsigned char *s;
|
||||
static const unsigned char reply_codes[4] =
|
||||
{ SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
|
||||
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0
|
||||
};
|
||||
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0
|
||||
};
|
||||
int rc;
|
||||
|
||||
if (session->userauth_pswd_state == libssh2_NB_state_idle) {
|
||||
@@ -256,7 +258,7 @@ userauth_password(LIBSSH2_SESSION *session, const char *username,
|
||||
memcpy(s, password, password_len);
|
||||
s += password_len;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Attempting to login using password authentication");
|
||||
|
||||
session->userauth_pswd_state = libssh2_NB_state_created;
|
||||
@@ -264,9 +266,9 @@ userauth_password(LIBSSH2_SESSION *session, const char *username,
|
||||
|
||||
if (session->userauth_pswd_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, session->userauth_pswd_data,
|
||||
session->userauth_pswd_data_len);
|
||||
session->userauth_pswd_data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send userauth-password request", 0);
|
||||
@@ -294,20 +296,31 @@ userauth_password(LIBSSH2_SESSION *session, const char *username,
|
||||
&session->
|
||||
userauth_pswd_packet_requirev_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
session->userauth_pswd_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Password authentication successful");
|
||||
LIBSSH2_FREE(session, session->userauth_pswd_data);
|
||||
session->userauth_pswd_data = NULL;
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
session->userauth_pswd_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
} else if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_FAILURE) {
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Password authentication failed");
|
||||
LIBSSH2_FREE(session, session->userauth_pswd_data);
|
||||
session->userauth_pswd_data = NULL;
|
||||
session->userauth_pswd_state = libssh2_NB_state_idle;
|
||||
libssh2_error(session,
|
||||
LIBSSH2_ERROR_AUTHENTICATION_FAILED,
|
||||
"Authentication failed (username/password)",
|
||||
0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
session->userauth_pswd_newpw = NULL;
|
||||
@@ -325,7 +338,7 @@ userauth_password(LIBSSH2_SESSION *session, const char *username,
|
||||
if ((session->userauth_pswd_state == libssh2_NB_state_sent1) ||
|
||||
(session->userauth_pswd_state == libssh2_NB_state_sent2)) {
|
||||
if (session->userauth_pswd_state == libssh2_NB_state_sent1) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Password change required");
|
||||
LIBSSH2_FREE(session, session->userauth_pswd_data);
|
||||
session->userauth_pswd_data = NULL;
|
||||
@@ -398,11 +411,11 @@ userauth_password(LIBSSH2_SESSION *session, const char *username,
|
||||
|
||||
if (session->userauth_pswd_state == libssh2_NB_state_sent2) {
|
||||
rc = _libssh2_transport_write(session,
|
||||
session->userauth_pswd_data,
|
||||
session->
|
||||
userauth_pswd_data_len);
|
||||
session->userauth_pswd_data,
|
||||
session->
|
||||
userauth_pswd_data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send userauth-password-change request",
|
||||
@@ -469,7 +482,10 @@ libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username,
|
||||
*
|
||||
* Read a public key from an id_???.pub style file
|
||||
*
|
||||
* Returns an allocated string in *pubkeydata on success.
|
||||
* Returns an allocated string containing the decoded key in *pubkeydata
|
||||
* on success.
|
||||
* Returns an allocated string containing the key method (e.g. "ssh-dss")
|
||||
* in method on success.
|
||||
*/
|
||||
static int
|
||||
file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
|
||||
@@ -484,7 +500,7 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
|
||||
size_t pubkey_len = 0;
|
||||
unsigned int tmp_len;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading public key file: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading public key file: %s",
|
||||
pubkeyfile);
|
||||
/* Read Public Key */
|
||||
fd = fopen(pubkeyfile, "r");
|
||||
@@ -542,15 +558,10 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
|
||||
LIBSSH2_FREE(session, pubkey);
|
||||
return -1;
|
||||
}
|
||||
/* Wasting some bytes here (okay, more than some),
|
||||
* but since it's likely to be freed soon anyway,
|
||||
* we'll just avoid the extra free/alloc and call it a wash */
|
||||
*method = pubkey;
|
||||
*method_len = sp1 - pubkey;
|
||||
|
||||
sp1++;
|
||||
|
||||
if ((sp2 = memchr(sp1, ' ', pubkey_len - *method_len)) == NULL) {
|
||||
if ((sp2 = memchr(sp1, ' ', pubkey_len - (sp1 - pubkey - 1))) == NULL) {
|
||||
/* Assume that the id string is missing, but that it's okay */
|
||||
sp2 = pubkey + pubkey_len;
|
||||
}
|
||||
@@ -562,6 +573,13 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
|
||||
LIBSSH2_FREE(session, pubkey);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Wasting some bytes here (okay, more than some), but since it's likely
|
||||
* to be freed soon anyway, we'll just avoid the extra free/alloc and call
|
||||
* it a wash */
|
||||
*method = pubkey;
|
||||
*method_len = sp1 - pubkey - 1;
|
||||
|
||||
*pubkeydata = tmp;
|
||||
*pubkeydata_len = tmp_len;
|
||||
|
||||
@@ -583,7 +601,7 @@ file_read_privatekey(LIBSSH2_SESSION * session,
|
||||
const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail =
|
||||
libssh2_hostkey_methods();
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading private key file: %s",
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading private key file: %s",
|
||||
privkeyfile);
|
||||
*hostkey_method = NULL;
|
||||
*hostkey_abstract = NULL;
|
||||
@@ -613,6 +631,45 @@ file_read_privatekey(LIBSSH2_SESSION * session,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct privkey_file {
|
||||
const char *filename;
|
||||
const char *passphrase;
|
||||
};
|
||||
|
||||
static int
|
||||
sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
|
||||
const unsigned char *data, size_t data_len, void **abstract)
|
||||
{
|
||||
struct privkey_file *privkey_file = (struct privkey_file *) (*abstract);
|
||||
const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
|
||||
void *hostkey_abstract;
|
||||
struct iovec datavec;
|
||||
|
||||
if (file_read_privatekey(session, &privkeyobj, &hostkey_abstract,
|
||||
session->userauth_pblc_method,
|
||||
session->userauth_pblc_method_len,
|
||||
privkey_file->filename,
|
||||
privkey_file->passphrase)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
datavec.iov_base = (unsigned char *)data;
|
||||
datavec.iov_len = data_len;
|
||||
|
||||
if (privkeyobj->signv(session, sig, (unsigned long *)sig_len, 1, &datavec,
|
||||
&hostkey_abstract)) {
|
||||
if (privkeyobj->dtor) {
|
||||
privkeyobj->dtor(session, abstract);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (privkeyobj->dtor) {
|
||||
privkeyobj->dtor(session, &hostkey_abstract);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* userauth_hostbased_fromfile
|
||||
@@ -627,8 +684,6 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session,
|
||||
const char *local_username,
|
||||
unsigned int local_username_len)
|
||||
{
|
||||
static const unsigned char reply_codes[3] =
|
||||
{ SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
|
||||
int rc;
|
||||
|
||||
if (session->userauth_host_state == libssh2_NB_state_idle) {
|
||||
@@ -797,7 +852,7 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session,
|
||||
session->userauth_host_s += sig_len;
|
||||
LIBSSH2_FREE(session, sig);
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Attempting hostbased authentication");
|
||||
|
||||
session->userauth_host_state = libssh2_NB_state_created;
|
||||
@@ -808,7 +863,7 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session,
|
||||
session->userauth_host_s -
|
||||
session->userauth_host_packet);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send userauth-hostbased request", 0);
|
||||
@@ -824,6 +879,8 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session,
|
||||
}
|
||||
|
||||
if (session->userauth_host_state == libssh2_NB_state_sent) {
|
||||
static const unsigned char reply_codes[3] =
|
||||
{ SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
|
||||
unsigned long data_len;
|
||||
rc = _libssh2_packet_requirev(session, reply_codes,
|
||||
&session->userauth_host_data,
|
||||
@@ -831,7 +888,7 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session,
|
||||
&session->
|
||||
userauth_host_packet_requirev_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
|
||||
session->userauth_host_state = libssh2_NB_state_idle;
|
||||
@@ -839,7 +896,7 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session,
|
||||
return -1;
|
||||
|
||||
if (session->userauth_host_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Hostbased authentication successful");
|
||||
/* We are us and we've proved it. */
|
||||
LIBSSH2_FREE(session, session->userauth_host_data);
|
||||
@@ -885,37 +942,47 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* userauth_publickey_fromfile
|
||||
* Authenticate using a keypair found in the named files
|
||||
*/
|
||||
static int
|
||||
userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
unsigned int username_len,
|
||||
const char *publickey,
|
||||
const char *privatekey,
|
||||
const char *passphrase)
|
||||
userauth_publickey(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
unsigned int username_len,
|
||||
const unsigned char *pubkeydata,
|
||||
unsigned long pubkeydata_len,
|
||||
LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)),
|
||||
void *abstract)
|
||||
{
|
||||
unsigned long pubkeydata_len = 0;
|
||||
unsigned char reply_codes[4] =
|
||||
{ SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
|
||||
SSH_MSG_USERAUTH_PK_OK, 0
|
||||
};
|
||||
SSH_MSG_USERAUTH_PK_OK, 0
|
||||
};
|
||||
int rc;
|
||||
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_idle) {
|
||||
unsigned char *pubkeydata;
|
||||
|
||||
/* Zero the whole thing out */
|
||||
memset(&session->userauth_pblc_packet_requirev_state, 0,
|
||||
sizeof(session->userauth_pblc_packet_requirev_state));
|
||||
|
||||
if (file_read_publickey(session, &session->userauth_pblc_method,
|
||||
&session->userauth_pblc_method_len,
|
||||
&pubkeydata, &pubkeydata_len,publickey)) {
|
||||
return -1;
|
||||
/*
|
||||
* As an optimisation, userauth_publickey_fromfile reuses a
|
||||
* previously allocated copy of the method name to avoid an extra
|
||||
* allocation/free.
|
||||
* For other uses, we allocate and populate it here.
|
||||
*/
|
||||
if (!session->userauth_pblc_method) {
|
||||
session->userauth_pblc_method_len = _libssh2_ntohu32(pubkeydata);
|
||||
session->userauth_pblc_method =
|
||||
LIBSSH2_ALLOC(session, session->userauth_pblc_method_len);
|
||||
if (!session->userauth_pblc_method) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for public key "
|
||||
"data", 0);
|
||||
return -1;
|
||||
}
|
||||
memcpy(session->userauth_pblc_method, pubkeydata + 4,
|
||||
session->userauth_pblc_method_len);
|
||||
}
|
||||
assert( /* preallocated method len should match what we expect */
|
||||
session->userauth_pblc_method_len == _libssh2_ntohu32(pubkeydata));
|
||||
|
||||
/*
|
||||
* 45 = packet_type(1) + username_len(4) + servicename_len(4) +
|
||||
@@ -940,7 +1007,6 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
if (!session->userauth_pblc_packet) {
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_method);
|
||||
session->userauth_pblc_method = NULL;
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -965,7 +1031,7 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
*(session->userauth_pblc_s++) = 0;
|
||||
|
||||
_libssh2_htonu32(session->userauth_pblc_s,
|
||||
session->userauth_pblc_method_len);
|
||||
session->userauth_pblc_method_len);
|
||||
session->userauth_pblc_s += 4;
|
||||
memcpy(session->userauth_pblc_s, session->userauth_pblc_method,
|
||||
session->userauth_pblc_method_len);
|
||||
@@ -975,9 +1041,8 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
session->userauth_pblc_s += 4;
|
||||
memcpy(session->userauth_pblc_s, pubkeydata, pubkeydata_len);
|
||||
session->userauth_pblc_s += pubkeydata_len;
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Attempting publickey authentication");
|
||||
|
||||
session->userauth_pblc_state = libssh2_NB_state_created;
|
||||
@@ -985,9 +1050,9 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, session->userauth_pblc_packet,
|
||||
session->userauth_pblc_packet_len);
|
||||
session->userauth_pblc_packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send userauth-publickey request", 0);
|
||||
@@ -1003,13 +1068,6 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
}
|
||||
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_sent) {
|
||||
const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
|
||||
void *abstract;
|
||||
unsigned char buf[5];
|
||||
struct iovec datavec[4];
|
||||
unsigned char *sig;
|
||||
unsigned long sig_len;
|
||||
|
||||
rc = _libssh2_packet_requirev(session, reply_codes,
|
||||
&session->userauth_pblc_data,
|
||||
&session->userauth_pblc_data_len, 0,
|
||||
@@ -1017,7 +1075,7 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
&session->
|
||||
userauth_pblc_packet_requirev_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_packet);
|
||||
session->userauth_pblc_packet = NULL;
|
||||
@@ -1028,7 +1086,7 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
}
|
||||
|
||||
if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Pubkey authentication prematurely successful");
|
||||
/*
|
||||
* God help any SSH server that allows an UNVERIFIED
|
||||
@@ -1053,7 +1111,7 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
session->userauth_pblc_packet = NULL;
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_method);
|
||||
session->userauth_pblc_method = NULL;
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED,
|
||||
libssh2_error(session, LIBSSH2_ERROR_AUTHENTICATION_FAILED,
|
||||
"Username/PublicKey combination invalid", 0);
|
||||
session->userauth_pblc_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
@@ -1063,44 +1121,45 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_data);
|
||||
session->userauth_pblc_data = NULL;
|
||||
|
||||
if (file_read_privatekey(session, &privkeyobj, &abstract,
|
||||
session->userauth_pblc_method,
|
||||
session->userauth_pblc_method_len,
|
||||
privatekey, passphrase)) {
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_method);
|
||||
session->userauth_pblc_method = NULL;
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_packet);
|
||||
session->userauth_pblc_packet = NULL;
|
||||
session->userauth_pblc_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*session->userauth_pblc_b = 0x01;
|
||||
session->userauth_pblc_state = libssh2_NB_state_sent1;
|
||||
}
|
||||
|
||||
_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 = session->userauth_pblc_packet;
|
||||
datavec[2].iov_len = session->userauth_pblc_packet_len;
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_sent1) {
|
||||
unsigned char *buf, *s;
|
||||
unsigned char *sig;
|
||||
size_t sig_len;
|
||||
|
||||
if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
|
||||
s = buf = LIBSSH2_ALLOC(session, 4 + session->session_id_len
|
||||
+ session->userauth_pblc_packet_len);
|
||||
if (!buf) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for userauth-publickey "
|
||||
"signed data", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_libssh2_htonu32(s, session->session_id_len);
|
||||
s += 4;
|
||||
memcpy (s, session->session_id, session->session_id_len);
|
||||
s += session->session_id_len;
|
||||
memcpy (s, session->userauth_pblc_packet,
|
||||
session->userauth_pblc_packet_len);
|
||||
s += session->userauth_pblc_packet_len;
|
||||
|
||||
rc = sign_callback(session, &sig, &sig_len, buf, s - buf, abstract);
|
||||
LIBSSH2_FREE(session, buf);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_method);
|
||||
session->userauth_pblc_method = NULL;
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_packet);
|
||||
session->userauth_pblc_packet = NULL;
|
||||
if (privkeyobj->dtor) {
|
||||
privkeyobj->dtor(session, &abstract);
|
||||
}
|
||||
session->userauth_pblc_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (privkeyobj->dtor) {
|
||||
privkeyobj->dtor(session, &abstract);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this function was restarted, pubkeydata_len might still be 0
|
||||
* which will cause an unnecessary but harmless realloc here.
|
||||
@@ -1152,18 +1211,18 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
session->userauth_pblc_s += sig_len;
|
||||
LIBSSH2_FREE(session, sig);
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Attempting publickey authentication -- phase 2");
|
||||
|
||||
session->userauth_pblc_state = libssh2_NB_state_sent1;
|
||||
session->userauth_pblc_state = libssh2_NB_state_sent2;
|
||||
}
|
||||
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_sent1) {
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_sent2) {
|
||||
rc = _libssh2_transport_write(session, session->userauth_pblc_packet,
|
||||
session->userauth_pblc_s -
|
||||
session->userauth_pblc_packet);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send userauth-publickey request", 0);
|
||||
@@ -1175,7 +1234,7 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_packet);
|
||||
session->userauth_pblc_packet = NULL;
|
||||
|
||||
session->userauth_pblc_state = libssh2_NB_state_sent2;
|
||||
session->userauth_pblc_state = libssh2_NB_state_sent3;
|
||||
}
|
||||
|
||||
/* PK_OK is no longer valid */
|
||||
@@ -1186,14 +1245,14 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
&session->userauth_pblc_data_len, 0, NULL, 0,
|
||||
&session->userauth_pblc_packet_requirev_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
session->userauth_pblc_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Publickey authentication successful");
|
||||
/* We are us and we've proved it. */
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_data);
|
||||
@@ -1214,6 +1273,44 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* userauth_publickey_fromfile
|
||||
* Authenticate using a keypair found in the named files
|
||||
*/
|
||||
static int
|
||||
userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
unsigned int username_len,
|
||||
const char *publickey,
|
||||
const char *privatekey,
|
||||
const char *passphrase)
|
||||
{
|
||||
unsigned char *pubkeydata = NULL;
|
||||
unsigned long pubkeydata_len = 0;
|
||||
struct privkey_file privkey_file;
|
||||
void *abstract = &privkey_file;
|
||||
int rc;
|
||||
|
||||
privkey_file.filename = privatekey;
|
||||
privkey_file.passphrase = passphrase;
|
||||
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_idle) {
|
||||
if (file_read_publickey(session, &session->userauth_pblc_method,
|
||||
&session->userauth_pblc_method_len,
|
||||
&pubkeydata, &pubkeydata_len, publickey)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rc = userauth_publickey(session, username, username_len,
|
||||
pubkeydata, pubkeydata_len,
|
||||
sign_fromfile, &abstract);
|
||||
if(pubkeydata)
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* libssh2_userauth_publickey_fromfile_ex
|
||||
* Authenticate using a keypair found in the named files
|
||||
*/
|
||||
@@ -1233,6 +1330,25 @@ libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* libssh2_userauth_publickey_ex
|
||||
* Authenticate using an external callback function
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
const char *user,
|
||||
const unsigned char *pubkeydata,
|
||||
size_t pubkeydata_len,
|
||||
LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)),
|
||||
void **abstract)
|
||||
{
|
||||
int rc;
|
||||
BLOCK_ADJUST(rc, session,
|
||||
userauth_publickey(session, user, strlen(user),
|
||||
pubkeydata, pubkeydata_len,
|
||||
sign_callback, abstract));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@@ -1249,7 +1365,8 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
||||
unsigned char *s;
|
||||
int rc;
|
||||
|
||||
static const unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS,
|
||||
static const unsigned char reply_codes[4] = {
|
||||
SSH_MSG_USERAUTH_SUCCESS,
|
||||
SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0
|
||||
};
|
||||
unsigned int language_tag_len;
|
||||
@@ -1316,7 +1433,7 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
||||
_libssh2_htonu32(s, 0);
|
||||
s += 4;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Attempting keyboard-interactive authentication");
|
||||
|
||||
session->userauth_kybd_state = libssh2_NB_state_created;
|
||||
@@ -1324,9 +1441,9 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
||||
|
||||
if (session->userauth_kybd_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, session->userauth_kybd_data,
|
||||
session->userauth_kybd_packet_len);
|
||||
session->userauth_kybd_packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send keyboard-interactive request", 0);
|
||||
@@ -1350,14 +1467,14 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
||||
&session->
|
||||
userauth_kybd_packet_requirev_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
session->userauth_kybd_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Keyboard-interactive authentication successful");
|
||||
LIBSSH2_FREE(session, session->userauth_kybd_data);
|
||||
session->userauth_kybd_data = NULL;
|
||||
@@ -1367,9 +1484,15 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
||||
}
|
||||
|
||||
if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) {
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Keyboard-interactive authentication failed");
|
||||
LIBSSH2_FREE(session, session->userauth_kybd_data);
|
||||
session->userauth_kybd_data = NULL;
|
||||
session->userauth_kybd_state = libssh2_NB_state_idle;
|
||||
libssh2_error(session,
|
||||
LIBSSH2_ERROR_AUTHENTICATION_FAILED,
|
||||
"Authentication failed (keyboard-interactive)",
|
||||
0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1482,7 +1605,7 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
||||
session->userauth_kybd_responses,
|
||||
&session->abstract);
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Keyboard-interactive response callback function"
|
||||
" invoked");
|
||||
|
||||
@@ -1525,9 +1648,9 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
||||
|
||||
if (session->userauth_kybd_state == libssh2_NB_state_sent1) {
|
||||
rc = _libssh2_transport_write(session, session->userauth_kybd_data,
|
||||
session->userauth_kybd_packet_len);
|
||||
session->userauth_kybd_packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
|
@@ -1,8 +0,0 @@
|
||||
.deps
|
||||
.libs
|
||||
*.gcno
|
||||
*.gcda
|
||||
Makefile
|
||||
Makefile.in
|
||||
simple
|
||||
ssh2
|
7
tests/.gitignore
vendored
7
tests/.gitignore
vendored
@@ -1 +1,8 @@
|
||||
.deps
|
||||
.libs
|
||||
*.gcno
|
||||
*.gcda
|
||||
Makefile
|
||||
Makefile.in
|
||||
simple
|
||||
ssh2
|
||||
|
@@ -6,7 +6,7 @@ noinst_PROGRAMS = ssh2
|
||||
ssh2_SOURCES = ssh2.c
|
||||
endif
|
||||
|
||||
ctests = simple
|
||||
ctests = simple$(EXEEXT)
|
||||
TESTS = $(ctests)
|
||||
if SSHD
|
||||
TESTS += ssh2.sh
|
||||
|
14
tests/ssh2.c
14
tests/ssh2.c
@@ -1,4 +1,4 @@
|
||||
/* Self test, based on examples/simple/ssh2.c. */
|
||||
/* Self test, based on examples/ssh2.c. */
|
||||
|
||||
#include "libssh2_config.h"
|
||||
#include <libssh2.h>
|
||||
@@ -10,12 +10,12 @@
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -59,7 +59,7 @@ int main(int argc, char *argv[])
|
||||
if (getenv ("PRIVKEY"))
|
||||
privkeyfile = getenv ("PRIVKEY");
|
||||
|
||||
if (getenv ("PRIVKEY"))
|
||||
if (getenv ("PUBKEY"))
|
||||
pubkeyfile = getenv ("PUBKEY");
|
||||
|
||||
hostaddr = htonl(0x7F000001);
|
||||
@@ -90,9 +90,9 @@ int main(int argc, char *argv[])
|
||||
* 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);
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(i = 0; i < 20; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
@@ -9,21 +9,26 @@ srcdir=${srcdir:-$PWD}
|
||||
SSHD=${SSHD:-/usr/sbin/sshd}
|
||||
|
||||
cmd="./ssh2${EXEEXT}"
|
||||
srcdir=`cd $srcdir; pwd`
|
||||
srcdir=`cd "$srcdir"; pwd`
|
||||
|
||||
PRIVKEY=$srcdir/etc/user
|
||||
export PRIVKEY
|
||||
PUBKEY=$srcdir/etc/user.pub
|
||||
export PUBKEY
|
||||
|
||||
chmod go-r $srcdir/etc/host*
|
||||
$SSHD -f /dev/null -h $srcdir/etc/host \
|
||||
if test -n "$DEBUG"; then
|
||||
libssh2_sshd_params="-d -d"
|
||||
fi
|
||||
|
||||
chmod go-rwx "$srcdir"/etc/host*
|
||||
$SSHD -f /dev/null -h "$srcdir"/etc/host \
|
||||
-o 'Port 4711' \
|
||||
-o 'Protocol 2' \
|
||||
-o "AuthorizedKeysFile $srcdir/etc/user.pub" \
|
||||
-o 'UsePrivilegeSeparation no' \
|
||||
-o 'StrictModes no' \
|
||||
-D &
|
||||
-D \
|
||||
$libssh2_sshd_params &
|
||||
sshdpid=$!
|
||||
|
||||
trap "kill ${sshdpid}; echo signal killing sshd; exit 1;" EXIT
|
||||
|
0
win32/.cvsignore → win32/.gitignore
vendored
0
win32/.cvsignore → win32/.gitignore
vendored
@@ -121,8 +121,7 @@ endif
|
||||
|
||||
CFLAGS += $(INCLUDES)
|
||||
|
||||
#ifeq ($(findstring msys,$(OSTYPE)),msys)
|
||||
ifdef __MSYS__
|
||||
ifeq ($(findstring /sh,$(SHELL)),/sh)
|
||||
DL = '
|
||||
DS = /
|
||||
else
|
||||
@@ -131,24 +130,10 @@ endif
|
||||
|
||||
vpath %.c . ../src
|
||||
|
||||
OBJECTS = \
|
||||
channel.o \
|
||||
comp.o \
|
||||
crypt.o \
|
||||
hostkey.o \
|
||||
kex.o \
|
||||
mac.o \
|
||||
misc.o \
|
||||
openssl.o \
|
||||
packet.o \
|
||||
pem.o \
|
||||
publickey.o \
|
||||
scp.o \
|
||||
session.o \
|
||||
sftp.o \
|
||||
transport.o \
|
||||
userauth.o
|
||||
# include Makefile.inc to get CSOURCES define
|
||||
include ../Makefile.inc
|
||||
|
||||
OBJECTS := $(patsubst %.c,%.o,$(CSOURCES))
|
||||
OBJS := $(addprefix $(OBJDIR)/,$(OBJECTS))
|
||||
OBJL = $(OBJS) $(OBJDIR)/$(TARGET).res
|
||||
|
||||
|
@@ -125,7 +125,7 @@ else
|
||||
DS = \\
|
||||
endif
|
||||
|
||||
vpath %.c ../../example/simple
|
||||
vpath %.c ../../example
|
||||
|
||||
.PRECIOUS: $(OBJDIR)/%.o $(OBJDIR)/%.rc $(OBJDIR)/%.res
|
||||
|
||||
|
Reference in New Issue
Block a user