Compare commits
231 Commits
RELEASE.0.
...
beforenb-0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c63ef86075 | ||
![]() |
1b733d1196 | ||
![]() |
3c61a44224 | ||
![]() |
20527d9688 | ||
![]() |
09ee2d4086 | ||
![]() |
5859642888 | ||
![]() |
ba1eb9f8fc | ||
![]() |
e2f6518d95 | ||
![]() |
a139ab0b45 | ||
![]() |
f1e7eb7ae8 | ||
![]() |
b790cabf6a | ||
![]() |
d2be40421a | ||
![]() |
b1d855d1ac | ||
![]() |
1826e7365d | ||
![]() |
7f9ea39a5d | ||
![]() |
6cf4420264 | ||
![]() |
bfb71f3075 | ||
![]() |
1f232d69ed | ||
![]() |
f252d350ec | ||
![]() |
4c2c468b08 | ||
![]() |
a86a4e0cfc | ||
![]() |
b1f8bafb64 | ||
![]() |
c9d40afa14 | ||
![]() |
51b9ff0f16 | ||
![]() |
0d9a7e3c2e | ||
![]() |
75115045ae | ||
![]() |
be984707e2 | ||
![]() |
2afd706ca1 | ||
![]() |
fe979040a2 | ||
![]() |
0fab9e9614 | ||
![]() |
576d37dafd | ||
![]() |
a0eda7365e | ||
![]() |
1f79c7da95 | ||
![]() |
6ede32c5e2 | ||
![]() |
10efccbb83 | ||
![]() |
2e8d9217b4 | ||
![]() |
d3c334c3d6 | ||
![]() |
e1bebf979b | ||
![]() |
50d587e2bc | ||
![]() |
e0fe196e45 | ||
![]() |
dc994f64a9 | ||
![]() |
46cd4f42d8 | ||
![]() |
19690441cd | ||
![]() |
dc7cdb8cb0 | ||
![]() |
be4461e4cd | ||
![]() |
23d772867e | ||
![]() |
c090ac7ed1 | ||
![]() |
6873ada0b7 | ||
![]() |
5c904b112e | ||
![]() |
b4d7a4eede | ||
![]() |
22225099bc | ||
![]() |
2d8ee8b37c | ||
![]() |
219fa19a5f | ||
![]() |
5443c76c8e | ||
![]() |
79761a6455 | ||
![]() |
362d3466cf | ||
![]() |
6d65428511 | ||
![]() |
677005375b | ||
![]() |
8a2421bad1 | ||
![]() |
5cd3efc297 | ||
![]() |
f527a88095 | ||
![]() |
fd2368d2b1 | ||
![]() |
036bb51421 | ||
![]() |
c92d1a5a23 | ||
![]() |
862a758026 | ||
![]() |
f7f897df07 | ||
![]() |
ef8d1a2af8 | ||
![]() |
556cafc457 | ||
![]() |
75b5e06773 | ||
![]() |
91e496ff41 | ||
![]() |
6b1dc88b14 | ||
![]() |
14b9deef24 | ||
![]() |
82d762cae5 | ||
![]() |
1c1c74479e | ||
![]() |
3a33680e14 | ||
![]() |
38fea1973d | ||
![]() |
c63a212559 | ||
![]() |
a8451f58df | ||
![]() |
1dbe8ff365 | ||
![]() |
82424d6735 | ||
![]() |
3b1b45e644 | ||
![]() |
84f10fca87 | ||
![]() |
077ba3efd5 | ||
![]() |
ab26693769 | ||
![]() |
1854b4536f | ||
![]() |
1baaa31792 | ||
![]() |
7058b7fc2a | ||
![]() |
1e889ca947 | ||
![]() |
bebd14a011 | ||
![]() |
7063d24724 | ||
![]() |
8069fa6f9a | ||
![]() |
1961e07287 | ||
![]() |
ace0c8f00b | ||
![]() |
adee5e5653 | ||
![]() |
5f85317efa | ||
![]() |
09b93e4bb6 | ||
![]() |
19cad102f4 | ||
![]() |
4d7726c551 | ||
![]() |
37307a8778 | ||
![]() |
fbcdff2161 | ||
![]() |
c45992da55 | ||
![]() |
2207b99afb | ||
![]() |
1d7522bc06 | ||
![]() |
a4e61c265b | ||
![]() |
502a48afa1 | ||
![]() |
efc3841fd2 | ||
![]() |
f9d65b0984 | ||
![]() |
edcdf43264 | ||
![]() |
722470994a | ||
![]() |
14f00247a8 | ||
![]() |
78048973c5 | ||
![]() |
e15f5d97a0 | ||
![]() |
01de39e585 | ||
![]() |
6cc50263e2 | ||
![]() |
beca3742a2 | ||
![]() |
d6cfa7c6b9 | ||
![]() |
ae17fbcd2c | ||
![]() |
0c53895bc0 | ||
![]() |
dc446eff08 | ||
![]() |
aa6e9c6eca | ||
![]() |
2e097c7760 | ||
![]() |
77bd3c1215 | ||
![]() |
0e5eb4d9c5 | ||
![]() |
8ee79a5118 | ||
![]() |
0ad861d74c | ||
![]() |
b6d13ebe8a | ||
![]() |
06e1136ea0 | ||
![]() |
2a6c49a73a | ||
![]() |
da653774aa | ||
![]() |
9203a62789 | ||
![]() |
6de7ed8a7b | ||
![]() |
8937980044 | ||
![]() |
cc7703092f | ||
![]() |
7502920c7f | ||
![]() |
ff6f2dbe52 | ||
![]() |
e5ee4a5be3 | ||
![]() |
30bb7db0d1 | ||
![]() |
8d90bbfc28 | ||
![]() |
e9b0710b4b | ||
![]() |
379e510c87 | ||
![]() |
ebfbd22e59 | ||
![]() |
9a0ba35457 | ||
![]() |
023c54d95d | ||
![]() |
ba2f21eb85 | ||
![]() |
3ea661a574 | ||
![]() |
30755999c5 | ||
![]() |
8e0e6d81dd | ||
![]() |
cba673de6f | ||
![]() |
11b27e52c3 | ||
![]() |
f289bcdd54 | ||
![]() |
66e7462f01 | ||
![]() |
ed88c32368 | ||
![]() |
83b95eb13e | ||
![]() |
ba420fc7bf | ||
![]() |
ae9ad1ef6f | ||
![]() |
d3f854c21b | ||
![]() |
5d9c0d50f3 | ||
![]() |
35a3e7a6c0 | ||
![]() |
15b8489046 | ||
![]() |
dce388e9c5 | ||
![]() |
0138e36352 | ||
![]() |
d6039f39e4 | ||
![]() |
0e0ed2aff4 | ||
![]() |
7c64e21df6 | ||
![]() |
c67bb667aa | ||
![]() |
141ac5b856 | ||
![]() |
9f64f34dfe | ||
![]() |
a1b87a952c | ||
![]() |
7db9aeecf8 | ||
![]() |
99e5547442 | ||
![]() |
ef7496b29a | ||
![]() |
37c55becdc | ||
![]() |
47b96a9771 | ||
![]() |
0a9a5ffc22 | ||
![]() |
c6e5188fb4 | ||
![]() |
fe7ea0df58 | ||
![]() |
500169bf97 | ||
![]() |
10a0c20eae | ||
![]() |
2427c1b803 | ||
![]() |
159120f844 | ||
![]() |
fc1563a41d | ||
![]() |
c6bbe0d42f | ||
![]() |
a05bf84ecf | ||
![]() |
2c5c54e999 | ||
![]() |
5f2864c0b4 | ||
![]() |
4675d1242b | ||
![]() |
b59f2ccc1b | ||
![]() |
b25446d0a5 | ||
![]() |
064c6cde3a | ||
![]() |
2c5a8480b0 | ||
![]() |
87d61a39e8 | ||
![]() |
0e878271db | ||
![]() |
bc16411dd3 | ||
![]() |
096ef86627 | ||
![]() |
2b414db02e | ||
![]() |
5f7470700e | ||
![]() |
bfc2f5039e | ||
![]() |
a3735795dd | ||
![]() |
a891971a63 | ||
![]() |
d4677dba5b | ||
![]() |
d1ae5a501f | ||
![]() |
72c4c38e37 | ||
![]() |
fe2513a18b | ||
![]() |
ee03669517 | ||
![]() |
22c105332d | ||
![]() |
c9e8f3a1a0 | ||
![]() |
54b852dfc9 | ||
![]() |
308d59910f | ||
![]() |
ecd83df6a7 | ||
![]() |
4191a8c56c | ||
![]() |
c5acc8a901 | ||
![]() |
a119685410 | ||
![]() |
dc4bb1af96 | ||
![]() |
8fe47a609a | ||
![]() |
c070bdacc7 | ||
![]() |
a9af84c51d | ||
![]() |
dfb3b8f0fd | ||
![]() |
c006dd4350 | ||
![]() |
4324a1a1d1 | ||
![]() |
cf8ca63ea0 | ||
![]() |
d1b33840bf | ||
![]() |
eef99ca106 | ||
![]() |
d86bcab2d2 | ||
![]() |
2e02ad041a | ||
![]() |
596b62c027 | ||
![]() |
143c6bf97f | ||
![]() |
371f5de682 | ||
![]() |
d2d8f8ad0b | ||
![]() |
a1e649b507 | ||
![]() |
99795a165e | ||
![]() |
6f13a93be9 |
25
.cvsignore
Normal file
25
.cvsignore
Normal file
@@ -0,0 +1,25 @@
|
||||
.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
|
51
INSTALL
51
INSTALL
@@ -5,5 +5,56 @@ Installing libssh2
|
||||
|
||||
* Run: ./configure (passing additional options as desired)
|
||||
|
||||
In addition the the standard set of ./configure options (e.g. --prefix)
|
||||
there are five switches which you may wish to pay attention to:
|
||||
|
||||
* --with-openssl=[DIR]
|
||||
|
||||
libssh2 requires the OpenSSL library (http://www.openssl.org) for
|
||||
cipher and hash method implementations.
|
||||
|
||||
./configure will attempt to locate OpenSSL in a number of default locations:
|
||||
/usr/local/ssl /usr/local /usr /usr/local/openssl
|
||||
If your installation of OpenSSL is in another location, specify it here.
|
||||
|
||||
* --with-zlib=[DIR]
|
||||
|
||||
If present, libssh2 will attempt to use the zlib (http://www.zlib.org)
|
||||
for payload compression, however zlib is not required.
|
||||
|
||||
./configure will attempt to location a zlib installation in a number of default locations:
|
||||
/usr/local /usr /usr/local/libz /usr/libz /usr/local/zlib /usr/zlib
|
||||
If your installation of zlib is in another location, you may specify it here.
|
||||
|
||||
* --enable-crypt-none
|
||||
|
||||
The SSH2 Transport allows for unencrypted data transmission using the "none" cipher.
|
||||
Because this is such a huge security hole, it is typically disabled on
|
||||
SSH2 implementations and is diabled in libssh2 by default as well.
|
||||
|
||||
Enabling this option will allow for "none" as a negotiable method,
|
||||
however it still requires that the method be advertized by the remote end
|
||||
and that no more-prefferable methods are available.
|
||||
|
||||
* --enable-mac-none
|
||||
|
||||
The SSH2 Transport also allows implementations to forego a message authentication code.
|
||||
While this is less of a security risk than using a "none" cipher, it is still not
|
||||
recommended as disabling MAC hashes removes a layer of security.
|
||||
|
||||
Enabling this option will allow for "none" as a negotiable method,
|
||||
however it still requires that the method be advertized by the remote end
|
||||
and that no more-prefferable methods are available.
|
||||
|
||||
* --disable-gex-new
|
||||
|
||||
The diffie-hellman-group-exchange-sha1 (dh-gex) key exchange method originally defined
|
||||
an exchange negotiation using packet type 30 to request a generation pair based
|
||||
on a single target value. Later refinement of dh-gex provided for range and target
|
||||
values. By default libssh2 will use the newer range method.
|
||||
|
||||
If you experience trouble connecting to an old SSH server using dh-gex,
|
||||
try this option to fallback on the older more reliable method.
|
||||
|
||||
* Run: make all install
|
||||
|
||||
|
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
|
19
Makefile.am
Normal file
19
Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
||||
AUTOMAKE_OPTIONS = foreign nostdinc
|
||||
|
||||
SUBDIRS = src tests
|
||||
|
||||
include_HEADERS = include/libssh2.h include/libssh2_publickey.h \
|
||||
include/libssh2_sftp.h
|
||||
|
||||
# and a sample tool
|
||||
noinst_PROGRAMS = ssh2_sample
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include
|
||||
|
||||
ssh2_sample_SOURCES = ssh2_sample.c
|
||||
|
||||
ssh2_sample_LDADD = src/libssh2.la
|
||||
|
||||
EXTRA_DIST = LICENSE win32
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
50
Makefile.in
50
Makefile.in
@@ -1,50 +0,0 @@
|
||||
subdirs = src/
|
||||
top_srcdir = @top_srcdir@
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
libdir = @exec_prefix@/lib
|
||||
incldir = @prefix@/include
|
||||
distdir = @top_srcdir@/dist
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = -c @CFLAGS@ -Iinclude/ -Wall -g
|
||||
LIBS = -lssh2 -Lsrc/
|
||||
INSTALL = @INSTALL@
|
||||
VERSION=0.3
|
||||
DISTLIB=libssh2-$(VERSION)
|
||||
|
||||
all:
|
||||
@for dir in ${subdirs}; do \
|
||||
(cd $$dir && $(MAKE) all) \
|
||||
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
||||
done && test -z "$$fail"
|
||||
$(CC) -o ssh2_sample.o ssh2_sample.c $(CFLAGS)
|
||||
$(CC) -o ssh2_sample ssh2_sample.o $(LIBS)
|
||||
install:
|
||||
$(top_srcdir)/mkinstalldirs $(incldir)
|
||||
$(top_srcdir)/mkinstalldirs $(libdir)
|
||||
@for dir in ${subdirs}; do \
|
||||
(cd $$dir && $(MAKE) install) \
|
||||
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
||||
done && test -z "$$fail"
|
||||
$(INSTALL) -m 644 include/libssh2.h $(incldir)/
|
||||
$(INSTALL) -m 644 include/libssh2_sftp.h $(incldir)/
|
||||
clean:
|
||||
@for dir in ${subdirs}; do \
|
||||
(cd $$dir && $(MAKE) clean) \
|
||||
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
||||
done && test -z "$$fail"
|
||||
rm -f ssh2_sample.o ssh2_sample
|
||||
dist:
|
||||
autoheader
|
||||
autoconf
|
||||
rm -f $(DISTLIB)
|
||||
ln -s . $(DISTLIB)
|
||||
tar -zcf $(DISTLIB).tar.gz \
|
||||
$(DISTLIB)/configure $(DISTLIB)/Makefile.in $(DISTLIB)/ssh2_sample.c \
|
||||
$(DISTLIB)/LICENSE $(DISTLIB)/README $(DISTLIB)/TODO $(DISTLIB)/INSTALL \
|
||||
$(DISTLIB)/mkinstalldirs $(DISTLIB)/install-sh \
|
||||
$(DISTLIB)/src/*.c $(DISTLIB)/src/Makefile.in \
|
||||
$(DISTLIB)/include/libssh2.h $(DISTLIB)/include/libssh2_priv.h $(DISTLIB)/include/libssh2_sftp.h \
|
||||
$(DISTLIB)/include/libssh2_config.h.in
|
||||
rm -f $(DISTLIB)
|
16
NMakefile
Normal file
16
NMakefile
Normal file
@@ -0,0 +1,16 @@
|
||||
!include "win32/config.mk"
|
||||
|
||||
SUBDIRS=src
|
||||
|
||||
all: all-sub ssh2_sample.exe
|
||||
|
||||
ssh2_sample.exe: ssh2_sample.c
|
||||
$(CC) $(CFLAGS) -DWIN32 -o ssh2_sample.exe ssh2_sample.c libssh2$(SUFFIX).lib $(LIBS)
|
||||
|
||||
all-sub:
|
||||
-for %D in ($(SUBDIRS)) do $(MAKE) /nologo /f %D/NMakefile BUILD=$(BUILD) SUBDIR=%D all-sub
|
||||
|
||||
clean:
|
||||
rmdir /s/q $(TARGET)
|
||||
|
||||
|
193
README
193
README
@@ -1,6 +1,199 @@
|
||||
libssh2 - SSH2 library
|
||||
======================
|
||||
|
||||
libssh2 is a library implementing the SSH2 protocol
|
||||
|
||||
Version
|
||||
------------
|
||||
|
||||
maximum SSH packet size is now some 35000 bytes
|
||||
|
||||
private include files are now in src/ and only public headers are in include/
|
||||
|
||||
automake and libtool are being used (increased portability)
|
||||
|
||||
fixed OpenSSL detection using pkg-config
|
||||
|
||||
simple self test added to tests/
|
||||
|
||||
libgcrypt is fully supported
|
||||
|
||||
Version 0.14
|
||||
------------
|
||||
|
||||
Plug leaks in EVP cipher init/shutdown. (Selcuk Gueney)
|
||||
|
||||
Allow socket_fd == 0 in libssh2_session_startup(). (puudeli)
|
||||
|
||||
Swap ordering of packet_add/packet-inspection to avoid inspect after free. (Selcuk)
|
||||
|
||||
Swap KEX_INIT ordering, send our KEX_INIT first.
|
||||
|
||||
Add check for oportunistic KEX_INIT packets. Burn bad guess if necessary.
|
||||
|
||||
Fix OpenSSL detection using pkg-config. (Dan Casey)
|
||||
|
||||
Version 0.13
|
||||
------------
|
||||
|
||||
Fixed channel not being marked closed when CHANNEL_CLOSE package cannot be sent. (David Robins)
|
||||
|
||||
Fixed payload packet allocation bug when invalid packet length received. (David Robins)
|
||||
|
||||
Fixed `make install' target for MacOSX.
|
||||
|
||||
Add terminating NULL character to readlink()/realpath() results.
|
||||
|
||||
BugFix#1436593: Apply build options for HPUX targets.
|
||||
|
||||
Version 0.12
|
||||
------------
|
||||
|
||||
Added support for publickey subsytem (not the same as publickey auth).
|
||||
|
||||
Fix x11_req. Multiple packet_len issues and error handling logic.
|
||||
(Thanks Simon Hart)
|
||||
|
||||
Fix generation of 'e' portion of Diffie-Hellman keyset.
|
||||
Use appropriate order for BN_rand() rather than fixed group1-specific value.
|
||||
|
||||
Re-fixed libssh2_sftp_rename_ex()
|
||||
Transport had right packet_len, but sftp layer still had extra 4 bytes.
|
||||
|
||||
Fixed build with newer OpenSSL headers.
|
||||
|
||||
Added extern "C" declarations to libssh2_sftp.h for C++ compatability.
|
||||
|
||||
Version 0.11
|
||||
------------
|
||||
|
||||
Added libssh2_chnnale_get_exit_status() -- Mikhail
|
||||
|
||||
Added libssh2_channel_wait_closed() -- Mikhail
|
||||
|
||||
Added libssh2_userauth_keyboard_interactive_ex() -- Mikhail
|
||||
|
||||
Added libssh2_channel_receive_window_adjust() to be able to increase the size of the receive window.
|
||||
|
||||
Added queueing for small window_adjust packets to avoid unnecessary packet conversation.
|
||||
|
||||
Fixed libssh2_sftp_rename_ex() to only send flags parameter if version >= 5 negotiated
|
||||
(not currently possible, but will be and might as well keep the API consistent).
|
||||
|
||||
Version 0.10
|
||||
------------
|
||||
|
||||
Added developer debugging hooks. See --enable-debug-* options to ./configure
|
||||
|
||||
Ignore extended data in the SFTP layer. With no other mechanism to deal with that data it'd just fill up and get stuck.
|
||||
|
||||
(Re)Fixed channel_write() to provide an opportunity for window space to become available again.
|
||||
|
||||
(Re)Fixed SFTP INIT to send the correct SFTP packet length.
|
||||
|
||||
Fixed segfault when client and host can't agree on a hostkey/crypt/mac/comp method. (Thanks puudeli)
|
||||
|
||||
Fixed major issue with sftp packet buffering mechanism. Using wrong blocking semantics. (No puudeli, YOU the man)
|
||||
|
||||
Reduced busy-looping of libssh2_sftp_packet_requirev.
|
||||
|
||||
Version 0.9
|
||||
-----------
|
||||
|
||||
Changed blocking_read to only block as much as necessary and not an arbitrary length of time. (Thanks Felix)
|
||||
|
||||
Fixed SFTP INIT/VERSION to exclude request_id and send correct maximum version number.
|
||||
|
||||
Fixed SFTP to be properly BC with version 1 and 2 servers.
|
||||
|
||||
Fixed libssh2_poll() to recognized closed sessions/channels.
|
||||
|
||||
Fixed libssh2_channel_write_ex() to fully block when set to blocking mode. Return actual bytes written as well. (Thanks deadem)
|
||||
|
||||
Added tests for -lm and -lsocket and add them when necessary.
|
||||
|
||||
Added libssh2_channel_window_read_ex() and libssh2_channel_window_write_ex()
|
||||
for examining the ssh transport windowing states.
|
||||
|
||||
Version 0.8
|
||||
-----------
|
||||
|
||||
Fix potential segfault in compression/decompression.
|
||||
|
||||
Fix compatability with older versions of OpenSSL
|
||||
|
||||
Swapped order of none,zlib compression modes to prefer no compression by default.
|
||||
|
||||
Added sys/uio.h for platforms (FBSD) which need it in order to define struct iovec.
|
||||
|
||||
Added libssh2_poll() to check status of sockets/channels/listeners.
|
||||
|
||||
Removed unnecessary inclusion of stdio.h (holdover from debugging)
|
||||
|
||||
Version 0.7
|
||||
-----------
|
||||
|
||||
Added libssh2_userauth_hostbased_fromfile_ex() for authenticating from hostkey.
|
||||
|
||||
Added configure recognition for MacOSX (Darwin) (Thanks Gabe)
|
||||
|
||||
Fixed extended data identification in libssh2_channel_read().
|
||||
|
||||
Fixed window adjust code. Hadn't acknowledged adjustments correctly.
|
||||
|
||||
Removed initial_window_size requirement for sending window adjust packet.
|
||||
|
||||
|
||||
Version 0.6
|
||||
-----------
|
||||
|
||||
Added LIBSSH2_FLAG_SIGPIPE to enable/disable SIGPIPE generated by send()/recv() calls. Default off.
|
||||
|
||||
Added libssh2_session_flag() to set optional session flags.
|
||||
|
||||
Collapsed exchanging_keys/newkeys/authenticated flags into single state attribute.
|
||||
|
||||
Fix zlib compression issue when internal buffer state misses partial sync.
|
||||
|
||||
Fix segfault when libssh2_session_methods() is called prior to session_startup().
|
||||
|
||||
Fixed client to server channel windowing. Pervent send queue overruns.
|
||||
|
||||
Swapped banner send/receive order (send first, then wait for response).
|
||||
|
||||
Version 0.5
|
||||
-----------
|
||||
|
||||
*** BC Break ***
|
||||
Reimplemented libssh2_session_methods() to match libssh2_session_method_pref() style
|
||||
|
||||
Fixed libssh2_attr2bin() (effects any setstat style call).
|
||||
|
||||
Fixed authenticating with encrypted private key.
|
||||
|
||||
Fixed authenticating via ssh-dss public key.
|
||||
|
||||
Fixed KEX_INIT cookie and packet padding to use actual random data
|
||||
|
||||
Added DESTDIR support to makefiles (Adam Go<47><6F>biowski -- I hope that character set translates right)
|
||||
|
||||
Added libssh2_channel_forward_listen_ex(), libssh2_channel_forward_cancel(), and libssh2_channel_forward_accept().
|
||||
|
||||
Added ./configure option '--disable-gex-new' to allow using the older group-exchange format
|
||||
|
||||
Added MAC methods hmac-md5 and hmac-md5-96.
|
||||
|
||||
Version 0.4
|
||||
-----------
|
||||
|
||||
Fixed crash when trying to free sftp_dirhandle data from a filehandle struct.
|
||||
|
||||
Fixed leak in sftp_open_ex(), handle->handle not freed in handle_close().
|
||||
|
||||
Fixed leak in sftp_symlink_ex(), result for READLINK and REALPATH not freed unless there was an error.
|
||||
|
||||
Added libssh2_banner_set(), specify an arbitrary banner to send on introduction.
|
||||
|
||||
Version 0.3
|
||||
-----------
|
||||
|
||||
|
149
acinclude.m4
Normal file
149
acinclude.m4
Normal file
@@ -0,0 +1,149 @@
|
||||
|
||||
dnl **********************************************************************
|
||||
dnl CURL_DETECT_ICC ([ACTION-IF-YES])
|
||||
dnl
|
||||
dnl check if this is the Intel ICC compiler, and if so run the ACTION-IF-YES
|
||||
dnl sets the $ICC variable to "yes" or "no"
|
||||
dnl **********************************************************************
|
||||
AC_DEFUN([CURL_DETECT_ICC],
|
||||
[
|
||||
ICC="no"
|
||||
AC_MSG_CHECKING([for icc in use])
|
||||
if test "$GCC" = "yes"; then
|
||||
dnl check if this is icc acting as gcc in disguise
|
||||
AC_EGREP_CPP([^__INTEL_COMPILER], [__INTEL_COMPILER],
|
||||
dnl action if the text is found, this it has not been replaced by the
|
||||
dnl cpp
|
||||
ICC="no",
|
||||
dnl the text was not found, it was replaced by the cpp
|
||||
ICC="yes"
|
||||
AC_MSG_RESULT([yes])
|
||||
[$1]
|
||||
)
|
||||
fi
|
||||
if test "$ICC" = "no"; then
|
||||
# this is not ICC
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
])
|
||||
|
||||
dnl We create a function for detecting which compiler we use and then set as
|
||||
dnl pendantic compiler options as possible for that particular compiler. The
|
||||
dnl options are only used for debug-builds.
|
||||
|
||||
AC_DEFUN([CURL_CC_DEBUG_OPTS],
|
||||
[
|
||||
if test "z$ICC" = "z"; then
|
||||
CURL_DETECT_ICC
|
||||
fi
|
||||
|
||||
if test "$GCC" = "yes"; then
|
||||
|
||||
dnl figure out gcc version!
|
||||
AC_MSG_CHECKING([gcc version])
|
||||
gccver=`$CC -dumpversion`
|
||||
num1=`echo $gccver | cut -d . -f1`
|
||||
num2=`echo $gccver | cut -d . -f2`
|
||||
gccnum=`(expr $num1 "*" 100 + $num2) 2>/dev/null`
|
||||
AC_MSG_RESULT($gccver)
|
||||
|
||||
if test "$ICC" = "yes"; then
|
||||
dnl this is icc, not gcc.
|
||||
|
||||
dnl ICC warnings we ignore:
|
||||
dnl * 269 warns on our "%Od" printf formatters for curl_off_t output:
|
||||
dnl "invalid format string conversion"
|
||||
dnl * 279 warns on static conditions in while expressions
|
||||
dnl * 981 warns on "operands are evaluated in unspecified order"
|
||||
dnl * 1418 "external definition with no prior declaration"
|
||||
dnl * 1419 warns on "external declaration in primary source file"
|
||||
dnl which we know and do on purpose.
|
||||
|
||||
WARN="-wd279,269,981,1418,1419"
|
||||
|
||||
if test "$gccnum" -gt "600"; then
|
||||
dnl icc 6.0 and older doesn't have the -Wall flag
|
||||
WARN="-Wall $WARN"
|
||||
fi
|
||||
else dnl $ICC = yes
|
||||
dnl this is a set of options we believe *ALL* gcc versions support:
|
||||
WARN="-W -Wall -Wwrite-strings -pedantic -Wpointer-arith -Wnested-externs -Winline -Wmissing-prototypes"
|
||||
|
||||
dnl -Wcast-align is a bit too annoying on all gcc versions ;-)
|
||||
|
||||
if test "$gccnum" -ge "207"; then
|
||||
dnl gcc 2.7 or later
|
||||
WARN="$WARN -Wmissing-declarations"
|
||||
fi
|
||||
|
||||
if test "$gccnum" -gt "295"; then
|
||||
dnl only if the compiler is newer than 2.95 since we got lots of
|
||||
dnl "`_POSIX_C_SOURCE' is not defined" in system headers with
|
||||
dnl gcc 2.95.4 on FreeBSD 4.9!
|
||||
WARN="$WARN -Wundef -Wno-long-long -Wsign-compare"
|
||||
fi
|
||||
|
||||
if test "$gccnum" -ge "296"; then
|
||||
dnl gcc 2.96 or later
|
||||
WARN="$WARN -Wfloat-equal"
|
||||
fi
|
||||
|
||||
if test "$gccnum" -gt "296"; then
|
||||
dnl this option does not exist in 2.96
|
||||
WARN="$WARN -Wno-format-nonliteral"
|
||||
fi
|
||||
|
||||
dnl -Wunreachable-code seems totally unreliable on my gcc 3.3.2 on
|
||||
dnl on i686-Linux as it gives us heaps with false positives.
|
||||
dnl Also, on gcc 4.0.X it is totally unbearable and complains all
|
||||
dnl over making it unusable for generic purposes. Let's not use it.
|
||||
|
||||
if test "$gccnum" -ge "303"; then
|
||||
dnl gcc 3.3 and later
|
||||
WARN="$WARN -Wendif-labels -Wstrict-prototypes"
|
||||
fi
|
||||
|
||||
if test "$gccnum" -ge "304"; then
|
||||
# try these on gcc 3.4
|
||||
WARN="$WARN -Wdeclaration-after-statement"
|
||||
fi
|
||||
|
||||
for flag in $CPPFLAGS; do
|
||||
case "$flag" in
|
||||
-I*)
|
||||
dnl Include path, provide a -isystem option for the same dir
|
||||
dnl to prevent warnings in those dirs. The -isystem was not very
|
||||
dnl reliable on earlier gcc versions.
|
||||
add=`echo $flag | sed 's/^-I/-isystem /g'`
|
||||
WARN="$WARN $add"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
fi dnl $ICC = no
|
||||
|
||||
CFLAGS="$CFLAGS $WARN"
|
||||
|
||||
AC_MSG_NOTICE([Added this set of compiler options: $WARN])
|
||||
|
||||
else dnl $GCC = yes
|
||||
|
||||
AC_MSG_NOTICE([Added no extra compiler options])
|
||||
|
||||
fi dnl $GCC = yes
|
||||
|
||||
dnl strip off optimizer flags
|
||||
NEWFLAGS=""
|
||||
for flag in $CFLAGS; do
|
||||
case "$flag" in
|
||||
-O*)
|
||||
dnl echo "cut off $flag"
|
||||
;;
|
||||
*)
|
||||
NEWFLAGS="$NEWFLAGS $flag"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
CFLAGS=$NEWFLAGS
|
||||
|
||||
]) dnl end of AC_DEFUN()
|
7
buildconf
Executable file
7
buildconf
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
${LIBTOOLIZE:-libtoolize} --copy --automake --force
|
||||
${ACLOCAL:-aclocal} -I m4 $ACLOCAL_FLAGS
|
||||
${AUTOHEADER:-autoheader}
|
||||
${AUTOCONF:-autoconf}
|
||||
${AUTOMAKE:-automake} --add-missing --copy
|
171
configure.in
171
configure.in
@@ -1,24 +1,62 @@
|
||||
# AC_PREREQ(2.57)
|
||||
AC_INIT(libssh2, 0.3 , sarag@libssh2.org)
|
||||
AC_INIT(libssh2, 0.15, libssh2-devel@lists.sourceforge.net)
|
||||
AM_INIT_AUTOMAKE(libssh2, 0.15)
|
||||
AC_CONFIG_SRCDIR([src])
|
||||
AC_CONFIG_HEADER([include/libssh2_config.h])
|
||||
AC_CONFIG_HEADER([src/libssh2_config.h])
|
||||
AB_INIT
|
||||
|
||||
# Check for the OS.
|
||||
# Daniel's note: this should not be necessary and we need to work to
|
||||
# get this removed.
|
||||
AC_CANONICAL_HOST
|
||||
case "$host" in
|
||||
*-cygwin)
|
||||
CFLAGS="$CFLAGS -DLIBSSH2_WIN32"
|
||||
;;
|
||||
*darwin*)
|
||||
CFLAGS="$CFLAGS -DLIBSSH2_DARWIN"
|
||||
;;
|
||||
*hpux*)
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_CHECK_LIB(socket, socket, [
|
||||
SHLIB_LDFLAGS="$SHLIB_LDFLAGS -lsocket"
|
||||
LIBS="$LIBS -lsocket"
|
||||
])
|
||||
AC_CHECK_LIB(m, ceil, [ SHLIB_LDFLAGS="$SHLIB_LDFLAGS -lm" ])
|
||||
|
||||
SHLIB_SUFFIX_NAME="so"
|
||||
SHLIB_LDFLAGS="-shared"
|
||||
|
||||
AC_SUBST(SHLIB_SUFFIX_NAME)
|
||||
AC_SUBST(SHLIB_LDFLAGS)
|
||||
AC_SUBST(LIBS)
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_LIBTOOL
|
||||
AC_C_BIGENDIAN
|
||||
if test -z "$PKG_CONFIG"; then
|
||||
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
|
||||
fi
|
||||
|
||||
# Look for libgcrypt.
|
||||
AC_ARG_WITH(libgcrypt,
|
||||
AC_HELP_STRING([--with-libgcrypt],[Use libgcrypt for crypto]),
|
||||
use_libgcrypt=$withval,use_libgcrypt=no)
|
||||
if test "$use_libgcrypt" != "no"; then
|
||||
AM_PATH_LIBGCRYPT(1:1.2.2,,use_libgcrypt=no)
|
||||
fi
|
||||
if test "$use_libgcrypt" != "no"; then
|
||||
CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
|
||||
LDFLAGS="$LDFLAGS $LIBGCRYPT_LIBS"
|
||||
AC_DEFINE(LIBSSH2_LIBGCRYPT, 1, [Use libgcrypt])
|
||||
fi
|
||||
AM_CONDITIONAL(LIBGCRYPT, test "$use_libgcrypt" != "no")
|
||||
|
||||
#
|
||||
# Look for OpenSSL
|
||||
#
|
||||
@@ -26,20 +64,25 @@ AC_ARG_WITH(openssl,
|
||||
AC_HELP_STRING([--with-openssl=DIR],[Look for OpenSSL in PATH]),
|
||||
[LIBSSH2_OPENSSL_DIR=$withval],[LIBSSH2_OPENSSL_DIR=yes])
|
||||
|
||||
if test "$use_libgcrypt" = "no"; then
|
||||
|
||||
if test "$LIBSSH2_OPENSSL_DIR" = "no" || test "$LIBSSH2_OPENSSL_DIR" = "yes"; then
|
||||
unset LIBSSH2_OPENSSL_DIR
|
||||
fi
|
||||
|
||||
found_openssl=no
|
||||
pkgcfg_openssl=no
|
||||
unset OPENSSL_INCDIR
|
||||
unset OPENSSL_LIBDIR
|
||||
unset OPENSSL_INCLINE
|
||||
unset OPENSSL_LIBLINE
|
||||
|
||||
AC_MSG_CHECKING([for OpenSSL])
|
||||
|
||||
# Explicit path given, use it rather than pkg-config
|
||||
if test ! -z "$LIBSSH2_OPENSSL_DIR"; then
|
||||
found_openssl=yes
|
||||
OPENSSL_LIBDIR=$LIBSSH2_OPENSSL_DIR/lib
|
||||
OPENSSL_LIBLINE="-L$LIBSSH2_OPENSSL_DIR/lib -lcrypto"
|
||||
OPENSSL_INCLINE="-I$LIBSSH2_OPENSSL_DIR/include"
|
||||
OPENSSL_INCDIR=$LIBSSH2_OPENSSL_DIR/include
|
||||
AC_MSG_RESULT([Using explicit path $LIBSSH2_OPENSSL_DIR])
|
||||
fi
|
||||
@@ -47,8 +90,9 @@ fi
|
||||
# If pkg-config is found try using it
|
||||
if test "$found_openssl" = "no" && test -x "$PKG_CONFIG" && $PKG_CONFIG --exists openssl; then
|
||||
found_openssl=yes
|
||||
OPENSSL_LIBDIR=`$PKG_CONFIG --libs openssl`
|
||||
OPENSSL_INCDIR=`$PKG_CONFIG --variable=includedir openssl`
|
||||
pkgcfg_openssl=yes
|
||||
OPENSSL_LIBLINE=`$PKG_CONFIG --libs openssl`
|
||||
OPENSSL_INCLINE=`$PKG_CONFIG --cflags-only-I openssl`
|
||||
AC_MSG_RESULT([Using paths from pkg-config])
|
||||
fi
|
||||
|
||||
@@ -58,39 +102,45 @@ if test "$found_openssl" = "no"; then
|
||||
|
||||
for i in $OPENSSL_SEARCH_PATH; do
|
||||
if test -r $i/include/openssl/evp.h; then
|
||||
OPENSSL_INCLINE="-I$i/include"
|
||||
OPENSSL_INCDIR=$i/include
|
||||
fi
|
||||
if test -r $i/include/openssl/hmac.h; then
|
||||
OPENSSL_INCLINE="-I$i/include"
|
||||
OPENSSL_INCDIR=$i/include
|
||||
fi
|
||||
if test -r $i/lib/libcrypto.a -o -r $i/lib/libcrypto.$SHLIB_SUFFIX_NAME; then
|
||||
OPENSSL_LIBDIR=$i/lib
|
||||
OPENSSL_LIBLINE="-L$i/lib -lcrypto"
|
||||
fi
|
||||
test -n "$OPENSSL_INCDIR" && test -n "$OPENSSL_LIBDIR" && break
|
||||
test -n "$OPENSSL_INCLINE" && test -n "$OPENSSL_LIBLINE" && break
|
||||
done
|
||||
|
||||
if test -z "$OPENSSL_INCDIR"; then
|
||||
if test -z "$OPENSSL_INCLINE"; then
|
||||
AC_MSG_ERROR([Cannot find OpenSSL's <evp.h> or <hmac.h>])
|
||||
fi
|
||||
|
||||
if test -z "$OPENSSL_LIBDIR"; then
|
||||
if test -z "$OPENSSL_LIBLINE"; then
|
||||
AC_MSG_ERROR([Cannot find OpenSSL's libcrypto])
|
||||
fi
|
||||
|
||||
AC_MSG_RESULT([$OPENSSL_INCDIR $OPENSSL_LIBDIR])
|
||||
AC_MSG_RESULT([$OPENSSL_INCLINE $OPENSSL_LIBLINE])
|
||||
fi
|
||||
|
||||
#
|
||||
# Confirm required OpenSSL libs
|
||||
#
|
||||
if test ! -r $OPENSSL_INCDIR/openssl/bn.h || test ! -r $OPENSSL_INCDIR/openssl/evp.h || \
|
||||
test ! -r $OPENSSL_INCDIR/openssl/hmac.h || test ! -r $OPENSSL_INCDIR/openssl/pem.h || \
|
||||
test ! -r $OPENSSL_INCDIR/openssl/sha.h; then
|
||||
AC_MSG_ERROR([Missing one or more of <openssl/bn.h>, <openssl/evp.h>, <openssl/hmac.h>, <openssl/pem.h>, <openssl/sha.h>])
|
||||
if test ! "$pkgcfg_openssl" = "yes"; then
|
||||
if test ! -r $OPENSSL_INCDIR/openssl/bn.h || test ! -r $OPENSSL_INCDIR/openssl/evp.h || \
|
||||
test ! -r $OPENSSL_INCDIR/openssl/hmac.h || test ! -r $OPENSSL_INCDIR/openssl/pem.h || \
|
||||
test ! -r $OPENSSL_INCDIR/openssl/sha.h; then
|
||||
AC_MSG_ERROR([Missing one or more of <openssl/bn.h>, <openssl/evp.h>, <openssl/hmac.h>, <openssl/pem.h>, <openssl/sha.h>])
|
||||
fi
|
||||
fi
|
||||
|
||||
CFLAGS="$CFLAGS -I$OPENSSL_INCDIR"
|
||||
LDFLAGS="$LDFLAGS -L$OPENSSL_LIBDIR -lcrypto"
|
||||
CFLAGS="$CFLAGS $OPENSSL_INCLINE"
|
||||
LDFLAGS="$LDFLAGS $OPENSSL_LIBLINE"
|
||||
|
||||
fi
|
||||
|
||||
#
|
||||
# zlib
|
||||
@@ -138,13 +188,90 @@ AC_ARG_ENABLE(mac-none,
|
||||
AC_HELP_STRING([--enable-mac-none],[Permit "none" MAC -- NOT RECOMMENDED]),
|
||||
[AC_DEFINE(LIBSSH2_MAC_NONE, 1, [Enable "none" MAC -- NOT RECOMMENDED])])
|
||||
|
||||
AC_ARG_ENABLE(gex-new,
|
||||
AC_HELP_STRING([--disable-gex-new],[Disable "new" diffie-hellman-group-exchange-sha1 method]),
|
||||
[GEX_NEW=$enableval])
|
||||
if test "$GEX_NEW" != "no"; then
|
||||
AC_DEFINE(LIBSSH2_DH_GEX_NEW, 1, [Enable newer diffie-hellman-group-exchange-sha1 syntax])
|
||||
fi
|
||||
|
||||
#
|
||||
# Optional debugging -- Meant for developer maintenance only
|
||||
# When enabled, the relevant debugging information will be written on stderr
|
||||
#
|
||||
AC_ARG_ENABLE(debug-transport,
|
||||
AC_HELP_STRING([--enable-debug-transport],[Output transport layer debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_TRANSPORT, 1, [Output transport layer debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-kex,
|
||||
AC_HELP_STRING([--enable-debug-kex],[Output Key Exchange debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_KEX, 1, [Output Key Exchange debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-userauth,
|
||||
AC_HELP_STRING([--enable-debug-userauth],[Output userauth debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_USERAUTH, 1, [Output userauth layer debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-channel,
|
||||
AC_HELP_STRING([--enable-debug-connection],[Output connection layer debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_CONNECTION, 1, [Output connection layer debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-scp,
|
||||
AC_HELP_STRING([--enable-debug-scp],[Output scp subsystem debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_SCP, 1, [Output scp subsystem debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-sftp,
|
||||
AC_HELP_STRING([--enable-debug-sftp],[Output sftp subsystem debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_SFTP, 1, [Output sftp subsystem debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-publickey,
|
||||
AC_HELP_STRING([--enable-debug-publickey],[Output publickey subsystem debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_PUBLICKEY, 1, [Output publickey subsystem debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-errors,
|
||||
AC_HELP_STRING([--enable-debug-errors],[Output failure events to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_ERRORS, 1, [Output failure events to stderr])])
|
||||
AC_ARG_ENABLE(debug-all,
|
||||
AC_HELP_STRING([--enable-debug-all],[Output debugging info for all layers to stderr]),
|
||||
[
|
||||
AC_DEFINE(LIBSSH2_DEBUG_TRANSPORT, 1, [Output transport layer debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_KEX, 1, [Output Key Exchange debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_USERAUTH, 1, [Output userauth layer debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_CONNECTION, 1, [Output connection layer debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_SCP, 1, [Output scp subsystem debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_SFTP, 1, [Output sftp subsystem debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_PUBLICKEY, 1, [Output publickey subsystem debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_ERRORS, 1, [Output failure events to stderr])
|
||||
])
|
||||
|
||||
|
||||
dnl ************************************************************
|
||||
dnl option to switch on compiler debug options
|
||||
dnl
|
||||
AC_MSG_CHECKING([whether to enable pedantic and debug compiler options])
|
||||
AC_ARG_ENABLE(debug-build,
|
||||
AC_HELP_STRING([--enable-debug-build],[Enable pedantic debug options])
|
||||
AC_HELP_STRING([--disable-debug-build],[Disable debug options]),
|
||||
[ case "$enableval" in
|
||||
no)
|
||||
AC_MSG_RESULT(no)
|
||||
;;
|
||||
*) AC_MSG_RESULT(yes)
|
||||
|
||||
CPPFLAGS="$CPPFLAGS -DLIBSSH2DEBUG"
|
||||
CFLAGS="$CFLAGS -g"
|
||||
|
||||
dnl set compiler "debug" options to become more picky, and remove
|
||||
dnl optimize options from CFLAGS
|
||||
CURL_CC_DEBUG_OPTS
|
||||
;;
|
||||
esac
|
||||
],
|
||||
AC_MSG_RESULT(no)
|
||||
)
|
||||
|
||||
# Checks for header files.
|
||||
# AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([errno.h fcntl.h stdio.h stdlib.h unistd.h])
|
||||
AC_CHECK_HEADERS([errno.h fcntl.h stdio.h stdlib.h unistd.h sys/uio.h sys/select.h])
|
||||
AC_CHECK_FUNCS(poll gettimeofday select)
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
src/Makefile])
|
||||
src/Makefile
|
||||
tests/Makefile])
|
||||
AC_OUTPUT
|
||||
|
16
docs/libssh2_channel_forward_accept.3
Normal file
16
docs/libssh2_channel_forward_accept.3
Normal file
@@ -0,0 +1,16 @@
|
||||
.\" $Id: libssh2_channel_forward_accept.3,v 1.1 2006/12/21 14:09:12 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_forward_accept 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_forward_accept - accept a queued connection
|
||||
.SH SYNOPSIS
|
||||
.B #include <libssh2.h>
|
||||
|
||||
.B LIBSSH2_CHANNEL * libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener);
|
||||
.SH DESCRIPTION
|
||||
\fIlistener\fP is a forwarding listener instance as returned by
|
||||
\fBlibssh2_channel_forward_listen(3)\fP.
|
||||
.SH RETURN VALUE
|
||||
A newly allocated channel instance or NULL on failure.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_channel_forward_listen(3)
|
40
docs/libssh2_channel_forward_listen_ex.3
Normal file
40
docs/libssh2_channel_forward_listen_ex.3
Normal file
@@ -0,0 +1,40 @@
|
||||
.\" $Id: libssh2_channel_forward_listen_ex.3,v 1.1 2006/12/21 14:09:13 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_forward_listen_ex 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_forward_listen_ex - listen to inbound connections
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
LIBSSH2_LISTENER * libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session,
|
||||
char *host,
|
||||
int port,
|
||||
int *bound_port,
|
||||
int queue_maxsize);
|
||||
|
||||
LIBSSH2_LISTENER * libssh2_channel_forward_listen(LIBSSH2_SESSION *session,
|
||||
int port);
|
||||
.SH DESCRIPTION
|
||||
Instruct the remote SSH server to begin listening for inbound TCP/IP
|
||||
connections. New connections will be queued by the library until accepted by
|
||||
\fIlibssh2_channel_forward_accept(3)\fP.
|
||||
|
||||
\fIsession\fP - instance as returned by libssh2_session_init().
|
||||
|
||||
\fIhost\fP - specific address to bind to on the remote host. Binding to
|
||||
0.0.0.0 (default when NULL is passed) will bind to all available addresses.
|
||||
|
||||
\fIport\fP - port to bind to on the remote host. When 0 is passed, the remote
|
||||
host will select the first available dynamic port.
|
||||
|
||||
\fIbound_port\fP - Populated with the actual port bound on the remote
|
||||
host. Useful when requesting dynamic port numbers.
|
||||
|
||||
\fIqueue_maxsize\fP - Maximum nuber of pending connections to queue before
|
||||
rejecting further attempts.
|
||||
|
||||
\fIlibssh2_channel_forward_listen(3)\fP is a macro.
|
||||
.SH RETURN VALUE
|
||||
A newly allocated LIBSSH2_LISTENER instance or NULL on failure.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_channel_forward_accept(3)
|
36
docs/libssh2_channel_read_ex.3
Normal file
36
docs/libssh2_channel_read_ex.3
Normal file
@@ -0,0 +1,36 @@
|
||||
.\" $Id: libssh2_channel_read_ex.3,v 1.4 2007/02/02 16:11:55 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_read_ex 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_read_ex - read data from a channel stream
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
char *buf, size_t buflen);
|
||||
|
||||
int libssh2_channel_read(LIBSSH2_CHANNEL *channel, char *buf,
|
||||
size_t buflen);
|
||||
|
||||
int libssh2_channel_read_stderr(LIBSSH2_CHANNEL *channel, char *buf,
|
||||
size_t buflen);
|
||||
.SH DESCRIPTION
|
||||
Attempt to read data from an active channel stream. All channel streams have
|
||||
one standard I/O substream (stream_id == 0), and may have up to 2^32 extended
|
||||
data streams as identified by the selected \fIstream_id\fP. The SSH2 protocol
|
||||
currently defines a stream ID of 1 to be the stderr substream.
|
||||
|
||||
\fIchannel\fP - active channel stream to read from.
|
||||
|
||||
\fIstream_id\fP - substream ID number (e.g. 0 or SSH_EXTENDED_DATA_STDERR)
|
||||
|
||||
\fIbuf\fP - pointer to storage buffer to read data into
|
||||
|
||||
\fIbuflen\fP - size of the buf storage
|
||||
|
||||
\fIlibssh2_channel_read(3)\fP and \fIlibssh2_channel_read_stderr(3)\fP are
|
||||
macros.
|
||||
.SH RETURN VALUE
|
||||
Actual number of bytes read or negative on failure.
|
||||
.SH "SEE ALSO"
|
||||
|
37
docs/libssh2_channel_readnb_ex.3
Normal file
37
docs/libssh2_channel_readnb_ex.3
Normal file
@@ -0,0 +1,37 @@
|
||||
.\" $Id: libssh2_channel_readnb_ex.3,v 1.1 2007/02/02 16:09:12 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_read_ex 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_read_ex - read data from a channel stream
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int libssh2_channel_readnb_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
char *buf, size_t buflen);
|
||||
|
||||
int libssh2_channel_readnb(LIBSSH2_CHANNEL *channel, char *buf,
|
||||
size_t buflen);
|
||||
|
||||
int libssh2_channel_readnb_stderr(LIBSSH2_CHANNEL *channel, char *buf,
|
||||
size_t buflen);
|
||||
.SH DESCRIPTION
|
||||
Attempt to read data from an active channel stream. All channel streams have
|
||||
one standard I/O substream (stream_id == 0), and may have up to 2^32 extended
|
||||
data streams as identified by the selected \fIstream_id\fP. The SSH2 protocol
|
||||
currently defines a stream ID of 1 to be the stderr substream.
|
||||
|
||||
\fIchannel\fP - active channel stream to read from.
|
||||
|
||||
\fIstream_id\fP - substream ID number (e.g. 0 or SSH_EXTENDED_DATA_STDERR)
|
||||
|
||||
\fIbuf\fP - pointer to storage buffer to read data into
|
||||
|
||||
\fIbuflen\fP - size of the buf storage
|
||||
|
||||
\fIlibssh2_channel_read(3)\fP and \fIlibssh2_channel_read_stderr(3)\fP are
|
||||
macros.
|
||||
.SH RETURN VALUE
|
||||
Actual number of bytes read or negative on failure. It returns
|
||||
LIBSSH2CHANNEL_EAGAIN when it would otherwise block. While
|
||||
LIBSSH2CHANNEL_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
.SH "SEE ALSO"
|
23
docs/libssh2_channel_set_blocking.3
Normal file
23
docs/libssh2_channel_set_blocking.3
Normal file
@@ -0,0 +1,23 @@
|
||||
.\" $Id: libssh2_channel_set_blocking.3,v 1.1 2006/12/21 14:09:13 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_set_blocking 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_set_blocking - set or clear blocking mode on channel
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
|
||||
.SH DESCRIPTION
|
||||
Set or clear blocking mode on the selected channel. If a read is performed on
|
||||
a channel with no data currently available, a blocking channel will wait for
|
||||
data to arrive and return what it receives. A non-blocking channel will return
|
||||
immediately with an empty buffer.
|
||||
|
||||
\fIchannel\fP - channel stream to set or clean blocking status on.
|
||||
|
||||
\fIblocking\fP - Set to a non-zero value to make the channel block, or zero to
|
||||
make it non-blocking.
|
||||
.SH RETURN VALUE
|
||||
None
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_channel_read_ex(3)
|
17
docs/libssh2_session_free.3
Normal file
17
docs/libssh2_session_free.3
Normal file
@@ -0,0 +1,17 @@
|
||||
.\" $Id: libssh2_session_free.3,v 1.1 2006/12/21 14:09:13 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_session_free 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_session_free - frees resources associated with a session instance
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
void libssh2_session_free(LIBSSH2_SESSION *session);
|
||||
.SH DESCRIPTION
|
||||
Frees resources associated with a session instance. Typically called after
|
||||
\fIlibssh2_session_disconnect(3)\fP.
|
||||
.SH RETURN VALUE
|
||||
None
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_session_init(3),
|
||||
.BI libssh2_session_disconnect(3)
|
29
docs/libssh2_session_init.3
Normal file
29
docs/libssh2_session_init.3
Normal file
@@ -0,0 +1,29 @@
|
||||
.\" $Id: libssh2_session_init.3,v 1.1 2006/12/21 14:09:13 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_session_init 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_session_init - initializes an SSH session object
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
LIBSSH2_SESSION *libssh2_session_init_ex(
|
||||
LIBSSH2_ALLOC_FUNC((*myalloc)),
|
||||
LIBSSH2_FREE_FUNC((*myfree)),
|
||||
LIBSSH2_REALLOC_FUNC((*myrealloc)),
|
||||
void *abstract);
|
||||
|
||||
LIBSSH2_SESSION *libssh2_session_init(void);
|
||||
.SH DESCRIPTION
|
||||
Initializes an SSH session object. By default system memory allocators
|
||||
(malloc(), free(), realloc()) will be used for any dynamicly allocated memory
|
||||
blocks. Alternate memory allocation functions may be specified using the
|
||||
extended version of this API call, and/or optional application specific data
|
||||
may be attached to the session object.
|
||||
|
||||
This method must be called first, prior to configuring session options or
|
||||
starting up an SSH session with a remote server.
|
||||
.SH RETURN VALUE
|
||||
Pointer to a newly allocated LIBSSH2_SESSION instance, or NULL on errors.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_session_free(3),
|
||||
.BI libssh2_session_startup(3)
|
16
docs/libssh2_session_startup.3
Normal file
16
docs/libssh2_session_startup.3
Normal file
@@ -0,0 +1,16 @@
|
||||
.\" $Id: libssh2_session_startup.3,v 1.2 2007/01/02 05:47:00 gusarov Exp $
|
||||
.\"
|
||||
.TH libssh2_session_startup 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_session_startup - begin transport layer
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int libssh2_session_startup(LIBSSH2_SESSION *session, int socket);
|
||||
.SH DESCRIPTION
|
||||
Begin transport layer protocol negotiation with the connected host.
|
||||
.SH RETURN VALUE
|
||||
0 on success, \-1 on failure
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_session_free(3),
|
||||
.BI libssh2_session_init(3)
|
20
docs/libssh2_sftp_init.3
Normal file
20
docs/libssh2_sftp_init.3
Normal file
@@ -0,0 +1,20 @@
|
||||
.\" $Id: libssh2_sftp_init.3,v 1.1 2007/02/02 16:09:12 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_sftp_init 3 "23 Jan 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_sftp_init -
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session);
|
||||
.SH DESCRIPTION
|
||||
Open a channel and initialize the SFTP subsystem. Although the SFTP subsystem
|
||||
operates over the same type of channel as those exported by the Channel API,
|
||||
the protocol itself implements its own unique binary packet protocol which
|
||||
must be managed with the libssh2_sftp_*() family of functions. When an SFTP
|
||||
session is complete, it must be destroyed using the
|
||||
\fIlibssh2_sftp_shutdown(3)\fP function.
|
||||
.SH RETURN VALUE
|
||||
A pointer to the newly allocated SFTP instance or NULL on failure.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_sftp_shutdown(3), libssh2_sftp_open_ex(3)
|
47
docs/libssh2_sftp_open_ex.3
Normal file
47
docs/libssh2_sftp_open_ex.3
Normal file
@@ -0,0 +1,47 @@
|
||||
.\" $Id: libssh2_sftp_open_ex.3,v 1.1 2007/02/02 16:09:12 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_sftp_open_ex 3 "23 Jan 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_sftp_open -
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp,
|
||||
char *filename, int filename_len,
|
||||
unsigned long flags, long mode, int open_type);
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *libssh2_sftp_open(LIBSSH2_SFTP *sftp,
|
||||
char *filename, unsigned long flags, long mode);
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *libssh2_sftp_opendir(LIBSSH2_SFTP *sftp,
|
||||
char *path);
|
||||
.SH DESCRIPTION
|
||||
* sftp
|
||||
|
||||
SFTP instance as returned by libssh2_sftp_init().
|
||||
|
||||
* filename
|
||||
|
||||
Remote file/directory resource to open
|
||||
|
||||
* filename_len
|
||||
|
||||
Length of filename
|
||||
|
||||
* flags
|
||||
|
||||
Any (reasonable) combination of the LIBSSH2_FXF_* constants corresponding fopen modes.
|
||||
|
||||
* mode
|
||||
|
||||
POSIX file permissions to assign if the file is being newly created.
|
||||
|
||||
* open_type
|
||||
|
||||
Either of LIBSSH2_SFTP_OPENFILE (to open a file) or LIBSSH2_SFTP_OPENDIR (to open a directory).
|
||||
.SH RETURN VALUE
|
||||
A pointer to the newly created LIBSSH2_SFTP_HANDLE instance or NULL on
|
||||
failure.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh_sftp_close(3)
|
||||
|
15
docs/template.3
Normal file
15
docs/template.3
Normal file
@@ -0,0 +1,15 @@
|
||||
.\" $Id: template.3,v 1.1 2007/02/02 16:09:12 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_template 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_template - short function description
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
void libssh2_template(void);
|
||||
.SH DESCRIPTION
|
||||
Long text describing the function and its input arguments.
|
||||
.SH RETURN VALUE
|
||||
Describe what the funtion returns.
|
||||
.SH "SEE ALSO"
|
||||
Add related functions
|
158
example/simple/scp.c
Normal file
158
example/simple/scp.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* $Id: scp.c,v 1.3 2007/02/01 22:39:45 bagder Exp $
|
||||
*
|
||||
* Sample showing how to do a simple SCP transfer.
|
||||
*/
|
||||
|
||||
#include <libssh2.h>
|
||||
|
||||
#ifndef WIN32
|
||||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
char *scppath=(char *)"/tmp/TEST";
|
||||
struct stat fileinfo;
|
||||
int rc;
|
||||
off_t got=0;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the
|
||||
* connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = htonl(0x7F000001);
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(!session)
|
||||
return -1;
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
rc = libssh2_session_startup(session, sock);
|
||||
if(rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if(argc > 1) {
|
||||
username = argv[1];
|
||||
}
|
||||
if(argc > 2) {
|
||||
password = argv[2];
|
||||
}
|
||||
if(argc > 3) {
|
||||
scppath = argv[3];
|
||||
}
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
/* Request a file via SCP */
|
||||
channel = libssh2_scp_recv(session, scppath, &fileinfo);
|
||||
|
||||
if (!channel) {
|
||||
fprintf(stderr, "Unable to open a session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
|
||||
while(got < fileinfo.st_size) {
|
||||
char mem[1024];
|
||||
int amount=sizeof(mem);
|
||||
|
||||
if((fileinfo.st_size -got) < amount) {
|
||||
amount = fileinfo.st_size -got;
|
||||
}
|
||||
|
||||
rc = libssh2_channel_read(channel, mem, amount);
|
||||
if(rc == amount) {
|
||||
write(2, mem, rc);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "libssh2_channel_read() failed: %d\n",
|
||||
rc);
|
||||
break;
|
||||
}
|
||||
got += rc;
|
||||
}
|
||||
|
||||
libssh2_channel_free(channel);
|
||||
channel = NULL;
|
||||
|
||||
shutdown:
|
||||
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
#else
|
||||
sleep(1);
|
||||
close(sock);
|
||||
#endif
|
||||
printf("all done\n");
|
||||
return 0;
|
||||
}
|
159
example/simple/sftp.c
Normal file
159
example/simple/sftp.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* $Id: sftp.c,v 1.1 2007/01/24 14:15:36 bagder Exp $
|
||||
*
|
||||
* Sample showing how to do SFTP transfers.
|
||||
*/
|
||||
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
|
||||
#ifndef WIN32
|
||||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
char *sftppath=(char *)"/tmp/TEST";
|
||||
int rc;
|
||||
LIBSSH2_SFTP *sftp_session;
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the
|
||||
* connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = htonl(0x7F000001);
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(!session)
|
||||
return -1;
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
rc = libssh2_session_startup(session, sock);
|
||||
if(rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if(argc > 1) {
|
||||
username = argv[1];
|
||||
}
|
||||
if(argc > 2) {
|
||||
password = argv[2];
|
||||
}
|
||||
if(argc > 3) {
|
||||
sftppath = argv[3];
|
||||
}
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
sftp_session = libssh2_sftp_init(session);
|
||||
|
||||
if (!sftp_session) {
|
||||
fprintf(stderr, "Unable to init SFTP session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/* Request a file via SFTP */
|
||||
sftp_handle =
|
||||
libssh2_sftp_open(sftp_session, sftppath, LIBSSH2_FXF_READ, 0);
|
||||
|
||||
if (!sftp_handle) {
|
||||
fprintf(stderr, "Unable to open file with SFTP\n");
|
||||
goto shutdown;
|
||||
}
|
||||
fprintf(stderr, "libssh2_sftp_open() is done, now receive data!\n");
|
||||
do {
|
||||
char mem[512];
|
||||
|
||||
/* loop until we fail */
|
||||
rc = libssh2_sftp_read(sftp_handle, mem, sizeof(mem));
|
||||
if(rc > 0) {
|
||||
write(2, mem, rc);
|
||||
}
|
||||
else
|
||||
break;
|
||||
break;
|
||||
|
||||
} while (1);
|
||||
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
libssh2_sftp_shutdown(sftp_session);
|
||||
|
||||
shutdown:
|
||||
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
#else
|
||||
sleep(1);
|
||||
close(sock);
|
||||
#endif
|
||||
printf("all done\n");
|
||||
return 0;
|
||||
}
|
152
example/simple/ssh2.c
Normal file
152
example/simple/ssh2.c
Normal file
@@ -0,0 +1,152 @@
|
||||
#include "libssh2.h"
|
||||
|
||||
#ifndef WIN32
|
||||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
#ifndef WIN32
|
||||
fcntl(sock, F_SETFL, 0);
|
||||
#endif
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = htonl(0x7F000001);
|
||||
if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a session instance and start it up
|
||||
* This will trade welcome banners, exchange keys, and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if (libssh2_session_startup(session, sock)) {
|
||||
fprintf(stderr, "Failure establishing SSH session\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't authenticated,
|
||||
* The first thing to do is check the hostkey's fingerprint against our known hosts
|
||||
* Your app may have it hard coded, may go to a file, may present it to the user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if(argc > 1) {
|
||||
username = argv[1];
|
||||
}
|
||||
if(argc > 2) {
|
||||
password = argv[2];
|
||||
}
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username, "/home/username/.ssh/id_rsa.pub", "/home/username/.ssh/id_rsa", password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
/* Request a shell */
|
||||
if (!(channel = libssh2_channel_open_session(session))) {
|
||||
fprintf(stderr, "Unable to open a session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/* Some environment variables may be set,
|
||||
* It's up to the server which ones it'll allow though
|
||||
*/
|
||||
libssh2_channel_setenv(channel, (char *)"FOO", (char *)"bar");
|
||||
|
||||
/* Request a terminal with 'vanilla' terminal emulation
|
||||
* See /etc/termcap for more options
|
||||
*/
|
||||
if (libssh2_channel_request_pty(channel, (char *)"vanilla")) {
|
||||
fprintf(stderr, "Failed requesting pty\n");
|
||||
goto skip_shell;
|
||||
}
|
||||
|
||||
/* Open a SHELL on that pty */
|
||||
if (libssh2_channel_shell(channel)) {
|
||||
fprintf(stderr, "Unable to request shell on allocated pty\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/* At this point the shell can be interacted with using
|
||||
* libssh2_channel_read()
|
||||
* libssh2_channel_read_stderr()
|
||||
* libssh2_channel_write()
|
||||
* libssh2_channel_write_stderr()
|
||||
*
|
||||
* Blocking mode may be (en|dis)abled with: libssh2_channel_set_blocking()
|
||||
* If the server send EOF, libssh2_channel_eof() will return non-0
|
||||
* To send EOF to the server use: libssh2_channel_send_eof()
|
||||
* A channel can be closed with: libssh2_channel_close()
|
||||
* A channel can be freed with: libssh2_channel_free()
|
||||
*/
|
||||
|
||||
skip_shell:
|
||||
if (channel) {
|
||||
libssh2_channel_free(channel);
|
||||
channel = NULL;
|
||||
}
|
||||
|
||||
/* Other channel types are supported via:
|
||||
* libssh2_scp_send()
|
||||
* libssh2_scp_recv()
|
||||
* libssh2_channel_direct_tcpip()
|
||||
*/
|
||||
|
||||
shutdown:
|
||||
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
#else
|
||||
sleep(1);
|
||||
close(sock);
|
||||
#endif
|
||||
printf("all done\n");
|
||||
return 0;
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -38,12 +38,41 @@
|
||||
#ifndef LIBSSH2_H
|
||||
#define LIBSSH2_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define LIBSSH2_VERSION "0.3"
|
||||
#define LIBSSH2_APINO 200412211608
|
||||
/* Allow alternate API prefix from CFLAGS or calling app */
|
||||
#ifndef LIBSSH2_API
|
||||
# ifdef LIBSSH2_WIN32
|
||||
# ifdef LIBSSH2_LIBRARY
|
||||
# define LIBSSH2_API __declspec(dllexport)
|
||||
# else
|
||||
# define LIBSSH2_API __declspec(dllimport)
|
||||
# endif /* LIBSSH2_LIBRARY */
|
||||
# else /* !LIBSSH2_WIN32 */
|
||||
# define LIBSSH2_API
|
||||
# endif /* LIBSSH2_WIN32 */
|
||||
#endif /* LIBSSH2_API */
|
||||
|
||||
#if defined(LIBSSH2_DARWIN) || (defined(LIBSSH2_WIN32) && !defined(_MSC_VER))
|
||||
# include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#if defined(LIBSSH2_WIN32) && _MSC_VER < 1300
|
||||
typedef unsigned __int64 libssh2_uint64_t;
|
||||
typedef __int64 libssh2_int64_t;
|
||||
#else
|
||||
typedef unsigned long long libssh2_uint64_t;
|
||||
typedef long long libssh2_int64_t;
|
||||
#endif
|
||||
|
||||
#define LIBSSH2_VERSION "0.14"
|
||||
#define LIBSSH2_APINO 200507211326
|
||||
|
||||
/* Part of every banner, user specified or not */
|
||||
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
|
||||
@@ -52,54 +81,6 @@
|
||||
#define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER
|
||||
#define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n"
|
||||
|
||||
/* Capabilities */
|
||||
#define LIBSSH2_KEX_DH_GROUP1
|
||||
#define LIBSSH2_KEX_DH_GROUP14
|
||||
#define LIBSSH2_KEX_DH_GROUP_EXCHANGE
|
||||
|
||||
#ifndef OPENSSL_NO_RSA
|
||||
#define LIBSSH2_HOSTKEY_RSA
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_DSA
|
||||
#define LIBSSH2_HOSTKEY_DSA
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_AES
|
||||
#define LIBSSH2_CRYPT_AES256_CBC
|
||||
#define LIBSSH2_CRYPT_RIJNDAEL_CBC_LYSATOR_LIU_SE
|
||||
#define LIBSSH2_CRYPT_AES192_CBC
|
||||
#define LIBSSH2_CRYPT_AES128_CBC
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_BLOWFISH
|
||||
#define LIBSSH2_CRYPT_BLOWFISH_CBC
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_RC4
|
||||
#define LIBSSH2_CRYPT_ARCFOUR
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_CAST
|
||||
#define LIBSSH2_CRYPT_CAST128_CBC
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_DES
|
||||
#define LIBSSH2_CRYPT_3DES_CBC
|
||||
#endif
|
||||
/* LIBSSH2_CRYPT_NONE already defined (or not) by ./configure */
|
||||
|
||||
#ifdef LIBSSH2_HAVE_ZLIB
|
||||
#define LIBSSH2_COMP_ZLIB
|
||||
#endif
|
||||
#define LIBSSH2_COMP_NONE
|
||||
|
||||
#define LIBSSH2_MAC_SHA1
|
||||
#define LIBSSH2_MAC_SHA1_96
|
||||
#ifndef OPENSSL_NO_RIPEMD
|
||||
#define LIBSSH2_MAC_RIPEMD160
|
||||
#define LIBSSH2_MAC_RIPEMD160_OPENSSH_COM
|
||||
#endif
|
||||
/* LIBSSH2_MAC_NONE already defined (or not) by ./configure */
|
||||
|
||||
/* Enable the "new" version of diffie-hellman-group-exchange-sha1 */
|
||||
#define LIBSSH2_DH_GEX_NEW
|
||||
|
||||
/* Default generate and safe prime sizes for diffie-hellman-group-exchange-sha1 */
|
||||
#define LIBSSH2_DH_GEX_MINGROUP 1024
|
||||
#define LIBSSH2_DH_GEX_OPTGROUP 1536
|
||||
@@ -130,12 +111,29 @@
|
||||
#define LIBSSH2_REALLOC_FUNC(name) void *name(void *ptr, size_t count, void **abstract)
|
||||
#define LIBSSH2_FREE_FUNC(name) void name(void *ptr, void **abstract)
|
||||
|
||||
typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT
|
||||
{
|
||||
char* text;
|
||||
unsigned int length;
|
||||
unsigned char echo;
|
||||
} LIBSSH2_USERAUTH_KBDINT_PROMPT;
|
||||
|
||||
typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
|
||||
{
|
||||
char* text;
|
||||
unsigned int length;
|
||||
} LIBSSH2_USERAUTH_KBDINT_RESPONSE;
|
||||
|
||||
/* 'keyboard-interactive' authentication callback */
|
||||
#define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) void name_(const char* name, int name_len, const char* instruction, int instruction_len, int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts, LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses, void **abstract)
|
||||
|
||||
/* Callbacks for special SSH packets */
|
||||
#define LIBSSH2_IGNORE_FUNC(name) void name(LIBSSH2_SESSION *session, const char *message, int message_len, void **abstract)
|
||||
#define LIBSSH2_DEBUG_FUNC(name) void name(LIBSSH2_SESSION *session, int always_display, const char *message, int message_len, const char *language, int language_len,void **abstract)
|
||||
#define LIBSSH2_DISCONNECT_FUNC(name) void name(LIBSSH2_SESSION *session, int reason, const char *message, int message_len, const char *language, int language_len, void **abstract)
|
||||
#define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name) void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, void **abstract)
|
||||
#define LIBSSH2_MACERROR_FUNC(name) int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, void **abstract)
|
||||
#define LIBSSH2_X11_OPEN_FUNC(name) void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, char *shost, int sport, void **abstract)
|
||||
|
||||
#define LIBSSH2_CHANNEL_CLOSE_FUNC(name) void name(LIBSSH2_SESSION *session, void **session_abstract, LIBSSH2_CHANNEL *channel, void **channel_abstract)
|
||||
|
||||
@@ -144,6 +142,7 @@
|
||||
#define LIBSSH2_CALLBACK_DEBUG 1
|
||||
#define LIBSSH2_CALLBACK_DISCONNECT 2
|
||||
#define LIBSSH2_CALLBACK_MACERROR 3
|
||||
#define LIBSSH2_CALLBACK_X11 4
|
||||
|
||||
/* libssh2_session_method_pref() constants */
|
||||
#define LIBSSH2_METHOD_KEX 0
|
||||
@@ -157,15 +156,47 @@
|
||||
#define LIBSSH2_METHOD_LANG_CS 8
|
||||
#define LIBSSH2_METHOD_LANG_SC 9
|
||||
|
||||
/* session.flags bits */
|
||||
#define LIBSSH2_FLAG_SIGPIPE 0x00000001
|
||||
|
||||
typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
|
||||
typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
|
||||
typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER;
|
||||
|
||||
#ifdef WIN_32
|
||||
#define LIBSSH2_API __declspec(dllexport)
|
||||
#else
|
||||
#define LIBSSH2_API
|
||||
#endif
|
||||
typedef struct _LIBSSH2_POLLFD {
|
||||
unsigned char type; /* LIBSSH2_POLLFD_* below */
|
||||
|
||||
union {
|
||||
int socket; /* File descriptors -- examined with system select() call */
|
||||
LIBSSH2_CHANNEL *channel; /* Examined by checking internal state */
|
||||
LIBSSH2_LISTENER *listener; /* Read polls only -- are inbound connections waiting to be accepted? */
|
||||
} fd;
|
||||
|
||||
unsigned long events; /* Requested Events */
|
||||
unsigned long revents; /* Returned Events */
|
||||
} LIBSSH2_POLLFD;
|
||||
|
||||
/* Poll FD Descriptor Types */
|
||||
#define LIBSSH2_POLLFD_SOCKET 1
|
||||
#define LIBSSH2_POLLFD_CHANNEL 2
|
||||
#define LIBSSH2_POLLFD_LISTENER 3
|
||||
|
||||
/* Note: Win32 Doesn't actually have a poll() implementation, so some of these values are faked with select() data */
|
||||
/* Poll FD events/revents -- Match sys/poll.h where possible */
|
||||
#define LIBSSH2_POLLFD_POLLIN 0x0001 /* Data available to be read or connection available -- All */
|
||||
#define LIBSSH2_POLLFD_POLLPRI 0x0002 /* Priority data available to be read -- Socket only */
|
||||
#define LIBSSH2_POLLFD_POLLEXT 0x0002 /* Extended data available to be read -- Channel only */
|
||||
#define LIBSSH2_POLLFD_POLLOUT 0x0004 /* Can may be written -- Socket/Channel */
|
||||
/* revents only */
|
||||
#define LIBSSH2_POLLFD_POLLERR 0x0008 /* Error Condition -- Socket */
|
||||
#define LIBSSH2_POLLFD_POLLHUP 0x0010 /* HangUp/EOF -- Socket */
|
||||
#define LIBSSH2_POLLFD_SESSION_CLOSED 0x0010 /* Session Disconnect */
|
||||
#define LIBSSH2_POLLFD_POLLNVAL 0x0020 /* Invalid request -- Socket Only */
|
||||
#define LIBSSH2_POLLFD_POLLEX 0x0040 /* Exception Condition -- Socket/Win32 */
|
||||
#define LIBSSH2_POLLFD_CHANNEL_CLOSED 0x0080 /* Channel Disconnect */
|
||||
#define LIBSSH2_POLLFD_LISTENER_CLOSED 0x0080 /* Listener Disconnect */
|
||||
|
||||
/* Hash Types */
|
||||
#define LIBSSH2_HOSTKEY_HASH_MD5 1
|
||||
#define LIBSSH2_HOSTKEY_HASH_SHA1 2
|
||||
|
||||
@@ -218,6 +249,11 @@ typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
|
||||
#define LIBSSH2_ERROR_ZLIB -29
|
||||
#define LIBSSH2_ERROR_SOCKET_TIMEOUT -30
|
||||
#define LIBSSH2_ERROR_SFTP_PROTOCOL -31
|
||||
#define LIBSSH2_ERROR_REQUEST_DENIED -32
|
||||
#define LIBSSH2_ERROR_METHOD_NOT_SUPPORTED -33
|
||||
#define LIBSSH2_ERROR_INVAL -34
|
||||
#define LIBSSH2_ERROR_INVALID_POLL_TYPE -35
|
||||
#define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL -36
|
||||
|
||||
/* Session API */
|
||||
LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), LIBSSH2_FREE_FUNC((*my_free)), LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract);
|
||||
@@ -225,38 +261,57 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_all
|
||||
LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session);
|
||||
|
||||
LIBSSH2_API void *libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbtype, void *callback);
|
||||
LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, const char *banner);
|
||||
|
||||
LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket);
|
||||
LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, char *description, char *lang);
|
||||
LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, const char *description, const char *lang);
|
||||
#define libssh2_session_disconnect(session, description) libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, (description), "")
|
||||
LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session);
|
||||
|
||||
LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
|
||||
|
||||
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, char *prefs);
|
||||
LIBSSH2_API void libssh2_session_methods(LIBSSH2_SESSION *session, char **kex, char **hostkey,
|
||||
char **crypt_cs, char **crypt_sc,
|
||||
char **mac_cs, char **mac_sc,
|
||||
char **comp_cs, char **comp_sc,
|
||||
char **lang_cs, char **lang_sc);
|
||||
LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
|
||||
|
||||
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, const char *prefs);
|
||||
LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type);
|
||||
LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf);
|
||||
|
||||
LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value);
|
||||
|
||||
/* Userauth API */
|
||||
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len);
|
||||
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len);
|
||||
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
|
||||
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *username, int username_len, char *password, int password_len, LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)));
|
||||
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len, const char *password, unsigned int password_len, LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)));
|
||||
#define libssh2_userauth_password(session, username, password) libssh2_userauth_password_ex((session), (username), strlen(username), (password), strlen(password), NULL)
|
||||
|
||||
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, char *username, int username_len,
|
||||
char *publickey, char *privatekey,
|
||||
char *passphrase);
|
||||
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
|
||||
const char *publickey, const char *privatekey,
|
||||
const char *passphrase);
|
||||
#define libssh2_userauth_publickey_fromfile(session, username, publickey, privatekey, passphrase) \
|
||||
libssh2_userauth_publickey_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase))
|
||||
LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
|
||||
const char *publickey, const char *privatekey,
|
||||
const char *passphrase,
|
||||
const char *hostname, unsigned int hostname_len,
|
||||
const char *local_username, unsigned int local_username_len);
|
||||
#define libssh2_userauth_hostbased_fromfile(session, username, publickey, privatekey, passphrase, hostname) \
|
||||
libssh2_userauth_hostbased_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase), (hostname), strlen(hostname), (username), strlen(username))
|
||||
|
||||
/*
|
||||
* response_callback is provided with filled by library prompts array,
|
||||
* but client must allocate and fill individual responses. Responses
|
||||
* array is already allocated. Responses data will be freed by libssh2
|
||||
* after callback return, but before subsequent callback invokation.
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session, const char *username, unsigned int username_len,
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)));
|
||||
#define libssh2_userauth_keyboard_interactive(session, username, response_callback) \
|
||||
libssh2_userauth_keyboard_interactive_ex((session), (username), strlen(username), (response_callback))
|
||||
|
||||
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout);
|
||||
|
||||
/* Channel API */
|
||||
#define LIBSSH2_CHANNEL_WINDOW_DEFAULT 65536
|
||||
#define LIBSSH2_CHANNEL_PACKET_DEFAULT 16384
|
||||
#define LIBSSH2_CHANNEL_MINADJUST 1024
|
||||
|
||||
/* Extended Data Handling */
|
||||
#define LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL 0
|
||||
@@ -265,18 +320,29 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
|
||||
#define SSH_EXTENDED_DATA_STDERR 1
|
||||
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, char *channel_type, int channel_type_len, int window_size, int packet_size, char *message, int message_len);
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type, unsigned int channel_type_len, unsigned int window_size, unsigned int packet_size, const char *message, unsigned int message_len);
|
||||
#define libssh2_channel_open_session(session) libssh2_channel_open_ex((session), "session", sizeof("session") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0)
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, char *host, int port, char *shost, int sport);
|
||||
#define libssh2_channel_direct_tcpip(session, host, port) libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22)
|
||||
|
||||
LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varname, int varname_len, char *value, int value_len);
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, char *host, int port, char *shost, int sport);
|
||||
#define libssh2_channel_direct_tcpip(session, host, port) libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22)
|
||||
|
||||
LIBSSH2_API LIBSSH2_LISTENER *libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, char *host, int port, int *bound_port, int queue_maxsize);
|
||||
#define libssh2_channel_forward_listen(session, port) libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16)
|
||||
|
||||
LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener);
|
||||
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener);
|
||||
|
||||
LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varname, unsigned int varname_len, char *value, unsigned int value_len);
|
||||
#define libssh2_channel_setenv(channel, varname, value) libssh2_channel_setenv_ex((channel), (varname), strlen(varname), (value), strlen(value))
|
||||
|
||||
LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *term, int term_len, char *modes, int modes_len, int width, int height, int width_px, int height_px);
|
||||
LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *term, unsigned int term_len, char *modes, unsigned int modes_len, int width, int height, int width_px, int height_px);
|
||||
#define libssh2_channel_request_pty(channel, term) libssh2_channel_request_pty_ex((channel), (term), strlen(term), NULL, 0, LIBSSH2_TERM_WIDTH, LIBSSH2_TERM_HEIGHT, LIBSSH2_TERM_WIDTH_PX, LIBSSH2_TERM_HEIGHT_PX)
|
||||
|
||||
LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, char *request, int request_len, char *message, int message_len);
|
||||
LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, char *auth_proto, char *auth_cookie, int screen_number);
|
||||
#define libssh2_channel_x11_req(channel, screen_number) libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number))
|
||||
|
||||
LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const char *request, unsigned int request_len, const char *message, unsigned int message_len);
|
||||
#define libssh2_channel_shell(channel) libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, NULL, 0)
|
||||
#define libssh2_channel_exec(channel, command) libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, (command), strlen(command))
|
||||
#define libssh2_channel_subsystem(channel, subsystem) libssh2_channel_process_startup((channel), "subsystem", sizeof("subsystem") - 1, (subsystem), strlen(subsystem))
|
||||
@@ -285,15 +351,25 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
#define libssh2_channel_read(channel, buf, buflen) libssh2_channel_read_ex((channel), 0, (buf), (buflen))
|
||||
#define libssh2_channel_read_stderr(channel, buf, buflen) libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
|
||||
|
||||
LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended);
|
||||
|
||||
LIBSSH2_API unsigned long libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, unsigned long *read_avail, unsigned long *window_size_initial);
|
||||
#define libssh2_channel_window_read(channel) libssh2_channel_window_read_ex((channel), NULL, NULL)
|
||||
|
||||
LIBSSH2_API unsigned long libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, unsigned long adjustment, unsigned char force);
|
||||
|
||||
LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id, const char *buf, size_t buflen);
|
||||
#define libssh2_channel_write(channel, buf, buflen) libssh2_channel_write_ex((channel), 0, (buf), (buflen))
|
||||
#define libssh2_channel_write_stderr(channel, buf, buflen) libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
|
||||
|
||||
LIBSSH2_API unsigned long libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, unsigned long *window_size_initial);
|
||||
#define libssh2_channel_window_write(channel) libssh2_channel_window_write_ex((channel), NULL)
|
||||
|
||||
LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
|
||||
LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode);
|
||||
/* libssh2_channel_ignore_extended_data() is defined below for BC with version 0.1
|
||||
* Future uses should use libssh2_channel_handle_extended_data() directly
|
||||
* if LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE is passed, extended data will be read (FIFO) from the standard data channel
|
||||
* if LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE is passed, extended data will be read (FIFO) from the standard data channel
|
||||
*/
|
||||
/* DEPRECATED */
|
||||
#define libssh2_channel_ignore_extended_data(channel, ignore) libssh2_channel_handle_extended_data((channel), (ignore) ? LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE : LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL )
|
||||
@@ -303,16 +379,22 @@ LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel,
|
||||
LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid);
|
||||
#define libssh2_channel_flush(channel) libssh2_channel_flush_ex((channel), 0)
|
||||
#define libssh2_channel_flush_stderr(channel) libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR)
|
||||
LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel);
|
||||
|
||||
LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel);
|
||||
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *path, struct stat *sb);
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char *path, int mode, size_t size, long mtime, long atime);
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb);
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime);
|
||||
#define libssh2_scp_send(session, path, mode, size) libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0)
|
||||
|
||||
LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, int *dest_len, char *src, int src_len);
|
||||
LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, unsigned int *dest_len, char *src, unsigned int src_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LIBSSH2_H */
|
||||
|
@@ -1,71 +0,0 @@
|
||||
/* include/libssh2_config.h.in. Generated from configure.in by autoheader. */
|
||||
|
||||
/* Define to 1 if you have the <errno.h> header file. */
|
||||
#undef HAVE_ERRNO_H
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#undef HAVE_STDIO_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Enable "none" cipher -- NOT RECOMMENDED */
|
||||
#undef LIBSSH2_CRYPT_NONE
|
||||
|
||||
/* Compile in zlib support */
|
||||
#undef LIBSSH2_HAVE_ZLIB
|
||||
|
||||
/* Enable "none" MAC -- NOT RECOMMENDED */
|
||||
#undef LIBSSH2_MAC_NONE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 1 if your processor stores words with the most significant byte
|
||||
first (like Motorola and SPARC, unlike Intel and VAX). */
|
||||
#undef WORDS_BIGENDIAN
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
101
include/libssh2_publickey.h
Normal file
101
include/libssh2_publickey.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names
|
||||
* of any other contributors may be used to endorse or
|
||||
* promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Note: This include file is only needed for using the
|
||||
* publickey SUBSYSTEM which is not the same as publickey
|
||||
* authentication. For authentication you only need libssh2.h
|
||||
*
|
||||
* For more information on the publickey subsystem,
|
||||
* refer to IETF draft: secsh-publickey
|
||||
*/
|
||||
|
||||
#ifndef LIBSSH2_PUBLICKEY_H
|
||||
#define LIBSSH2_PUBLICKEY_H 1
|
||||
|
||||
typedef struct _LIBSSH2_PUBLICKEY LIBSSH2_PUBLICKEY;
|
||||
|
||||
typedef struct _libssh2_publickey_attribute {
|
||||
char *name;
|
||||
unsigned long name_len;
|
||||
char *value;
|
||||
unsigned long value_len;
|
||||
char mandatory;
|
||||
} libssh2_publickey_attribute;
|
||||
|
||||
typedef struct _libssh2_publickey_list {
|
||||
unsigned char *packet; /* For freeing */
|
||||
|
||||
unsigned char *name;
|
||||
unsigned long name_len;
|
||||
unsigned char *blob;
|
||||
unsigned long blob_len;
|
||||
unsigned long num_attrs;
|
||||
libssh2_publickey_attribute *attrs; /* free me */
|
||||
} libssh2_publickey_list;
|
||||
|
||||
/* Generally use the first macro here, but if both name and value are string literals, you can use _fast() to take advantage of preprocessing */
|
||||
#define libssh2_publickey_attribute(name, value, mandatory) { (name), strlen(name), (value), strlen(value), (mandatory) },
|
||||
#define libssh2_publickey_attribute_fast(name, value, mandatory) { (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) },
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Publickey Subsystem */
|
||||
LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session);
|
||||
|
||||
LIBSSH2_API int libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
|
||||
const unsigned char *blob, unsigned long blob_len, char overwrite,
|
||||
unsigned long num_attrs, libssh2_publickey_attribute attrs[]);
|
||||
#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, num_attrs, attrs) \
|
||||
libssh2_publickey_add_ex((pkey), (name), strlen(name), (blob), (blob_len), (overwrite), (num_attrs), (attrs))
|
||||
|
||||
LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
|
||||
const unsigned char *blob, unsigned long blob_len);
|
||||
#define libssh2_publickey_remove(pkey, name, blob, blob_len) \
|
||||
libssh2_publickey_remove_ex((pkey), (name), strlen(name), (blob), (blob_len))
|
||||
|
||||
LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned long *num_keys, libssh2_publickey_list **pkey_list);
|
||||
LIBSSH2_API void libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey, libssh2_publickey_list *pkey_list);
|
||||
|
||||
LIBSSH2_API void libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* ndef: LIBSSH2_PUBLICKEY_H */
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -38,6 +38,10 @@
|
||||
#ifndef LIBSSH2_SFTP_H
|
||||
#define LIBSSH2_SFTP_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Note: Version 6 was documented at the time of writing
|
||||
* However it was marked as "DO NOT IMPLEMENT" due to pending changes
|
||||
*
|
||||
@@ -82,7 +86,7 @@ struct _LIBSSH2_SFTP_ATTRIBUTES {
|
||||
*/
|
||||
unsigned long flags;
|
||||
|
||||
unsigned long long filesize;
|
||||
libssh2_uint64_t filesize;
|
||||
unsigned long uid, gid;
|
||||
unsigned long permissions;
|
||||
unsigned long atime, mtime;
|
||||
@@ -99,6 +103,39 @@ struct _LIBSSH2_SFTP_ATTRIBUTES {
|
||||
#define LIBSSH2_SFTP_TYPE_BLOCK_DEVICE 8
|
||||
#define LIBSSH2_SFTP_TYPE_FIFO 9
|
||||
|
||||
/*
|
||||
* Reproduce the POSIX file modes here for systems that are not
|
||||
* POSIX compliant.
|
||||
*
|
||||
* These is used in "permissions" of "struct _LIBSSH2_SFTP_ATTRIBUTES"
|
||||
*/
|
||||
/* File type */
|
||||
#define LIBSSH2_SFTP_S_IFMT 0170000 /* type of file mask */
|
||||
#define LIBSSH2_SFTP_S_IFIFO 0010000 /* named pipe (fifo) */
|
||||
#define LIBSSH2_SFTP_S_IFCHR 0020000 /* character special */
|
||||
#define LIBSSH2_SFTP_S_IFDIR 0040000 /* directory */
|
||||
#define LIBSSH2_SFTP_S_IFBLK 0060000 /* block special */
|
||||
#define LIBSSH2_SFTP_S_IFREG 0100000 /* regular */
|
||||
#define LIBSSH2_SFTP_S_IFLNK 0120000 /* symbolic link */
|
||||
#define LIBSSH2_SFTP_S_IFSOCK 0140000 /* socket */
|
||||
|
||||
/* File mode */
|
||||
/* Read, write, execute/search by owner */
|
||||
#define LIBSSH2_SFTP_S_IRWXU 0000700 /* RWX mask for owner */
|
||||
#define LIBSSH2_SFTP_S_IRUSR 0000400 /* R for owner */
|
||||
#define LIBSSH2_SFTP_S_IWUSR 0000200 /* W for owner */
|
||||
#define LIBSSH2_SFTP_S_IXUSR 0000100 /* X for owner */
|
||||
/* Read, write, execute/search by group */
|
||||
#define LIBSSH2_SFTP_S_IRWXG 0000070 /* RWX mask for group */
|
||||
#define LIBSSH2_SFTP_S_IRGRP 0000040 /* R for group */
|
||||
#define LIBSSH2_SFTP_S_IWGRP 0000020 /* W for group */
|
||||
#define LIBSSH2_SFTP_S_IXGRP 0000010 /* X for group */
|
||||
/* Read, write, execute/search by others */
|
||||
#define LIBSSH2_SFTP_S_IRWXO 0000007 /* RWX mask for other */
|
||||
#define LIBSSH2_SFTP_S_IROTH 0000004 /* R for other */
|
||||
#define LIBSSH2_SFTP_S_IWOTH 0000002 /* W for other */
|
||||
#define LIBSSH2_SFTP_S_IXOTH 0000001 /* X for other */
|
||||
|
||||
/* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open())
|
||||
* Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */
|
||||
#define LIBSSH2_FXF_READ 0x00000001
|
||||
@@ -138,7 +175,7 @@ LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp);
|
||||
LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp);
|
||||
|
||||
/* File / Directory Ops */
|
||||
LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *filename, int filename_len, unsigned long flags, long mode, int open_type);
|
||||
LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *filename, unsigned int filename_len, unsigned long flags, long mode, int open_type);
|
||||
#define libssh2_sftp_open(sftp, filename, flags, mode) libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), (mode), LIBSSH2_SFTP_OPENFILE)
|
||||
#define libssh2_sftp_opendir(sftp, path) libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, LIBSSH2_SFTP_OPENDIR)
|
||||
|
||||
@@ -162,29 +199,33 @@ LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_
|
||||
|
||||
|
||||
/* Miscellaneous Ops */
|
||||
LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filename, int srouce_filename_len,
|
||||
char *dest_filename, int dest_filename_len,
|
||||
LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filename, unsigned int srouce_filename_len,
|
||||
char *dest_filename, unsigned int dest_filename_len,
|
||||
long flags);
|
||||
#define libssh2_sftp_rename(sftp, sourcefile, destfile) libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), (destfile), strlen(destfile), \
|
||||
LIBSSH2_SFTP_RENAME_OVERWRITE | LIBSSH2_SFTP_RENAME_ATOMIC | LIBSSH2_SFTP_RENAME_NATIVE)
|
||||
|
||||
LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, int filename_len);
|
||||
LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, unsigned int filename_len);
|
||||
#define libssh2_sftp_unlink(sftp, filename) libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename))
|
||||
|
||||
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_len, long mode);
|
||||
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, unsigned int path_len, long mode);
|
||||
#define libssh2_sftp_mkdir(sftp, path, mode) libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode))
|
||||
|
||||
LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_len);
|
||||
LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, unsigned int path_len);
|
||||
#define libssh2_sftp_rmdir(sftp, path) libssh2_sftp_rmdir_ex((sftp), (path), strlen(path))
|
||||
|
||||
LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, int path_len, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs);
|
||||
LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, unsigned int path_len, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs);
|
||||
#define libssh2_sftp_stat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, (attrs))
|
||||
#define libssh2_sftp_lstat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, (attrs))
|
||||
#define libssh2_sftp_setstat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, (attrs))
|
||||
|
||||
LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, int path_len, char *target, int target_len, int link_type);
|
||||
LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, char *target, unsigned int target_len, int link_type);
|
||||
#define libssh2_sftp_symlink(sftp, orig, linkpath) libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), strlen(linkpath), LIBSSH2_SFTP_SYMLINK)
|
||||
#define libssh2_sftp_readlink(sftp, path, target, maxlen) libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), LIBSSH2_SFTP_READLINK)
|
||||
#define libssh2_sftp_realpath(sftp, path, target, maxlen) libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), LIBSSH2_SFTP_REALPATH)
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LIBSSH2_SFTP_H */
|
||||
|
44
m4/autobuild.m4
Normal file
44
m4/autobuild.m4
Normal file
@@ -0,0 +1,44 @@
|
||||
# autobuild.m4 serial 3
|
||||
# Copyright (C) 2004, 2006 Simon Josefsson
|
||||
#
|
||||
# This file is free software, distributed under the terms of the GNU
|
||||
# General Public License. As a special exception to the GNU General
|
||||
# Public License, this file may be distributed as part of a program
|
||||
# that contains a configuration script generated by Autoconf, under
|
||||
# the same distribution terms as the rest of that program.
|
||||
#
|
||||
# This file can can be used in projects which are not available under
|
||||
# the GNU General Public License or the GNU Library General Public
|
||||
# License but which still want to provide support for Autobuild.
|
||||
|
||||
# Usage: AB_INIT([MODE]).
|
||||
AC_DEFUN([AB_INIT],
|
||||
[
|
||||
AC_REQUIRE([AC_CANONICAL_BUILD])
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
|
||||
if test -z "$AB_PACKAGE"; then
|
||||
AB_PACKAGE=${PACKAGE_NAME:-$PACKAGE}
|
||||
fi
|
||||
AC_MSG_NOTICE([autobuild project... $AB_PACKAGE])
|
||||
|
||||
if test -z "$AB_VERSION"; then
|
||||
AB_VERSION=${PACKAGE_VERSION:-$VERSION}
|
||||
fi
|
||||
AC_MSG_NOTICE([autobuild revision... $AB_VERSION])
|
||||
|
||||
hostname=`hostname`
|
||||
if test "$hostname"; then
|
||||
AC_MSG_NOTICE([autobuild hostname... $hostname])
|
||||
fi
|
||||
|
||||
ifelse([$1],[],,[AC_MSG_NOTICE([autobuild mode... $1])])
|
||||
|
||||
date=`date +%Y%m%d-%H%M%S`
|
||||
if test "$?" != 0; then
|
||||
date=`date`
|
||||
fi
|
||||
if test "$date"; then
|
||||
AC_MSG_NOTICE([autobuild timestamp... $date])
|
||||
fi
|
||||
])
|
108
m4/libgcrypt.m4
Normal file
108
m4/libgcrypt.m4
Normal file
@@ -0,0 +1,108 @@
|
||||
dnl Autoconf macros for libgcrypt
|
||||
dnl Copyright (C) 2002, 2004 Free Software Foundation, Inc.
|
||||
dnl
|
||||
dnl This file is free software; as a special exception the author gives
|
||||
dnl unlimited permission to copy and/or distribute it, with or without
|
||||
dnl modifications, as long as this notice is preserved.
|
||||
dnl
|
||||
dnl This file is distributed in the hope that it will be useful, but
|
||||
dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
dnl AM_PATH_LIBGCRYPT([MINIMUM-VERSION,
|
||||
dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
|
||||
dnl Test for libgcrypt and define LIBGCRYPT_CFLAGS and LIBGCRYPT_LIBS.
|
||||
dnl MINIMUN-VERSION is a string with the version number optionalliy prefixed
|
||||
dnl with the API version to also check the API compatibility. Example:
|
||||
dnl a MINIMUN-VERSION of 1:1.2.5 won't pass the test unless the installed
|
||||
dnl version of libgcrypt is at least 1.2.5 *and* the API number is 1. Using
|
||||
dnl this features allows to prevent build against newer versions of libgcrypt
|
||||
dnl with a changed API.
|
||||
dnl
|
||||
AC_DEFUN([AM_PATH_LIBGCRYPT],
|
||||
[ AC_ARG_WITH(libgcrypt-prefix,
|
||||
AC_HELP_STRING([--with-libgcrypt-prefix=PFX],
|
||||
[prefix where LIBGCRYPT is installed (optional)]),
|
||||
libgcrypt_config_prefix="$withval", libgcrypt_config_prefix="")
|
||||
if test x$libgcrypt_config_prefix != x ; then
|
||||
if test x${LIBGCRYPT_CONFIG+set} != xset ; then
|
||||
LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_PATH_PROG(LIBGCRYPT_CONFIG, libgcrypt-config, no)
|
||||
tmp=ifelse([$1], ,1:1.2.0,$1)
|
||||
if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then
|
||||
req_libgcrypt_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'`
|
||||
min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'`
|
||||
else
|
||||
req_libgcrypt_api=0
|
||||
min_libgcrypt_version="$tmp"
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(for LIBGCRYPT - version >= $min_libgcrypt_version)
|
||||
ok=no
|
||||
if test "$LIBGCRYPT_CONFIG" != "no" ; then
|
||||
req_major=`echo $min_libgcrypt_version | \
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
|
||||
req_minor=`echo $min_libgcrypt_version | \
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
|
||||
req_micro=`echo $min_libgcrypt_version | \
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
|
||||
libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version`
|
||||
major=`echo $libgcrypt_config_version | \
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
|
||||
minor=`echo $libgcrypt_config_version | \
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
|
||||
micro=`echo $libgcrypt_config_version | \
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'`
|
||||
if test "$major" -gt "$req_major"; then
|
||||
ok=yes
|
||||
else
|
||||
if test "$major" -eq "$req_major"; then
|
||||
if test "$minor" -gt "$req_minor"; then
|
||||
ok=yes
|
||||
else
|
||||
if test "$minor" -eq "$req_minor"; then
|
||||
if test "$micro" -ge "$req_micro"; then
|
||||
ok=yes
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test $ok = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
if test $ok = yes; then
|
||||
# If we have a recent libgcrypt, we should also check that the
|
||||
# API is compatible
|
||||
if test "$req_libgcrypt_api" -gt 0 ; then
|
||||
tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0`
|
||||
if test "$tmp" -gt 0 ; then
|
||||
AC_MSG_CHECKING([LIBGCRYPT API version])
|
||||
if test "$req_libgcrypt_api" -eq "$tmp" ; then
|
||||
AC_MSG_RESULT(okay)
|
||||
else
|
||||
ok=no
|
||||
AC_MSG_RESULT([does not match. want=$req_libgcrypt_api got=$tmp])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test $ok = yes; then
|
||||
LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags`
|
||||
LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs`
|
||||
ifelse([$2], , :, [$2])
|
||||
else
|
||||
LIBGCRYPT_CFLAGS=""
|
||||
LIBGCRYPT_LIBS=""
|
||||
ifelse([$3], , :, [$3])
|
||||
fi
|
||||
AC_SUBST(LIBGCRYPT_CFLAGS)
|
||||
AC_SUBST(LIBGCRYPT_LIBS)
|
||||
])
|
18
src/.cvsignore
Normal file
18
src/.cvsignore
Normal file
@@ -0,0 +1,18 @@
|
||||
.deps
|
||||
.libs
|
||||
*.lib
|
||||
*.pdb
|
||||
*.dll
|
||||
*.exe
|
||||
*.obj
|
||||
.*.swp
|
||||
Debug
|
||||
Release
|
||||
*.exp
|
||||
Makefile
|
||||
Makefile.in
|
||||
*.lo
|
||||
libssh2.la
|
||||
libssh2_config.h
|
||||
libssh2_config.h.in
|
||||
stamp-h1
|
52
src/Makefile.am
Normal file
52
src/Makefile.am
Normal file
@@ -0,0 +1,52 @@
|
||||
AUTOMAKE_OPTIONS = foreign nostdinc
|
||||
|
||||
libssh2_la_SOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c \
|
||||
misc.c packet.c publickey.c scp.c session.c sftp.c userauth.c \
|
||||
libssh2_priv.h openssl.h libgcrypt.h pem.c
|
||||
|
||||
if LIBGCRYPT
|
||||
libssh2_la_SOURCES += libgcrypt.c
|
||||
else
|
||||
libssh2_la_SOURCES += openssl.c
|
||||
endif
|
||||
|
||||
EXTRA_DIST = libssh2_config.h.in
|
||||
|
||||
lib_LTLIBRARIES = libssh2.la
|
||||
|
||||
# srcdir/include for the shipped headers
|
||||
# builddir/src for the generated config header when building out of the source
|
||||
# tree
|
||||
INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/src
|
||||
|
||||
VERSION=-version-info 0:0:0
|
||||
|
||||
# This flag accepts an argument of the form current[:revision[:age]]. So,
|
||||
# passing -version-info 3:12:1 sets current to 3, revision to 12, and age to
|
||||
# 1.
|
||||
#
|
||||
# If either revision or age are omitted, they default to 0. Also note that age
|
||||
# must be less than or equal to the current interface number.
|
||||
#
|
||||
# Here are a set of rules to help you update your library version information:
|
||||
#
|
||||
# 1.Start with version information of 0:0:0 for each libtool library.
|
||||
#
|
||||
# 2.Update the version information only immediately before a public release of
|
||||
# your software. More frequent updates are unnecessary, and only guarantee
|
||||
# that the current interface number gets larger faster.
|
||||
#
|
||||
# 3.If the library source code has changed at all since the last update, then
|
||||
# increment revision (c:r+1:a)
|
||||
#
|
||||
# 4.If any interfaces have been added, removed, or changed since the last
|
||||
# update, increment current, and set revision to 0. (c+1:r=0:a)
|
||||
#
|
||||
# 5.If any interfaces have been added since the last public release, then
|
||||
# increment age. (c:r:a+1)
|
||||
#
|
||||
# 6.If any interfaces have been removed since the last public release, then
|
||||
# set age to 0. (c:r:a=0)
|
||||
#
|
||||
|
||||
libssh2_la_LDFLAGS = $(VERSION)
|
@@ -1,63 +0,0 @@
|
||||
OBJECTS = channel.o comp.o crypt.o hostkey.o kex.o mac.o misc.o packet.o scp.o session.o sftp.o userauth.o
|
||||
|
||||
top_srcdir = @top_srcdir@
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
libdir = @exec_prefix@/lib
|
||||
incldir = @prefix@/include
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = -c @CFLAGS@ -Wall -g -I../include/ -fPIC
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
channel.o: channel.c
|
||||
$(CC) -o channel.o channel.c $(CFLAGS) $(LIBS)
|
||||
|
||||
comp.o: comp.c
|
||||
$(CC) -o comp.o comp.c $(CFLAGS) $(LIBS)
|
||||
|
||||
crypt.o: crypt.c
|
||||
$(CC) -o crypt.o crypt.c $(CFLAGS) $(LIBS)
|
||||
|
||||
hostkey.o: hostkey.c
|
||||
$(CC) -o hostkey.o hostkey.c $(CFLAGS) $(LIBS)
|
||||
|
||||
kex.o: kex.c
|
||||
$(CC) -o kex.o kex.c $(CFLAGS) $(LIBS)
|
||||
|
||||
mac.o: mac.c
|
||||
$(CC) -o mac.o mac.c $(CFLAGS) $(LIBS)
|
||||
|
||||
misc.o: misc.c
|
||||
$(CC) -o misc.o misc.c $(CFLAGS) $(LIBS)
|
||||
|
||||
packet.o: packet.c
|
||||
$(CC) -o packet.o packet.c $(CFLAGS) $(LIBS)
|
||||
|
||||
scp.o: scp.c
|
||||
$(CC) -o scp.o scp.c $(CFLAGS) $(LIBS)
|
||||
|
||||
session.o: session.c
|
||||
$(CC) -o session.o session.c $(CFLAGS) $(LIBS)
|
||||
|
||||
sftp.o: sftp.c
|
||||
$(CC) -o sftp.o sftp.c $(CFLAGS) $(LIBS)
|
||||
|
||||
userauth.o: userauth.c
|
||||
$(CC) -o userauth.o userauth.c $(CFLAGS) $(LIBS)
|
||||
|
||||
all: libssh2.@SHLIB_SUFFIX_NAME@
|
||||
|
||||
libssh2.@SHLIB_SUFFIX_NAME@: $(OBJECTS)
|
||||
$(CC) -o libssh2.@SHLIB_SUFFIX_NAME@ $(SHLIB_LDFLAGS) $(OBJECTS) $(LIBS) $(LDFLAGS) @SHLIB_LDFLAGS@
|
||||
libssh2.a: $(OBJECTS)
|
||||
rm -f libssh2.a
|
||||
ar q libssh2.a $(OBJECTS)
|
||||
@RANLIB@ libssh2.a
|
||||
install: all
|
||||
$(INSTALL) libssh2.@SHLIB_SUFFIX_NAME@ $(libdir)
|
||||
clean:
|
||||
rm -f *~ libssh2.a libssh2.@SHLIB_SUFFIX_NAME@ *.o
|
||||
|
18
src/NMakefile
Normal file
18
src/NMakefile
Normal file
@@ -0,0 +1,18 @@
|
||||
!include "win32/config.mk"
|
||||
|
||||
CFLAGS=$(CFLAGS)
|
||||
|
||||
OBJECTS = $(INTDIR)\channel.obj $(INTDIR)\comp.obj $(INTDIR)\crypt.obj \
|
||||
$(INTDIR)\hostkey.obj $(INTDIR)\kex.obj $(INTDIR)\mac.obj \
|
||||
$(INTDIR)\misc.obj $(INTDIR)\packet.obj $(INTDIR)\scp.obj \
|
||||
$(INTDIR)\session.obj $(INTDIR)\sftp.obj $(INTDIR)\userauth.obj
|
||||
|
||||
DLL=libssh2$(SUFFIX).dll
|
||||
|
||||
$(DLL): $(OBJECTS)
|
||||
$(CC) -o $(DLL) $(DLLFLAGS) $(OBJECTS) $(LIBS)
|
||||
|
||||
all: $(DLL)
|
||||
|
||||
!include "win32/rules.mk"
|
||||
|
784
src/channel.c
784
src/channel.c
File diff suppressed because it is too large
Load Diff
109
src/comp.c
109
src/comp.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -45,10 +45,20 @@
|
||||
/* {{{ libssh2_comp_method_none_comp
|
||||
* Minimalist compression: Absolutely none
|
||||
*/
|
||||
static int libssh2_comp_method_none_comp(LIBSSH2_SESSION *session, int compress,
|
||||
unsigned char **dest, unsigned long *dest_len, unsigned long payload_limit, int *free_dest,
|
||||
const unsigned char *src, unsigned long src_len, void **abstract)
|
||||
static int libssh2_comp_method_none_comp(LIBSSH2_SESSION *session,
|
||||
int compress,
|
||||
unsigned char **dest,
|
||||
unsigned long *dest_len,
|
||||
unsigned long payload_limit,
|
||||
int *free_dest,
|
||||
const unsigned char *src,
|
||||
unsigned long src_len,
|
||||
void **abstract)
|
||||
{
|
||||
(void)session;
|
||||
(void)compress;
|
||||
(void)payload_limit;
|
||||
(void)abstract;
|
||||
*dest = (unsigned char *)src;
|
||||
*dest_len = src_len;
|
||||
|
||||
@@ -59,7 +69,7 @@ static int libssh2_comp_method_none_comp(LIBSSH2_SESSION *session, int compress,
|
||||
/* }}} */
|
||||
|
||||
static LIBSSH2_COMP_METHOD libssh2_comp_method_none = {
|
||||
"none",
|
||||
(char *)"none",
|
||||
NULL,
|
||||
libssh2_comp_method_none_comp,
|
||||
NULL
|
||||
@@ -129,28 +139,36 @@ static int libssh2_comp_method_zlib_init(LIBSSH2_SESSION *session, int compress,
|
||||
/* {{{ libssh2_comp_method_zlib_comp
|
||||
* zlib, a compression standard for all occasions
|
||||
*/
|
||||
static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
|
||||
unsigned char **dest, unsigned long *dest_len, unsigned long payload_limit, int *free_dest,
|
||||
const unsigned char *src, unsigned long src_len, void **abstract)
|
||||
static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session,
|
||||
int compress,
|
||||
unsigned char **dest,
|
||||
unsigned long *dest_len,
|
||||
unsigned long payload_limit,
|
||||
int *free_dest,
|
||||
const unsigned char *src,
|
||||
unsigned long src_len,
|
||||
void **abstract)
|
||||
{
|
||||
z_stream *strm = *abstract;
|
||||
/* A short-term alloc of a full data chunk is better than a series of reallocs */
|
||||
/* A short-term alloc of a full data chunk is better than a series of
|
||||
reallocs */
|
||||
char *out;
|
||||
int out_maxlen = compress ? src_len : (2 * src_len);
|
||||
int out_maxlen = compress ? (src_len + 4) : (2 * src_len);
|
||||
int limiter = 0;
|
||||
|
||||
/* In practice they never come smaller than this */
|
||||
if (out_maxlen < 21) {
|
||||
out_maxlen = 21;
|
||||
if (out_maxlen < 25) {
|
||||
out_maxlen = 25;
|
||||
}
|
||||
|
||||
if (out_maxlen > payload_limit) {
|
||||
if (out_maxlen > (int)payload_limit) {
|
||||
out_maxlen = payload_limit;
|
||||
}
|
||||
|
||||
strm->next_in = (char *)src;
|
||||
strm->next_in = (unsigned char *)src;
|
||||
strm->avail_in = src_len;
|
||||
out = strm->next_out = LIBSSH2_ALLOC(session, out_maxlen);
|
||||
strm->next_out = (unsigned char *)LIBSSH2_ALLOC(session, out_maxlen);
|
||||
out = (char *)strm->next_out;
|
||||
strm->avail_out = out_maxlen;
|
||||
if (!strm->next_out) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate compression/decompression buffer", 0);
|
||||
@@ -166,31 +184,70 @@ static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
|
||||
}
|
||||
if (status != Z_OK) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compress/decompression failure", 0);
|
||||
LIBSSH2_FREE(session, strm->next_out);
|
||||
LIBSSH2_FREE(session, out);
|
||||
return -1;
|
||||
}
|
||||
if (strm->avail_in) {
|
||||
unsigned long out_ofs = out_maxlen - strm->avail_out;
|
||||
|
||||
out_maxlen += compress ? strm->avail_in : (2 * strm->avail_in);
|
||||
out_maxlen += compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
|
||||
|
||||
if ((out_maxlen > payload_limit) && !compress && limiter++) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "Excessive growth in decompression phase", 0);
|
||||
LIBSSH2_FREE(session, strm->next_out);
|
||||
if ((out_maxlen > (int)payload_limit) &&
|
||||
!compress && limiter++) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
||||
"Excessive growth in decompression phase", 0);
|
||||
LIBSSH2_FREE(session, out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
out = LIBSSH2_REALLOC(session, out, out_maxlen);
|
||||
out = LIBSSH2_REALLOC(session, out, out_maxlen);
|
||||
if (!out) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to expand compress/decompression buffer", 0);
|
||||
return -1;
|
||||
}
|
||||
strm->next_out = out + out_ofs;
|
||||
strm->avail_out += compress ? strm->avail_in : (2 * strm->avail_in);
|
||||
strm->next_out = (unsigned char *)out + out_ofs;
|
||||
strm->avail_out += compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
|
||||
} else while (!strm->avail_out) {
|
||||
/* Done with input, might be a byte or two in internal buffer during compress
|
||||
* Or potentially many bytes if it's a decompress
|
||||
*/
|
||||
int grow_size = compress ? 8 : 1024;
|
||||
|
||||
if (out_maxlen >= (int)payload_limit) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "Excessive growth in decompression phase", 0);
|
||||
LIBSSH2_FREE(session, out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (grow_size > (int)(payload_limit - out_maxlen)) {
|
||||
grow_size = payload_limit - out_maxlen;
|
||||
}
|
||||
|
||||
out_maxlen += grow_size;
|
||||
strm->avail_out = grow_size;
|
||||
|
||||
out = LIBSSH2_REALLOC(session, out, out_maxlen);
|
||||
if (!out) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to expand final compress/decompress buffer", 0);
|
||||
return -1;
|
||||
}
|
||||
strm->next_out = (unsigned char *)out + out_maxlen -
|
||||
grow_size;
|
||||
|
||||
if (compress) {
|
||||
status = deflate(strm, Z_PARTIAL_FLUSH);
|
||||
} else {
|
||||
status = inflate(strm, Z_PARTIAL_FLUSH);
|
||||
}
|
||||
if (status != Z_OK) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compress/decompression failure", 0);
|
||||
LIBSSH2_FREE(session, out);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*dest = out;
|
||||
*dest = (unsigned char *)out;
|
||||
*dest_len = out_maxlen - strm->avail_out;
|
||||
*free_dest = 1;
|
||||
|
||||
@@ -224,7 +281,7 @@ static int libssh2_comp_method_zlib_dtor(LIBSSH2_SESSION *session, int compress,
|
||||
/* }}} */
|
||||
|
||||
static LIBSSH2_COMP_METHOD libssh2_comp_method_zlib = {
|
||||
"zlib",
|
||||
(char *)"zlib",
|
||||
libssh2_comp_method_zlib_init,
|
||||
libssh2_comp_method_zlib_comp,
|
||||
libssh2_comp_method_zlib_dtor,
|
||||
@@ -236,10 +293,10 @@ static LIBSSH2_COMP_METHOD libssh2_comp_method_zlib = {
|
||||
*********************** */
|
||||
|
||||
static LIBSSH2_COMP_METHOD *_libssh2_comp_methods[] = {
|
||||
&libssh2_comp_method_none,
|
||||
#ifdef LIBSSH2_HAVE_ZLIB
|
||||
&libssh2_comp_method_zlib,
|
||||
#endif /* LIBSSH2_HAVE_ZLIB */
|
||||
&libssh2_comp_method_none,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
193
src/crypt.c
193
src/crypt.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -36,9 +36,8 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#ifdef LIBSSH2_CRYPT_NONE
|
||||
#if LIBSSH2_CRYPT_NONE
|
||||
/* {{{ libssh2_crypt_none_crypt
|
||||
* Minimalist cipher: VERY secure *wink*
|
||||
*/
|
||||
@@ -59,29 +58,67 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = {
|
||||
libssh2_crypt_none_crypt,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
#endif /* LIBSSH2_CRYPT_NONE */
|
||||
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = {
|
||||
"3des-cbc",
|
||||
8, /* blocksize */
|
||||
8, /* initial value length */
|
||||
24, /* secret length */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_des_ede3_cbc,
|
||||
NULL,
|
||||
struct crypt_ctx {
|
||||
int encrypt;
|
||||
_libssh2_cipher_type(algo);
|
||||
_libssh2_cipher_ctx h;
|
||||
};
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)
|
||||
static int init (LIBSSH2_SESSION *session,
|
||||
LIBSSH2_CRYPT_METHOD *method,
|
||||
unsigned char *iv, int *free_iv,
|
||||
unsigned char *secret, int *free_secret,
|
||||
int encrypt, void **abstract)
|
||||
{
|
||||
struct crypt_ctx *ctx = LIBSSH2_ALLOC(session,
|
||||
sizeof(struct crypt_ctx));
|
||||
if (!ctx) {
|
||||
return -1;
|
||||
}
|
||||
ctx->encrypt = encrypt;
|
||||
ctx->algo = method->algo;
|
||||
if (_libssh2_cipher_init (&ctx->h, ctx->algo, iv, secret, encrypt))
|
||||
{
|
||||
LIBSSH2_FREE (session, ctx);
|
||||
return -1;
|
||||
}
|
||||
*abstract = ctx;
|
||||
*free_iv = 1;
|
||||
*free_secret = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypt(LIBSSH2_SESSION *session, unsigned char *block, void **abstract)
|
||||
{
|
||||
struct crypt_ctx *cctx = *(struct crypt_ctx **)abstract;
|
||||
return _libssh2_cipher_crypt(&cctx->h, cctx->algo,
|
||||
cctx->encrypt, block);
|
||||
}
|
||||
|
||||
static int dtor(LIBSSH2_SESSION *session, void **abstract)
|
||||
{
|
||||
struct crypt_ctx **cctx = (struct crypt_ctx **)abstract;
|
||||
if (cctx && *cctx) {
|
||||
_libssh2_cipher_dtor(&(*cctx)->h);
|
||||
LIBSSH2_FREE(session, *cctx);
|
||||
*abstract = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LIBSSH2_AES
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = {
|
||||
"aes128-cbc",
|
||||
16, /* blocksize */
|
||||
16, /* initial value length */
|
||||
16, /* secret length -- 16*8 == 128bit */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_aes_128_cbc,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_aes128
|
||||
};
|
||||
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = {
|
||||
@@ -89,10 +126,11 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = {
|
||||
16, /* blocksize */
|
||||
16, /* initial value length */
|
||||
24, /* secret length -- 24*8 == 192bit */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_aes_192_cbc,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_aes192
|
||||
};
|
||||
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = {
|
||||
@@ -100,10 +138,11 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = {
|
||||
16, /* blocksize */
|
||||
16, /* initial value length */
|
||||
32, /* secret length -- 32*8 == 256bit */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_aes_256_cbc,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_aes256
|
||||
};
|
||||
|
||||
/* rijndael-cbc@lysator.liu.se == aes256-cbc */
|
||||
@@ -112,73 +151,91 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_rijndael_cbc_lysator_liu_se = {
|
||||
16, /* blocksize */
|
||||
16, /* initial value length */
|
||||
32, /* secret length -- 32*8 == 256bit */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_aes_256_cbc,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_aes256
|
||||
};
|
||||
#endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)*/
|
||||
#endif /* LIBSSH2_AES */
|
||||
|
||||
#ifndef OPENSSL_NO_BLOWFISH
|
||||
#if LIBSSH2_BLOWFISH
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = {
|
||||
"blowfish-cbc",
|
||||
8, /* blocksize */
|
||||
8, /* initial value length */
|
||||
16, /* secret length */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_bf_cbc,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_blowfish
|
||||
};
|
||||
#endif /* ! OPENSSL_NO_BLOWFISH */
|
||||
#endif /* LIBSSH2_BLOWFISH */
|
||||
|
||||
#ifndef OPENSSL_NO_CAST
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = {
|
||||
"cast128-cbc",
|
||||
8, /* blocksize */
|
||||
8, /* initial value length */
|
||||
16, /* secret length */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_cast5_cbc,
|
||||
NULL,
|
||||
};
|
||||
#endif /* ! OPENSSL_NO_CAST */
|
||||
|
||||
#ifndef OPENSSL_NO_RC4
|
||||
#if LIBSSH2_RC4
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = {
|
||||
"arcfour",
|
||||
8, /* blocksize */
|
||||
8, /* initial value length */
|
||||
16, /* secret length */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_rc4,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_arcfour
|
||||
};
|
||||
#endif /* ! OPENSSL_NO_RC4 */
|
||||
#endif /* LIBSSH2_RC4 */
|
||||
|
||||
#if LIBSSH2_CAST
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = {
|
||||
"cast128-cbc",
|
||||
8, /* blocksize */
|
||||
8, /* initial value length */
|
||||
16, /* secret length */
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_cast5
|
||||
};
|
||||
#endif /* LIBSSH2_CAST */
|
||||
|
||||
#if LIBSSH2_3DES
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = {
|
||||
"3des-cbc",
|
||||
8, /* blocksize */
|
||||
8, /* initial value length */
|
||||
24, /* secret length */
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_3des
|
||||
};
|
||||
#endif
|
||||
|
||||
static LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = {
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)
|
||||
#if LIBSSH2_AES
|
||||
&libssh2_crypt_method_aes256_cbc,
|
||||
&libssh2_crypt_method_rijndael_cbc_lysator_liu_se, /* == aes256-cbc */
|
||||
&libssh2_crypt_method_aes192_cbc,
|
||||
&libssh2_crypt_method_aes128_cbc,
|
||||
#endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES) */
|
||||
#ifndef OPENSSL_NO_BLOWFISH
|
||||
#endif /* LIBSSH2_AES */
|
||||
#if LIBSSH2_BLOWFISH
|
||||
&libssh2_crypt_method_blowfish_cbc,
|
||||
#endif /* ! OPENSSL_NO_BLOWFISH */
|
||||
#ifndef OPENSSL_NO_RC4
|
||||
#endif /* LIBSSH2_BLOWFISH */
|
||||
#if LIBSSH2_RC4
|
||||
&libssh2_crypt_method_arcfour,
|
||||
#endif /* ! OPENSSL_NO_RC4 */
|
||||
#ifndef OPENSSL_NO_CAST
|
||||
#endif /* LIBSSH2_RC4 */
|
||||
#if LIBSSH2_CAST
|
||||
&libssh2_crypt_method_cast128_cbc,
|
||||
#endif /* ! OPENSSL_NO_CAST */
|
||||
#ifndef OPENSSL_NO_DES
|
||||
#endif /* LIBSSH2_CAST */
|
||||
#if LIBSSH2_3DES
|
||||
&libssh2_crypt_method_3des_cbc,
|
||||
#endif /* ! OPENSSL_NO_DES */
|
||||
#ifdef LIBSSH2_CRYPT_NONE
|
||||
&libssh2_crypt_method_none,
|
||||
#endif /* LIBSSH2_DES */
|
||||
#if LIBSSH2_CRYPT_NONE
|
||||
&libssh2_crypt_method_none,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
329
src/hostkey.c
329
src/hostkey.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -36,10 +36,13 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#ifndef OPENSSL_NO_RSA
|
||||
/* Needed for struct iovec on some platforms */
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#if LIBSSH2_RSA
|
||||
/* ***********
|
||||
* ssh-rsa *
|
||||
*********** */
|
||||
@@ -49,33 +52,42 @@ static int libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION *session, void **
|
||||
/* {{{ libssh2_hostkey_method_ssh_rsa_init
|
||||
* Initialize the server hostkey working area with e/n pair
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION *session, unsigned char *hostkey_data, unsigned long hostkey_data_len, void **abstract)
|
||||
static int
|
||||
libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION *session,
|
||||
unsigned char *hostkey_data,
|
||||
unsigned long hostkey_data_len,
|
||||
void **abstract)
|
||||
{
|
||||
RSA *rsactx;
|
||||
libssh2_rsa_ctx *rsactx;
|
||||
unsigned char *s, *e, *n;
|
||||
unsigned long len, e_len, n_len;
|
||||
|
||||
(void)hostkey_data_len;
|
||||
|
||||
if (*abstract) {
|
||||
libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
|
||||
*abstract = NULL;
|
||||
}
|
||||
|
||||
s = hostkey_data;
|
||||
len = libssh2_ntohu32(s); s += 4;
|
||||
if (len != 7 || strncmp(s, "ssh-rsa", 7) != 0) {
|
||||
return -1;
|
||||
} s += 7;
|
||||
len = libssh2_ntohu32(s);
|
||||
s += 4;
|
||||
|
||||
if (len != 7 || strncmp((char *)s, "ssh-rsa", 7) != 0) {
|
||||
return -1;
|
||||
}
|
||||
s += 7;
|
||||
|
||||
e_len = libssh2_ntohu32(s);
|
||||
s += 4;
|
||||
|
||||
e_len = libssh2_ntohu32(s); s += 4;
|
||||
e = s; s += e_len;
|
||||
n_len = libssh2_ntohu32(s); s += 4;
|
||||
n = s; s += n_len;
|
||||
|
||||
rsactx = RSA_new();
|
||||
rsactx->e = BN_new();
|
||||
BN_bin2bn(e, e_len, rsactx->e);
|
||||
rsactx->n = BN_new();
|
||||
BN_bin2bn(n, n_len, rsactx->n);
|
||||
if (_libssh2_rsa_new (&rsactx, e, e_len, n, n_len, NULL, 0,
|
||||
NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0))
|
||||
return -1;
|
||||
|
||||
*abstract = rsactx;
|
||||
|
||||
@@ -83,29 +95,15 @@ static int libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION *session, unsigne
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_hostkey_method_ssh_rsa_passphrase_cb
|
||||
* TODO: Optionally call a passphrase callback specified by the calling program
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_rsadsa_passphrase_cb(char *buf, int size, int rwflag, char *passphrase){
|
||||
int passphrase_len = strlen(passphrase);
|
||||
|
||||
if (passphrase_len > (size - 1)) {
|
||||
passphrase_len = size - 1;
|
||||
}
|
||||
memcpy(buf, passphrase, passphrase_len);
|
||||
buf[passphrase_len] = '\0';
|
||||
|
||||
return passphrase_len;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_hostkey_method_ssh_rsa_initPEM
|
||||
* Load a Private Key from a PEM file
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsigned char *privkeyfile, unsigned char *passphrase, void **abstract)
|
||||
static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session,
|
||||
const char *privkeyfile, unsigned const char *passphrase, void **abstract)
|
||||
{
|
||||
RSA *rsactx;
|
||||
libssh2_rsa_ctx *rsactx;
|
||||
FILE *fp;
|
||||
int ret;
|
||||
|
||||
if (*abstract) {
|
||||
libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
|
||||
@@ -116,12 +114,12 @@ static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsi
|
||||
if (!fp) {
|
||||
return -1;
|
||||
}
|
||||
rsactx = PEM_read_RSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, passphrase);
|
||||
if (!rsactx) {
|
||||
fclose(fp);
|
||||
|
||||
ret = _libssh2_rsa_new_private (&rsactx, session, fp, passphrase);
|
||||
fclose(fp);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
*abstract = rsactx;
|
||||
|
||||
@@ -132,56 +130,19 @@ static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsi
|
||||
/* {{{ libssh2_hostkey_method_ssh_rsa_sign
|
||||
* Verify signature created by remote
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION *session, const unsigned char *sig, unsigned long sig_len,
|
||||
const unsigned char *m, unsigned long m_len, void **abstract)
|
||||
static int libssh2_hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION *session,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len,
|
||||
void **abstract)
|
||||
{
|
||||
RSA *rsactx = (RSA*)(*abstract);
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
int ret;
|
||||
libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx*)(*abstract);
|
||||
(void)session;
|
||||
|
||||
/* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */
|
||||
sig += 15; sig_len -= 15;
|
||||
SHA1(m, m_len, hash);
|
||||
ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH, (char *)sig, sig_len, rsactx);
|
||||
|
||||
return (ret == 1) ? 0 : -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_hostkey_method_ssh_rsa_sign
|
||||
* Sign data to send to remote
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_rsa_sign(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len,
|
||||
const unsigned char *buf, unsigned long buf_len, void **abstract)
|
||||
{
|
||||
RSA *rsactx = (RSA*)(*abstract);
|
||||
int ret;
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
SHA_CTX ctx;
|
||||
char *sig;
|
||||
int sig_len;
|
||||
|
||||
sig_len = RSA_size(rsactx);
|
||||
sig = LIBSSH2_ALLOC(session, sig_len);
|
||||
|
||||
if (!sig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, buf, buf_len);
|
||||
SHA1_Final(hash, &ctx);
|
||||
|
||||
ret = RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sig, &sig_len, rsactx);
|
||||
if (!ret) {
|
||||
LIBSSH2_FREE(session, sig);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*signature = sig;
|
||||
*signature_len = sig_len;
|
||||
|
||||
return 0;
|
||||
return _libssh2_rsa_sha1_verify (rsactx, sig, sig_len, m, m_len);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -191,36 +152,24 @@ static int libssh2_hostkey_method_ssh_rsa_sign(LIBSSH2_SESSION *session, unsigne
|
||||
static int libssh2_hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len,
|
||||
unsigned long veccount, const struct iovec datavec[], void **abstract)
|
||||
{
|
||||
RSA *rsactx = (RSA*)(*abstract);
|
||||
int ret, i;
|
||||
libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx*)(*abstract);
|
||||
int ret;
|
||||
unsigned int i;
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
SHA_CTX ctx;
|
||||
char *sig;
|
||||
int sig_len;
|
||||
libssh2_sha1_ctx ctx;
|
||||
|
||||
sig_len = RSA_size(rsactx);
|
||||
sig = LIBSSH2_ALLOC(session, sig_len);
|
||||
|
||||
if (!sig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SHA1_Init(&ctx);
|
||||
libssh2_sha1_init(&ctx);
|
||||
for(i = 0; i < veccount; i++) {
|
||||
SHA1_Update(&ctx, datavec[i].iov_base, datavec[i].iov_len);
|
||||
libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
|
||||
}
|
||||
SHA1_Final(hash, &ctx);
|
||||
libssh2_sha1_final(ctx, hash);
|
||||
|
||||
ret = RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sig, &sig_len, rsactx);
|
||||
|
||||
if (!ret) {
|
||||
LIBSSH2_FREE(session, sig);
|
||||
ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH,
|
||||
signature, signature_len);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*signature = sig;
|
||||
*signature_len = sig_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -228,11 +177,13 @@ static int libssh2_hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION *session, unsign
|
||||
/* {{{ libssh2_hostkey_method_ssh_rsa_dtor
|
||||
* Shutdown the hostkey
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION *session, void **abstract)
|
||||
static int libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION *session,
|
||||
void **abstract)
|
||||
{
|
||||
RSA *rsactx = (RSA*)(*abstract);
|
||||
libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx*)(*abstract);
|
||||
(void)session;
|
||||
|
||||
RSA_free(rsactx);
|
||||
_libssh2_rsa_free(rsactx);
|
||||
|
||||
*abstract = NULL;
|
||||
|
||||
@@ -246,14 +197,13 @@ static LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_rsa = {
|
||||
libssh2_hostkey_method_ssh_rsa_init,
|
||||
libssh2_hostkey_method_ssh_rsa_initPEM,
|
||||
libssh2_hostkey_method_ssh_rsa_sig_verify,
|
||||
libssh2_hostkey_method_ssh_rsa_sign,
|
||||
libssh2_hostkey_method_ssh_rsa_signv,
|
||||
NULL, /* encrypt */
|
||||
libssh2_hostkey_method_ssh_rsa_dtor,
|
||||
};
|
||||
#endif /* ! OPENSSL_NO_RSA */
|
||||
#endif /* LIBSSH2_RSA */
|
||||
|
||||
#ifndef OPENSSL_NO_DSA
|
||||
#if LIBSSH2_DSA
|
||||
/* ***********
|
||||
* ssh-dss *
|
||||
*********** */
|
||||
@@ -263,11 +213,16 @@ static int libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION *session, void **
|
||||
/* {{{ libssh2_hostkey_method_ssh_dss_init
|
||||
* Initialize the server hostkey working area with p/q/g/y set
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session, unsigned char *hostkey_data, unsigned long hostkey_data_len, void **abstract)
|
||||
static int
|
||||
libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session,
|
||||
unsigned char *hostkey_data,
|
||||
unsigned long hostkey_data_len,
|
||||
void **abstract)
|
||||
{
|
||||
DSA *dsactx;
|
||||
libssh2_dsa_ctx *dsactx;
|
||||
unsigned char *p, *q, *g, *y, *s;
|
||||
unsigned long p_len, q_len, g_len, y_len, len;
|
||||
(void)hostkey_data_len;
|
||||
|
||||
if (*abstract) {
|
||||
libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
|
||||
@@ -276,7 +231,7 @@ static int libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session, unsigne
|
||||
|
||||
s = hostkey_data;
|
||||
len = libssh2_ntohu32(s); s += 4;
|
||||
if (len != 7 || strncmp(s, "ssh-dss", 7) != 0) {
|
||||
if (len != 7 || strncmp((char *)s, "ssh-dss", 7) != 0) {
|
||||
return -1;
|
||||
} s += 7;
|
||||
|
||||
@@ -289,15 +244,8 @@ static int libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session, unsigne
|
||||
y_len = libssh2_ntohu32(s); s += 4;
|
||||
y = s; s += y_len;
|
||||
|
||||
dsactx = DSA_new();
|
||||
dsactx->p = BN_new();
|
||||
BN_bin2bn(p, p_len, dsactx->p);
|
||||
dsactx->q = BN_new();
|
||||
BN_bin2bn(q, q_len, dsactx->q);
|
||||
dsactx->g = BN_new();
|
||||
BN_bin2bn(g, g_len, dsactx->g);
|
||||
dsactx->pub_key = BN_new();
|
||||
BN_bin2bn(y, y_len, dsactx->pub_key);
|
||||
_libssh2_dsa_new(&dsactx, p, p_len, q, q_len, g, g_len,
|
||||
y, y_len, NULL, 0);
|
||||
|
||||
*abstract = dsactx;
|
||||
|
||||
@@ -308,10 +256,14 @@ static int libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session, unsigne
|
||||
/* {{{ libssh2_hostkey_method_ssh_dss_initPEM
|
||||
* Load a Private Key from a PEM file
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsigned char *privkeyfile, unsigned char *passphrase, void **abstract)
|
||||
static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session,
|
||||
const char *privkeyfile,
|
||||
unsigned const char *passphrase,
|
||||
void **abstract)
|
||||
{
|
||||
DSA *dsactx;
|
||||
libssh2_dsa_ctx *dsactx;
|
||||
FILE *fp;
|
||||
int ret;
|
||||
|
||||
if (*abstract) {
|
||||
libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
|
||||
@@ -322,12 +274,12 @@ static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsi
|
||||
if (!fp) {
|
||||
return -1;
|
||||
}
|
||||
dsactx = PEM_read_DSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, passphrase);
|
||||
if (!dsactx) {
|
||||
fclose(fp);
|
||||
|
||||
ret = _libssh2_dsa_new_private (&dsactx, session, fp, passphrase);
|
||||
fclose(fp);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
*abstract = dsactx;
|
||||
|
||||
@@ -341,10 +293,7 @@ static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsi
|
||||
static int libssh2_hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION *session, const unsigned char *sig, unsigned long sig_len,
|
||||
const unsigned char *m, unsigned long m_len, void **abstract)
|
||||
{
|
||||
DSA *dsactx = (DSA*)(*abstract);
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
DSA_SIG dsasig;
|
||||
int ret;
|
||||
libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx*)(*abstract);
|
||||
|
||||
/* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
|
||||
sig += 15; sig_len -= 15;
|
||||
@@ -352,91 +301,42 @@ static int libssh2_hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION *session, c
|
||||
libssh2_error(session, LIBSSH2_ERROR_PROTO, "Invalid DSS signature length", 0);
|
||||
return -1;
|
||||
}
|
||||
dsasig.r = BN_new();
|
||||
BN_bin2bn(sig, 20, dsasig.r);
|
||||
dsasig.s = BN_new();
|
||||
BN_bin2bn(sig + 20, 20, dsasig.s);
|
||||
|
||||
SHA1(m, m_len, hash);
|
||||
ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, &dsasig, dsactx);
|
||||
|
||||
return (ret == 1) ? 0 : -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_hostkey_method_ssh_dss_sign
|
||||
* Sign data to send to remote
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_dss_sign(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len,
|
||||
const unsigned char *buf, unsigned long buf_len, void **abstract)
|
||||
{
|
||||
DSA *dsactx = (DSA*)(*abstract);
|
||||
int ret;
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
SHA_CTX ctx;
|
||||
char *sig;
|
||||
int sig_len;
|
||||
|
||||
sig_len = DSA_size(dsactx);
|
||||
sig = LIBSSH2_ALLOC(session, sig_len);
|
||||
|
||||
if (!sig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, buf, buf_len);
|
||||
SHA1_Final(hash, &ctx);
|
||||
|
||||
ret = DSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sig, &sig_len, dsactx);
|
||||
if (!ret) {
|
||||
LIBSSH2_FREE(session, sig);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*signature = sig;
|
||||
*signature_len = sig_len;
|
||||
|
||||
return 0;
|
||||
return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_hostkey_method_ssh_dss_signv
|
||||
* Construct a signature from an array of vectors
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len,
|
||||
static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len,
|
||||
unsigned long veccount, const struct iovec datavec[], void **abstract)
|
||||
{
|
||||
DSA *dsactx = (DSA*)(*abstract);
|
||||
int ret, i;
|
||||
libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx*)(*abstract);
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
SHA_CTX ctx;
|
||||
char *sig;
|
||||
int sig_len;
|
||||
libssh2_sha1_ctx ctx;
|
||||
unsigned int i;
|
||||
|
||||
sig_len = DSA_size(dsactx);
|
||||
sig = LIBSSH2_ALLOC(session, sig_len);
|
||||
*signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
|
||||
*signature_len = 2 * SHA_DIGEST_LENGTH;
|
||||
memset(*signature, 0, 2 * SHA_DIGEST_LENGTH);
|
||||
|
||||
if (!sig) {
|
||||
if (!(*signature)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SHA1_Init(&ctx);
|
||||
libssh2_sha1_init(&ctx);
|
||||
for(i = 0; i < veccount; i++) {
|
||||
SHA1_Update(&ctx, datavec[i].iov_base, datavec[i].iov_len);
|
||||
libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
|
||||
}
|
||||
SHA1_Final(hash, &ctx);
|
||||
libssh2_sha1_final(ctx, hash);
|
||||
|
||||
ret = DSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sig, &sig_len, dsactx);
|
||||
|
||||
if (!ret) {
|
||||
LIBSSH2_FREE(session, sig);
|
||||
if (_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH,
|
||||
*signature))
|
||||
{
|
||||
LIBSSH2_FREE(session, *signature);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*signature = sig;
|
||||
*signature_len = sig_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -444,11 +344,13 @@ static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsign
|
||||
/* {{{ libssh2_hostkey_method_ssh_dss_dtor
|
||||
* Shutdown the hostkey method
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION *session, void **abstract)
|
||||
static int libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION *session,
|
||||
void **abstract)
|
||||
{
|
||||
DSA *dsactx = (DSA*)(*abstract);
|
||||
libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx*)(*abstract);
|
||||
(void)session;
|
||||
|
||||
DSA_free(dsactx);
|
||||
_libssh2_dsa_free(dsactx);
|
||||
|
||||
*abstract = NULL;
|
||||
|
||||
@@ -462,20 +364,19 @@ static LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_dss = {
|
||||
libssh2_hostkey_method_ssh_dss_init,
|
||||
libssh2_hostkey_method_ssh_dss_initPEM,
|
||||
libssh2_hostkey_method_ssh_dss_sig_verify,
|
||||
libssh2_hostkey_method_ssh_dss_sign,
|
||||
libssh2_hostkey_method_ssh_dss_signv,
|
||||
NULL, /* encrypt */
|
||||
libssh2_hostkey_method_ssh_dss_dtor,
|
||||
};
|
||||
#endif /* ! OPENSSL_NO_DSA */
|
||||
#endif /* LIBSSH2_DSA */
|
||||
|
||||
static LIBSSH2_HOSTKEY_METHOD *_libssh2_hostkey_methods[] = {
|
||||
#ifndef OPENSSL_NO_RSA
|
||||
#if LIBSSH2_RSA
|
||||
&libssh2_hostkey_method_ssh_rsa,
|
||||
#endif /* ! OPENSSL_NO_RSA */
|
||||
#ifndef OPENSSL_NO_DSA
|
||||
#endif /* LIBSSH2_RSA */
|
||||
#if LIBSSH2_DSA
|
||||
&libssh2_hostkey_method_ssh_dss,
|
||||
#endif /* ! OPENSSL_NO_DSA */
|
||||
#endif /* LIBSSH2_DSA */
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -490,19 +391,17 @@ LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void)
|
||||
* Length of buffer is determined by hash type
|
||||
* i.e. MD5 == 16, SHA1 == 20
|
||||
*/
|
||||
LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type)
|
||||
LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type)
|
||||
{
|
||||
switch (hash_type) {
|
||||
#ifndef OPENSSL_NO_MD5
|
||||
#if LIBSSH2_MD5
|
||||
case LIBSSH2_HOSTKEY_HASH_MD5:
|
||||
return session->server_hostkey_md5;
|
||||
return (char *)session->server_hostkey_md5;
|
||||
break;
|
||||
#endif /* ! OPENSSL_NO_MD5 */
|
||||
#ifndef OPENSSL_NO_SHA
|
||||
#endif /* LIBSSH2_MD5 */
|
||||
case LIBSSH2_HOSTKEY_HASH_SHA1:
|
||||
return session->server_hostkey_sha1;
|
||||
return (char *)session->server_hostkey_sha1;
|
||||
break;
|
||||
#endif /* ! OPENSSL_NO_SHA */
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
482
src/kex.c
482
src/kex.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -36,60 +36,57 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
/* TODO: Switch this to an inline and handle alloc() failures */
|
||||
/* Helper macro called from libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange */
|
||||
#define LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(value, reqlen, version) \
|
||||
{ \
|
||||
SHA_CTX hash; \
|
||||
libssh2_sha1_ctx hash; \
|
||||
unsigned long len = 0; \
|
||||
if (!(value)) { \
|
||||
value = LIBSSH2_ALLOC(session, reqlen + SHA_DIGEST_LENGTH); \
|
||||
} \
|
||||
while (len < reqlen) { \
|
||||
SHA1_Init(&hash); \
|
||||
SHA1_Update(&hash, k_value, k_value_len); \
|
||||
SHA1_Update(&hash, h_sig_comp, SHA_DIGEST_LENGTH); \
|
||||
if (len > 0) { \
|
||||
SHA1_Update(&hash, value, len); \
|
||||
} else { \
|
||||
SHA1_Update(&hash, (version), 1); \
|
||||
SHA1_Update(&hash, session->session_id, session->session_id_len); \
|
||||
} \
|
||||
SHA1_Final((value) + len, &hash); \
|
||||
len += SHA_DIGEST_LENGTH; \
|
||||
} \
|
||||
} \
|
||||
while (len < reqlen) { \
|
||||
libssh2_sha1_init(&hash); \
|
||||
libssh2_sha1_update(hash, k_value, k_value_len); \
|
||||
libssh2_sha1_update(hash, h_sig_comp, SHA_DIGEST_LENGTH); \
|
||||
if (len > 0) { \
|
||||
libssh2_sha1_update(hash, value, len); \
|
||||
} else { \
|
||||
libssh2_sha1_update(hash, (version), 1); \
|
||||
libssh2_sha1_update(hash, session->session_id, session->session_id_len); \
|
||||
} \
|
||||
libssh2_sha1_final(hash, (value) + len); \
|
||||
len += SHA_DIGEST_LENGTH; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* {{{ libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange
|
||||
* Diffie Hellman Key Exchange, Group Agnostic
|
||||
*/
|
||||
static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session, BIGNUM *g, BIGNUM *p,
|
||||
static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session, _libssh2_bn *g, _libssh2_bn *p, int group_order,
|
||||
unsigned char packet_type_init, unsigned char packet_type_reply,
|
||||
unsigned char *midhash, unsigned long midhash_len)
|
||||
{
|
||||
unsigned char *e_packet = NULL, *s_packet = NULL, *tmp, h_sig_comp[SHA_DIGEST_LENGTH], c;
|
||||
unsigned long e_packet_len, s_packet_len, tmp_len;
|
||||
int ret = 0;
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BIGNUM *x = BN_new(); /* Random from client */
|
||||
BIGNUM *e = BN_new(); /* g^x mod p */
|
||||
BIGNUM *f = BN_new(); /* g^(Random from server) mod p */
|
||||
BIGNUM *k = BN_new(); /* The shared secret: f^x mod p */
|
||||
_libssh2_bn_ctx *ctx = _libssh2_bn_ctx_new();
|
||||
_libssh2_bn *x = _libssh2_bn_init(); /* Random from client */
|
||||
_libssh2_bn *e = _libssh2_bn_init(); /* g^x mod p */
|
||||
_libssh2_bn *f = _libssh2_bn_init(); /* g^(Random from server) mod p */
|
||||
_libssh2_bn *k = _libssh2_bn_init(); /* The shared secret: f^x mod p */
|
||||
unsigned char *s, *f_value, *k_value = NULL, *h_sig;
|
||||
unsigned long f_value_len, k_value_len, h_sig_len;
|
||||
SHA_CTX exchange_hash;
|
||||
libssh2_sha1_ctx exchange_hash;
|
||||
|
||||
/* Generate x and e */
|
||||
BN_rand(x, 128, 0, -1);
|
||||
BN_mod_exp(e, g, x, p, ctx);
|
||||
_libssh2_bn_rand(x, group_order, 0, -1);
|
||||
_libssh2_bn_mod_exp(e, g, x, p, ctx);
|
||||
|
||||
/* Send KEX init */
|
||||
e_packet_len = BN_num_bytes(e) + 6; /* packet_type(1) + String Length(4) + leading 0(1) */
|
||||
if (BN_num_bits(e) % 8) {
|
||||
e_packet_len = _libssh2_bn_bytes(e) + 6; /* packet_type(1) + String Length(4) + leading 0(1) */
|
||||
if (_libssh2_bn_bits(e) % 8) {
|
||||
/* Leading 00 not needed */
|
||||
e_packet_len--;
|
||||
}
|
||||
@@ -101,19 +98,42 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
}
|
||||
e_packet[0] = packet_type_init;
|
||||
libssh2_htonu32(e_packet + 1, e_packet_len - 5);
|
||||
if (BN_num_bits(e) % 8) {
|
||||
BN_bn2bin(e, e_packet + 5);
|
||||
if (_libssh2_bn_bits(e) % 8) {
|
||||
_libssh2_bn_to_bin(e, e_packet + 5);
|
||||
} else {
|
||||
e_packet[5] = 0;
|
||||
BN_bn2bin(e, e_packet + 6);
|
||||
_libssh2_bn_to_bin(e, e_packet + 6);
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending KEX packet %d", (int)packet_type_init);
|
||||
#endif
|
||||
if (libssh2_packet_write(session, e_packet, e_packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send KEX init message", 0);
|
||||
ret = -11;
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (session->burn_optimistic_kexinit) {
|
||||
/* The first KEX packet to come along will be the guess initially sent by the server
|
||||
* That guess turned out to be wrong so we need to silently ignore it */
|
||||
int burn_type;
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Waiting for badly guessed KEX packet (to be ignored)");
|
||||
#endif
|
||||
burn_type = libssh2_packet_burn(session);
|
||||
if (burn_type <= 0) {
|
||||
/* Failed to receive a packet */
|
||||
ret = -1;
|
||||
goto clean_exit;
|
||||
}
|
||||
session->burn_optimistic_kexinit = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Burnt packet of type: %02x", (unsigned int)burn_type);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Wait for KEX reply */
|
||||
if (libssh2_packet_require(session, packet_type_reply, &s_packet, &s_packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, "Timed out waiting for KEX reply", 0);
|
||||
@@ -134,25 +154,45 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
memcpy(session->server_hostkey, s, session->server_hostkey_len);
|
||||
s += session->server_hostkey_len;
|
||||
|
||||
#ifndef OPENSSL_NO_MD5
|
||||
#if LIBSSH2_MD5
|
||||
{
|
||||
MD5_CTX fingerprint_ctx;
|
||||
libssh2_md5_ctx fingerprint_ctx;
|
||||
|
||||
MD5_Init(&fingerprint_ctx);
|
||||
MD5_Update(&fingerprint_ctx, session->server_hostkey, session->server_hostkey_len);
|
||||
MD5_Final(session->server_hostkey_md5, &fingerprint_ctx);
|
||||
libssh2_md5_init(&fingerprint_ctx);
|
||||
libssh2_md5_update(fingerprint_ctx, session->server_hostkey, session->server_hostkey_len);
|
||||
libssh2_md5_final(fingerprint_ctx, session->server_hostkey_md5);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_SHA
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
{
|
||||
SHA_CTX fingerprint_ctx;
|
||||
|
||||
SHA1_Init(&fingerprint_ctx);
|
||||
SHA1_Update(&fingerprint_ctx, session->server_hostkey, session->server_hostkey_len);
|
||||
SHA1_Final(session->server_hostkey_sha1, &fingerprint_ctx);
|
||||
char fingerprint[50], *fprint = fingerprint;
|
||||
int i;
|
||||
for(i = 0; i < 16; i++, fprint += 3) {
|
||||
snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]);
|
||||
}
|
||||
*(--fprint) = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server's MD5 Fingerprint: %s", fingerprint);
|
||||
}
|
||||
#endif
|
||||
#endif /* LIBSSH2_DEBUG_KEX */
|
||||
#endif /* ! LIBSSH2_MD5 */
|
||||
|
||||
{
|
||||
libssh2_sha1_ctx fingerprint_ctx;
|
||||
|
||||
libssh2_sha1_init(&fingerprint_ctx);
|
||||
libssh2_sha1_update (fingerprint_ctx, session->server_hostkey, session->server_hostkey_len);
|
||||
libssh2_sha1_final(fingerprint_ctx, session->server_hostkey_sha1);
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
{
|
||||
char fingerprint[64], *fprint = fingerprint;
|
||||
int i;
|
||||
for(i = 0; i < 20; i++, fprint += 3) {
|
||||
snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]);
|
||||
}
|
||||
*(--fprint) = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server's SHA1 Fingerprint: %s", fingerprint);
|
||||
}
|
||||
#endif /* LIBSSH2_DEBUG_KEX */
|
||||
|
||||
if (session->hostkey->init(session, session->server_hostkey, session->server_hostkey_len, &session->server_hostkey_abstract)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, "Unable to initialize hostkey importer", 0);
|
||||
@@ -160,18 +200,17 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
|
||||
f_value_len = libssh2_ntohu32(s); s += 4;
|
||||
f_value = s; s += f_value_len;
|
||||
BN_bin2bn(f_value, f_value_len, f);
|
||||
_libssh2_bn_from_bin(f, f_value_len, f_value);
|
||||
|
||||
h_sig_len = libssh2_ntohu32(s); s += 4;
|
||||
h_sig = s;
|
||||
|
||||
/* Compute the shared secret */
|
||||
BN_mod_exp(k, f, x, p, ctx);
|
||||
k_value_len = BN_num_bytes(k) + 5;
|
||||
if (BN_num_bits(k) % 8) {
|
||||
_libssh2_bn_mod_exp(k, f, x, p, ctx);
|
||||
k_value_len = _libssh2_bn_bytes(k) + 5;
|
||||
if (_libssh2_bn_bits(k) % 8) {
|
||||
/* don't need leading 00 */
|
||||
k_value_len--;
|
||||
}
|
||||
@@ -182,39 +221,43 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
goto clean_exit;
|
||||
}
|
||||
libssh2_htonu32(k_value, k_value_len - 4);
|
||||
if (BN_num_bits(k) % 8) {
|
||||
BN_bn2bin(k, k_value + 4);
|
||||
if (_libssh2_bn_bits(k) % 8) {
|
||||
_libssh2_bn_to_bin(k, k_value + 4);
|
||||
} else {
|
||||
k_value[4] = 0;
|
||||
BN_bn2bin(k, k_value + 5);
|
||||
_libssh2_bn_to_bin(k, k_value + 5);
|
||||
}
|
||||
|
||||
SHA1_Init(&exchange_hash);
|
||||
libssh2_sha1_init(&exchange_hash);
|
||||
if (session->local.banner) {
|
||||
libssh2_htonu32(h_sig_comp, strlen(session->local.banner) - 2);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
SHA1_Update(&exchange_hash, session->local.banner, strlen(session->local.banner) - 2);
|
||||
libssh2_htonu32(h_sig_comp,
|
||||
strlen((char *)session->local.banner) - 2);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, (char *)session->local.banner,
|
||||
strlen((char *)session->local.banner) - 2);
|
||||
} else {
|
||||
libssh2_htonu32(h_sig_comp, sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
SHA1_Update(&exchange_hash, LIBSSH2_SSH_DEFAULT_BANNER, sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, LIBSSH2_SSH_DEFAULT_BANNER,
|
||||
sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
|
||||
}
|
||||
|
||||
libssh2_htonu32(h_sig_comp, strlen(session->remote.banner));
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
SHA1_Update(&exchange_hash, session->remote.banner, strlen(session->remote.banner));
|
||||
libssh2_htonu32(h_sig_comp, strlen((char *)session->remote.banner));
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, session->remote.banner,
|
||||
strlen((char *)session->remote.banner));
|
||||
|
||||
libssh2_htonu32(h_sig_comp, session->local.kexinit_len);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
SHA1_Update(&exchange_hash, session->local.kexinit, session->local.kexinit_len);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, session->local.kexinit, session->local.kexinit_len);
|
||||
|
||||
libssh2_htonu32(h_sig_comp, session->remote.kexinit_len);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
SHA1_Update(&exchange_hash, session->remote.kexinit, session->remote.kexinit_len);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, session->remote.kexinit, session->remote.kexinit_len);
|
||||
|
||||
libssh2_htonu32(h_sig_comp, session->server_hostkey_len);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
SHA1_Update(&exchange_hash, session->server_hostkey, session->server_hostkey_len);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, session->server_hostkey, session->server_hostkey_len);
|
||||
|
||||
if (packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) {
|
||||
/* diffie-hellman-group-exchange hashes additional fields */
|
||||
@@ -222,26 +265,26 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
libssh2_htonu32(h_sig_comp, LIBSSH2_DH_GEX_MINGROUP);
|
||||
libssh2_htonu32(h_sig_comp + 4, LIBSSH2_DH_GEX_OPTGROUP);
|
||||
libssh2_htonu32(h_sig_comp + 8, LIBSSH2_DH_GEX_MAXGROUP);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 12);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 12);
|
||||
#else
|
||||
libssh2_htonu32(h_sig_comp, LIBSSH2_DH_GEX_OPTGROUP);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (midhash) {
|
||||
SHA1_Update(&exchange_hash, midhash, midhash_len);
|
||||
libssh2_sha1_update(exchange_hash, midhash, midhash_len);
|
||||
}
|
||||
|
||||
SHA1_Update(&exchange_hash, e_packet + 1, e_packet_len - 1);
|
||||
libssh2_sha1_update(exchange_hash, e_packet + 1, e_packet_len - 1);
|
||||
|
||||
libssh2_htonu32(h_sig_comp, f_value_len);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
SHA1_Update(&exchange_hash, f_value, f_value_len);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, f_value, f_value_len);
|
||||
|
||||
SHA1_Update(&exchange_hash, k_value, k_value_len);
|
||||
libssh2_sha1_update(exchange_hash, k_value, k_value_len);
|
||||
|
||||
SHA1_Final(h_sig_comp, &exchange_hash);
|
||||
libssh2_sha1_final(exchange_hash, h_sig_comp);
|
||||
|
||||
if (session->hostkey->sig_verify(session, h_sig, h_sig_len, h_sig_comp, 20, &session->server_hostkey_abstract)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, "Unable to verify hostkey signature", 0);
|
||||
@@ -249,6 +292,9 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending NEWKEYS message");
|
||||
#endif
|
||||
c = SSH_MSG_NEWKEYS;
|
||||
if (libssh2_packet_write(session, &c, 1)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send NEWKEYS message", 0);
|
||||
@@ -262,7 +308,10 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
goto clean_exit;
|
||||
}
|
||||
/* The first key exchange has been performed, switch to active crypt/comp/mac mode */
|
||||
session->newkeys = 1;
|
||||
session->state |= LIBSSH2_STATE_NEWKEYS;
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Received NEWKEYS message");
|
||||
#endif
|
||||
|
||||
/* This will actually end up being just packet_type(1) for this packet type anyway */
|
||||
LIBSSH2_FREE(session, tmp);
|
||||
@@ -275,45 +324,28 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
}
|
||||
memcpy(session->session_id, h_sig_comp, SHA_DIGEST_LENGTH);
|
||||
session->session_id_len = SHA_DIGEST_LENGTH;
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "session_id calculated");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Cleanup any existing cipher */
|
||||
if (session->local.crypt->dtor) {
|
||||
session->local.crypt->dtor(session, &session->local.crypt_abstract);
|
||||
}
|
||||
|
||||
/* Calculate IV/Secret/Key for each direction */
|
||||
if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
if (session->local.crypt_abstract) {
|
||||
LIBSSH2_FREE(session, session->local.crypt_abstract);
|
||||
session->local.crypt_abstract = NULL;
|
||||
}
|
||||
} else {
|
||||
if (session->local.crypt->dtor) {
|
||||
/* Cleanup any existing cipher */
|
||||
session->local.crypt->dtor(session, &session->local.crypt_abstract);
|
||||
}
|
||||
}
|
||||
|
||||
if (session->local.crypt->init || (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP)) {
|
||||
if (session->local.crypt->init) {
|
||||
unsigned char *iv = NULL, *secret = NULL;
|
||||
int free_iv = 0, free_secret = 0;
|
||||
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, session->local.crypt->iv_len, "A");
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, session->local.crypt->secret_len, "C");
|
||||
if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
EVP_CIPHER *(*get_cipher)(void) = (void*)session->local.crypt->crypt;
|
||||
EVP_CIPHER *cipher = get_cipher();
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
ctx = LIBSSH2_ALLOC(session, sizeof(EVP_CIPHER_CTX));
|
||||
if (!ctx) {
|
||||
LIBSSH2_FREE(session, iv);
|
||||
LIBSSH2_FREE(session, secret);
|
||||
ret = -1;
|
||||
goto clean_exit;
|
||||
}
|
||||
EVP_CipherInit(ctx, cipher, secret, iv, 1);
|
||||
session->local.crypt_abstract = ctx;
|
||||
free_iv = 1;
|
||||
free_secret = 1;
|
||||
} else {
|
||||
session->local.crypt->init(session, iv, &free_iv, secret, &free_secret, 1, &session->local.crypt_abstract);
|
||||
if (session->local.crypt->init(session, session->local.crypt, iv, &free_iv, secret, &free_secret, 1, &session->local.crypt_abstract)) {
|
||||
LIBSSH2_FREE(session, iv);
|
||||
LIBSSH2_FREE(session, secret);
|
||||
ret = -1;
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (free_iv) {
|
||||
@@ -326,43 +358,26 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
LIBSSH2_FREE(session, secret);
|
||||
}
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Client to Server IV and Key calculated");
|
||||
#endif
|
||||
|
||||
if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
if (session->remote.crypt_abstract) {
|
||||
LIBSSH2_FREE(session, session->remote.crypt_abstract);
|
||||
session->remote.crypt_abstract = NULL;
|
||||
}
|
||||
} else {
|
||||
if (session->remote.crypt->dtor) {
|
||||
/* Cleanup any existing cipher */
|
||||
session->remote.crypt->dtor(session, &session->remote.crypt_abstract);
|
||||
}
|
||||
if (session->remote.crypt->dtor) {
|
||||
/* Cleanup any existing cipher */
|
||||
session->remote.crypt->dtor(session, &session->remote.crypt_abstract);
|
||||
}
|
||||
|
||||
if (session->remote.crypt->init || (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP)) {
|
||||
if (session->remote.crypt->init) {
|
||||
unsigned char *iv = NULL, *secret = NULL;
|
||||
int free_iv = 0, free_secret = 0;
|
||||
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, session->remote.crypt->iv_len, "B");
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, session->remote.crypt->secret_len, "D");
|
||||
if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
EVP_CIPHER *(*get_cipher)(void) = (void*)session->remote.crypt->crypt;
|
||||
EVP_CIPHER *cipher = get_cipher();
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
ctx = LIBSSH2_ALLOC(session, sizeof(EVP_CIPHER_CTX));
|
||||
if (!ctx) {
|
||||
LIBSSH2_FREE(session, iv);
|
||||
LIBSSH2_FREE(session, secret);
|
||||
ret = -1;
|
||||
goto clean_exit;
|
||||
}
|
||||
EVP_CipherInit(ctx, cipher, secret, iv, 0);
|
||||
session->remote.crypt_abstract = ctx;
|
||||
free_iv = 1;
|
||||
free_secret = 1;
|
||||
} else {
|
||||
session->remote.crypt->init(session, iv, &free_iv, secret, &free_secret, 0, &session->remote.crypt_abstract);
|
||||
if (session->remote.crypt->init(session, session->remote.crypt, iv, &free_iv, secret, &free_secret, 0, &session->remote.crypt_abstract)) {
|
||||
LIBSSH2_FREE(session, iv);
|
||||
LIBSSH2_FREE(session, secret);
|
||||
ret = -1;
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (free_iv) {
|
||||
@@ -375,6 +390,9 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
LIBSSH2_FREE(session, secret);
|
||||
}
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server to Client IV and Key calculated");
|
||||
#endif
|
||||
|
||||
if (session->local.mac->dtor) {
|
||||
session->local.mac->dtor(session, &session->local.mac_abstract);
|
||||
@@ -384,14 +402,17 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
unsigned char *key = NULL;
|
||||
int free_key = 0;
|
||||
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->kex->key_len, "E");
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->local.mac->key_len, "E");
|
||||
session->local.mac->init(session, key, &free_key, &session->local.mac_abstract);
|
||||
|
||||
if (free_key) {
|
||||
memset(key, 0, session->kex->key_len);
|
||||
memset(key, 0, session->local.mac->key_len);
|
||||
LIBSSH2_FREE(session, key);
|
||||
}
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Client to Server HMAC Key calculated");
|
||||
#endif
|
||||
|
||||
if (session->remote.mac->dtor) {
|
||||
session->remote.mac->dtor(session, &session->remote.mac_abstract);
|
||||
@@ -401,21 +422,24 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
unsigned char *key = NULL;
|
||||
int free_key = 0;
|
||||
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->kex->key_len, "F");
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->remote.mac->key_len, "F");
|
||||
session->remote.mac->init(session, key, &free_key, &session->remote.mac_abstract);
|
||||
|
||||
if (free_key) {
|
||||
memset(key, 0, session->kex->key_len);
|
||||
memset(key, 0, session->remote.mac->key_len);
|
||||
LIBSSH2_FREE(session, key);
|
||||
}
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server to Client HMAC Key calculated");
|
||||
#endif
|
||||
|
||||
clean_exit:
|
||||
BN_clear_free(x);
|
||||
BN_clear_free(e);
|
||||
BN_clear_free(f);
|
||||
BN_clear_free(k);
|
||||
BN_CTX_free(ctx);
|
||||
_libssh2_bn_free(x);
|
||||
_libssh2_bn_free(e);
|
||||
_libssh2_bn_free(f);
|
||||
_libssh2_bn_free(k);
|
||||
_libssh2_bn_ctx_free(ctx);
|
||||
|
||||
if (e_packet) {
|
||||
LIBSSH2_FREE(session, e_packet);
|
||||
@@ -461,18 +485,21 @@ static int libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SE
|
||||
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
/* g == 2 */
|
||||
BIGNUM *p = BN_new(); /* SSH2 defined value (p_value) */
|
||||
BIGNUM *g = BN_new(); /* SSH2 defined value (2) */
|
||||
_libssh2_bn *p = _libssh2_bn_init(); /* SSH2 defined value (p_value) */
|
||||
_libssh2_bn *g = _libssh2_bn_init(); /* SSH2 defined value (2) */
|
||||
int ret;
|
||||
|
||||
/* Initialize P and G */
|
||||
BN_set_word(g, 2);
|
||||
BN_bin2bn(p_value, 128, p);
|
||||
_libssh2_bn_set_word(g, 2);
|
||||
_libssh2_bn_from_bin(p, 128, p_value);
|
||||
|
||||
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, NULL, 0);
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group1 Key Exchange");
|
||||
#endif
|
||||
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, 128, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, NULL, 0);
|
||||
|
||||
BN_clear_free(p);
|
||||
BN_clear_free(g);
|
||||
_libssh2_bn_free(p);
|
||||
_libssh2_bn_free(g);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -517,18 +544,21 @@ static int libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_S
|
||||
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
/* g == 2 */
|
||||
BIGNUM *p = BN_new(); /* SSH2 defined value (p_value) */
|
||||
BIGNUM *g = BN_new(); /* SSH2 defined value (2) */
|
||||
_libssh2_bn *p = _libssh2_bn_init(); /* SSH2 defined value (p_value) */
|
||||
_libssh2_bn *g = _libssh2_bn_init(); /* SSH2 defined value (2) */
|
||||
int ret;
|
||||
|
||||
/* Initialize P and G */
|
||||
BN_set_word(g, 2);
|
||||
BN_bin2bn(p_value, 256, p);
|
||||
_libssh2_bn_set_word(g, 2);
|
||||
_libssh2_bn_from_bin(p, 256, p_value);
|
||||
|
||||
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, NULL, 0);
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group14 Key Exchange");
|
||||
#endif
|
||||
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, 256, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, NULL, 0);
|
||||
|
||||
BN_clear_free(p);
|
||||
BN_clear_free(g);
|
||||
_libssh2_bn_free(p);
|
||||
_libssh2_bn_free(g);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -541,9 +571,9 @@ static int libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_S
|
||||
static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LIBSSH2_SESSION *session)
|
||||
{
|
||||
unsigned char request[13], *s, *data;
|
||||
unsigned long data_len, len, request_len;
|
||||
BIGNUM *p = BN_new();
|
||||
BIGNUM *g = BN_new();
|
||||
unsigned long data_len, p_len, g_len, request_len;
|
||||
_libssh2_bn *p = _libssh2_bn_init ();
|
||||
_libssh2_bn *g = _libssh2_bn_init ();
|
||||
int ret;
|
||||
|
||||
/* Ask for a P and G pair */
|
||||
@@ -553,10 +583,16 @@ static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LI
|
||||
libssh2_htonu32(request + 5, LIBSSH2_DH_GEX_OPTGROUP);
|
||||
libssh2_htonu32(request + 9, LIBSSH2_DH_GEX_MAXGROUP);
|
||||
request_len = 13;
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group-Exchange (New Method)");
|
||||
#endif
|
||||
#else
|
||||
request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD;
|
||||
libssh2_htonu32(request + 1, LIBSSH2_DH_GEX_OPTGROUP);
|
||||
request_len = 5;
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group-Exchange (Old Method)");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (libssh2_packet_write(session, request, request_len)) {
|
||||
@@ -572,19 +608,19 @@ static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LI
|
||||
}
|
||||
|
||||
s = data + 1;
|
||||
len = libssh2_ntohu32(s); s += 4;
|
||||
BN_bin2bn(s, len, p); s += len;
|
||||
p_len = libssh2_ntohu32(s); s += 4;
|
||||
_libssh2_bn_from_bin(p, p_len, s); s += p_len;
|
||||
|
||||
len = libssh2_ntohu32(s); s += 4;
|
||||
BN_bin2bn(s, len, g); s += len;
|
||||
g_len = libssh2_ntohu32(s); s += 4;
|
||||
_libssh2_bn_from_bin(g, g_len, s); s += g_len;
|
||||
|
||||
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, SSH_MSG_KEX_DH_GEX_INIT, SSH_MSG_KEX_DH_GEX_REPLY, data + 1, data_len - 1);
|
||||
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, p_len, SSH_MSG_KEX_DH_GEX_INIT, SSH_MSG_KEX_DH_GEX_REPLY, data + 1, data_len - 1);
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
dh_gex_clean_exit:
|
||||
BN_clear_free(g);
|
||||
BN_clear_free(p);
|
||||
_libssh2_bn_free(g);
|
||||
_libssh2_bn_free(p);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -595,21 +631,18 @@ static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LI
|
||||
|
||||
LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group1_sha1 = {
|
||||
"diffie-hellman-group1-sha1",
|
||||
SHA_DIGEST_LENGTH,
|
||||
libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange,
|
||||
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
|
||||
};
|
||||
|
||||
LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group14_sha1 = {
|
||||
"diffie-hellman-group14-sha1",
|
||||
SHA_DIGEST_LENGTH,
|
||||
libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange,
|
||||
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
|
||||
};
|
||||
|
||||
LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group_exchange_sha1 = {
|
||||
"diffie-hellman-group-exchange-sha1",
|
||||
SHA_DIGEST_LENGTH,
|
||||
libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange,
|
||||
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
|
||||
};
|
||||
@@ -720,8 +753,7 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
|
||||
|
||||
*(s++) = SSH_MSG_KEXINIT;
|
||||
|
||||
/* TODO: Build a better cookie (and the mice will beat a path to my door...) */
|
||||
memcpy(s, "mysecretMYSECRET", 16);
|
||||
libssh2_random(s, 16);
|
||||
s += 16;
|
||||
|
||||
/* Ennumerating through these lists twice is probably (certainly?) inefficient from a CPU standpoint, but it saves multiple malloc/realloc calls */
|
||||
@@ -749,6 +781,23 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
|
||||
*(s++) = 0;
|
||||
*(s++) = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
{
|
||||
/* Funnily enough, they'll all "appear" to be '\0' terminated */
|
||||
char *p = data + 21; /* type(1) + cookie(16) + len(4) */
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent KEX: %s", p); p += kex_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent HOSTKEY: %s", p); p += hostkey_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_CS: %s", p); p += crypt_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_SC: %s", p); p += crypt_sc_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_CS: %s", p); p += mac_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_SC: %s", p); p += mac_sc_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_CS: %s", p); p += comp_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_SC: %s", p); p += comp_sc_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_CS: %s", p); p += lang_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_SC: %s", p); p += lang_sc_len + 4;
|
||||
}
|
||||
#endif /* LIBSSH2_DEBUG_KEX */
|
||||
if (libssh2_packet_write(session, data, data_len)) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send KEXINIT packet to remote host", 0);
|
||||
@@ -857,7 +906,7 @@ static int libssh2_kex_agree_hostkey(LIBSSH2_SESSION *session, unsigned long kex
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((*hostkeyp)->name) {
|
||||
while (hostkeyp && (*hostkeyp)->name) {
|
||||
s = libssh2_kex_agree_instr(hostkey, hostkey_len, (*hostkeyp)->name, strlen((*hostkeyp)->name));
|
||||
if (s) {
|
||||
/* So far so good, but does it suit our purposes? (Encrypting vs Signing) */
|
||||
@@ -892,9 +941,9 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
|
||||
s = session->kex_prefs;
|
||||
|
||||
while (s && *s) {
|
||||
unsigned char *p = strchr(s, ',');
|
||||
unsigned char *q, *p = strchr(s, ',');
|
||||
int method_len = (p ? (p - s) : strlen(s));
|
||||
if (libssh2_kex_agree_instr(kex, kex_len, s, method_len)) {
|
||||
if ((q = libssh2_kex_agree_instr(kex, kex_len, s, method_len))) {
|
||||
LIBSSH2_KEX_METHOD *method = (LIBSSH2_KEX_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)kexp);
|
||||
|
||||
if (!method) {
|
||||
@@ -907,6 +956,12 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
|
||||
*/
|
||||
if (libssh2_kex_agree_hostkey(session, method->flags, hostkey, hostkey_len) == 0) {
|
||||
session->kex = method;
|
||||
if (session->burn_optimistic_kexinit && (kex == q)) {
|
||||
/* Server sent an optimistic packet,
|
||||
* and client agrees with preference
|
||||
* cancel burning the first KEX_INIT packet that comes in */
|
||||
session->burn_optimistic_kexinit = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -924,6 +979,12 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
|
||||
*/
|
||||
if (libssh2_kex_agree_hostkey(session, (*kexp)->flags, hostkey, hostkey_len) == 0) {
|
||||
session->kex = *kexp;
|
||||
if (session->burn_optimistic_kexinit && (kex == s)) {
|
||||
/* Server sent an optimistic packet,
|
||||
* and client agrees with preference
|
||||
* cancel burning the first KEX_INIT packet that comes in */
|
||||
session->burn_optimistic_kexinit = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -936,7 +997,10 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
|
||||
/* {{{ libssh2_kex_agree_crypt
|
||||
* Agree on a cipher algo
|
||||
*/
|
||||
static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *crypt, unsigned long crypt_len)
|
||||
static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session,
|
||||
libssh2_endpoint_data *endpoint,
|
||||
unsigned char *crypt,
|
||||
unsigned long crypt_len)
|
||||
{
|
||||
LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods();
|
||||
unsigned char *s;
|
||||
@@ -949,7 +1013,8 @@ static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_da
|
||||
int method_len = (p ? (p - s) : strlen(s));
|
||||
|
||||
if (libssh2_kex_agree_instr(crypt, crypt_len, s, method_len)) {
|
||||
LIBSSH2_CRYPT_METHOD *method = (LIBSSH2_CRYPT_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)cryptp);
|
||||
LIBSSH2_CRYPT_METHOD *method =
|
||||
(LIBSSH2_CRYPT_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)cryptp);
|
||||
|
||||
if (!method) {
|
||||
/* Invalid method -- Should never be reached */
|
||||
@@ -965,7 +1030,7 @@ static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_da
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((*cryptp)->name) {
|
||||
while (*cryptp && (*cryptp)->name) {
|
||||
s = libssh2_kex_agree_instr(crypt, crypt_len, (*cryptp)->name, strlen((*cryptp)->name));
|
||||
if (s) {
|
||||
endpoint->crypt = *cryptp;
|
||||
@@ -1010,7 +1075,7 @@ static int libssh2_kex_agree_mac(LIBSSH2_SESSION *session, libssh2_endpoint_data
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((*macp)->name) {
|
||||
while (*macp && (*macp)->name) {
|
||||
s = libssh2_kex_agree_instr(mac, mac_len, (*macp)->name, strlen((*macp)->name));
|
||||
if (s) {
|
||||
endpoint->mac = *macp;
|
||||
@@ -1055,7 +1120,7 @@ static int libssh2_kex_agree_comp(LIBSSH2_SESSION *session, libssh2_endpoint_dat
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((*compp)->name) {
|
||||
while (*compp && (*compp)->name) {
|
||||
s = libssh2_kex_agree_instr(comp, comp_len, (*compp)->name, strlen((*compp)->name));
|
||||
if (s) {
|
||||
endpoint->comp = *compp;
|
||||
@@ -1099,6 +1164,12 @@ static int libssh2_kex_agree_methods(LIBSSH2_SESSION *session, unsigned char *da
|
||||
lang_cs_len = libssh2_ntohu32(s); lang_cs = s + 4; s += 4 + lang_cs_len;
|
||||
lang_sc_len = libssh2_ntohu32(s); lang_sc = s + 4; s += 4 + lang_sc_len;
|
||||
|
||||
/* If the server sent an optimistic packet, assume that it guessed wrong.
|
||||
* If the guess is determined to be right (by libssh2_kex_agree_kex_hostkey)
|
||||
* This flag will be reset to zero so that it's not ignored */
|
||||
session->burn_optimistic_kexinit = *(s++);
|
||||
/* Next uint32 in packet is all zeros (reserved) */
|
||||
|
||||
if (libssh2_kex_agree_kex_hostkey(session, kex, kex_len, hostkey, hostkey_len)) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1123,6 +1194,19 @@ static int libssh2_kex_agree_methods(LIBSSH2_SESSION *session, unsigned char *da
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on KEX method: %s", session->kex->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on HOSTKEY method: %s", session->hostkey->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_CS method: %s", session->local.crypt->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_SC method: %s", session->remote.crypt->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_CS method: %s", session->local.mac->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_SC method: %s", session->remote.mac->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_CS method: %s", session->local.comp->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_SC method: %s", session->remote.comp->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_CS method:"); /* None yet */
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_SC method:"); /* None yet */
|
||||
#endif
|
||||
|
||||
/* Initialize compression layer */
|
||||
if (session->local.comp && session->local.comp->init &&
|
||||
session->local.comp->init(session, 1, &session->local.comp_abstract)) {
|
||||
@@ -1148,7 +1232,7 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
|
||||
unsigned long data_len;
|
||||
|
||||
/* Prevent loop in packet_add() */
|
||||
session->exchanging_keys = 1;
|
||||
session->state |= LIBSSH2_STATE_EXCHANGING_KEYS;
|
||||
|
||||
if (reexchange) {
|
||||
session->kex = NULL;
|
||||
@@ -1160,7 +1244,23 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
|
||||
}
|
||||
|
||||
if (!session->kex || !session->hostkey) {
|
||||
/* Preserve in case of failure */
|
||||
unsigned char *oldlocal = session->local.kexinit;
|
||||
unsigned long oldlocal_len = session->local.kexinit_len;
|
||||
|
||||
session->local.kexinit = NULL;
|
||||
if (libssh2_kexinit(session)) {
|
||||
session->local.kexinit = oldlocal;
|
||||
session->local.kexinit_len = oldlocal_len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_packet_require(session, SSH_MSG_KEXINIT, &data, &data_len)) {
|
||||
if (session->local.kexinit) {
|
||||
LIBSSH2_FREE(session, session->local.kexinit);
|
||||
}
|
||||
session->local.kexinit = oldlocal;
|
||||
session->local.kexinit_len = oldlocal_len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1170,10 +1270,6 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
|
||||
session->remote.kexinit = data;
|
||||
session->remote.kexinit_len = data_len;
|
||||
|
||||
if (libssh2_kexinit(session)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_kex_agree_methods(session, data, data_len)) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1194,7 +1290,7 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
|
||||
session->remote.kexinit = NULL;
|
||||
}
|
||||
|
||||
session->exchanging_keys = 0;
|
||||
session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1203,7 +1299,7 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
|
||||
/* {{{ libssh2_session_method_pref
|
||||
* Set preferred method
|
||||
*/
|
||||
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, char *prefs)
|
||||
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, const char *prefs)
|
||||
{
|
||||
char **prefvar, *s, *newprefs;
|
||||
int prefs_len = strlen(prefs);
|
||||
@@ -1251,6 +1347,7 @@ LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method
|
||||
mlist = NULL;
|
||||
break;
|
||||
default:
|
||||
libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid parameter specified for method_type", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1282,6 +1379,7 @@ LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method
|
||||
}
|
||||
|
||||
if (strlen(newprefs) == 0) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, "The requested method(s) are not currently supported", 0);
|
||||
LIBSSH2_FREE(session, newprefs);
|
||||
return -1;
|
||||
}
|
||||
|
567
src/libgcrypt.c
Normal file
567
src/libgcrypt.c
Normal file
@@ -0,0 +1,567 @@
|
||||
/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
* Author: Simon Josefsson
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names
|
||||
* of any other contributors may be used to endorse or
|
||||
* promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <string.h>
|
||||
|
||||
int _libssh2_rsa_new(libssh2_rsa_ctx **rsa,
|
||||
const unsigned char *edata,
|
||||
unsigned long elen,
|
||||
const unsigned char *ndata,
|
||||
unsigned long nlen,
|
||||
const unsigned char *ddata,
|
||||
unsigned long dlen,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *e1data,
|
||||
unsigned long e1len,
|
||||
const unsigned char *e2data,
|
||||
unsigned long e2len,
|
||||
const unsigned char *coeffdata,
|
||||
unsigned long coefflen)
|
||||
{
|
||||
int rc;
|
||||
(void)e1data;
|
||||
(void)e1len;
|
||||
(void)e2data;
|
||||
(void)e2len;
|
||||
|
||||
if (ddata) {
|
||||
rc = gcry_sexp_build
|
||||
(rsa, NULL,
|
||||
"(private-key(rsa(n%b)(e%b)(d%b)(q%b)(p%b)(u%b)))",
|
||||
nlen, ndata, elen, edata, dlen, ddata, plen, pdata,
|
||||
qlen, qdata, coefflen, coeffdata);
|
||||
} else {
|
||||
rc = gcry_sexp_build (rsa, NULL, "(public-key(rsa(n%b)(e%b)))",
|
||||
nlen, ndata, elen, edata);
|
||||
}
|
||||
if (rc)
|
||||
{
|
||||
*rsa = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx *rsa,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len)
|
||||
{
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
gcry_sexp_t s_sig, s_hash;
|
||||
int rc = -1;
|
||||
|
||||
libssh2_sha1(m, m_len, hash);
|
||||
|
||||
rc = gcry_sexp_build (&s_hash, NULL,
|
||||
"(data (flags pkcs1) (hash sha1 %b))",
|
||||
SHA_DIGEST_LENGTH, hash);
|
||||
if (rc != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s %b)))",
|
||||
sig_len, sig);
|
||||
if (rc != 0) {
|
||||
gcry_sexp_release (s_hash);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = gcry_pk_verify (s_sig, s_hash, rsa);
|
||||
gcry_sexp_release (s_sig);
|
||||
gcry_sexp_release (s_hash);
|
||||
|
||||
return (rc == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_new(libssh2_dsa_ctx **dsactx,
|
||||
const unsigned char *p,
|
||||
unsigned long p_len,
|
||||
const unsigned char *q,
|
||||
unsigned long q_len,
|
||||
const unsigned char *g,
|
||||
unsigned long g_len,
|
||||
const unsigned char *y,
|
||||
unsigned long y_len,
|
||||
const unsigned char *x,
|
||||
unsigned long x_len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (x_len) {
|
||||
rc = gcry_sexp_build
|
||||
(dsactx, NULL,
|
||||
"(private-key(dsa(p%b)(q%b)(g%b)(y%b)(x%b)))",
|
||||
p_len, p, q_len, q, g_len, g, y_len, y, x_len, x);
|
||||
} else {
|
||||
rc = gcry_sexp_build (dsactx, NULL,
|
||||
"(public-key(dsa(p%b)(q%b)(g%b)(y%b)))",
|
||||
p_len, p, q_len, q, g_len, g, y_len, y);
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
*dsactx = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_rsa_new_private (libssh2_rsa_ctx **rsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase)
|
||||
{
|
||||
char *data, *save_data;
|
||||
unsigned int datalen;
|
||||
int ret;
|
||||
char *n, *e, *d, *p, *q, *e1, *e2, *coeff;
|
||||
unsigned int nlen, elen, dlen, plen, qlen, e1len, e2len, coefflen;
|
||||
|
||||
(void)passphrase;
|
||||
|
||||
ret = _libssh2_pem_parse (session,
|
||||
"-----BEGIN RSA PRIVATE KEY-----",
|
||||
"-----END RSA PRIVATE KEY-----",
|
||||
fp, &data, &datalen);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
save_data = data;
|
||||
|
||||
if (_libssh2_pem_decode_sequence (&data, &datalen)) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
/* First read Version field (should be 0). */
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &n, &nlen);
|
||||
if (ret != 0 || (nlen != 1 && *n != '\0')) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &n, &nlen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &e, &elen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &d, &dlen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &p, &plen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &q, &qlen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &e1, &e1len);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &e2, &e2len);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &coeff, &coefflen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (_libssh2_rsa_new (rsa, e, elen, n, nlen, d, dlen, p, plen,
|
||||
q, qlen, e1, e1len, e2, e2len,
|
||||
coeff, coefflen)) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
fail:
|
||||
LIBSSH2_FREE (session, save_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_new_private (libssh2_dsa_ctx **dsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase)
|
||||
{
|
||||
char *data, *save_data;
|
||||
unsigned int datalen;
|
||||
int ret;
|
||||
char *p, *q, *g, *y, *x;
|
||||
unsigned int plen, qlen, glen, ylen, xlen;
|
||||
|
||||
(void)passphrase;
|
||||
|
||||
ret = _libssh2_pem_parse (session,
|
||||
"-----BEGIN DSA PRIVATE KEY-----",
|
||||
"-----END DSA PRIVATE KEY-----",
|
||||
fp, &data, &datalen);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
save_data = data;
|
||||
|
||||
if (_libssh2_pem_decode_sequence (&data, &datalen)) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* First read Version field (should be 0). */
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &p, &plen);
|
||||
if (ret != 0 || (plen != 1 && *p != '\0')) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &p, &plen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &q, &qlen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &g, &glen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &y, &ylen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &x, &xlen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (datalen != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (_libssh2_dsa_new (dsa, p, plen, q, qlen,
|
||||
g, glen, y, ylen, x, xlen)) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
fail:
|
||||
LIBSSH2_FREE (session, save_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION *session,
|
||||
libssh2_dsa_ctx *rsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char **signature,
|
||||
unsigned long *signature_len)
|
||||
{
|
||||
gcry_sexp_t sig_sexp;
|
||||
gcry_sexp_t data;
|
||||
int rc;
|
||||
const char *tmp;
|
||||
size_t size;
|
||||
|
||||
if (hash_len != SHA_DIGEST_LENGTH) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gcry_sexp_build (&data, NULL,
|
||||
"(data (flags pkcs1) (hash sha1 %b))",
|
||||
hash_len, hash)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = gcry_pk_sign (&sig_sexp, data, rsactx);
|
||||
|
||||
gcry_sexp_release (data);
|
||||
|
||||
if (rc != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data = gcry_sexp_find_token(sig_sexp, "s", 0);
|
||||
if (!data) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp = gcry_sexp_nth_data(data, 1, &size);
|
||||
if (!tmp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tmp[0] == '\0') {
|
||||
tmp++;
|
||||
size--;
|
||||
}
|
||||
|
||||
*signature = LIBSSH2_ALLOC(session, size);
|
||||
memcpy (*signature, tmp, size);
|
||||
*signature_len = size;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx *dsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char *sig)
|
||||
{
|
||||
unsigned char zhash[SHA_DIGEST_LENGTH+1];
|
||||
gcry_sexp_t sig_sexp;
|
||||
gcry_sexp_t data;
|
||||
int ret;
|
||||
const char *tmp;
|
||||
size_t size;
|
||||
|
||||
if (hash_len != SHA_DIGEST_LENGTH) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy (zhash + 1, hash, hash_len);
|
||||
zhash[0] = 0;
|
||||
|
||||
if (gcry_sexp_build (&data, NULL, "(data (value %b))",
|
||||
hash_len + 1, zhash)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = gcry_pk_sign (&sig_sexp, data, dsactx);
|
||||
|
||||
gcry_sexp_release (data);
|
||||
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Extract R. */
|
||||
|
||||
data = gcry_sexp_find_token(sig_sexp, "r", 0);
|
||||
if (!data) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp = gcry_sexp_nth_data(data, 1, &size);
|
||||
if (!tmp) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tmp[0] == '\0') {
|
||||
tmp++;
|
||||
size--;
|
||||
}
|
||||
|
||||
if (size != 20) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy (sig, tmp, 20);
|
||||
|
||||
gcry_sexp_release (data);
|
||||
|
||||
/* Extract S. */
|
||||
|
||||
data = gcry_sexp_find_token(sig_sexp, "s",0);
|
||||
if (!data) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp = gcry_sexp_nth_data(data, 1, &size);
|
||||
if (!tmp) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tmp[0] == '\0') {
|
||||
tmp++;
|
||||
size--;
|
||||
}
|
||||
|
||||
if (size != 20) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy (sig + 20, tmp, 20);
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
if (sig_sexp) {
|
||||
gcry_sexp_release (sig_sexp);
|
||||
}
|
||||
if (data) {
|
||||
gcry_sexp_release (data);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx *dsactx,
|
||||
const unsigned char *sig,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len)
|
||||
{
|
||||
unsigned char hash[SHA_DIGEST_LENGTH+1];
|
||||
gcry_sexp_t s_sig, s_hash;
|
||||
int rc = -1;
|
||||
|
||||
libssh2_sha1(m, m_len, hash+1);
|
||||
hash[0] = 0;
|
||||
|
||||
if (gcry_sexp_build (&s_hash, NULL, "(data(flags raw)(value %b))",
|
||||
SHA_DIGEST_LENGTH+1, hash)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gcry_sexp_build (&s_sig, NULL, "(sig-val(dsa(r %b)(s %b)))",
|
||||
20, sig, 20, sig + 20)) {
|
||||
gcry_sexp_release (s_hash);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = gcry_pk_verify (s_sig, s_hash, dsactx);
|
||||
gcry_sexp_release (s_sig);
|
||||
gcry_sexp_release (s_hash);
|
||||
|
||||
return (rc == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
int _libssh2_cipher_init (_libssh2_cipher_ctx *h,
|
||||
_libssh2_cipher_type(algo),
|
||||
unsigned char *iv,
|
||||
unsigned char *secret,
|
||||
int encrypt)
|
||||
{
|
||||
int mode = 0, ret;
|
||||
int keylen = gcry_cipher_get_algo_keylen (algo);
|
||||
|
||||
(void)encrypt;
|
||||
|
||||
if (algo != GCRY_CIPHER_ARCFOUR) {
|
||||
mode = GCRY_CIPHER_MODE_CBC;
|
||||
}
|
||||
|
||||
ret = gcry_cipher_open (h, algo, mode, 0);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = gcry_cipher_setkey (*h, secret, keylen);
|
||||
if (ret) {
|
||||
gcry_cipher_close (*h);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (algo != GCRY_CIPHER_ARCFOUR) {
|
||||
int blklen = gcry_cipher_get_algo_blklen (algo);
|
||||
ret = gcry_cipher_setiv (*h, iv, blklen);
|
||||
if (ret) {
|
||||
gcry_cipher_close (*h);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_cipher_crypt(_libssh2_cipher_ctx *ctx,
|
||||
_libssh2_cipher_type(algo),
|
||||
int encrypt,
|
||||
unsigned char *block)
|
||||
{
|
||||
size_t blklen = gcry_cipher_get_algo_blklen (algo);
|
||||
int ret;
|
||||
if (blklen == 1) {
|
||||
/* Hack for arcfour. */
|
||||
blklen = 8;
|
||||
}
|
||||
|
||||
if (encrypt) {
|
||||
ret = gcry_cipher_encrypt (*ctx, block, blklen,
|
||||
block, blklen);
|
||||
} else {
|
||||
ret = gcry_cipher_decrypt (*ctx, block, blklen,
|
||||
block, blklen);
|
||||
}
|
||||
return ret;
|
||||
}
|
195
src/libgcrypt.h
Normal file
195
src/libgcrypt.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
* Author: Simon Josefsson
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names
|
||||
* of any other contributors may be used to endorse or
|
||||
* promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
#define LIBSSH2_MD5 1
|
||||
|
||||
#define LIBSSH2_HMAC_RIPEMD 1
|
||||
|
||||
#define LIBSSH2_AES 1
|
||||
#define LIBSSH2_BLOWFISH 1
|
||||
#define LIBSSH2_RC4 1
|
||||
#define LIBSSH2_CAST 1
|
||||
#define LIBSSH2_3DES 1
|
||||
|
||||
#define LIBSSH2_RSA 1
|
||||
#define LIBSSH2_DSA 1
|
||||
|
||||
#define MD5_DIGEST_LENGTH 16
|
||||
#define SHA_DIGEST_LENGTH 20
|
||||
|
||||
#define libssh2_random(buf, len) \
|
||||
(gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1)
|
||||
|
||||
#define libssh2_sha1_ctx gcry_md_hd_t
|
||||
#define libssh2_sha1_init(ctx) gcry_md_open (ctx, GCRY_MD_SHA1, 0);
|
||||
#define libssh2_sha1_update(ctx, data, len) gcry_md_write (ctx, data, len)
|
||||
#define libssh2_sha1_final(ctx, out) \
|
||||
memcpy (out, gcry_md_read (ctx, 0), 20), gcry_md_close (ctx)
|
||||
#define libssh2_sha1(message, len, out) \
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, out, message, len)
|
||||
|
||||
#define libssh2_md5_ctx gcry_md_hd_t
|
||||
#define libssh2_md5_init(ctx) gcry_md_open (ctx, GCRY_MD_MD5, 0);
|
||||
#define libssh2_md5_update(ctx, data, len) gcry_md_write (ctx, data, len)
|
||||
#define libssh2_md5_final(ctx, out) \
|
||||
memcpy (out, gcry_md_read (ctx, 0), 20), gcry_md_close (ctx)
|
||||
#define libssh2_md5(message, len, out) \
|
||||
gcry_md_hash_buffer (GCRY_MD_MD5, out, message, len)
|
||||
|
||||
#define libssh2_hmac_ctx gcry_md_hd_t
|
||||
#define libssh2_hmac_sha1_init(ctx, key, keylen) \
|
||||
gcry_md_open (ctx, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC), \
|
||||
gcry_md_setkey (*ctx, key, keylen)
|
||||
#define libssh2_hmac_md5_init(ctx, key, keylen) \
|
||||
gcry_md_open (ctx, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC), \
|
||||
gcry_md_setkey (*ctx, key, keylen)
|
||||
#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
|
||||
gcry_md_open (ctx, GCRY_MD_RMD160, GCRY_MD_FLAG_HMAC), \
|
||||
gcry_md_setkey (*ctx, key, keylen)
|
||||
#define libssh2_hmac_update(ctx, data, datalen) \
|
||||
gcry_md_write (ctx, data, datalen)
|
||||
#define libssh2_hmac_final(ctx, data) \
|
||||
memcpy (data, gcry_md_read (ctx, 0), \
|
||||
gcry_md_get_algo_dlen (gcry_md_get_algo (ctx)))
|
||||
#define libssh2_hmac_cleanup(ctx) gcry_md_close (*ctx);
|
||||
|
||||
#define libssh2_crypto_init() gcry_control (GCRYCTL_DISABLE_SECMEM)
|
||||
|
||||
#define libssh2_rsa_ctx struct gcry_sexp
|
||||
|
||||
int _libssh2_rsa_new(libssh2_rsa_ctx **rsa,
|
||||
const unsigned char *edata,
|
||||
unsigned long elen,
|
||||
const unsigned char *ndata,
|
||||
unsigned long nlen,
|
||||
const unsigned char *ddata,
|
||||
unsigned long dlen,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *e1data,
|
||||
unsigned long e1len,
|
||||
const unsigned char *e2data,
|
||||
unsigned long e2len,
|
||||
const unsigned char *coeffdata,
|
||||
unsigned long coefflen);
|
||||
int _libssh2_rsa_new_private (libssh2_rsa_ctx **rsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx *rsa,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len);
|
||||
int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION *session,
|
||||
libssh2_rsa_ctx *rsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char **signature,
|
||||
unsigned long *signature_len);
|
||||
|
||||
#define _libssh2_rsa_free(rsactx) gcry_sexp_release (rsactx)
|
||||
|
||||
#define libssh2_dsa_ctx struct gcry_sexp
|
||||
|
||||
int _libssh2_dsa_new(libssh2_dsa_ctx **dsa,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *gdata,
|
||||
unsigned long glen,
|
||||
const unsigned char *ydata,
|
||||
unsigned long ylen,
|
||||
const unsigned char *x,
|
||||
unsigned long x_len);
|
||||
int _libssh2_dsa_new_private (libssh2_dsa_ctx **dsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx *dsa,
|
||||
const unsigned char *sig,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len);
|
||||
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx *dsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char *sig);
|
||||
|
||||
#define _libssh2_dsa_free(dsactx) gcry_sexp_release (dsactx)
|
||||
|
||||
#define _libssh2_cipher_type(name) int name
|
||||
#define _libssh2_cipher_ctx gcry_cipher_hd_t
|
||||
|
||||
#define _libssh2_cipher_aes256 GCRY_CIPHER_AES256
|
||||
#define _libssh2_cipher_aes192 GCRY_CIPHER_AES192
|
||||
#define _libssh2_cipher_aes128 GCRY_CIPHER_AES128
|
||||
#define _libssh2_cipher_blowfish GCRY_CIPHER_BLOWFISH
|
||||
#define _libssh2_cipher_arcfour GCRY_CIPHER_ARCFOUR
|
||||
#define _libssh2_cipher_cast5 GCRY_CIPHER_CAST5
|
||||
#define _libssh2_cipher_3des GCRY_CIPHER_3DES
|
||||
|
||||
int _libssh2_cipher_init (_libssh2_cipher_ctx *h,
|
||||
_libssh2_cipher_type(algo),
|
||||
unsigned char *iv,
|
||||
unsigned char *secret,
|
||||
int encrypt);
|
||||
|
||||
int _libssh2_cipher_crypt(_libssh2_cipher_ctx *ctx,
|
||||
_libssh2_cipher_type(algo),
|
||||
int encrypt,
|
||||
unsigned char *block);
|
||||
|
||||
#define _libssh2_cipher_dtor(ctx) gcry_cipher_close(*(ctx))
|
||||
|
||||
#define _libssh2_bn struct gcry_mpi
|
||||
#define _libssh2_bn_ctx int
|
||||
#define _libssh2_bn_ctx_new() 0
|
||||
#define _libssh2_bn_ctx_free(bnctx) 0
|
||||
#define _libssh2_bn_init() gcry_mpi_new(0)
|
||||
#define _libssh2_bn_rand(bn, bits, top, bottom) gcry_mpi_randomize (bn, bits, GCRY_WEAK_RANDOM)
|
||||
#define _libssh2_bn_mod_exp(r, a, p, m, ctx) gcry_mpi_powm (r, a, p, m)
|
||||
#define _libssh2_bn_set_word(bn, val) gcry_mpi_set_ui(bn, val)
|
||||
#define _libssh2_bn_from_bin(bn, len, val) gcry_mpi_scan(&((bn)), GCRYMPI_FMT_USG, val, len, NULL)
|
||||
#define _libssh2_bn_to_bin(bn, val) gcry_mpi_print (GCRYMPI_FMT_USG, val, _libssh2_bn_bytes(bn), NULL, bn)
|
||||
#define _libssh2_bn_bytes(bn) (gcry_mpi_get_nbits (bn) / 8 + ((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1))
|
||||
#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn)
|
||||
#define _libssh2_bn_free(bn) gcry_mpi_release(bn)
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -38,15 +38,24 @@
|
||||
#ifndef LIBSSH2_PRIV_H
|
||||
#define LIBSSH2_PRIV_H 1
|
||||
|
||||
/* Definitions shared with the public */
|
||||
#define LIBSSH2_LIBRARY
|
||||
#include "libssh2_config.h"
|
||||
#include "libssh2.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <sys/socket.h>
|
||||
#include <openssl/evp.h>
|
||||
#endif
|
||||
|
||||
#ifdef LIBSSH2_LIBGCRYPT
|
||||
#include "libgcrypt.h"
|
||||
#else
|
||||
#include "openssl.h"
|
||||
#endif
|
||||
|
||||
#define LIBSSH2_ALLOC(session, count) session->alloc((count), &(session)->abstract)
|
||||
#define LIBSSH2_REALLOC(session, ptr, count) session->realloc((ptr), (count), &(session)->abstract)
|
||||
#define LIBSSH2_REALLOC(session, ptr, count) ((ptr) ? session->realloc((ptr), (count), &(session)->abstract) : session->alloc((count), &(session)->abstract))
|
||||
#define LIBSSH2_FREE(session, ptr) session->free((ptr), &(session)->abstract)
|
||||
|
||||
#define LIBSSH2_IGNORE(session, data, datalen) session->ssh_msg_ignore((session), (data), (datalen), &(session)->abstract)
|
||||
@@ -56,6 +65,7 @@
|
||||
session->ssh_msg_disconnect((session), (reason), (message), (message_len), (language), (language_len), &(session)->abstract)
|
||||
|
||||
#define LIBSSH2_MACERROR(session, data, datalen) session->macerror((session), (data), (datalen), &(session)->abstract)
|
||||
#define LIBSSH2_X11_OPEN(channel, shost, sport) channel->session->x11(((channel)->session), (channel), (shost), (sport), (&(channel)->session->abstract))
|
||||
|
||||
#define LIBSSH2_CHANNEL_CLOSE(session, channel) channel->close_cb((session), &(session)->abstract, (channel), &(channel)->abstract)
|
||||
|
||||
@@ -109,7 +119,11 @@ struct _LIBSSH2_CHANNEL {
|
||||
|
||||
int blocking;
|
||||
|
||||
/* channel's program exit status */
|
||||
int exit_status;
|
||||
|
||||
libssh2_channel_data local, remote;
|
||||
unsigned long adjust_queue; /* Amount of bytes to be refunded to receive window (but not yet sent) */
|
||||
|
||||
LIBSSH2_SESSION *session;
|
||||
|
||||
@@ -123,6 +137,19 @@ struct _LIBSSH2_CHANNEL_BRIGADE {
|
||||
LIBSSH2_CHANNEL *head, *tail;
|
||||
};
|
||||
|
||||
struct _LIBSSH2_LISTENER {
|
||||
LIBSSH2_SESSION *session;
|
||||
|
||||
char *host;
|
||||
int port;
|
||||
|
||||
LIBSSH2_CHANNEL *queue;
|
||||
int queue_size;
|
||||
int queue_maxsize;
|
||||
|
||||
LIBSSH2_LISTENER *prev, *next;
|
||||
};
|
||||
|
||||
typedef struct _libssh2_endpoint_data {
|
||||
unsigned char *banner;
|
||||
|
||||
@@ -158,17 +185,18 @@ struct _LIBSSH2_SESSION {
|
||||
LIBSSH2_DEBUG_FUNC((*ssh_msg_debug));
|
||||
LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect));
|
||||
LIBSSH2_MACERROR_FUNC((*macerror));
|
||||
LIBSSH2_X11_OPEN_FUNC((*x11));
|
||||
|
||||
/* Method preferences -- NULL yields "load order" */
|
||||
char *kex_prefs;
|
||||
char *hostkey_prefs;
|
||||
|
||||
int exchanging_keys;
|
||||
int newkeys;
|
||||
int authenticated;
|
||||
int state;
|
||||
int flags;
|
||||
|
||||
/* Agreed Key Exchange Method */
|
||||
LIBSSH2_KEX_METHOD *kex;
|
||||
int burn_optimistic_kexinit:1;
|
||||
|
||||
unsigned char *session_id;
|
||||
unsigned long session_id_len;
|
||||
@@ -182,12 +210,10 @@ struct _LIBSSH2_SESSION {
|
||||
*/
|
||||
unsigned char *server_hostkey;
|
||||
unsigned long server_hostkey_len;
|
||||
#ifndef OPENSSL_NO_MD5
|
||||
#if LIBSSH2_MD5
|
||||
unsigned char server_hostkey_md5[MD5_DIGEST_LENGTH];
|
||||
#endif /* ! OPENSSL_NO_MD5 */
|
||||
#ifndef OPENSSL_NO_SHA
|
||||
#endif /* ! LIBSSH2_MD5 */
|
||||
unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH];
|
||||
#endif
|
||||
|
||||
/* (remote as source of data -- packet_read ) */
|
||||
libssh2_endpoint_data remote;
|
||||
@@ -202,6 +228,8 @@ struct _LIBSSH2_SESSION {
|
||||
LIBSSH2_CHANNEL_BRIGADE channels;
|
||||
unsigned long next_channel;
|
||||
|
||||
LIBSSH2_LISTENER *listeners;
|
||||
|
||||
/* Actual I/O socket */
|
||||
int socket_fd;
|
||||
int socket_block;
|
||||
@@ -214,13 +242,25 @@ struct _LIBSSH2_SESSION {
|
||||
int err_code;
|
||||
};
|
||||
|
||||
/* session.state bits */
|
||||
#define LIBSSH2_STATE_EXCHANGING_KEYS 0x00000001
|
||||
#define LIBSSH2_STATE_NEWKEYS 0x00000002
|
||||
#define LIBSSH2_STATE_AUTHENTICATED 0x00000004
|
||||
|
||||
/* session.flag helpers */
|
||||
#ifdef MSG_NOSIGNAL
|
||||
#define LIBSSH2_SOCKET_SEND_FLAGS(session) (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
|
||||
#define LIBSSH2_SOCKET_RECV_FLAGS(session) (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
|
||||
#else
|
||||
/* If MSG_NOSIGNAL isn't defined we're SOL on blocking SIGPIPE */
|
||||
#define LIBSSH2_SOCKET_SEND_FLAGS(session) 0
|
||||
#define LIBSSH2_SOCKET_RECV_FLAGS(session) 0
|
||||
#endif
|
||||
|
||||
/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional methods via .so/.dll */
|
||||
|
||||
struct _LIBSSH2_KEX_METHOD {
|
||||
char *name;
|
||||
|
||||
/* integrity key length */
|
||||
unsigned long key_len;
|
||||
const char *name;
|
||||
|
||||
/* Key exchange, populates session->* and returns 0 on success, non-0 on error */
|
||||
int (*exchange_keys)(LIBSSH2_SESSION *session);
|
||||
@@ -229,26 +269,19 @@ struct _LIBSSH2_KEX_METHOD {
|
||||
};
|
||||
|
||||
struct _LIBSSH2_HOSTKEY_METHOD {
|
||||
char *name;
|
||||
const char *name;
|
||||
unsigned long hash_len;
|
||||
|
||||
int (*init)(LIBSSH2_SESSION *session, unsigned char *hostkey_data, unsigned long hostkey_data_len, void **abstract);
|
||||
int (*initPEM)(LIBSSH2_SESSION *session, unsigned char *privkeyfile, unsigned char *passphrase, void **abstract);
|
||||
int (*initPEM)(LIBSSH2_SESSION *session, const char *privkeyfile, unsigned const char *passphrase, void **abstract);
|
||||
int (*sig_verify)(LIBSSH2_SESSION *session, const unsigned char *sig, unsigned long sig_len, const unsigned char *m, unsigned long m_len, void **abstract);
|
||||
int (*sign)(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len, const unsigned char *data, unsigned long data_len, void **abstract);
|
||||
int (*signv)(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len, unsigned long veccount, const struct iovec datavec[], void **abstract);
|
||||
int (*encrypt)(LIBSSH2_SESSION *session, unsigned char **dst, unsigned long *dst_len, const unsigned char *src, unsigned long src_len, void **abstract);
|
||||
int (*dtor)(LIBSSH2_SESSION *session, void **abstract);
|
||||
};
|
||||
|
||||
/* When FLAG_EVP is set, crypt contains a pointer to an EVP_CIPHER generator and init and dtor are ignored
|
||||
* Yes, I know it's a hack.
|
||||
*/
|
||||
|
||||
#define LIBSSH2_CRYPT_METHOD_FLAG_EVP 0x0001
|
||||
|
||||
struct _LIBSSH2_CRYPT_METHOD {
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
int blocksize;
|
||||
|
||||
@@ -258,13 +291,15 @@ struct _LIBSSH2_CRYPT_METHOD {
|
||||
|
||||
long flags;
|
||||
|
||||
int (*init)(LIBSSH2_SESSION *session, unsigned char *iv, int *free_iv, unsigned char *secret, int *free_secret, int encrypt, void **abstract);
|
||||
int (*init)(LIBSSH2_SESSION *session, LIBSSH2_CRYPT_METHOD *method, unsigned char *iv, int *free_iv, unsigned char *secret, int *free_secret, int encrypt, void **abstract);
|
||||
int (*crypt)(LIBSSH2_SESSION *session, unsigned char *block, void **abstract);
|
||||
int (*dtor)(LIBSSH2_SESSION *session, void **abstract);
|
||||
|
||||
_libssh2_cipher_type(algo);
|
||||
};
|
||||
|
||||
struct _LIBSSH2_COMP_METHOD {
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
int (*init)(LIBSSH2_SESSION *session, int compress, void **abstract);
|
||||
int (*comp)(LIBSSH2_SESSION *session, int compress, unsigned char **dest, unsigned long *dest_len, unsigned long payload_limit, int *free_dest,
|
||||
@@ -273,17 +308,52 @@ struct _LIBSSH2_COMP_METHOD {
|
||||
};
|
||||
|
||||
struct _LIBSSH2_MAC_METHOD {
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
/* The length of a given MAC packet */
|
||||
int mac_len;
|
||||
|
||||
/* integrity key length */
|
||||
int key_len;
|
||||
|
||||
/* Message Authentication Code Hashing algo */
|
||||
int (*init)(LIBSSH2_SESSION *session, unsigned char *key, int *free_key, void **abstract);
|
||||
int (*hash)(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno, const unsigned char *packet, unsigned long packet_len, const unsigned char *addtl, unsigned long addtl_len, void **abstract);
|
||||
int (*dtor)(LIBSSH2_SESSION *session, void **abstract);
|
||||
};
|
||||
|
||||
#if defined(LIBSSH2_DEBUG_TRANSPORT) || defined(LIBSSH2_DEBUG_KEX) || defined(LIBSSH2_DEBUG_USERAUTH) || defined(LIBSSH2_DEBUG_CONNECTION) || defined(LIBSSH2_DEBUG_SCP) || defined(LIBSSH2_DEBUG_SFTP) || defined(LIBSSH2_DEBUG_ERRORS)
|
||||
#define LIBSSH2_DEBUG_ENABLED
|
||||
|
||||
/* Internal debugging contexts -- Used with --enable-debug-* */
|
||||
#define LIBSSH2_DBG_TRANS 1
|
||||
#define LIBSSH2_DBG_KEX 2
|
||||
#define LIBSSH2_DBG_AUTH 3
|
||||
#define LIBSSH2_DBG_CONN 4
|
||||
#define LIBSSH2_DBG_SCP 5
|
||||
#define LIBSSH2_DBG_SFTP 6
|
||||
#define LIBSSH2_DBG_ERROR 7
|
||||
#define LIBSSH2_DBG_PUBLICKEY 8
|
||||
|
||||
void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, ...);
|
||||
|
||||
#endif /* LIBSSH2_DEBUG_ENABLED */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_ERRORS
|
||||
#define libssh2_error(session, errcode, errmsg, should_free) \
|
||||
{ \
|
||||
if (session->err_msg && session->err_should_free) { \
|
||||
LIBSSH2_FREE(session, session->err_msg); \
|
||||
} \
|
||||
session->err_msg = errmsg; \
|
||||
session->err_msglen = strlen(errmsg); \
|
||||
session->err_should_free = should_free; \
|
||||
session->err_code = errcode; \
|
||||
_libssh2_debug(session, LIBSSH2_DBG_ERROR, "%d - %s", session->err_code, session->err_msg); \
|
||||
}
|
||||
|
||||
#else /* ! LIBSSH2_DEBUG_ERRORS */
|
||||
|
||||
#define libssh2_error(session, errcode, errmsg, should_free) \
|
||||
{ \
|
||||
if (session->err_msg && session->err_should_free) { \
|
||||
@@ -295,6 +365,9 @@ struct _LIBSSH2_MAC_METHOD {
|
||||
session->err_code = errcode; \
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_DEBUG_ENABLED */
|
||||
|
||||
|
||||
#define LIBSSH2_SOCKET_UNKNOWN 1
|
||||
#define LIBSSH2_SOCKET_CONNECTED 0
|
||||
#define LIBSSH2_SOCKET_DISCONNECTED -1
|
||||
@@ -339,6 +412,9 @@ struct _LIBSSH2_MAC_METHOD {
|
||||
#define SSH_MSG_USERAUTH_PK_OK 60
|
||||
/* "password" method */
|
||||
#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60
|
||||
/* "keyboard-interactive" method */
|
||||
#define SSH_MSG_USERAUTH_INFO_REQUEST 60
|
||||
#define SSH_MSG_USERAUTH_INFO_RESPONSE 61
|
||||
|
||||
/* Channels */
|
||||
#define SSH_MSG_GLOBAL_REQUEST 80
|
||||
@@ -360,19 +436,27 @@ struct _LIBSSH2_MAC_METHOD {
|
||||
void libssh2_session_shutdown(LIBSSH2_SESSION *session);
|
||||
|
||||
unsigned long libssh2_ntohu32(const unsigned char *buf);
|
||||
unsigned long long libssh2_ntohu64(const unsigned char *buf);
|
||||
libssh2_uint64_t libssh2_ntohu64(const unsigned char *buf);
|
||||
void libssh2_htonu32(unsigned char *buf, unsigned long val);
|
||||
void libssh2_htonu64(unsigned char *buf, unsigned long long val);
|
||||
void libssh2_htonu64(unsigned char *buf, libssh2_uint64_t val);
|
||||
|
||||
int libssh2_packet_read(LIBSSH2_SESSION *session, int block);
|
||||
int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, int poll_socket);
|
||||
#define libssh2_packet_ask(session, packet_type, data, data_len, poll_socket) \
|
||||
libssh2_packet_ask_ex((session), (packet_type), (data), (data_len), 0, NULL, 0, (poll_socket))
|
||||
int libssh2_packet_askv_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, int poll_socket);
|
||||
#define libssh2_packet_askv(session, packet_types, data, data_len, poll_socket) \
|
||||
libssh2_packet_askv_ex((session), (packet_types), (data), (data_len), 0, NULL, 0, (poll_socket))
|
||||
int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len);
|
||||
#define libssh2_packet_require(session, packet_type, data, data_len) \
|
||||
libssh2_packet_require_ex((session), (packet_type), (data), (data_len), 0, NULL, 0)
|
||||
int libssh2_packet_requirev_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len);
|
||||
#define libssh2_packet_requirev(session, packet_types, data, data_len) \
|
||||
libssh2_packet_requirev_ex((session), (packet_types), (data), (data_len), 0, NULL, 0)
|
||||
int libssh2_packet_burn(LIBSSH2_SESSION *session);
|
||||
int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len);
|
||||
int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange);
|
||||
unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session);
|
||||
LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long channel_id);
|
||||
|
||||
/* Let crypt.c/hostkey.c/comp.c/mac.c expose their method structs */
|
||||
@@ -384,4 +468,14 @@ LIBSSH2_MAC_METHOD **libssh2_mac_methods(void);
|
||||
/* Language API doesn't exist yet. Just act like we've agreed on a language */
|
||||
#define libssh2_kex_agree_lang(session, endpoint, str, str_len) 0
|
||||
|
||||
/* pem.c */
|
||||
int _libssh2_pem_parse (LIBSSH2_SESSION *session,
|
||||
const char *headerbegin,
|
||||
const char *headerend,
|
||||
FILE *fp,
|
||||
char **data, unsigned int *datalen);
|
||||
int _libssh2_pem_decode_sequence (unsigned char **data, unsigned int *datalen);
|
||||
int _libssh2_pem_decode_integer (unsigned char **data, unsigned int *datalen,
|
||||
unsigned char **i, unsigned int *ilen);
|
||||
|
||||
#endif /* LIBSSH2_H */
|
92
src/mac.c
92
src/mac.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -36,7 +36,6 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#ifdef LIBSSH2_MAC_NONE
|
||||
/* {{{ libssh2_mac_none_MAC
|
||||
@@ -54,6 +53,7 @@ static int libssh2_mac_none_MAC(LIBSSH2_SESSION *session, unsigned char *buf, un
|
||||
static LIBSSH2_MAC_METHOD libssh2_mac_method_none = {
|
||||
"none",
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
libssh2_mac_none_MAC,
|
||||
NULL
|
||||
@@ -67,6 +67,7 @@ static int libssh2_mac_method_common_init(LIBSSH2_SESSION *session, unsigned cha
|
||||
{
|
||||
*abstract = key;
|
||||
*free_key = 0;
|
||||
(void)session;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -93,19 +94,20 @@ static int libssh2_mac_method_hmac_sha1_hash(LIBSSH2_SESSION *session, unsigned
|
||||
const unsigned char *packet, unsigned long packet_len,
|
||||
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
|
||||
{
|
||||
HMAC_CTX ctx;
|
||||
libssh2_hmac_ctx ctx;
|
||||
unsigned char seqno_buf[4];
|
||||
(void)session;
|
||||
|
||||
libssh2_htonu32(seqno_buf, seqno);
|
||||
|
||||
HMAC_Init(&ctx, *abstract, session->kex->key_len, EVP_sha1());
|
||||
HMAC_Update(&ctx, seqno_buf, 4);
|
||||
HMAC_Update(&ctx, packet, packet_len);
|
||||
libssh2_hmac_sha1_init(&ctx, *abstract, 20);
|
||||
libssh2_hmac_update(ctx, seqno_buf, 4);
|
||||
libssh2_hmac_update(ctx, packet, packet_len);
|
||||
if (addtl && addtl_len) {
|
||||
HMAC_Update(&ctx, addtl, addtl_len);
|
||||
libssh2_hmac_update(ctx, addtl, addtl_len);
|
||||
}
|
||||
HMAC_Final(&ctx, buf, NULL);
|
||||
HMAC_cleanup(&ctx);
|
||||
libssh2_hmac_final(ctx, buf);
|
||||
libssh2_hmac_cleanup(&ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -113,7 +115,8 @@ static int libssh2_mac_method_hmac_sha1_hash(LIBSSH2_SESSION *session, unsigned
|
||||
|
||||
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1 = {
|
||||
"hmac-sha1",
|
||||
SHA_DIGEST_LENGTH,
|
||||
20,
|
||||
20,
|
||||
libssh2_mac_method_common_init,
|
||||
libssh2_mac_method_hmac_sha1_hash,
|
||||
libssh2_mac_method_common_dtor,
|
||||
@@ -126,10 +129,10 @@ static int libssh2_mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION *session, unsign
|
||||
const unsigned char *packet, unsigned long packet_len,
|
||||
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
|
||||
{
|
||||
char temp[SHA_DIGEST_LENGTH];
|
||||
unsigned char temp[SHA_DIGEST_LENGTH];
|
||||
|
||||
libssh2_mac_method_hmac_sha1_hash(session, temp, seqno, packet, packet_len, addtl, addtl_len, abstract);
|
||||
memcpy(buf, temp, 96 / 8);
|
||||
memcpy(buf, (char *)temp, 96 / 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -137,13 +140,13 @@ static int libssh2_mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION *session, unsign
|
||||
|
||||
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1_96 = {
|
||||
"hmac-sha1-96",
|
||||
96 / 8,
|
||||
12,
|
||||
20,
|
||||
libssh2_mac_method_common_init,
|
||||
libssh2_mac_method_hmac_sha1_96_hash,
|
||||
libssh2_mac_method_common_dtor,
|
||||
};
|
||||
|
||||
#ifdef WHY_DOESNT_MD5_WORK
|
||||
/* {{{ libssh2_mac_method_hmac_md5_hash
|
||||
* Calculate hash using full md5 value
|
||||
*/
|
||||
@@ -151,19 +154,20 @@ static int libssh2_mac_method_hmac_md5_hash(LIBSSH2_SESSION *session, unsigned c
|
||||
const unsigned char *packet, unsigned long packet_len,
|
||||
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
|
||||
{
|
||||
HMAC_CTX ctx;
|
||||
libssh2_hmac_ctx ctx;
|
||||
unsigned char seqno_buf[4];
|
||||
(void)session;
|
||||
|
||||
libssh2_htonu32(seqno_buf, seqno);
|
||||
|
||||
HMAC_Init(&ctx, *abstract, session->kex->key_len, EVP_md5());
|
||||
HMAC_Update(&ctx, seqno_buf, 4);
|
||||
HMAC_Update(&ctx, packet, packet_len);
|
||||
libssh2_hmac_md5_init(&ctx, *abstract, 16);
|
||||
libssh2_hmac_update(ctx, seqno_buf, 4);
|
||||
libssh2_hmac_update(ctx, packet, packet_len);
|
||||
if (addtl && addtl_len) {
|
||||
HMAC_Update(&ctx, addtl, addtl_len);
|
||||
libssh2_hmac_update(ctx, addtl, addtl_len);
|
||||
}
|
||||
HMAC_Final(&ctx, buf, NULL);
|
||||
HMAC_cleanup(&ctx);
|
||||
libssh2_hmac_final(ctx, buf);
|
||||
libssh2_hmac_cleanup(&ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -171,7 +175,8 @@ static int libssh2_mac_method_hmac_md5_hash(LIBSSH2_SESSION *session, unsigned c
|
||||
|
||||
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5 = {
|
||||
"hmac-md5",
|
||||
MD5_DIGEST_LENGTH,
|
||||
16,
|
||||
16,
|
||||
libssh2_mac_method_common_init,
|
||||
libssh2_mac_method_hmac_md5_hash,
|
||||
libssh2_mac_method_common_dtor,
|
||||
@@ -180,14 +185,14 @@ static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5 = {
|
||||
/* {{{ libssh2_mac_method_hmac_md5_96_hash
|
||||
* Calculate hash using first 96 bits of md5 value
|
||||
*/
|
||||
static int libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION *session, unsigned char *buf, unsigned seqno,
|
||||
const unsigned char *packet, unsigned packet_len,
|
||||
static int libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno,
|
||||
const unsigned char *packet, unsigned long packet_len,
|
||||
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
|
||||
{
|
||||
char temp[MD5_DIGEST_LENGTH];
|
||||
unsigned char temp[MD5_DIGEST_LENGTH];
|
||||
|
||||
libssh2_mac_method_hmac_md5_hash(session, temp, seqno, packet, packet_len, addtl, addtl_len, abstract);
|
||||
memcpy(buf, temp, 96 / 8);
|
||||
memcpy(buf, (char *)temp, 96 / 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -195,14 +200,14 @@ static int libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION *session, unsigne
|
||||
|
||||
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5_96 = {
|
||||
"hmac-md5-96",
|
||||
96 / 8,
|
||||
12,
|
||||
16,
|
||||
libssh2_mac_method_common_init,
|
||||
libssh2_mac_method_hmac_md5_96_hash,
|
||||
libssh2_mac_method_common_dtor,
|
||||
};
|
||||
#endif /* WHY_DOESNT_MD5_WORK */
|
||||
|
||||
#ifndef OPENSSL_NO_RIPEMD
|
||||
#if LIBSSH2_HMAC_RIPEMD
|
||||
/* {{{ libssh2_mac_method_hmac_ripemd160_hash
|
||||
* Calculate hash using ripemd160 value
|
||||
*/
|
||||
@@ -210,19 +215,20 @@ static int libssh2_mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION *session, unsi
|
||||
const unsigned char *packet, unsigned long packet_len,
|
||||
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
|
||||
{
|
||||
HMAC_CTX ctx;
|
||||
libssh2_hmac_ctx ctx;
|
||||
unsigned char seqno_buf[4];
|
||||
(void)session;
|
||||
|
||||
libssh2_htonu32(seqno_buf, seqno);
|
||||
|
||||
HMAC_Init(&ctx, *abstract, session->kex->key_len, EVP_ripemd160());
|
||||
HMAC_Update(&ctx, seqno_buf, 4);
|
||||
HMAC_Update(&ctx, packet, packet_len);
|
||||
libssh2_hmac_ripemd160_init(&ctx, *abstract, 20);
|
||||
libssh2_hmac_update(ctx, seqno_buf, 4);
|
||||
libssh2_hmac_update(ctx, packet, packet_len);
|
||||
if (addtl && addtl_len) {
|
||||
HMAC_Update(&ctx, addtl, addtl_len);
|
||||
libssh2_hmac_update(ctx, addtl, addtl_len);
|
||||
}
|
||||
HMAC_Final(&ctx, buf, NULL);
|
||||
HMAC_cleanup(&ctx);
|
||||
libssh2_hmac_final(ctx, buf);
|
||||
libssh2_hmac_cleanup(&ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -230,7 +236,8 @@ static int libssh2_mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION *session, unsi
|
||||
|
||||
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160 = {
|
||||
"hmac-ripemd160",
|
||||
160 / 8,
|
||||
20,
|
||||
20,
|
||||
libssh2_mac_method_common_init,
|
||||
libssh2_mac_method_hmac_ripemd160_hash,
|
||||
libssh2_mac_method_common_dtor,
|
||||
@@ -238,24 +245,23 @@ static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160 = {
|
||||
|
||||
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160_openssh_com = {
|
||||
"hmac-ripemd160@openssh.com",
|
||||
160 / 8,
|
||||
20,
|
||||
20,
|
||||
libssh2_mac_method_common_init,
|
||||
libssh2_mac_method_hmac_ripemd160_hash,
|
||||
libssh2_mac_method_common_dtor,
|
||||
};
|
||||
#endif /* ! OPENSSL_NO_RIPEMD */
|
||||
#endif /* LIBSSH2_HMAC_RIPEMD */
|
||||
|
||||
static LIBSSH2_MAC_METHOD *_libssh2_mac_methods[] = {
|
||||
&libssh2_mac_method_hmac_sha1,
|
||||
&libssh2_mac_method_hmac_sha1_96,
|
||||
#ifdef WHY_DOESNT_MD5_WORK
|
||||
&libssh2_mac_method_hmac_md5,
|
||||
&libssh2_mac_method_hmac_md5_96,
|
||||
#endif /* WHY_DOESNT_MD5_WORK */
|
||||
#ifndef OPENSSL_NO_RIPEMD
|
||||
#ifdef LIBSSH2_HMAC_RIPEMD
|
||||
&libssh2_mac_method_hmac_ripemd160,
|
||||
&libssh2_mac_method_hmac_ripemd160_openssh_com,
|
||||
#endif /* ! OPENSSL_NO_RIPEMD */
|
||||
#endif /* LIBSSH2_HMAC_RIPEMD */
|
||||
#ifdef LIBSSH2_MAC_NONE
|
||||
&libssh2_mac_method_none,
|
||||
#endif /* LIBSSH2_MAC_NONE */
|
||||
|
50
src/misc.c
50
src/misc.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -49,7 +49,7 @@ unsigned long libssh2_ntohu32(const unsigned char *buf)
|
||||
* Note: Some 32-bit platforms have issues with bitops on long longs
|
||||
* Work around this by doing expensive (but safer) arithmetic ops with optimization defying parentheses
|
||||
*/
|
||||
unsigned long long libssh2_ntohu64(const unsigned char *buf)
|
||||
libssh2_uint64_t libssh2_ntohu64(const unsigned char *buf)
|
||||
{
|
||||
unsigned long msl, lsl;
|
||||
|
||||
@@ -73,7 +73,7 @@ void libssh2_htonu32(unsigned char *buf, unsigned long value)
|
||||
|
||||
/* {{{ libssh2_htonu64
|
||||
*/
|
||||
void libssh2_htonu64(unsigned char *buf, unsigned long long value)
|
||||
void libssh2_htonu64(unsigned char *buf, libssh2_uint64_t value)
|
||||
{
|
||||
unsigned long msl = (value / 65536) / 65536;
|
||||
|
||||
@@ -126,19 +126,20 @@ static const short libssh2_base64_reverse_table[256] = {
|
||||
/* {{{ libssh2_base64_decode
|
||||
* Decode a base64 chunk and store it into a newly alloc'd buffer
|
||||
*/
|
||||
LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, int *datalen,
|
||||
char *src, int src_len)
|
||||
LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, unsigned int *datalen,
|
||||
char *src, unsigned int src_len)
|
||||
{
|
||||
unsigned char *s, *d;
|
||||
short v;
|
||||
int i = 0, len = 0;
|
||||
|
||||
*data = d = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1);
|
||||
*data = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1);
|
||||
d = (unsigned char *)*data;
|
||||
if (!d) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(s = src; ((char*)s) < (src + src_len); s++) {
|
||||
for(s = (unsigned char *)src; ((char*)s) < (src + src_len); s++) {
|
||||
if ((v = libssh2_base64_reverse_table[*s]) < 0) continue;
|
||||
switch (i % 4) {
|
||||
case 0:
|
||||
@@ -169,3 +170,38 @@ LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, int
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_ENABLED
|
||||
/* {{{ _libssh2_debug
|
||||
* Internal debug logging facility
|
||||
* Just writes to stderr until a good reason comes up to support anything else
|
||||
*/
|
||||
void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, ...)
|
||||
{
|
||||
char buffer[1536];
|
||||
int len;
|
||||
va_list vargs;
|
||||
char *contexts[9] = { "Unknown",
|
||||
"Transport",
|
||||
"Key Exhange",
|
||||
"Userauth",
|
||||
"Connection",
|
||||
"scp",
|
||||
"SFTP Subsystem",
|
||||
"Failure Event",
|
||||
"Publickey Subsystem",
|
||||
};
|
||||
|
||||
if (context < 1 || context > 8) {
|
||||
context = 0;
|
||||
}
|
||||
|
||||
len = snprintf(buffer, 1535, "[libssh2] %s: ", contexts[context]);
|
||||
|
||||
va_start(vargs, format);
|
||||
len += vsnprintf(buffer + len, 1535 - len, format, vargs);
|
||||
buffer[len] = '\n';
|
||||
va_end(vargs);
|
||||
write(2, buffer, len + 1);
|
||||
}
|
||||
/* }}} */
|
||||
#endif
|
||||
|
313
src/openssl.c
Normal file
313
src/openssl.c
Normal file
@@ -0,0 +1,313 @@
|
||||
/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
* Author: Simon Josefsson
|
||||
* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names
|
||||
* of any other contributors may be used to endorse or
|
||||
* promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <string.h>
|
||||
|
||||
int _libssh2_rsa_new(libssh2_rsa_ctx **rsa,
|
||||
const unsigned char *edata,
|
||||
unsigned long elen,
|
||||
const unsigned char *ndata,
|
||||
unsigned long nlen,
|
||||
const unsigned char *ddata,
|
||||
unsigned long dlen,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *e1data,
|
||||
unsigned long e1len,
|
||||
const unsigned char *e2data,
|
||||
unsigned long e2len,
|
||||
const unsigned char *coeffdata,
|
||||
unsigned long coefflen)
|
||||
{
|
||||
*rsa = RSA_new();
|
||||
|
||||
(*rsa)->e = BN_new();
|
||||
BN_bin2bn(edata, elen, (*rsa)->e);
|
||||
|
||||
(*rsa)->n = BN_new();
|
||||
BN_bin2bn(ndata, nlen, (*rsa)->n);
|
||||
|
||||
if (ddata)
|
||||
{
|
||||
(*rsa)->d = BN_new();
|
||||
BN_bin2bn(ddata, dlen, (*rsa)->d);
|
||||
|
||||
(*rsa)->p = BN_new();
|
||||
BN_bin2bn(pdata, plen, (*rsa)->p);
|
||||
|
||||
(*rsa)->q = BN_new();
|
||||
BN_bin2bn(qdata, qlen, (*rsa)->q);
|
||||
|
||||
(*rsa)->dmp1 = BN_new();
|
||||
BN_bin2bn(e1data, e1len, (*rsa)->dmp1);
|
||||
|
||||
(*rsa)->dmq1 = BN_new();
|
||||
BN_bin2bn(e2data, e2len, (*rsa)->dmq1);
|
||||
|
||||
(*rsa)->iqmp = BN_new();
|
||||
BN_bin2bn(coeffdata, coefflen, (*rsa)->iqmp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx *rsactx,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len)
|
||||
{
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
int ret;
|
||||
|
||||
SHA1(m, m_len, hash);
|
||||
ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
|
||||
(unsigned char *)sig, sig_len, rsactx);
|
||||
return (ret == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_new(libssh2_dsa_ctx **dsactx,
|
||||
const unsigned char *p,
|
||||
unsigned long p_len,
|
||||
const unsigned char *q,
|
||||
unsigned long q_len,
|
||||
const unsigned char *g,
|
||||
unsigned long g_len,
|
||||
const unsigned char *y,
|
||||
unsigned long y_len,
|
||||
const unsigned char *x,
|
||||
unsigned long x_len)
|
||||
{
|
||||
*dsactx = DSA_new();
|
||||
|
||||
(*dsactx)->p = BN_new();
|
||||
BN_bin2bn(p, p_len, (*dsactx)->p);
|
||||
|
||||
(*dsactx)->q = BN_new();
|
||||
BN_bin2bn(q, q_len, (*dsactx)->q);
|
||||
|
||||
(*dsactx)->g = BN_new();
|
||||
BN_bin2bn(g, g_len, (*dsactx)->g);
|
||||
|
||||
(*dsactx)->pub_key = BN_new();
|
||||
BN_bin2bn(y, y_len, (*dsactx)->pub_key);
|
||||
|
||||
if (x_len) {
|
||||
(*dsactx)->priv_key = BN_new();
|
||||
BN_bin2bn(x, x_len, (*dsactx)->priv_key);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx *dsactx,
|
||||
const unsigned char *sig,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len)
|
||||
{
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
DSA_SIG dsasig;
|
||||
int ret;
|
||||
|
||||
dsasig.r = BN_new();
|
||||
BN_bin2bn(sig, 20, dsasig.r);
|
||||
dsasig.s = BN_new();
|
||||
BN_bin2bn(sig + 20, 20, dsasig.s);
|
||||
|
||||
libssh2_sha1(m, m_len, hash);
|
||||
ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, &dsasig, dsactx);
|
||||
|
||||
return (ret == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
int _libssh2_cipher_init (_libssh2_cipher_ctx *h,
|
||||
_libssh2_cipher_type(algo),
|
||||
unsigned char *iv,
|
||||
unsigned char *secret,
|
||||
int encrypt)
|
||||
{
|
||||
EVP_CIPHER_CTX_init(h);
|
||||
EVP_CipherInit(h, algo(), secret, iv, encrypt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_cipher_crypt(_libssh2_cipher_ctx *ctx,
|
||||
_libssh2_cipher_type(algo),
|
||||
int encrypt,
|
||||
unsigned char *block)
|
||||
{
|
||||
int blocksize = ctx->cipher->block_size;
|
||||
unsigned char buf[EVP_MAX_BLOCK_LENGTH];
|
||||
int ret;
|
||||
(void)algo;
|
||||
(void)encrypt;
|
||||
|
||||
if (blocksize == 1) {
|
||||
/* Hack for arcfour. */
|
||||
blocksize = 8;
|
||||
}
|
||||
ret = EVP_Cipher(ctx, buf, block, blocksize);
|
||||
if (ret == 1) {
|
||||
memcpy(block, buf, blocksize);
|
||||
}
|
||||
return ret == 1 ? 0 : 1;
|
||||
}
|
||||
|
||||
/* TODO: Optionally call a passphrase callback specified by the
|
||||
* calling program
|
||||
*/
|
||||
static int
|
||||
passphrase_cb(char *buf, int size,
|
||||
int rwflag, char *passphrase)
|
||||
{
|
||||
int passphrase_len = strlen(passphrase);
|
||||
(void)rwflag;
|
||||
|
||||
if (passphrase_len > (size - 1)) {
|
||||
passphrase_len = size - 1;
|
||||
}
|
||||
memcpy(buf, passphrase, passphrase_len);
|
||||
buf[passphrase_len] = '\0';
|
||||
|
||||
return passphrase_len;
|
||||
}
|
||||
|
||||
int _libssh2_rsa_new_private (libssh2_rsa_ctx **rsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase)
|
||||
{
|
||||
(void)session;
|
||||
if (!EVP_get_cipherbyname("des")) {
|
||||
/* If this cipher isn't loaded it's a pretty good indication that none are.
|
||||
* I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
|
||||
* Someone buy me an OpenSSL manual and I'll read up on it.
|
||||
*/
|
||||
OpenSSL_add_all_ciphers();
|
||||
}
|
||||
*rsa = PEM_read_RSAPrivateKey(fp, NULL, (void*)passphrase_cb,
|
||||
(void*)passphrase);
|
||||
if (!*rsa) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_new_private (libssh2_dsa_ctx **dsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase)
|
||||
{
|
||||
(void)session;
|
||||
if (!EVP_get_cipherbyname("des")) {
|
||||
/* If this cipher isn't loaded it's a pretty good indication that none are.
|
||||
* I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
|
||||
* Someone buy me an OpenSSL manual and I'll read up on it.
|
||||
*/
|
||||
OpenSSL_add_all_ciphers();
|
||||
}
|
||||
*dsa = PEM_read_DSAPrivateKey(fp, NULL, (void*)passphrase_cb,
|
||||
(void*)passphrase);
|
||||
if (!*dsa) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION *session,
|
||||
libssh2_rsa_ctx *rsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char **signature,
|
||||
unsigned long *signature_len)
|
||||
{
|
||||
int ret;
|
||||
unsigned char *sig;
|
||||
unsigned int sig_len;
|
||||
|
||||
sig_len = RSA_size(rsactx);
|
||||
sig = LIBSSH2_ALLOC(session, sig_len);
|
||||
|
||||
if (!sig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx);
|
||||
|
||||
if (!ret) {
|
||||
LIBSSH2_FREE(session, sig);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*signature = sig;
|
||||
*signature_len = sig_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx *dsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char *signature)
|
||||
{
|
||||
DSA_SIG *sig;
|
||||
int r_len, s_len, rs_pad;
|
||||
(void)hash_len;
|
||||
|
||||
sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
|
||||
if (!sig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
r_len = BN_num_bytes(sig->r);
|
||||
s_len = BN_num_bytes(sig->s);
|
||||
rs_pad = (2 * SHA_DIGEST_LENGTH) - (r_len + s_len);
|
||||
if (rs_pad < 0) {
|
||||
DSA_SIG_free(sig);
|
||||
return -1;
|
||||
}
|
||||
|
||||
BN_bn2bin(sig->r, signature + rs_pad);
|
||||
BN_bn2bin(sig->s, signature + rs_pad + r_len);
|
||||
|
||||
DSA_SIG_free(sig);
|
||||
|
||||
return 0;
|
||||
}
|
233
src/openssl.h
Normal file
233
src/openssl.h
Normal file
@@ -0,0 +1,233 @@
|
||||
/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
* Author: Simon Josefsson
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names
|
||||
* of any other contributors may be used to endorse or
|
||||
* promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <openssl/sha.h>
|
||||
#ifndef OPENSSL_NO_MD5
|
||||
#include <openssl/md5.h>
|
||||
#endif
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#ifdef OPENSSL_NO_RSA
|
||||
# define LIBSSH2_RSA 0
|
||||
#else
|
||||
# define LIBSSH2_RSA 1
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_DSA
|
||||
# define LIBSSH2_DSA 0
|
||||
#else
|
||||
# define LIBSSH2_DSA 1
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_MD5
|
||||
# define LIBSSH2_MD5 0
|
||||
#else
|
||||
# define LIBSSH2_MD5 1
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_RIPEMD
|
||||
# define LIBSSH2_HMAC_RIPEMD 0
|
||||
#else
|
||||
# define LIBSSH2_HMAC_RIPEMD 1
|
||||
#endif
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)
|
||||
# define LIBSSH2_AES 1
|
||||
#else
|
||||
# define LIBSSH2_AES 0
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_BLOWFISH
|
||||
# define LIBSSH2_BLOWFISH 0
|
||||
#else
|
||||
# define LIBSSH2_BLOWFISH 1
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_RC4
|
||||
# define LIBSSH2_RC4 0
|
||||
#else
|
||||
# define LIBSSH2_RC4 1
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_CAST
|
||||
# define LIBSSH2_CAST 0
|
||||
#else
|
||||
# define LIBSSH2_CAST 1
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_DES
|
||||
# define LIBSSH2_3DES 0
|
||||
#else
|
||||
# define LIBSSH2_3DES 1
|
||||
#endif
|
||||
|
||||
#define libssh2_random(buf, len) \
|
||||
RAND_bytes ((buf), (len))
|
||||
|
||||
#define libssh2_sha1_ctx SHA_CTX
|
||||
#define libssh2_sha1_init(ctx) SHA1_Init(ctx)
|
||||
#define libssh2_sha1_update(ctx, data, len) SHA1_Update(&(ctx), data, len)
|
||||
#define libssh2_sha1_final(ctx, out) SHA1_Final(out, &(ctx))
|
||||
#define libssh2_sha1(message, len, out) SHA1(message, len, out)
|
||||
|
||||
#define libssh2_md5_ctx MD5_CTX
|
||||
#define libssh2_md5_init(ctx) MD5_Init(ctx)
|
||||
#define libssh2_md5_update(ctx, data, len) MD5_Update(&(ctx), data, len)
|
||||
#define libssh2_md5_final(ctx, out) MD5_Final(out, &(ctx))
|
||||
#define libssh2_md5(message, len, out) MD5(message, len, out)
|
||||
|
||||
#define libssh2_hmac_ctx HMAC_CTX
|
||||
#define libssh2_hmac_sha1_init(ctx, key, keylen) \
|
||||
HMAC_Init(ctx, key, keylen, EVP_sha1())
|
||||
#define libssh2_hmac_md5_init(ctx, key, keylen) \
|
||||
HMAC_Init(ctx, key, keylen, EVP_md5())
|
||||
#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
|
||||
HMAC_Init(ctx, key, keylen, EVP_ripemd160())
|
||||
#define libssh2_hmac_update(ctx, data, datalen) \
|
||||
HMAC_Update(&(ctx), data, datalen)
|
||||
#define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL)
|
||||
#define libssh2_hmac_cleanup(ctx) HMAC_cleanup(ctx)
|
||||
|
||||
#define libssh2_crypto_init()
|
||||
|
||||
#define libssh2_rsa_ctx RSA
|
||||
|
||||
int _libssh2_rsa_new(libssh2_rsa_ctx **rsa,
|
||||
const unsigned char *edata,
|
||||
unsigned long elen,
|
||||
const unsigned char *ndata,
|
||||
unsigned long nlen,
|
||||
const unsigned char *ddata,
|
||||
unsigned long dlen,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *e1data,
|
||||
unsigned long e1len,
|
||||
const unsigned char *e2data,
|
||||
unsigned long e2len,
|
||||
const unsigned char *coeffdata,
|
||||
unsigned long coefflen);
|
||||
int _libssh2_rsa_new_private (libssh2_rsa_ctx **rsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx *rsa,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len);
|
||||
int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION *session,
|
||||
libssh2_rsa_ctx *rsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char **signature,
|
||||
unsigned long *signature_len);
|
||||
|
||||
#define _libssh2_rsa_free(rsactx) RSA_free(rsactx)
|
||||
|
||||
#define libssh2_dsa_ctx DSA
|
||||
|
||||
int _libssh2_dsa_new(libssh2_dsa_ctx **dsa,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *gdata,
|
||||
unsigned long glen,
|
||||
const unsigned char *ydata,
|
||||
unsigned long ylen,
|
||||
const unsigned char *x,
|
||||
unsigned long x_len);
|
||||
int _libssh2_dsa_new_private (libssh2_dsa_ctx **dsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx *dsactx,
|
||||
const unsigned char *sig,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len);
|
||||
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx *dsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char *sig);
|
||||
|
||||
#define _libssh2_dsa_free(dsactx) DSA_free(dsactx)
|
||||
|
||||
#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void)
|
||||
#define _libssh2_cipher_ctx EVP_CIPHER_CTX
|
||||
|
||||
#define _libssh2_cipher_aes256 EVP_aes_256_cbc
|
||||
#define _libssh2_cipher_aes192 EVP_aes_192_cbc
|
||||
#define _libssh2_cipher_aes128 EVP_aes_128_cbc
|
||||
#define _libssh2_cipher_blowfish EVP_bf_cbc
|
||||
#define _libssh2_cipher_arcfour EVP_rc4
|
||||
#define _libssh2_cipher_cast5 EVP_cast5_cbc
|
||||
#define _libssh2_cipher_3des EVP_des_ede3_cbc
|
||||
|
||||
int _libssh2_cipher_init (_libssh2_cipher_ctx *h,
|
||||
_libssh2_cipher_type(algo),
|
||||
unsigned char *iv,
|
||||
unsigned char *secret,
|
||||
int encrypt);
|
||||
|
||||
int _libssh2_cipher_crypt(_libssh2_cipher_ctx *ctx,
|
||||
_libssh2_cipher_type(algo),
|
||||
int encrypt,
|
||||
unsigned char *block);
|
||||
|
||||
#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_cleanup(ctx)
|
||||
|
||||
#define _libssh2_bn BIGNUM
|
||||
#define _libssh2_bn_ctx BN_CTX
|
||||
#define _libssh2_bn_ctx_new() BN_CTX_new()
|
||||
#define _libssh2_bn_ctx_free(bnctx) BN_CTX_free(bnctx)
|
||||
#define _libssh2_bn_init() BN_new()
|
||||
#define _libssh2_bn_rand(bn, bits, top, bottom) BN_rand(bn, bits, top, bottom)
|
||||
#define _libssh2_bn_mod_exp(r, a, p, m, ctx) BN_mod_exp(r, a, p, m, ctx)
|
||||
#define _libssh2_bn_set_word(bn, val) BN_set_word(bn, val)
|
||||
#define _libssh2_bn_from_bin(bn, len, val) BN_bin2bn(val, len, bn)
|
||||
#define _libssh2_bn_to_bin(bn, val) BN_bn2bin(bn, val)
|
||||
#define _libssh2_bn_bytes(bn) BN_num_bytes(bn)
|
||||
#define _libssh2_bn_bits(bn) BN_num_bits(bn)
|
||||
#define _libssh2_bn_free(bn) BN_clear_free(bn)
|
768
src/packet.c
768
src/packet.c
File diff suppressed because it is too large
Load Diff
229
src/pem.c
Normal file
229
src/pem.c
Normal file
@@ -0,0 +1,229 @@
|
||||
/* Copyright (C) 2007 The Written Word, Inc. All rights reserved.
|
||||
* Author: Simon Josefsson
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names
|
||||
* of any other contributors may be used to endorse or
|
||||
* promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
|
||||
static int readline (char *line, int line_size, FILE *fp)
|
||||
{
|
||||
if (!fgets(line, line_size, fp))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (*line && line[strlen(line) - 1] == '\r')
|
||||
{
|
||||
line[strlen(line) - 1] = '\0';
|
||||
}
|
||||
if (*line && line[strlen(line) - 1] == '\n')
|
||||
{
|
||||
line[strlen(line) - 1] = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define LINE_SIZE 128
|
||||
|
||||
int _libssh2_pem_parse (LIBSSH2_SESSION *session,
|
||||
const char *headerbegin,
|
||||
const char *headerend,
|
||||
FILE *fp,
|
||||
char **data, unsigned int *datalen)
|
||||
{
|
||||
char line[LINE_SIZE];
|
||||
char *b64data = NULL;
|
||||
unsigned int b64datalen = 0;
|
||||
int ret;
|
||||
|
||||
do
|
||||
{
|
||||
if (readline(line, LINE_SIZE, fp))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
while (strcmp (line, headerbegin) != 0);
|
||||
|
||||
*line = '\0';
|
||||
|
||||
do
|
||||
{
|
||||
if (*line)
|
||||
{
|
||||
char *tmp;
|
||||
size_t linelen;
|
||||
|
||||
linelen = strlen (line);
|
||||
tmp = LIBSSH2_REALLOC (session, b64data,
|
||||
b64datalen + linelen);
|
||||
if (!tmp)
|
||||
{
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
memcpy (tmp + b64datalen, line, linelen);
|
||||
b64data = tmp;
|
||||
b64datalen += linelen;
|
||||
}
|
||||
|
||||
if (readline(line, LINE_SIZE, fp))
|
||||
{
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
} while (strcmp (line, headerend) != 0);
|
||||
|
||||
if (libssh2_base64_decode(session, data, datalen,
|
||||
b64data, b64datalen))
|
||||
{
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
if (b64data) {
|
||||
LIBSSH2_FREE (session, b64data);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_asn1_length (const unsigned char *data,
|
||||
unsigned int datalen,
|
||||
unsigned int *len)
|
||||
{
|
||||
unsigned int lenlen;
|
||||
int nextpos;
|
||||
|
||||
if (datalen < 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
*len = data[0];
|
||||
|
||||
if (*len >= 0x80)
|
||||
{
|
||||
lenlen = *len & 0x7F;
|
||||
*len = data[1];
|
||||
if (1 + lenlen > datalen)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (lenlen > 1)
|
||||
{
|
||||
*len <<= 8;
|
||||
*len |= data[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lenlen = 0;
|
||||
}
|
||||
|
||||
nextpos = 1 + lenlen;
|
||||
if (lenlen > 2 || 1 + lenlen + *len > datalen)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nextpos;
|
||||
}
|
||||
|
||||
int _libssh2_pem_decode_sequence (unsigned char **data, unsigned int *datalen)
|
||||
{
|
||||
unsigned int len;
|
||||
int lenlen;
|
||||
|
||||
if (*datalen < 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((*data)[0] != '\x30')
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*data)++;
|
||||
(*datalen)--;
|
||||
|
||||
lenlen = read_asn1_length (*data, *datalen, &len);
|
||||
if (lenlen < 0 || lenlen + len != *datalen)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*data += lenlen;
|
||||
*datalen -= lenlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_pem_decode_integer (unsigned char **data, unsigned int *datalen,
|
||||
unsigned char **i, unsigned int *ilen)
|
||||
{
|
||||
unsigned int len;
|
||||
int lenlen;
|
||||
|
||||
if (*datalen < 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((*data)[0] != '\x02')
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*data)++;
|
||||
(*datalen)--;
|
||||
|
||||
lenlen = read_asn1_length (*data, *datalen, &len);
|
||||
if (lenlen < 0 || lenlen + len > *datalen)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*data += lenlen;
|
||||
*datalen -= lenlen;
|
||||
|
||||
*i = *data;
|
||||
*ilen = len;
|
||||
|
||||
*data += len;
|
||||
*datalen -= len;
|
||||
|
||||
return 0;
|
||||
}
|
730
src/publickey.c
Normal file
730
src/publickey.c
Normal file
@@ -0,0 +1,730 @@
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names
|
||||
* of any other contributors may be used to endorse or
|
||||
* promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include "libssh2_publickey.h"
|
||||
|
||||
struct _LIBSSH2_PUBLICKEY {
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
unsigned long version;
|
||||
};
|
||||
|
||||
#define LIBSSH2_PUBLICKEY_VERSION 2
|
||||
|
||||
/* Numericised response codes -- Not IETF standard, just a local representation */
|
||||
#define LIBSSH2_PUBLICKEY_RESPONSE_STATUS 0
|
||||
#define LIBSSH2_PUBLICKEY_RESPONSE_VERSION 1
|
||||
#define LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY 2
|
||||
|
||||
typedef struct _LIBSSH2_PUBLICKEY_CODE_LIST {
|
||||
int code;
|
||||
char *name;
|
||||
int name_len;
|
||||
} LIBSSH2_PUBLICKEY_CODE_LIST;
|
||||
|
||||
static LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_response_codes[] = {
|
||||
{ LIBSSH2_PUBLICKEY_RESPONSE_STATUS, "status", sizeof("status") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_RESPONSE_VERSION, "version", sizeof("version") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY, "publickey", sizeof("publickey") - 1 },
|
||||
{ 0, NULL, 0 }
|
||||
};
|
||||
|
||||
/* PUBLICKEY status codes -- IETF defined */
|
||||
#define LIBSSH2_PUBLICKEY_SUCCESS 0
|
||||
#define LIBSSH2_PUBLICKEY_ACCESS_DENIED 1
|
||||
#define LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED 2
|
||||
#define LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED 3
|
||||
#define LIBSSH2_PUBLICKEY_KEY_NOT_FOUND 4
|
||||
#define LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED 5
|
||||
#define LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT 6
|
||||
#define LIBSSH2_PUBLICKEY_GENERAL_FAILURE 7
|
||||
#define LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED 8
|
||||
|
||||
#define LIBSSH2_PUBLICKEY_STATUS_CODE_MAX 8
|
||||
|
||||
static LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_status_codes[] = {
|
||||
{ LIBSSH2_PUBLICKEY_SUCCESS, "success", sizeof("success") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_ACCESS_DENIED, "access denied", sizeof("access denied") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED, "storage exceeded", sizeof("storage exceeded") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED, "version not supported", sizeof("version not supported") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_KEY_NOT_FOUND, "key not found", sizeof("key not found") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED, "key not supported", sizeof("key not supported") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT, "key already present", sizeof("key already present") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_GENERAL_FAILURE, "general failure", sizeof("general failure") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED, "request not supported", sizeof("request not supported") - 1 },
|
||||
{ 0, NULL, 0 }
|
||||
};
|
||||
|
||||
/* {{{ libssh2_publickey_status_error
|
||||
* Format an error message from a status code
|
||||
*/
|
||||
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_START "Publickey Subsystem Error: \""
|
||||
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_MID "\" Server Resports: \""
|
||||
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_END "\""
|
||||
static void libssh2_publickey_status_error(LIBSSH2_PUBLICKEY *pkey, LIBSSH2_SESSION *session, int status, unsigned char *message, int message_len)
|
||||
{
|
||||
char *status_text;
|
||||
int status_text_len;
|
||||
char *m, *s;
|
||||
int m_len;
|
||||
|
||||
/* GENERAL_FAILURE got remapped between version 1 and 2 */
|
||||
if (status == 6 && pkey && pkey->version == 1) {
|
||||
status = 7;
|
||||
}
|
||||
|
||||
if (status < 0 || status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) {
|
||||
status_text = "unknown";
|
||||
status_text_len = sizeof("unknown") - 1;
|
||||
} else {
|
||||
status_text = libssh2_publickey_status_codes[status].name;
|
||||
status_text_len = libssh2_publickey_status_codes[status].name_len;
|
||||
}
|
||||
|
||||
m_len = (sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1) + status_text_len +
|
||||
(sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1) + message_len +
|
||||
(sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
|
||||
m = LIBSSH2_ALLOC(session, m_len + 1);
|
||||
if (!m) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for status message", 0);
|
||||
return;
|
||||
}
|
||||
s = m;
|
||||
memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_START, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1);
|
||||
s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1;
|
||||
memcpy(s, status_text, status_text_len); s += status_text_len;
|
||||
memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_MID, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1);
|
||||
s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1;
|
||||
memcpy(s, message, message_len); s += message_len;
|
||||
memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_END, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
|
||||
s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, m, 1);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_packet_receive
|
||||
* Read a packet from the subsystem
|
||||
*/
|
||||
static int libssh2_publickey_packet_receive(LIBSSH2_PUBLICKEY *pkey, unsigned char **data, unsigned long *data_len)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = pkey->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char buffer[4];
|
||||
unsigned long packet_len;
|
||||
unsigned char *packet;
|
||||
|
||||
if (libssh2_channel_read(channel, (char *)buffer, 4) != 4) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid response from publickey subsystem", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
packet_len = libssh2_ntohu32(buffer);
|
||||
packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate publickey response buffer", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_channel_read(channel, (char *)packet, packet_len) != packet_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for publickey subsystem response packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*data = packet;
|
||||
*data_len = packet_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_response_id
|
||||
* Translate a string response name to a numeric code
|
||||
* Data will be incremented by 4 + response_len on success only
|
||||
*/
|
||||
static int libssh2_publickey_response_id(unsigned char **pdata, int data_len)
|
||||
{
|
||||
unsigned long response_len;
|
||||
unsigned char *data = *pdata;
|
||||
LIBSSH2_PUBLICKEY_CODE_LIST *codes = libssh2_publickey_response_codes;
|
||||
|
||||
if (data_len < 4) {
|
||||
/* Malformed response */
|
||||
return -1;
|
||||
}
|
||||
response_len = libssh2_ntohu32(data); data += 4; data_len -= 4;
|
||||
if (data_len < response_len) {
|
||||
/* Malformed response */
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (codes->name) {
|
||||
if (codes->name_len == response_len &&
|
||||
strncmp(codes->name, (char *)data, response_len) == 0) {
|
||||
*pdata = data + response_len;
|
||||
return codes->code;
|
||||
}
|
||||
codes++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_response_success
|
||||
* Generic helper routine to wait for success response and nothing else
|
||||
*/
|
||||
static int libssh2_publickey_response_success(LIBSSH2_PUBLICKEY *pkey)
|
||||
{
|
||||
LIBSSH2_SESSION *session = pkey->channel->session;
|
||||
unsigned char *data, *s;
|
||||
unsigned long data_len;
|
||||
int response;
|
||||
|
||||
while (1) {
|
||||
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = data;
|
||||
if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (response) {
|
||||
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
|
||||
/* Error, or processing complete */
|
||||
{
|
||||
unsigned long status, descr_len, lang_len;
|
||||
unsigned char *descr, *lang;
|
||||
|
||||
status = libssh2_ntohu32(s); s += 4;
|
||||
descr_len = libssh2_ntohu32(s); s += 4;
|
||||
descr = s; s += descr_len;
|
||||
lang_len = libssh2_ntohu32(s); s += 4;
|
||||
lang = s; s += lang_len;
|
||||
|
||||
if (s > data + data_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
libssh2_publickey_status_error(pkey, session, status, descr, descr_len);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
default:
|
||||
/* Unknown/Unexpected */
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
data = NULL;
|
||||
}
|
||||
}
|
||||
/* never reached, but include `return` to silence compiler warnings */
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* *****************
|
||||
* Publickey API *
|
||||
***************** */
|
||||
|
||||
/* {{{ libssh2_publickey_init
|
||||
* Startup the publickey subsystem
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session)
|
||||
{
|
||||
LIBSSH2_PUBLICKEY *pkey = NULL;
|
||||
LIBSSH2_CHANNEL *channel = NULL;
|
||||
unsigned char buffer[19];
|
||||
/* packet_len(4) +
|
||||
version_len(4) +
|
||||
"version"(7) +
|
||||
version_num(4) */
|
||||
unsigned char *s, *data = NULL;
|
||||
unsigned long data_len;
|
||||
int response;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Initializing publickey subsystem");
|
||||
#endif
|
||||
|
||||
channel = libssh2_channel_open_session(session);
|
||||
if (!channel) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to startup channel", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
if (libssh2_channel_subsystem(channel, "publickey")) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to request publickey subsystem", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
libssh2_channel_set_blocking(channel, 1);
|
||||
libssh2_channel_handle_extended_data(channel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
|
||||
|
||||
pkey = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PUBLICKEY));
|
||||
if (!pkey) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a new publickey structure", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
pkey->channel = channel;
|
||||
pkey->version = 0;
|
||||
|
||||
s = buffer;
|
||||
libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4); s += 4;
|
||||
libssh2_htonu32(s, sizeof("version") - 1); s += 4;
|
||||
memcpy(s, "version", sizeof("version") - 1); s += sizeof("version") - 1;
|
||||
libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION); s += 4;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey version packet advertising version %d support", (int)LIBSSH2_PUBLICKEY_VERSION);
|
||||
#endif
|
||||
if ((s - buffer) != libssh2_channel_write(channel, (char*)buffer, (s - buffer))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey version packet", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
s = data;
|
||||
if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
switch (response) {
|
||||
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
|
||||
/* Error */
|
||||
{
|
||||
unsigned long status, descr_len, lang_len;
|
||||
unsigned char *descr, *lang;
|
||||
|
||||
status = libssh2_ntohu32(s); s += 4;
|
||||
descr_len = libssh2_ntohu32(s); s += 4;
|
||||
descr = s; s += descr_len;
|
||||
lang_len = libssh2_ntohu32(s); s += 4;
|
||||
lang = s; s += lang_len;
|
||||
|
||||
if (s > data + data_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
libssh2_publickey_status_error(NULL, session, status, descr, descr_len);
|
||||
goto err_exit;
|
||||
}
|
||||
case LIBSSH2_PUBLICKEY_RESPONSE_VERSION:
|
||||
/* What we want */
|
||||
pkey->version = libssh2_ntohu32(s);
|
||||
if (pkey->version > LIBSSH2_PUBLICKEY_VERSION) {
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Truncating remote publickey version from %lu", pkey->version);
|
||||
#endif
|
||||
pkey->version = LIBSSH2_PUBLICKEY_VERSION;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Enabling publickey subsystem version %lu", pkey->version);
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
return pkey;
|
||||
default:
|
||||
/* Unknown/Unexpected */
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Never reached except by direct goto */
|
||||
err_exit:
|
||||
if (channel) {
|
||||
libssh2_channel_close(channel);
|
||||
}
|
||||
if (pkey) {
|
||||
LIBSSH2_FREE(session, pkey);
|
||||
}
|
||||
if (data) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_add_ex
|
||||
* Add a new public key entry
|
||||
*/
|
||||
LIBSSH2_API int libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
|
||||
const unsigned char *blob, unsigned long blob_len, char overwrite,
|
||||
unsigned long num_attrs, libssh2_publickey_attribute attrs[])
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = pkey->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char *packet = NULL, *s;
|
||||
unsigned long i, packet_len = 19 + name_len + blob_len;
|
||||
unsigned char *comment = NULL;
|
||||
unsigned long comment_len = 0;
|
||||
/* packet_len(4) +
|
||||
add_len(4) +
|
||||
"add"(3) +
|
||||
name_len(4) +
|
||||
{name}
|
||||
blob_len(4) +
|
||||
{blob} */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Adding %s pubickey", name);
|
||||
#endif
|
||||
|
||||
if (pkey->version == 1) {
|
||||
for(i = 0; i < num_attrs; i++) {
|
||||
/* Search for a comment attribute */
|
||||
if (attrs[i].name_len == (sizeof("comment") - 1) &&
|
||||
strncmp(attrs[i].name, "comment", sizeof("comment") - 1) == 0) {
|
||||
comment = (unsigned char *)attrs[i].value;
|
||||
comment_len = attrs[i].value_len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
packet_len += 4 + comment_len;
|
||||
} else {
|
||||
packet_len += 5; /* overwrite(1) + attribute_count(4) */
|
||||
for(i = 0; i < num_attrs; i++) {
|
||||
packet_len += 9 + attrs[i].name_len + attrs[i].value_len;
|
||||
/* name_len(4) + value_len(4) + mandatory(1) */
|
||||
}
|
||||
}
|
||||
|
||||
packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"add\" packet", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = packet;
|
||||
libssh2_htonu32(s, packet_len - 4); s += 4;
|
||||
libssh2_htonu32(s, sizeof("add") - 1); s += 4;
|
||||
memcpy(s, "add", sizeof("add") - 1); s += sizeof("add") - 1;
|
||||
if (pkey->version == 1) {
|
||||
libssh2_htonu32(s, comment_len); s += 4;
|
||||
if (comment) {
|
||||
memcpy(s, comment, comment_len); s += comment_len;
|
||||
}
|
||||
|
||||
libssh2_htonu32(s, name_len); s += 4;
|
||||
memcpy(s, name, name_len); s += name_len;
|
||||
libssh2_htonu32(s, blob_len); s += 4;
|
||||
memcpy(s, blob, blob_len); s += blob_len;
|
||||
} else {
|
||||
/* Version == 2 */
|
||||
|
||||
libssh2_htonu32(s, name_len); s += 4;
|
||||
memcpy(s, name, name_len); s += name_len;
|
||||
libssh2_htonu32(s, blob_len); s += 4;
|
||||
memcpy(s, blob, blob_len); s += blob_len;
|
||||
*(s++) = overwrite ? 0xFF : 0;
|
||||
libssh2_htonu32(s, num_attrs); s += 4;
|
||||
for(i = 0; i < num_attrs; i++) {
|
||||
libssh2_htonu32(s, attrs[i].name_len); s += 4;
|
||||
memcpy(s, attrs[i].name, attrs[i].name_len); s += attrs[i].name_len;
|
||||
libssh2_htonu32(s, attrs[i].value_len); s += 4;
|
||||
memcpy(s, attrs[i].value, attrs[i].value_len); s += attrs[i].value_len;
|
||||
*(s++) = attrs[i].mandatory ? 0xFF : 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"add\" packet: type=%s blob_len=%ld num_attrs=%ld", name, blob_len, num_attrs);
|
||||
#endif
|
||||
if ((s - packet) != libssh2_channel_write(channel, (char *)packet, (s - packet))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey add packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
packet = NULL;
|
||||
|
||||
return libssh2_publickey_response_success(pkey);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_remove_ex
|
||||
* Remove an existing publickey so that authentication can no longer be performed using it
|
||||
*/
|
||||
LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
|
||||
const unsigned char *blob, unsigned long blob_len)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = pkey->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char *s, *packet = NULL;
|
||||
unsigned long packet_len = 22 + name_len + blob_len;
|
||||
/* packet_len(4) +
|
||||
remove_len(4) +
|
||||
"remove"(6) +
|
||||
name_len(4) +
|
||||
{name}
|
||||
blob_len(4) +
|
||||
{blob} */
|
||||
|
||||
packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"remove\" packet", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = packet;
|
||||
libssh2_htonu32(s, packet_len - 4); s += 4;
|
||||
libssh2_htonu32(s, sizeof("remove") - 1); s += 4;
|
||||
memcpy(s, "remove", sizeof("remove") - 1); s += sizeof("remove") - 1;
|
||||
libssh2_htonu32(s, name_len); s += 4;
|
||||
memcpy(s, name, name_len); s += name_len;
|
||||
libssh2_htonu32(s, blob_len); s += 4;
|
||||
memcpy(s, blob, blob_len); s += blob_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"remove\" packet: type=%s blob_len=%ld", name, blob_len);
|
||||
#endif
|
||||
if ((s - packet) != libssh2_channel_write(channel, (char *)packet, (s - packet))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey remove packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
packet = NULL;
|
||||
|
||||
return libssh2_publickey_response_success(pkey);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_list_fetch
|
||||
* Fetch a list of supported public key from a server
|
||||
*/
|
||||
LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned long *num_keys, libssh2_publickey_list **pkey_list)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = pkey->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
libssh2_publickey_list *list = NULL;
|
||||
unsigned char *s, buffer[12], *data = NULL;
|
||||
unsigned long buffer_len = 12, keys = 0, max_keys = 0, data_len, i;
|
||||
/* packet_len(4) +
|
||||
list_len(4) +
|
||||
"list"(4) */
|
||||
int response;
|
||||
|
||||
s = buffer;
|
||||
libssh2_htonu32(s, buffer_len - 4); s += 4;
|
||||
libssh2_htonu32(s, sizeof("list") - 1); s += 4;
|
||||
memcpy(s, "list", sizeof("list") - 1); s += sizeof("list") - 1;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"list\" packet");
|
||||
#endif
|
||||
if ((s - buffer) != libssh2_channel_write(channel, (char *)buffer, (s - buffer))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey list packet", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
s = data;
|
||||
if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
switch (response) {
|
||||
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
|
||||
/* Error, or processing complete */
|
||||
{
|
||||
unsigned long status, descr_len, lang_len;
|
||||
unsigned char *descr, *lang;
|
||||
|
||||
status = libssh2_ntohu32(s); s += 4;
|
||||
descr_len = libssh2_ntohu32(s); s += 4;
|
||||
descr = s; s += descr_len;
|
||||
lang_len = libssh2_ntohu32(s); s += 4;
|
||||
lang = s; s += lang_len;
|
||||
|
||||
if (s > data + data_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
*pkey_list = list;
|
||||
*num_keys = keys;
|
||||
return 0;
|
||||
}
|
||||
|
||||
libssh2_publickey_status_error(pkey, session, status, descr, descr_len);
|
||||
goto err_exit;
|
||||
}
|
||||
case LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY:
|
||||
/* What we want */
|
||||
if (keys >= max_keys) {
|
||||
/* Grow the key list if necessary */
|
||||
max_keys += 8;
|
||||
list = LIBSSH2_REALLOC(session, list, (max_keys + 1) * sizeof(libssh2_publickey_list));
|
||||
if (!list) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey list", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
}
|
||||
if (pkey->version == 1) {
|
||||
unsigned long comment_len;
|
||||
|
||||
comment_len = libssh2_ntohu32(s); s += 4;
|
||||
if (comment_len) {
|
||||
list[keys].num_attrs = 1;
|
||||
list[keys].attrs = LIBSSH2_ALLOC(session, sizeof(libssh2_publickey_attribute));
|
||||
if (!list[keys].attrs) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey attributes", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
list[keys].attrs[0].name = "comment";
|
||||
list[keys].attrs[0].name_len = sizeof("comment") - 1;
|
||||
list[keys].attrs[0].value = (char *)s;
|
||||
list[keys].attrs[0].value_len = comment_len;
|
||||
list[keys].attrs[0].mandatory = 0;
|
||||
|
||||
s += comment_len;
|
||||
} else {
|
||||
list[keys].num_attrs = 0;
|
||||
list[keys].attrs = NULL;
|
||||
}
|
||||
list[keys].name_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].name = s; s += list[keys].name_len;
|
||||
list[keys].blob_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].blob = s; s += list[keys].blob_len;
|
||||
} else {
|
||||
/* Version == 2 */
|
||||
list[keys].name_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].name = s; s += list[keys].name_len;
|
||||
list[keys].blob_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].blob = s; s += list[keys].blob_len;
|
||||
list[keys].num_attrs = libssh2_ntohu32(s); s += 4;
|
||||
if (list[keys].num_attrs) {
|
||||
list[keys].attrs = LIBSSH2_ALLOC(session, list[keys].num_attrs * sizeof(libssh2_publickey_attribute));
|
||||
if (!list[keys].attrs) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey attributes", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
for(i = 0; i < list[keys].num_attrs; i++) {
|
||||
list[keys].attrs[i].name_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].attrs[i].name = (char *)s; s += list[keys].attrs[i].name_len;
|
||||
list[keys].attrs[i].value_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].attrs[i].value = (char *)s; s += list[keys].attrs[i].value_len;
|
||||
list[keys].attrs[i].mandatory = 0; /* actually an ignored value */
|
||||
}
|
||||
} else {
|
||||
list[keys].attrs = NULL;
|
||||
}
|
||||
}
|
||||
list[keys].packet = data; /* To be FREEd in libssh2_publickey_list_free() */
|
||||
keys++;
|
||||
|
||||
list[keys].packet = NULL; /* Terminate the list */
|
||||
data = NULL;
|
||||
break;
|
||||
default:
|
||||
/* Unknown/Unexpected */
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Only reached via explicit goto */
|
||||
err_exit:
|
||||
if (data) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
}
|
||||
if (list) {
|
||||
libssh2_publickey_list_free(pkey, list);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_list_free
|
||||
* Free a previously fetched list of public keys
|
||||
*/
|
||||
LIBSSH2_API void libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey, libssh2_publickey_list *pkey_list)
|
||||
{
|
||||
LIBSSH2_SESSION *session = pkey->channel->session;
|
||||
libssh2_publickey_list *p = pkey_list;
|
||||
|
||||
while (p->packet) {
|
||||
if (p->attrs) {
|
||||
LIBSSH2_FREE(session, p->attrs);
|
||||
}
|
||||
LIBSSH2_FREE(session, p->packet);
|
||||
p++;
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, pkey_list);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_shutdown
|
||||
* Shutdown the publickey subsystem
|
||||
*/
|
||||
LIBSSH2_API void libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey)
|
||||
{
|
||||
LIBSSH2_SESSION *session = pkey->channel->session;
|
||||
|
||||
libssh2_channel_free(pkey->channel);
|
||||
LIBSSH2_FREE(session, pkey);
|
||||
}
|
||||
/* }}} */
|
33
src/scp.c
33
src/scp.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -37,7 +37,6 @@
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define LIBSSH2_SCP_RESPONSE_BUFLEN 256
|
||||
@@ -45,7 +44,7 @@
|
||||
/* {{{ libssh2_scp_recv
|
||||
* Open a channel and request a remote file via SCP
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *path, struct stat *sb)
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb)
|
||||
{
|
||||
int path_len = strlen(path);
|
||||
unsigned char *command, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
@@ -71,6 +70,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
}
|
||||
command[command_len - 1] = '\0';
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Opening channel for SCP receive");
|
||||
#endif
|
||||
/* Allocate a channel */
|
||||
if ((channel = libssh2_channel_open_session(session)) == NULL) {
|
||||
LIBSSH2_FREE(session, command);
|
||||
@@ -87,6 +89,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
}
|
||||
LIBSSH2_FREE(session, command);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup");
|
||||
#endif
|
||||
/* SCP ACK */
|
||||
response[0] = '\0';
|
||||
if (libssh2_channel_write(channel, response, 1) != 1) {
|
||||
@@ -198,6 +203,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "mtime = %ld, atime = %ld", mtime, atime);
|
||||
#endif
|
||||
|
||||
/* We *should* check that atime.usec is valid, but why let that stop use? */
|
||||
break;
|
||||
@@ -296,6 +304,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "mod = 0%lo size = %ld", mode, size);
|
||||
#endif
|
||||
|
||||
/* We *should* check that basename is valid, but why let that stop us? */
|
||||
break;
|
||||
@@ -319,11 +330,12 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
/* {{{ libssh2_scp_send_ex
|
||||
* Send a file using SCP
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char *path, int mode, size_t size, long mtime, long atime)
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime)
|
||||
{
|
||||
int path_len = strlen(path);
|
||||
unsigned char *command, *base, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
unsigned char *command, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
unsigned long response_len, command_len = path_len + sizeof("scp -t ");
|
||||
unsigned const char *base;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
|
||||
if (mtime || atime) {
|
||||
@@ -345,8 +357,12 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
||||
}
|
||||
command[command_len - 1] = '\0';
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Opening channel for SCP send");
|
||||
#endif
|
||||
/* Allocate a channel */
|
||||
if ((channel = libssh2_channel_open_session(session)) == NULL) {
|
||||
/* previous call set libssh2_session_last_error(), pass it through */
|
||||
LIBSSH2_FREE(session, command);
|
||||
return NULL;
|
||||
}
|
||||
@@ -355,6 +371,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
||||
|
||||
/* Request SCP for the desired file */
|
||||
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
|
||||
/* previous call set libssh2_session_last_error(), pass it through */
|
||||
LIBSSH2_FREE(session, command);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
@@ -371,6 +388,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
||||
/* Send mtime and atime to be used for file */
|
||||
if (mtime || atime) {
|
||||
response_len = snprintf(response, LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", mtime, atime);
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s", response);
|
||||
#endif
|
||||
if (libssh2_channel_write(channel, response, response_len) != response_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send time data for SCP file", 0);
|
||||
libssh2_channel_free(channel);
|
||||
@@ -393,6 +413,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
||||
}
|
||||
|
||||
response_len = snprintf(response, LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %lu %s\n", mode, (unsigned long)size, base);
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s", response);
|
||||
#endif
|
||||
if (libssh2_channel_write(channel, response, response_len) != response_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send core file data for SCP file", 0);
|
||||
libssh2_channel_free(channel);
|
||||
|
566
src/session.c
566
src/session.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -37,9 +37,31 @@
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <errno.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
#include <sys/time.h>
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
# include <sys/poll.h>
|
||||
#else
|
||||
# ifdef HAVE_SELECT
|
||||
# ifdef HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
# else
|
||||
# include <sys/time.h>
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* {{{ libssh2_default_alloc
|
||||
*/
|
||||
static LIBSSH2_ALLOC_FUNC(libssh2_default_alloc)
|
||||
@@ -79,11 +101,30 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
|
||||
char c = '\0';
|
||||
int ret;
|
||||
|
||||
ret = read(session->socket_fd, &c, 1);
|
||||
ret = recv(session->socket_fd, &c, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
|
||||
if ((ret < 0) && (ret != EAGAIN)) {
|
||||
/* Some kinda error, but don't break for non-blocking issues */
|
||||
return 1;
|
||||
if (ret < 0) {
|
||||
#ifdef WIN32
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAEWOULDBLOCK:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
case WSAENOTSOCK:
|
||||
errno = EBADF;
|
||||
break;
|
||||
case WSAENOTCONN:
|
||||
case WSAECONNABORTED:
|
||||
errno = ENOTCONN;
|
||||
break;
|
||||
case WSAEINTR:
|
||||
errno = EINTR;
|
||||
break;
|
||||
}
|
||||
#endif /* WIN32 */
|
||||
if (errno != EAGAIN) {
|
||||
/* Some kinda error, but don't break for non-blocking issues */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret <= 0) continue;
|
||||
@@ -106,6 +147,9 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
|
||||
session->remote.banner = LIBSSH2_ALLOC(session, banner_len + 1);
|
||||
memcpy(session->remote.banner, banner, banner_len);
|
||||
session->remote.banner[banner_len] = '\0';
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Received Banner: %s", session->remote.banner);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -123,8 +167,59 @@ static int libssh2_banner_send(LIBSSH2_SESSION *session)
|
||||
banner_len = strlen(session->local.banner);
|
||||
banner = session->local.banner;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
{
|
||||
/* Hack and slash to avoid sending CRLF in debug output */
|
||||
char banner_dup[256];
|
||||
|
||||
return (write(session->socket_fd, banner, banner_len) == banner_len) ? 0 : 1;
|
||||
if (banner_len < 256) {
|
||||
memcpy(banner_dup, banner, banner_len - 2);
|
||||
banner_dup[banner_len - 2] = '\0';
|
||||
} else {
|
||||
memcpy(banner_dup, banner, 255);
|
||||
banner[255] = '\0';
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending Banner: %s", banner_dup);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (send(session->socket_fd, banner, banner_len, LIBSSH2_SOCKET_SEND_FLAGS(session)) == banner_len) ? 0 : 1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_banner_set
|
||||
* Set the local banner
|
||||
*/
|
||||
LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, const char *banner)
|
||||
{
|
||||
int banner_len = banner ? strlen(banner) : 0;
|
||||
|
||||
if (session->local.banner) {
|
||||
LIBSSH2_FREE(session, session->local.banner);
|
||||
session->local.banner = NULL;
|
||||
}
|
||||
|
||||
if (!banner_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
session->local.banner = LIBSSH2_ALLOC(session, banner_len + 3);
|
||||
if (!session->local.banner) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for local banner", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(session->local.banner, banner, banner_len);
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
session->local.banner[banner_len] = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting local Banner: %s", session->local.banner);
|
||||
#endif
|
||||
session->local.banner[banner_len++] = '\r';
|
||||
session->local.banner[banner_len++] = '\n';
|
||||
session->local.banner[banner_len++] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -155,6 +250,11 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(
|
||||
session->free = local_free;
|
||||
session->realloc = local_realloc;
|
||||
session->abstract = abstract;
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "New session resource allocated");
|
||||
#endif
|
||||
|
||||
libssh2_crypto_init ();
|
||||
|
||||
return session;
|
||||
}
|
||||
@@ -189,7 +289,15 @@ LIBSSH2_API void* libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbt
|
||||
session->macerror = callback;
|
||||
return oldcb;
|
||||
break;
|
||||
case LIBSSH2_CALLBACK_X11:
|
||||
oldcb = session->x11;
|
||||
session->x11 = callback;
|
||||
return oldcb;
|
||||
break;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting Callback %d", cbtype);
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -208,14 +316,22 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
|
||||
unsigned char service[sizeof("ssh-userauth") + 5 - 1];
|
||||
unsigned long service_length;
|
||||
|
||||
if (socket <= 0) {
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "session_startup for socket %d", socket);
|
||||
#endif
|
||||
if (socket < 0) {
|
||||
/* Did we forget something? */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE, "No socket provided", 0);
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE, "Bad socket provided", 0);
|
||||
return LIBSSH2_ERROR_SOCKET_NONE;
|
||||
}
|
||||
session->socket_fd = socket;
|
||||
|
||||
/* TODO: Liveness check */
|
||||
if (libssh2_banner_send(session)) {
|
||||
/* Unable to send banner? */
|
||||
libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND, "Error sending banner to remote host", 0);
|
||||
return LIBSSH2_ERROR_BANNER_SEND;
|
||||
}
|
||||
|
||||
if (libssh2_banner_receive(session)) {
|
||||
/* Unable to receive banner from remote */
|
||||
@@ -223,17 +339,14 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
|
||||
return LIBSSH2_ERROR_BANNER_NONE;
|
||||
}
|
||||
|
||||
if (libssh2_banner_send(session)) {
|
||||
/* Unable to send banner? */
|
||||
libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND, "Error sending banner to remote host", 0);
|
||||
return LIBSSH2_ERROR_BANNER_SEND;
|
||||
}
|
||||
|
||||
if (libssh2_kex_exchange(session, 0)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, "Unable to exchange encryption keys", 0);
|
||||
return LIBSSH2_ERROR_KEX_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Requesting userauth service");
|
||||
#endif
|
||||
/* Request the userauth service */
|
||||
service[0] = SSH_MSG_SERVICE_REQUEST;
|
||||
libssh2_htonu32(service + 1, sizeof("ssh-userauth") - 1);
|
||||
@@ -266,6 +379,9 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
|
||||
*/
|
||||
LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
{
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Freeing session resource", session->remote.banner);
|
||||
#endif
|
||||
while (session->channels.head) {
|
||||
LIBSSH2_CHANNEL *tmp = session->channels.head;
|
||||
|
||||
@@ -284,7 +400,11 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
}
|
||||
}
|
||||
|
||||
if (session->newkeys) {
|
||||
while (session->listeners) {
|
||||
libssh2_channel_forward_cancel(session->listeners);
|
||||
}
|
||||
|
||||
if (session->state & LIBSSH2_STATE_NEWKEYS) {
|
||||
/* hostkey */
|
||||
if (session->hostkey && session->hostkey->dtor) {
|
||||
session->hostkey->dtor(session, &session->server_hostkey_abstract);
|
||||
@@ -292,15 +412,8 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
|
||||
/* Client to Server */
|
||||
/* crypt */
|
||||
if (session->local.crypt) {
|
||||
if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
if (session->local.crypt_abstract) {
|
||||
LIBSSH2_FREE(session, session->local.crypt_abstract);
|
||||
session->local.crypt_abstract = NULL;
|
||||
}
|
||||
} else if (session->local.crypt->dtor) {
|
||||
session->local.crypt->dtor(session, &session->local.crypt_abstract);
|
||||
}
|
||||
if (session->local.crypt && session->local.crypt->dtor) {
|
||||
session->local.crypt->dtor(session, &session->local.crypt_abstract);
|
||||
}
|
||||
/* comp */
|
||||
if (session->local.comp && session->local.comp->dtor) {
|
||||
@@ -313,15 +426,8 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
|
||||
/* Server to Client */
|
||||
/* crypt */
|
||||
if (session->remote.crypt) {
|
||||
if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
if (session->remote.crypt_abstract) {
|
||||
LIBSSH2_FREE(session, session->remote.crypt_abstract);
|
||||
session->remote.crypt_abstract = NULL;
|
||||
}
|
||||
} else if (session->remote.crypt->dtor) {
|
||||
session->remote.crypt->dtor(session, &session->remote.crypt_abstract);
|
||||
}
|
||||
if (session->remote.crypt && session->remote.crypt->dtor) {
|
||||
session->remote.crypt->dtor(session, &session->remote.crypt_abstract);
|
||||
}
|
||||
/* comp */
|
||||
if (session->remote.comp && session->remote.comp->dtor) {
|
||||
@@ -392,21 +498,20 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
LIBSSH2_FREE(session, tmp);
|
||||
}
|
||||
|
||||
if (session->local.banner) {
|
||||
LIBSSH2_FREE(session, session->local.banner);
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, session);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_session_disconnect_ex
|
||||
*/
|
||||
LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, char *description, char *lang)
|
||||
LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, const char *description, const char *lang)
|
||||
{
|
||||
unsigned char *s, *data;
|
||||
unsigned long data_len, descr_len = 0, lang_len = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Disconnecting: reason=%d, desc=%s, lang=%s", reason, description, lang);
|
||||
#endif
|
||||
if (description) {
|
||||
descr_len = strlen(description);
|
||||
}
|
||||
@@ -445,51 +550,63 @@ LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reas
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_session_methods
|
||||
* Return the currently active methods
|
||||
* Return the currently active methods for method_type
|
||||
* NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string regardless of actual negotiation
|
||||
* Strings should NOT be freed
|
||||
*/
|
||||
LIBSSH2_API void libssh2_session_methods(LIBSSH2_SESSION *session, char **kex, char **hostkey,
|
||||
char **crypt_cs, char **crypt_sc,
|
||||
char **mac_cs, char **mac_sc,
|
||||
char **comp_cs, char **comp_sc,
|
||||
char **lang_cs, char **lang_sc)
|
||||
LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type)
|
||||
{
|
||||
if (kex) {
|
||||
*kex = session->kex->name;
|
||||
/* All methods have char *name as their first element */
|
||||
LIBSSH2_KEX_METHOD *method = NULL;
|
||||
|
||||
switch(method_type) {
|
||||
case LIBSSH2_METHOD_KEX:
|
||||
method = session->kex;
|
||||
break;
|
||||
case LIBSSH2_METHOD_HOSTKEY:
|
||||
method = (LIBSSH2_KEX_METHOD*)session->hostkey;
|
||||
break;
|
||||
case LIBSSH2_METHOD_CRYPT_CS:
|
||||
method = (LIBSSH2_KEX_METHOD*)session->local.crypt;
|
||||
break;
|
||||
case LIBSSH2_METHOD_CRYPT_SC:
|
||||
method = (LIBSSH2_KEX_METHOD*)session->remote.crypt;
|
||||
break;
|
||||
case LIBSSH2_METHOD_MAC_CS:
|
||||
method = (LIBSSH2_KEX_METHOD*)session->local.mac;
|
||||
break;
|
||||
case LIBSSH2_METHOD_MAC_SC:
|
||||
method = (LIBSSH2_KEX_METHOD*)session->remote.mac;
|
||||
break;
|
||||
case LIBSSH2_METHOD_COMP_CS:
|
||||
method = (LIBSSH2_KEX_METHOD*)session->local.comp;
|
||||
break;
|
||||
case LIBSSH2_METHOD_COMP_SC:
|
||||
method = (LIBSSH2_KEX_METHOD*)session->remote.comp;
|
||||
break;
|
||||
case LIBSSH2_METHOD_LANG_CS:
|
||||
return "";
|
||||
break;
|
||||
case LIBSSH2_METHOD_LANG_SC:
|
||||
return "";
|
||||
break;
|
||||
default:
|
||||
libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid parameter specified for method_type", 0);
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
if (hostkey) {
|
||||
*hostkey = session->hostkey->name;
|
||||
}
|
||||
if (crypt_cs) {
|
||||
*crypt_cs = session->local.crypt->name;
|
||||
}
|
||||
if (crypt_sc) {
|
||||
*crypt_sc = session->remote.crypt->name;
|
||||
}
|
||||
if (mac_cs) {
|
||||
*mac_cs = session->local.mac->name;
|
||||
}
|
||||
if (mac_sc) {
|
||||
*mac_sc = session->remote.mac->name;
|
||||
}
|
||||
if (comp_cs) {
|
||||
*comp_cs = session->local.comp->name;
|
||||
}
|
||||
if (comp_sc) {
|
||||
*comp_sc = session->remote.comp->name;
|
||||
}
|
||||
if (lang_cs) {
|
||||
*lang_cs = "";
|
||||
}
|
||||
if (lang_sc) {
|
||||
*lang_sc = "";
|
||||
|
||||
if (!method) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, "No method negotiated", 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return method->name;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_session_abstract
|
||||
* Retreive a pointer to the abstract property
|
||||
* Retrieve a pointer to the abstract property
|
||||
*/
|
||||
LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session)
|
||||
{
|
||||
@@ -551,3 +668,306 @@ LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errm
|
||||
return session->err_code;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_session_flag
|
||||
* Set/Get session flags
|
||||
* Passing flag==0 will avoid changing session->flags while still returning its current value
|
||||
*/
|
||||
LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value)
|
||||
{
|
||||
if (value) {
|
||||
session->flags |= flag;
|
||||
} else {
|
||||
session->flags &= ~flag;
|
||||
}
|
||||
|
||||
return session->flags;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_poll_channel_read
|
||||
* Returns 0 if no data is waiting on channel,
|
||||
* non-0 if data is available
|
||||
*/
|
||||
LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended)
|
||||
{
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
LIBSSH2_PACKET *packet = session->packets.head;
|
||||
|
||||
while (packet) {
|
||||
if (((packet->data[0] == SSH_MSG_CHANNEL_DATA) && (extended == 0) && (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
|
||||
((packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (extended != 0) && (channel->local.id == libssh2_ntohu32(packet->data + 1)))) {
|
||||
/* Found data waiting to be read */
|
||||
return 1;
|
||||
}
|
||||
packet = packet->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_poll_channel_write
|
||||
* Returns 0 if writing to channel would block,
|
||||
* non-0 if data can be written without blocking
|
||||
*/
|
||||
inline int libssh2_poll_channel_write(LIBSSH2_CHANNEL *channel)
|
||||
{
|
||||
return channel->local.window_size ? 1 : 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_poll_listener_queued
|
||||
* Returns 0 if no connections are waiting to be accepted
|
||||
* non-0 if one or more connections are available
|
||||
*/
|
||||
inline int libssh2_poll_listener_queued(LIBSSH2_LISTENER *listener)
|
||||
{
|
||||
return listener->queue ? 1 : 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_poll
|
||||
* Poll sockets, channels, and listeners for activity
|
||||
*/
|
||||
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout)
|
||||
{
|
||||
long timeout_remaining;
|
||||
int i, active_fds;
|
||||
#ifdef HAVE_POLL
|
||||
LIBSSH2_SESSION *session = NULL;
|
||||
struct pollfd sockets[nfds];
|
||||
|
||||
/* Setup sockets for polling */
|
||||
for(i = 0; i < nfds; i++) {
|
||||
fds[i].revents = 0;
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_SOCKET:
|
||||
sockets[i].fd = fds[i].fd.socket;
|
||||
sockets[i].events = fds[i].events;
|
||||
sockets[i].revents = 0;
|
||||
break;
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
sockets[i].fd = fds[i].fd.channel->session->socket_fd;
|
||||
sockets[i].events = POLLIN;
|
||||
sockets[i].revents = 0;
|
||||
if (!session) session = fds[i].fd.channel->session;
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
sockets[i].fd = fds[i].fd.listener->session->socket_fd;
|
||||
sockets[i].events = POLLIN;
|
||||
sockets[i].revents = 0;
|
||||
if (!session) session = fds[i].fd.listener->session;
|
||||
break;
|
||||
default:
|
||||
if (session) libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, "Invalid descriptor passed to libssh2_poll()", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_SELECT)
|
||||
LIBSSH2_SESSION *session = NULL;
|
||||
int maxfd = 0;
|
||||
fd_set rfds,wfds;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
for(i = 0; i < nfds; i++) {
|
||||
fds[i].revents = 0;
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_SOCKET:
|
||||
if (fds[i].events & LIBSSH2_POLLFD_POLLIN) {
|
||||
FD_SET(fds[i].fd.socket, &rfds);
|
||||
if (fds[i].fd.socket > maxfd) maxfd = fds[i].fd.socket;
|
||||
}
|
||||
if (fds[i].events & LIBSSH2_POLLFD_POLLOUT) {
|
||||
FD_SET(fds[i].fd.socket, &wfds);
|
||||
if (fds[i].fd.socket > maxfd) maxfd = fds[i].fd.socket;
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
FD_SET(fds[i].fd.channel->session->socket_fd, &rfds);
|
||||
if (fds[i].fd.channel->session->socket_fd > maxfd) maxfd = fds[i].fd.channel->session->socket_fd;
|
||||
if (!session) session = fds[i].fd.channel->session;
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
FD_SET(fds[i].fd.listener->session->socket_fd, &rfds);
|
||||
if (fds[i].fd.listener->session->socket_fd > maxfd) maxfd = fds[i].fd.listener->session->socket_fd;
|
||||
if (!session) session = fds[i].fd.listener->session;
|
||||
break;
|
||||
default:
|
||||
if (session) libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, "Invalid descriptor passed to libssh2_poll()", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* No select() or poll()
|
||||
* no sockets sturcture to setup
|
||||
*/
|
||||
|
||||
timeout = 0;
|
||||
#endif /* HAVE_POLL or HAVE_SELECT */
|
||||
|
||||
timeout_remaining = timeout;
|
||||
do {
|
||||
#if defined(HAVE_POLL) || defined(HAVE_SELECT)
|
||||
int sysret;
|
||||
#endif
|
||||
|
||||
active_fds = 0;
|
||||
|
||||
for (i = 0; i < nfds; i++) {
|
||||
if (fds[i].events != fds[i].revents) {
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want to be ready for read */
|
||||
((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* Not yet known to be ready for read */
|
||||
fds[i].revents |= libssh2_poll_channel_read(fds[i].fd.channel, 0) ? LIBSSH2_POLLFD_POLLIN : 0;
|
||||
}
|
||||
if ((fds[i].events & LIBSSH2_POLLFD_POLLEXT) && /* Want to be ready for extended read */
|
||||
((fds[i].revents & LIBSSH2_POLLFD_POLLEXT) == 0)) { /* Not yet known to be ready for extended read */
|
||||
fds[i].revents |= libssh2_poll_channel_read(fds[i].fd.channel, 1) ? LIBSSH2_POLLFD_POLLEXT : 0;
|
||||
}
|
||||
if ((fds[i].events & LIBSSH2_POLLFD_POLLOUT) && /* Want to be ready for write */
|
||||
((fds[i].revents & LIBSSH2_POLLFD_POLLOUT) == 0)) { /* Not yet known to be ready for write */
|
||||
fds[i].revents |= libssh2_poll_channel_write(fds[i].fd.channel) ? LIBSSH2_POLLFD_POLLOUT : 0;
|
||||
}
|
||||
if (fds[i].fd.channel->remote.close || fds[i].fd.channel->local.close) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED;
|
||||
}
|
||||
if (fds[i].fd.channel->session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want a connection */
|
||||
((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* No connections known of yet */
|
||||
fds[i].revents |= libssh2_poll_listener_queued(fds[i].fd.listener) ? LIBSSH2_POLLFD_POLLIN : 0;
|
||||
}
|
||||
if (fds[i].fd.listener->session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_LISTENER_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fds[i].revents) {
|
||||
active_fds++;
|
||||
}
|
||||
}
|
||||
|
||||
if (active_fds) {
|
||||
/* Don't block on the sockets if we have channels/listeners which are ready */
|
||||
timeout_remaining = 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
{
|
||||
struct timeval tv_begin, tv_end;
|
||||
|
||||
gettimeofday((struct timeval *)&tv_begin, NULL);
|
||||
sysret = poll(sockets, nfds, timeout_remaining);
|
||||
gettimeofday((struct timeval *)&tv_end, NULL);
|
||||
timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
|
||||
timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
|
||||
}
|
||||
#else
|
||||
/* If the platform doesn't support gettimeofday,
|
||||
* then just make the call non-blocking and walk away
|
||||
*/
|
||||
sysret = poll(sockets, nfds, timeout_remaining);
|
||||
timeout_remaining = 0;
|
||||
#endif /* HAVE_GETTIMEOFDAY */
|
||||
|
||||
if (sysret > 0) {
|
||||
for (i = 0; i < nfds; i++) {
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_SOCKET:
|
||||
fds[i].revents = sockets[i].revents;
|
||||
sockets[i].revents = 0; /* In case we loop again, be nice */
|
||||
if (fds[i].revents) {
|
||||
active_fds++;
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
if (sockets[i].events & POLLIN) {
|
||||
/* Spin session until no data available */
|
||||
while (libssh2_packet_read(fds[i].fd.channel->session, 0) > 0);
|
||||
}
|
||||
if (sockets[i].revents & POLLHUP) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
|
||||
}
|
||||
sockets[i].revents = 0;
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
if (sockets[i].events & POLLIN) {
|
||||
/* Spin session until no data available */
|
||||
while (libssh2_packet_read(fds[i].fd.listener->session, 0) > 0);
|
||||
}
|
||||
if (sockets[i].revents & POLLHUP) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_LISTENER_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
|
||||
}
|
||||
sockets[i].revents = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_SELECT)
|
||||
tv.tv_sec = timeout_remaining / 1000;
|
||||
tv.tv_usec = (timeout_remaining % 1000) * 1000;
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
{
|
||||
struct timeval tv_begin, tv_end;
|
||||
|
||||
gettimeofday((struct timeval *)&tv_begin, NULL);
|
||||
sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
|
||||
gettimeofday((struct timeval *)&tv_end, NULL);
|
||||
|
||||
timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
|
||||
timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
|
||||
}
|
||||
#else
|
||||
/* If the platform doesn't support gettimeofday,
|
||||
* then just make the call non-blocking and walk away
|
||||
*/
|
||||
sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
|
||||
timeout_remaining = 0;
|
||||
#endif
|
||||
|
||||
if (sysret > 0) {
|
||||
for (i = 0; i < nfds; i++) {
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_SOCKET:
|
||||
if (FD_ISSET(fds[i].fd.socket, &rfds)) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_POLLIN;
|
||||
}
|
||||
if (FD_ISSET(fds[i].fd.socket, &wfds)) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_POLLOUT;
|
||||
}
|
||||
if (fds[i].revents) {
|
||||
active_fds++;
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) {
|
||||
/* Spin session until no data available */
|
||||
while (libssh2_packet_read(fds[i].fd.channel->session, 0) > 0);
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
if (FD_ISSET(fds[i].fd.listener->session->socket_fd, &rfds)) {
|
||||
/* Spin session until no data available */
|
||||
while (libssh2_packet_read(fds[i].fd.listener->session, 0) > 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* else no select() or poll() -- timeout (and by extension timeout_remaining) will be equal to 0 */
|
||||
} while ((timeout_remaining > 0) && !active_fds);
|
||||
|
||||
return active_fds;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
248
src/sftp.c
248
src/sftp.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -83,12 +83,17 @@ struct _LIBSSH2_SFTP {
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *handles;
|
||||
|
||||
unsigned long errno;
|
||||
unsigned long last_errno;
|
||||
};
|
||||
|
||||
#define LIBSSH2_SFTP_HANDLE_FILE 0
|
||||
#define LIBSSH2_SFTP_HANDLE_DIR 1
|
||||
|
||||
/* S_IFREG */
|
||||
#define LIBSSH2_SFTP_ATTR_PFILETYPE_FILE 0100000
|
||||
/* S_IFDIR */
|
||||
#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR 0040000
|
||||
|
||||
struct _LIBSSH2_SFTP_HANDLE {
|
||||
LIBSSH2_SFTP *sftp;
|
||||
LIBSSH2_SFTP_HANDLE *prev, *next;
|
||||
@@ -100,7 +105,7 @@ struct _LIBSSH2_SFTP_HANDLE {
|
||||
|
||||
union _libssh2_sftp_handle_data {
|
||||
struct _libssh2_sftp_handle_file_data {
|
||||
unsigned long long offset;
|
||||
libssh2_uint64_t offset;
|
||||
} file;
|
||||
struct _libssh2_sftp_handle_dir_data {
|
||||
unsigned long names_left;
|
||||
@@ -118,6 +123,9 @@ static int libssh2_sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data, unsi
|
||||
LIBSSH2_SESSION *session = sftp->channel->session;
|
||||
LIBSSH2_PACKET *packet;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Received packet %d", (int)data[0]);
|
||||
#endif
|
||||
packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate datablock for SFTP packet", 0);
|
||||
@@ -151,8 +159,11 @@ static int libssh2_sftp_packet_read(LIBSSH2_SFTP *sftp, int should_block)
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char buffer[4]; /* To store the packet length */
|
||||
unsigned char *packet;
|
||||
unsigned long packet_len;
|
||||
unsigned long packet_len, packet_received;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Waiting for packet: %s block", should_block ? "will" : "willnot");
|
||||
#endif
|
||||
if (should_block) {
|
||||
libssh2_channel_set_blocking(channel, 1);
|
||||
if (4 != libssh2_channel_read(channel, buffer, 4)) {
|
||||
@@ -172,6 +183,9 @@ static int libssh2_sftp_packet_read(LIBSSH2_SFTP *sftp, int should_block)
|
||||
}
|
||||
}
|
||||
packet_len = libssh2_ntohu32(buffer);
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Data begin - Packet Length: %lu", packet_len);
|
||||
#endif
|
||||
if (packet_len > LIBSSH2_SFTP_PACKET_MAXLEN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, "SFTP packet too large", 0);
|
||||
return -1;
|
||||
@@ -183,10 +197,16 @@ static int libssh2_sftp_packet_read(LIBSSH2_SFTP *sftp, int should_block)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (packet_len != libssh2_channel_read(channel, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for SFTP packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
packet_received = 0;
|
||||
while (packet_len > packet_received) {
|
||||
long bytes_received = libssh2_channel_read(channel, packet + packet_received, packet_len - packet_received);
|
||||
|
||||
if (bytes_received < 0) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Receive error waiting for SFTP packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
packet_received += bytes_received;
|
||||
}
|
||||
|
||||
if (libssh2_sftp_packet_add(sftp, packet, packet_len)) {
|
||||
@@ -206,7 +226,11 @@ static int libssh2_sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type
|
||||
LIBSSH2_SESSION *session = sftp->channel->session;
|
||||
LIBSSH2_PACKET *packet = sftp->packets.head;
|
||||
unsigned char match_buf[5];
|
||||
int match_len = 5;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Asking for %d packet", (int)packet_type);
|
||||
#endif
|
||||
if (poll_channel) {
|
||||
if (libssh2_sftp_packet_read(sftp, 0) < 0) {
|
||||
return -1;
|
||||
@@ -214,10 +238,15 @@ static int libssh2_sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type
|
||||
}
|
||||
|
||||
match_buf[0] = packet_type;
|
||||
libssh2_htonu32(match_buf + 1, request_id);
|
||||
if (packet_type == SSH_FXP_VERSION) {
|
||||
/* Special consideration when matching VERSION packet */
|
||||
match_len = 1;
|
||||
} else {
|
||||
libssh2_htonu32(match_buf + 1, request_id);
|
||||
}
|
||||
|
||||
while (packet) {
|
||||
if (strncmp(packet->data, match_buf, 5) == 0) {
|
||||
if (strncmp(packet->data, match_buf, match_len) == 0) {
|
||||
*data = packet->data;
|
||||
*data_len = packet->data_len;
|
||||
|
||||
@@ -250,6 +279,9 @@ static int libssh2_sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_
|
||||
{
|
||||
LIBSSH2_SESSION *session = sftp->channel->session;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Requiring %d packet", (int)packet_type);
|
||||
#endif
|
||||
if (libssh2_sftp_packet_ask(sftp, packet_type, request_id, data, data_len, 0) == 0) {
|
||||
/* A packet was available in the packet brigade */
|
||||
return 0;
|
||||
@@ -280,12 +312,21 @@ static int libssh2_sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_respon
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Flush */
|
||||
while (libssh2_sftp_packet_read(sftp, 0) > 0);
|
||||
|
||||
while (sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
||||
int ret;
|
||||
for(i = 0; i < num_valid_responses; i++) {
|
||||
if (libssh2_sftp_packet_ask(sftp, valid_responses[i], request_id, data, data_len, !i) == 0) {
|
||||
if (libssh2_sftp_packet_ask(sftp, valid_responses[i], request_id, data, data_len, 0) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ret = libssh2_sftp_packet_read(sftp, 1);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) continue;
|
||||
}
|
||||
|
||||
return -1;
|
||||
@@ -318,13 +359,16 @@ static int libssh2_sftp_attrsize(LIBSSH2_SFTP_ATTRIBUTES *attrs)
|
||||
static int libssh2_sftp_attr2bin(unsigned char *p, LIBSSH2_SFTP_ATTRIBUTES *attrs)
|
||||
{
|
||||
unsigned char *s = p;
|
||||
unsigned long flag_mask = LIBSSH2_SFTP_ATTR_SIZE | LIBSSH2_SFTP_ATTR_UIDGID | LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME;
|
||||
|
||||
/* TODO: When we add SFTP4+ functionality flag_mask can get additional bits */
|
||||
|
||||
if (!attrs) {
|
||||
libssh2_htonu32(s, 0);
|
||||
return 4;
|
||||
}
|
||||
|
||||
libssh2_htonu32(s, attrs->flags & 0x0000000); s += 4;
|
||||
libssh2_htonu32(s, attrs->flags & flag_mask); s += 4;
|
||||
|
||||
if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
|
||||
libssh2_htonu64(s, attrs->filesize); s += 8;
|
||||
@@ -405,9 +449,12 @@ LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session)
|
||||
{
|
||||
LIBSSH2_SFTP *sftp;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
unsigned char *data, *s, buffer[13]; /* sftp_header(9) + version_id(4) */
|
||||
unsigned long data_len, request_id;
|
||||
unsigned char *data, *s, buffer[9]; /* sftp_header(5){excludes request_id} + version_id(4) */
|
||||
unsigned long data_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Initializing SFTP subsystem");
|
||||
#endif
|
||||
channel = libssh2_channel_open_session(session);
|
||||
if (!channel) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to startup channel", 0);
|
||||
@@ -421,6 +468,8 @@ LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session)
|
||||
|
||||
libssh2_channel_set_blocking(channel, 1);
|
||||
|
||||
libssh2_channel_handle_extended_data(channel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
|
||||
|
||||
sftp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP));
|
||||
if (!sftp) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a new SFTP structure", 0);
|
||||
@@ -429,21 +478,23 @@ LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session)
|
||||
}
|
||||
memset(sftp, 0, sizeof(LIBSSH2_SFTP));
|
||||
sftp->channel = channel;
|
||||
sftp->request_id = 0;
|
||||
|
||||
request_id = sftp->request_id++;
|
||||
libssh2_htonu32(buffer, 4 + 5);
|
||||
libssh2_htonu32(buffer, 5);
|
||||
buffer[4] = SSH_FXP_INIT;
|
||||
libssh2_htonu32(buffer + 5, request_id);
|
||||
libssh2_htonu32(buffer + 9, 6);
|
||||
libssh2_htonu32(buffer + 5, LIBSSH2_SFTP_VERSION);
|
||||
|
||||
if (13 != libssh2_channel_write(channel, buffer, 13)) {
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending FXP_INIT packet advertising version %d support", (int)LIBSSH2_SFTP_VERSION);
|
||||
#endif
|
||||
if (9 != libssh2_channel_write(channel, buffer, 9)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send SSH_FXP_INIT", 0);
|
||||
libssh2_channel_free(channel);
|
||||
LIBSSH2_FREE(session, sftp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (libssh2_sftp_packet_require(sftp, SSH_FXP_VERSION, request_id, &data, &data_len)) {
|
||||
if (libssh2_sftp_packet_require(sftp, SSH_FXP_VERSION, 0, &data, &data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from SFTP subsystem", 0);
|
||||
libssh2_channel_free(channel);
|
||||
LIBSSH2_FREE(session, sftp);
|
||||
@@ -459,8 +510,14 @@ LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session)
|
||||
s = data + 1;
|
||||
sftp->version = libssh2_ntohu32(s); s += 4;
|
||||
if (sftp->version > LIBSSH2_SFTP_VERSION) {
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Truncating remote SFTP version from %lu", sftp->version);
|
||||
#endif
|
||||
sftp->version = LIBSSH2_SFTP_VERSION;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Enabling SFTP version %lu compatability", sftp->version);
|
||||
#endif
|
||||
while (s < (data + data_len)) {
|
||||
char *extension_name, *extension_data;
|
||||
unsigned long extname_len, extdata_len;
|
||||
@@ -498,7 +555,7 @@ LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp) {
|
||||
/* {{{ libssh2_sftp_open_ex
|
||||
*
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *filename, int filename_len, unsigned long flags, long mode, int open_type)
|
||||
LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *filename, unsigned int filename_len, unsigned long flags, long mode, int open_type)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
@@ -512,10 +569,11 @@ LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *
|
||||
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_REMOVE packet", 0);
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_OPEN or FXP_OPENDIR packet", 0);
|
||||
return NULL;
|
||||
}
|
||||
attrs.permissions = mode;
|
||||
/* Filetype in SFTP 3 and earlier */
|
||||
attrs.permissions = mode | ((open_type == LIBSSH2_SFTP_OPENFILE) ? LIBSSH2_SFTP_ATTR_PFILETYPE_FILE : LIBSSH2_SFTP_ATTR_PFILETYPE_DIR);
|
||||
|
||||
libssh2_htonu32(s, packet_len - 4); s += 4;
|
||||
*(s++) = (open_type == LIBSSH2_SFTP_OPENFILE) ? SSH_FXP_OPEN : SSH_FXP_OPENDIR;
|
||||
@@ -528,8 +586,11 @@ LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *
|
||||
s += libssh2_sftp_attr2bin(s, &attrs);
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending %s open request", (open_type == LIBSSH2_SFTP_OPENFILE) ? "file" : "directory");
|
||||
#endif
|
||||
if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0);
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_OPEN or FXP_OPENDIR command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return NULL;
|
||||
}
|
||||
@@ -542,7 +603,7 @@ LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *
|
||||
|
||||
if (data[0] == SSH_FXP_STATUS) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Failed opening remote file", 0);
|
||||
sftp->errno = libssh2_ntohu32(data + 5);
|
||||
sftp->last_errno = libssh2_ntohu32(data + 5);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return NULL;
|
||||
}
|
||||
@@ -580,6 +641,9 @@ LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *
|
||||
|
||||
fp->u.file.offset = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Open command successful");
|
||||
#endif
|
||||
return fp;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -598,6 +662,9 @@ LIBSSH2_API size_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
unsigned char read_responses[2] = { SSH_FXP_DATA, SSH_FXP_STATUS };
|
||||
size_t bytes_read = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Reading %lu bytes from SFTP handle", (unsigned long)buffer_maxlen);
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_CLOSE packet", 0);
|
||||
@@ -627,7 +694,7 @@ LIBSSH2_API size_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
|
||||
switch (data[0]) {
|
||||
case SSH_FXP_STATUS:
|
||||
sftp->errno = libssh2_ntohu32(data + 5);
|
||||
sftp->last_errno = libssh2_ntohu32(data + 5);
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
@@ -636,6 +703,9 @@ LIBSSH2_API size_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
if (bytes_read > (data_len - 9)) {
|
||||
return -1;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu bytes returned", (unsigned long)bytes_read);
|
||||
#endif
|
||||
memcpy(buffer, data + 9, bytes_read);
|
||||
handle->u.file.offset += bytes_read;
|
||||
LIBSSH2_FREE(session, data);
|
||||
@@ -670,6 +740,11 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
filename_len = buffer_maxlen;
|
||||
}
|
||||
memcpy(buffer, s, filename_len); s += real_filename_len;
|
||||
|
||||
/* The filename is not null terminated, make it so if possible */
|
||||
if (filename_len < buffer_maxlen) {
|
||||
buffer[filename_len] = '\0';
|
||||
}
|
||||
|
||||
/* Skip longname */
|
||||
s += 4 + libssh2_ntohu32(s);
|
||||
@@ -702,6 +777,9 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
libssh2_htonu32(s, handle->handle_len); s += 4;
|
||||
memcpy(s, handle->handle, handle->handle_len); s += handle->handle_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Reading entries from directory handle");
|
||||
#endif
|
||||
if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_READ command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
@@ -722,13 +800,16 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
if (retcode == LIBSSH2_FX_EOF) {
|
||||
return 0;
|
||||
} else {
|
||||
sftp->errno = retcode;
|
||||
sftp->last_errno = retcode;
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
num_names = libssh2_ntohu32(data + 5);
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu entries returned", num_names);
|
||||
#endif
|
||||
if (num_names <= 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
return (num_names == 0) ? 0 : -1;
|
||||
@@ -743,6 +824,11 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
}
|
||||
memcpy(buffer, data + 13, filename_len);
|
||||
|
||||
/* The filename is not null terminated, make it so if possible */
|
||||
if (filename_len < buffer_maxlen) {
|
||||
buffer[filename_len] = '\0';
|
||||
}
|
||||
|
||||
if (attrs) {
|
||||
memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
|
||||
libssh2_sftp_bin2attr(attrs, data + 13 + real_filename_len + (4 + libssh2_ntohu32(data + 13 + real_filename_len)));
|
||||
@@ -773,6 +859,9 @@ LIBSSH2_API size_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *b
|
||||
unsigned long packet_len = handle->handle_len + count + 25; /* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) + offset(8) + count(4) */
|
||||
unsigned char *packet, *s, *data;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Writing %lu bytes", (unsigned long)count);
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_WRITE packet", 0);
|
||||
@@ -809,7 +898,7 @@ LIBSSH2_API size_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *b
|
||||
return count;
|
||||
}
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
|
||||
sftp->errno = retcode;
|
||||
sftp->last_errno = retcode;
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -829,6 +918,9 @@ LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_
|
||||
unsigned char *packet, *s, *data;
|
||||
unsigned char fstat_responses[2] = { SSH_FXP_ATTRS, SSH_FXP_STATUS };
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Issuing %s command", setstat ? "set-stat" : "stat");
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FSTAT/FSETSTAT packet", 0);
|
||||
@@ -865,7 +957,7 @@ LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_
|
||||
if (retcode == LIBSSH2_FX_OK) {
|
||||
return 0;
|
||||
} else {
|
||||
sftp->errno = retcode;
|
||||
sftp->last_errno = retcode;
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
|
||||
return -1;
|
||||
}
|
||||
@@ -909,6 +1001,9 @@ LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
|
||||
unsigned long packet_len = handle->handle_len + 13; /* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
|
||||
unsigned char *packet, *s, *data;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Closing handle");
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_CLOSE packet", 0);
|
||||
@@ -938,7 +1033,7 @@ LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
if (retcode != LIBSSH2_FX_OK) {
|
||||
sftp->errno = retcode;
|
||||
sftp->last_errno = retcode;
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
|
||||
return -1;
|
||||
}
|
||||
@@ -950,10 +1045,12 @@ LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
|
||||
handle->next->prev = NULL;
|
||||
}
|
||||
|
||||
if (handle->u.dir.names_left) {
|
||||
if ((handle->handle_type == LIBSSH2_SFTP_HANDLE_DIR) &&
|
||||
handle->u.dir.names_left) {
|
||||
LIBSSH2_FREE(session, handle->u.dir.names_packet);
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, handle->handle);
|
||||
LIBSSH2_FREE(session, handle);
|
||||
|
||||
return 0;
|
||||
@@ -967,7 +1064,7 @@ LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
|
||||
/* {{{ libssh2_sftp_unlink_ex
|
||||
* Delete a file from the remote server
|
||||
*/
|
||||
LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, int filename_len)
|
||||
LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, unsigned int filename_len)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
@@ -975,6 +1072,9 @@ LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, int f
|
||||
unsigned long packet_len = filename_len + 13; /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */
|
||||
unsigned char *packet, *s, *data;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Unlinking %s", filename);
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_REMOVE packet", 0);
|
||||
@@ -1006,7 +1106,7 @@ LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, int f
|
||||
if (retcode == LIBSSH2_FX_OK) {
|
||||
return 0;
|
||||
} else {
|
||||
sftp->errno = retcode;
|
||||
sftp->last_errno = retcode;
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
|
||||
return -1;
|
||||
}
|
||||
@@ -1016,17 +1116,26 @@ LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, int f
|
||||
/* {{{ libssh2_sftp_rename_ex
|
||||
* Rename a file on the remote server
|
||||
*/
|
||||
LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filename, int source_filename_len,
|
||||
char *dest_filename, int dest_filename_len,
|
||||
LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filename, unsigned int source_filename_len,
|
||||
char *dest_filename, unsigned int dest_filename_len,
|
||||
long flags)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned long data_len, retcode = -1, request_id;
|
||||
unsigned long packet_len = source_filename_len + dest_filename_len + 21; /* packet_len(4) + packet_type(1) + request_id(4) +
|
||||
source_filename_len(4) + dest_filename_len(4) + flags(4) */
|
||||
unsigned long packet_len = source_filename_len + dest_filename_len + 17 + (sftp->version >= 5 ? 4 : 0);
|
||||
/* packet_len(4) + packet_type(1) + request_id(4) +
|
||||
source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */
|
||||
unsigned char *packet, *s, *data;
|
||||
|
||||
if (sftp->version < 2) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Server does not support RENAME", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Renaming %s to %s", source_filename, dest_filename);
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_RENAME packet", 0);
|
||||
@@ -1041,10 +1150,13 @@ LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filenam
|
||||
memcpy(s, source_filename, source_filename_len); s += source_filename_len;
|
||||
libssh2_htonu32(s, dest_filename_len); s += 4;
|
||||
memcpy(s, dest_filename, dest_filename_len); s += dest_filename_len;
|
||||
libssh2_htonu32(s, flags); s += 4;
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0);
|
||||
if (sftp->version >= 5) {
|
||||
libssh2_htonu32(s, flags); s += 4;
|
||||
}
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, packet, s - packet)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_RENAME command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
@@ -1064,17 +1176,17 @@ LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filenam
|
||||
break;
|
||||
case LIBSSH2_FX_FILE_ALREADY_EXISTS:
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "File already exists and SSH_FXP_RENAME_OVERWRITE not specified", 0);
|
||||
sftp->errno = retcode;
|
||||
sftp->last_errno = retcode;
|
||||
retcode = -1;
|
||||
break;
|
||||
case LIBSSH2_FX_OP_UNSUPPORTED:
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Operation Not Supported", 0);
|
||||
sftp->errno = retcode;
|
||||
sftp->last_errno = retcode;
|
||||
retcode = -1;
|
||||
break;
|
||||
default:
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
|
||||
sftp->errno = retcode;
|
||||
sftp->last_errno = retcode;
|
||||
retcode = -1;
|
||||
}
|
||||
|
||||
@@ -1085,7 +1197,7 @@ LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filenam
|
||||
/* {{{ libssh2_sftp_mkdir_ex
|
||||
* Create a directory
|
||||
*/
|
||||
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_len, long mode)
|
||||
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, unsigned int path_len, long mode)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
@@ -1095,12 +1207,16 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
|
||||
/* packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
|
||||
unsigned char *packet, *s, *data;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Creating directory %s with mode 0%lo", path, mode);
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_MKDIR packet", 0);
|
||||
return -1;
|
||||
}
|
||||
attrs.permissions = mode;
|
||||
/* Filetype in SFTP 3 and earlier */
|
||||
attrs.permissions = mode | LIBSSH2_SFTP_ATTR_PFILETYPE_DIR;
|
||||
|
||||
libssh2_htonu32(s, packet_len - 4); s += 4;
|
||||
*(s++) = SSH_FXP_MKDIR;
|
||||
@@ -1111,7 +1227,7 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
|
||||
s += libssh2_sftp_attr2bin(s, &attrs);
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0);
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_MKDIR command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
@@ -1129,7 +1245,7 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
|
||||
return 0;
|
||||
} else {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
|
||||
sftp->errno = retcode;
|
||||
sftp->last_errno = retcode;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -1138,7 +1254,7 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
|
||||
/* {{{ libssh2_sftp_rmdir_ex
|
||||
* Remove a directory
|
||||
*/
|
||||
LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_len)
|
||||
LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, unsigned int path_len)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
@@ -1146,6 +1262,9 @@ LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
|
||||
unsigned long packet_len = path_len + 13; /* packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
|
||||
unsigned char *packet, *s, *data;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Removing directory: %s", path);
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_MKDIR packet", 0);
|
||||
@@ -1160,7 +1279,7 @@ LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
|
||||
memcpy(s, path, path_len); s += path_len;
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0);
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_MKDIR command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
@@ -1177,7 +1296,7 @@ LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
|
||||
if (retcode == LIBSSH2_FX_OK) {
|
||||
return 0;
|
||||
} else {
|
||||
sftp->errno = retcode;
|
||||
sftp->last_errno = retcode;
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
|
||||
return -1;
|
||||
}
|
||||
@@ -1187,7 +1306,7 @@ LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
|
||||
/* {{{ libssh2_sftp_stat_ex
|
||||
* Stat a file or symbolic link
|
||||
*/
|
||||
LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, int path_len, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs)
|
||||
LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, unsigned int path_len, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
@@ -1197,6 +1316,9 @@ LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, int path_le
|
||||
unsigned char *packet, *s, *data;
|
||||
unsigned char stat_responses[2] = { SSH_FXP_ATTRS, SSH_FXP_STATUS };
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s", (stat_type == LIBSSH2_SFTP_SETSTAT) ? "Set-statting" : (stat_type == LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path);
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_MKDIR packet", 0);
|
||||
@@ -1243,7 +1365,7 @@ LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, int path_le
|
||||
if (retcode == LIBSSH2_FX_OK) {
|
||||
return 0;
|
||||
} else {
|
||||
sftp->errno = retcode;
|
||||
sftp->last_errno = retcode;
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
|
||||
return -1;
|
||||
}
|
||||
@@ -1260,7 +1382,7 @@ LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, int path_le
|
||||
/* {{{ libssh2_sftp_symlink_ex
|
||||
* Read or set a symlink
|
||||
*/
|
||||
LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, int path_len, char *target, int target_len, int link_type)
|
||||
LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, char *target, unsigned int target_len, int link_type)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
@@ -1270,12 +1392,22 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, in
|
||||
unsigned char *packet, *s, *data;
|
||||
unsigned char link_responses[2] = { SSH_FXP_NAME, SSH_FXP_STATUS };
|
||||
|
||||
if ((sftp->version < 3) &&
|
||||
(link_type != LIBSSH2_SFTP_REALPATH)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Server does not support SYMLINK or READLINK", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for SYMLINK/READLINK/REALPATH packet", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s on %s", (link_type == LIBSSH2_SFTP_SYMLINK) ? "Creating" : "Reading",
|
||||
(link_type == LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", path);
|
||||
#endif
|
||||
libssh2_htonu32(s, packet_len - 4); s += 4;
|
||||
switch (link_type) {
|
||||
case LIBSSH2_SFTP_REALPATH:
|
||||
@@ -1317,7 +1449,7 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, in
|
||||
if (retcode == LIBSSH2_FX_OK) {
|
||||
return 0;
|
||||
} else {
|
||||
sftp->errno = retcode;
|
||||
sftp->last_errno = retcode;
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
|
||||
return -1;
|
||||
}
|
||||
@@ -1330,10 +1462,12 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, in
|
||||
}
|
||||
|
||||
link_len = libssh2_ntohu32(data + 9);
|
||||
if (link_len > target_len) {
|
||||
link_len = target_len;
|
||||
if (link_len >= target_len) {
|
||||
link_len = target_len - 1;
|
||||
}
|
||||
memcpy(target, data + 13, link_len);
|
||||
target[link_len] = 0;
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
return link_len;
|
||||
}
|
||||
@@ -1344,6 +1478,6 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, in
|
||||
*/
|
||||
LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp)
|
||||
{
|
||||
return sftp->errno;
|
||||
return sftp->last_errno;
|
||||
}
|
||||
/* }}} */
|
||||
|
655
src/userauth.c
655
src/userauth.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -36,16 +36,25 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Needed for struct iovec on some platforms */
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* {{{ proto libssh2_userauth_list
|
||||
* List authentication methods
|
||||
* Will yield successful login if "none" happens to be allowable for this user
|
||||
* Not a common configuration for any SSH server though
|
||||
* username should be NULL, or a null terminated string
|
||||
*/
|
||||
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len)
|
||||
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len)
|
||||
{
|
||||
unsigned char reply_codes[3] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
|
||||
unsigned long data_len = username_len + 31; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" +
|
||||
method_len(4) + method(4)"none" */
|
||||
unsigned long methods_len;
|
||||
@@ -76,25 +85,23 @@ LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
while (1) {
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
|
||||
/* Wow, who'dve thought... */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->authenticated = 1;
|
||||
return NULL;
|
||||
}
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_FAILURE, &data, &data_len, 0) == 0) {
|
||||
/* What we *actually* wanted to happen */
|
||||
break;
|
||||
}
|
||||
/* TODO: Timeout? */
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
/* Wow, who'dve thought... */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
methods_len = libssh2_ntohu32(data + 1);
|
||||
memcpy(data, data + 5, methods_len);
|
||||
data[methods_len] = '\0';
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Permitted auth methods: %s", data);
|
||||
#endif
|
||||
return data;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -105,18 +112,18 @@ LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session)
|
||||
{
|
||||
return session->authenticated;
|
||||
return session->state & LIBSSH2_STATE_AUTHENTICATED;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_userauth_password
|
||||
* Plain ol' login
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *username, int username_len,
|
||||
char *password, int password_len,
|
||||
LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
|
||||
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
|
||||
const char *password, unsigned int password_len,
|
||||
LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
|
||||
{
|
||||
unsigned char *data, *s;
|
||||
unsigned char *data, *s, reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0 };
|
||||
unsigned long data_len = username_len + password_len + 40; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" +
|
||||
method_len(4) + method(8)"password" + chgpwdbool(1) + password_len(4) */
|
||||
|
||||
@@ -141,6 +148,9 @@ LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *use
|
||||
libssh2_htonu32(s, password_len); s += 4;
|
||||
memcpy(s, password, password_len); s += password_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting to login using password authentication");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, data, data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-password request", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
@@ -148,71 +158,78 @@ LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *use
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
while (1) {
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->authenticated = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_FAILURE, &data, &data_len, 0) == 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, &data, &data_len, 0) == 0) {
|
||||
char *newpw = NULL;
|
||||
int newpw_len = 0;
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
if (passwd_change_cb) {
|
||||
passwd_change_cb(session, &newpw, &newpw_len, &session->abstract);
|
||||
if (!newpw) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password expired, and callback failed", 0);
|
||||
return -1;
|
||||
}
|
||||
data_len = username_len + password_len + 44 + newpw_len; /* basic data_len + newpw_len(4) */
|
||||
s = data = LIBSSH2_ALLOC(session, data_len);
|
||||
if (!data) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for userauth-password-change request", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*(s++) = SSH_MSG_USERAUTH_REQUEST;
|
||||
libssh2_htonu32(s, username_len); s += 4;
|
||||
memcpy(s, username, username_len); s += username_len;
|
||||
|
||||
libssh2_htonu32(s, sizeof("ssh-connection") - 1); s += 4;
|
||||
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1); s += sizeof("ssh-connection") - 1;
|
||||
|
||||
libssh2_htonu32(s, sizeof("password") - 1); s += 4;
|
||||
memcpy(s, "password", sizeof("password") - 1); s += sizeof("password") - 1;
|
||||
|
||||
*s = 0xFF; s++;
|
||||
|
||||
libssh2_htonu32(s, password_len); s += 4;
|
||||
memcpy(s, password, password_len); s += password_len;
|
||||
|
||||
libssh2_htonu32(s, newpw_len); s += 4;
|
||||
memcpy(s, newpw, newpw_len); s += newpw_len;
|
||||
|
||||
if (libssh2_packet_write(session, data, data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-password-change request", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, newpw);
|
||||
/* TODO: Reset timeout? */
|
||||
} else {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password Expired, and no callback specified", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* TODO: Timeout? */
|
||||
password_response:
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Password authentication successful");
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) {
|
||||
char *newpw = NULL;
|
||||
int newpw_len = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Password change required");
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
if (passwd_change_cb) {
|
||||
passwd_change_cb(session, &newpw, &newpw_len, &session->abstract);
|
||||
if (!newpw) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password expired, and callback failed", 0);
|
||||
return -1;
|
||||
}
|
||||
data_len = username_len + password_len + 44 + newpw_len; /* basic data_len + newpw_len(4) */
|
||||
s = data = LIBSSH2_ALLOC(session, data_len);
|
||||
if (!data) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for userauth-password-change request", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*(s++) = SSH_MSG_USERAUTH_REQUEST;
|
||||
libssh2_htonu32(s, username_len); s += 4;
|
||||
memcpy(s, username, username_len); s += username_len;
|
||||
|
||||
libssh2_htonu32(s, sizeof("ssh-connection") - 1); s += 4;
|
||||
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1); s += sizeof("ssh-connection") - 1;
|
||||
|
||||
libssh2_htonu32(s, sizeof("password") - 1); s += 4;
|
||||
memcpy(s, "password", sizeof("password") - 1); s += sizeof("password") - 1;
|
||||
|
||||
*s = 0xFF; s++;
|
||||
|
||||
libssh2_htonu32(s, password_len); s += 4;
|
||||
memcpy(s, password, password_len); s += password_len;
|
||||
|
||||
libssh2_htonu32(s, newpw_len); s += 4;
|
||||
memcpy(s, newpw, newpw_len); s += newpw_len;
|
||||
|
||||
if (libssh2_packet_write(session, data, data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-password-change request", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, newpw);
|
||||
|
||||
/* Ugliest use of goto ever. Blame it on the askN => requirev migration. */
|
||||
goto password_response;
|
||||
} else {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password Expired, and no callback specified", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* FAILURE */
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -221,12 +238,16 @@ LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *use
|
||||
*/
|
||||
static int libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char **method, unsigned long *method_len,
|
||||
unsigned char **pubkeydata, unsigned long *pubkeydata_len,
|
||||
char *pubkeyfile)
|
||||
const char *pubkeyfile)
|
||||
{
|
||||
FILE *fd;
|
||||
char *pubkey = NULL, c, *sp1, *sp2, *tmp;
|
||||
int pubkey_len = 0, tmp_len;
|
||||
size_t pubkey_len = 0;
|
||||
unsigned int tmp_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading public key file: %s", pubkeyfile);
|
||||
#endif
|
||||
/* Read Public Key */
|
||||
fd = fopen(pubkeyfile, "r");
|
||||
if (!fd) {
|
||||
@@ -234,8 +255,12 @@ static int libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char *
|
||||
return -1;
|
||||
}
|
||||
while (!feof(fd) && (c = fgetc(fd)) != '\r' && c != '\n') pubkey_len++;
|
||||
if (feof(fd)) {
|
||||
/* the last character was EOF */
|
||||
pubkey_len--;
|
||||
}
|
||||
rewind(fd);
|
||||
|
||||
|
||||
if (pubkey_len <= 1) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid data in public key file", 0);
|
||||
fclose(fd);
|
||||
@@ -255,7 +280,10 @@ static int libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char *
|
||||
return -1;
|
||||
}
|
||||
fclose(fd);
|
||||
while (pubkey_len && (pubkey[pubkey_len-1] == '\r' || pubkey[pubkey_len-1] == '\n')) pubkey_len--;
|
||||
/*
|
||||
* Remove trailing whitespace
|
||||
*/
|
||||
while (pubkey_len && isspace(pubkey[pubkey_len-1])) pubkey_len--;
|
||||
|
||||
if (!pubkey_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_FILE, "Missing public key data", 0);
|
||||
@@ -293,15 +321,18 @@ static int libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char *
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_file_read_publickey
|
||||
/* {{{ libssh2_file_read_privatekey
|
||||
* Read a PEM encoded private key from an id_??? style file
|
||||
*/
|
||||
static int libssh2_file_read_privatekey(LIBSSH2_SESSION *session, LIBSSH2_HOSTKEY_METHOD **hostkey_method, void **hostkey_abstract,
|
||||
char *method, int method_len,
|
||||
char *privkeyfile, char *passphrase)
|
||||
const char *method, int method_len,
|
||||
const char *privkeyfile, const char *passphrase)
|
||||
{
|
||||
LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = libssh2_hostkey_methods();
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading private key file: %s", privkeyfile);
|
||||
#endif
|
||||
*hostkey_method = NULL;
|
||||
*hostkey_abstract = NULL;
|
||||
while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) {
|
||||
@@ -326,19 +357,151 @@ static int libssh2_file_read_privatekey(LIBSSH2_SESSION *session, LIBSSH2_HOSTKE
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_userauth_publickey_fromfile_ex
|
||||
/* {{{ libssh2_userauth_hostbased_fromfile_ex
|
||||
* Authenticate using a keypair found in the named files
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, char *username, int username_len,
|
||||
char *publickey, char *privatekey,
|
||||
char *passphrase)
|
||||
LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
|
||||
const char *publickey, const char *privatekey,
|
||||
const char *passphrase,
|
||||
const char *hostname, unsigned int hostname_len,
|
||||
const char *local_username, unsigned int local_username_len)
|
||||
{
|
||||
LIBSSH2_HOSTKEY_METHOD *privkeyobj;
|
||||
void *abstract;
|
||||
unsigned char buf[5];
|
||||
struct iovec datavec[4];
|
||||
unsigned char *method, *pubkeydata, *packet, *s, *b, *sig;
|
||||
unsigned long method_len, pubkeydata_len, packet_len, sig_len;
|
||||
unsigned char *method, *pubkeydata, *packet, *s, *sig, *data, reply_codes[3] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
|
||||
unsigned long method_len, pubkeydata_len, packet_len, sig_len, data_len;
|
||||
|
||||
if (libssh2_file_read_publickey(session, &method, &method_len, &pubkeydata, &pubkeydata_len, publickey)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
packet_len = username_len + method_len + hostname_len + local_username_len + pubkeydata_len + 48;
|
||||
/* packet_type(1) + username_len(4) + servicename_len(4) + service_name(14)"ssh-connection" +
|
||||
* authmethod_len(4) + authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) +
|
||||
* local_username_len(4)
|
||||
*/
|
||||
/* Preallocate space for an overall length, method name again,
|
||||
* and the signature, which won't be any larger than the size of the publickeydata itself */
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len + 4 + (4 + method_len) + (4 + pubkeydata_len));
|
||||
|
||||
*(s++) = SSH_MSG_USERAUTH_REQUEST;
|
||||
libssh2_htonu32(s, username_len); s += 4;
|
||||
memcpy(s, username, username_len); s += username_len;
|
||||
|
||||
libssh2_htonu32(s, 14); s += 4;
|
||||
memcpy(s, "ssh-connection", 14); s += 14;
|
||||
|
||||
libssh2_htonu32(s, 9); s += 4;
|
||||
memcpy(s, "hostbased", 9); s += 9;
|
||||
|
||||
libssh2_htonu32(s, method_len); s += 4;
|
||||
memcpy(s, method, method_len); s += method_len;
|
||||
|
||||
libssh2_htonu32(s, pubkeydata_len); s += 4;
|
||||
memcpy(s, pubkeydata, pubkeydata_len); s += pubkeydata_len;
|
||||
|
||||
libssh2_htonu32(s, hostname_len); s += 4;
|
||||
memcpy(s, hostname, hostname_len); s += hostname_len;
|
||||
|
||||
libssh2_htonu32(s, local_username_len); s += 4;
|
||||
memcpy(s, local_username, local_username_len); s += local_username_len;
|
||||
|
||||
if (libssh2_file_read_privatekey(session, &privkeyobj, &abstract, method, method_len, privatekey, passphrase)) {
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
|
||||
libssh2_htonu32(buf, session->session_id_len);
|
||||
datavec[0].iov_base = buf;
|
||||
datavec[0].iov_len = 4;
|
||||
datavec[1].iov_base = session->session_id;
|
||||
datavec[1].iov_len = session->session_id_len;
|
||||
datavec[2].iov_base = packet;
|
||||
datavec[2].iov_len = packet_len;
|
||||
|
||||
if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
if (privkeyobj->dtor) {
|
||||
privkeyobj->dtor(session, &abstract);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (privkeyobj->dtor) {
|
||||
privkeyobj->dtor(session, &abstract);
|
||||
}
|
||||
|
||||
if (sig_len > pubkeydata_len ) {
|
||||
/* Should *NEVER* happen, but...well.. better safe than sorry */
|
||||
packet = LIBSSH2_REALLOC(session, packet, packet_len + 4 + (4 + method_len) + (4 + sig_len)); /* PK sigblob */
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating additional space for userauth-hostbased packet", 0);
|
||||
LIBSSH2_FREE(session, method);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
s = packet + packet_len;
|
||||
|
||||
libssh2_htonu32(s, 4 + method_len + 4 + sig_len); s += 4;
|
||||
|
||||
libssh2_htonu32(s, method_len); s += 4;
|
||||
memcpy(s, method, method_len); s += method_len;
|
||||
LIBSSH2_FREE(session, method);
|
||||
|
||||
libssh2_htonu32(s, sig_len); s += 4;
|
||||
memcpy(s, sig, sig_len); s += sig_len;
|
||||
LIBSSH2_FREE(session, sig);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting hostbased authentication");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, packet, s - packet)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-hostbased request", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Hostbased authentication successful");
|
||||
#endif
|
||||
/* We are us and we've proved it. */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This public key is not allowed for this user on this server */
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid signature for supplied public key, or bad username/public key combination", 0);
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_userauth_publickey_fromfile_ex
|
||||
* Authenticate using a keypair found in the named files
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
|
||||
const char *publickey, const char *privatekey,
|
||||
const char *passphrase)
|
||||
{
|
||||
LIBSSH2_HOSTKEY_METHOD *privkeyobj;
|
||||
void *abstract;
|
||||
unsigned char buf[5];
|
||||
struct iovec datavec[4];
|
||||
unsigned char *method, *pubkeydata, *packet, *s, *b, *sig, *data;
|
||||
unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PK_OK, 0 };
|
||||
unsigned long method_len, pubkeydata_len, packet_len, sig_len, data_len;
|
||||
|
||||
if (libssh2_file_read_publickey(session, &method, &method_len, &pubkeydata, &pubkeydata_len, publickey)) {
|
||||
return -1;
|
||||
@@ -371,6 +534,9 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
libssh2_htonu32(s, pubkeydata_len); s += 4;
|
||||
memcpy(s, pubkeydata, pubkeydata_len); s += pubkeydata_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
@@ -379,45 +545,38 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
|
||||
/* God help any SSH server that allows an UNVERIFIED public key to validate the user */
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
session->authenticated = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_FAILURE, &data, &data_len, 0) == 0) {
|
||||
/* This public key is not allowed for this user on this server */
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED, "Username/PublicKey combination invalid", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_PK_OK, &data, &data_len, 0) == 0) {
|
||||
/* Semi-Success! */
|
||||
if ((libssh2_ntohu32(data + 1) != method_len) ||
|
||||
strncmp(data + 5, method, method_len) ||
|
||||
(libssh2_ntohu32(data + 5 + method_len) != pubkeydata_len) ||
|
||||
strncmp(data + 5 + method_len + 4, pubkeydata, pubkeydata_len)) {
|
||||
/* Unlikely but possible, the server has responded to a different userauth public key request */
|
||||
LIBSSH2_FREE(session, data);
|
||||
continue;
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
break;
|
||||
}
|
||||
/* TODO: Timeout? */
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
LIBSSH2_FREE(session, packet);
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Pubkey authentication prematurely successful");
|
||||
#endif
|
||||
/* God help any SSH server that allows an UNVERIFIED public key to validate the user */
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_FAILURE) {
|
||||
/* This public key is not allowed for this user on this server */
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED, "Username/PublicKey combination invalid", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Semi-Success! */
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
|
||||
if (libssh2_file_read_privatekey(session, &privkeyobj, &abstract, method, method_len, privatekey, passphrase)) {
|
||||
@@ -471,6 +630,9 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
memcpy(s, sig, sig_len); s += sig_len;
|
||||
LIBSSH2_FREE(session, sig);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication -- phase 2");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, packet, s - packet)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
@@ -478,26 +640,227 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
while (1) {
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
/* PK_OK is no longer valid */
|
||||
reply_codes[2] = 0;
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
|
||||
/* We are us and we've proved it. */
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Publickey authentication successful");
|
||||
#endif
|
||||
/* We are us and we've proved it. */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This public key is not allowed for this user on this server */
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid signature for supplied public key, or bad username/public key combination", 0);
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_userauth_keyboard_interactive
|
||||
* Authenticate using a challenge-response authentication
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
|
||||
{
|
||||
unsigned char *s, *data; /* packet */
|
||||
unsigned long packet_len;
|
||||
|
||||
packet_len = 1 /* byte SSH_MSG_USERAUTH_REQUEST */
|
||||
+ 4 + username_len /* string user name (ISO-10646 UTF-8, as defined in [RFC-3629]) */
|
||||
+ 4 + 14 /* string service name (US-ASCII) */
|
||||
+ 4 + 20 /* string "keyboard-interactive" (US-ASCII) */
|
||||
+ 4 + 0 /* string language tag (as defined in [RFC-3066]) */
|
||||
+ 4 + 0 /* string submethods (ISO-10646 UTF-8) */
|
||||
;
|
||||
|
||||
if (!(data = s = LIBSSH2_ALLOC(session, packet_len))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive authentication", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*s++ = SSH_MSG_USERAUTH_REQUEST;
|
||||
|
||||
/* user name */
|
||||
libssh2_htonu32(s, username_len); s += 4;
|
||||
memcpy(s, username, username_len); s += username_len;
|
||||
|
||||
/* service name */
|
||||
libssh2_htonu32(s, sizeof("ssh-connection") - 1); s += 4;
|
||||
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1); s += sizeof("ssh-connection") - 1;
|
||||
|
||||
/* "keyboard-interactive" */
|
||||
libssh2_htonu32(s, sizeof("keyboard-interactive") - 1); s += 4;
|
||||
memcpy(s, "keyboard-interactive", sizeof("keyboard-interactive") - 1); s += sizeof("keyboard-interactive") - 1;
|
||||
|
||||
/* language tag */
|
||||
libssh2_htonu32(s, 0); s += 4;
|
||||
|
||||
/* submethods */
|
||||
libssh2_htonu32(s, 0); s += 4;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting keyboard-interactive authentication");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, data, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send keyboard-interactive request", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
for (;;) {
|
||||
unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0 };
|
||||
unsigned int auth_name_len;
|
||||
char* auth_name = NULL;
|
||||
unsigned auth_instruction_len;
|
||||
char* auth_instruction = NULL;
|
||||
unsigned int language_tag_len;
|
||||
unsigned long data_len;
|
||||
unsigned int num_prompts = 0;
|
||||
unsigned int i;
|
||||
int auth_failure = 1;
|
||||
LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts = NULL;
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses = NULL;
|
||||
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Keyboard-interactive authentication successful");
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->authenticated = 1;
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_FAILURE, &data, &data_len, 0) == 0) {
|
||||
/* This public key is not allowed for this user on this server */
|
||||
if (data[0] == SSH_MSG_USERAUTH_FAILURE) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid signature for supplied public key, or bad username/public key combination", 0);
|
||||
return -1;
|
||||
}
|
||||
/* TODO: Timeout? */
|
||||
|
||||
/* server requested PAM-like conversation */
|
||||
|
||||
s = data + 1;
|
||||
|
||||
/* string name (ISO-10646 UTF-8) */
|
||||
auth_name_len = libssh2_ntohu32(s); s += 4;
|
||||
if (!(auth_name = LIBSSH2_ALLOC(session, auth_name_len))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive 'name' request field", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(auth_name, s, auth_name_len); s += auth_name_len;
|
||||
|
||||
/* string instruction (ISO-10646 UTF-8) */
|
||||
auth_instruction_len = libssh2_ntohu32(s); s += 4;
|
||||
if (!(auth_instruction = LIBSSH2_ALLOC(session, auth_instruction_len))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive 'instruction' request field", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(auth_instruction, s, auth_instruction_len); s += auth_instruction_len;
|
||||
|
||||
/* string language tag (as defined in [RFC-3066]) */
|
||||
language_tag_len = libssh2_ntohu32(s); s += 4;
|
||||
/* ignoring this field as deprecated */ s += language_tag_len;
|
||||
|
||||
/* int num-prompts */
|
||||
num_prompts = libssh2_ntohu32(s); s += 4;
|
||||
|
||||
prompts = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * num_prompts);
|
||||
if (!prompts) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompts array", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memset(prompts, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * num_prompts);
|
||||
|
||||
responses = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * num_prompts);
|
||||
if (!responses) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive responses array", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memset(responses, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * num_prompts);
|
||||
|
||||
for(i = 0; i != num_prompts; ++i) {
|
||||
/* string prompt[1] (ISO-10646 UTF-8) */
|
||||
prompts[i].length = libssh2_ntohu32(s); s += 4;
|
||||
if (!(prompts[i].text = LIBSSH2_ALLOC(session, prompts[i].length))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompt message", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(prompts[i].text, s, prompts[i].length); s += prompts[i].length;
|
||||
|
||||
/* boolean echo[1] */
|
||||
prompts[i].echo = *s++;
|
||||
}
|
||||
|
||||
response_callback(auth_name, auth_name_len, auth_instruction, auth_instruction_len, num_prompts, prompts, responses, &session->abstract);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Keyboard-interactive response callback function invoked");
|
||||
#endif
|
||||
|
||||
packet_len = 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */
|
||||
+ 4 /* int num-responses */
|
||||
;
|
||||
|
||||
for (i = 0; i != num_prompts; ++i) {
|
||||
packet_len += 4 + responses[i].length; /* string response[1] (ISO-10646 UTF-8) */
|
||||
}
|
||||
|
||||
if (!(data = s = LIBSSH2_ALLOC(session, packet_len))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive response packet", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*s = SSH_MSG_USERAUTH_INFO_RESPONSE; s++;
|
||||
libssh2_htonu32(s, num_prompts); s += 4;
|
||||
|
||||
for (i = 0; i != num_prompts; ++i) {
|
||||
libssh2_htonu32(s, responses[i].length); s += 4;
|
||||
memcpy(s, responses[i].text, responses[i].length); s += responses[i].length;
|
||||
}
|
||||
|
||||
if (libssh2_packet_write(session, data, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-keyboard-interactive request", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
auth_failure = 0;
|
||||
|
||||
cleanup:
|
||||
/* It's safe to clean all the data here, because unallocated pointers
|
||||
* are filled by zeroes
|
||||
*/
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
if (prompts) {
|
||||
for (i = 0; i != num_prompts; ++i) {
|
||||
LIBSSH2_FREE(session, prompts[i].text);
|
||||
}
|
||||
}
|
||||
|
||||
if (responses) {
|
||||
for (i = 0; i != num_prompts; ++i) {
|
||||
LIBSSH2_FREE(session, responses[i].text);
|
||||
}
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, prompts);
|
||||
LIBSSH2_FREE(session, responses);
|
||||
|
||||
if (auth_failure) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
@@ -1,29 +1,48 @@
|
||||
#include "libssh2.h"
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifndef WIN32
|
||||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
char *fingerprint;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
#ifndef WIN32
|
||||
fcntl(sock, F_SETFL, 0);
|
||||
#endif
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = htonl(0x7F000001);
|
||||
connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in));
|
||||
if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a session instance and start it up
|
||||
* This will trade welcome banners, exchange keys, and setup crypto, compression, and MAC layers
|
||||
@@ -45,15 +64,22 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if(argc > 1) {
|
||||
username = argv[1];
|
||||
}
|
||||
if(argc > 2) {
|
||||
password = argv[2];
|
||||
}
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, "username", "password")) {
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, "username", "/home/username/.ssh/id_rsa.pub", "/home/username/.ssh/id_rsa", "pasphrase")) {
|
||||
if (libssh2_userauth_publickey_fromfile(session, username, "/home/username/.ssh/id_rsa.pub", "/home/username/.ssh/id_rsa", password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
@@ -68,12 +94,12 @@ int main(int argc, char *argv[]) {
|
||||
/* Some environment variables may be set,
|
||||
* It's up to the server which ones it'll allow though
|
||||
*/
|
||||
libssh2_channel_setenv(channel, "FOO", "bar");
|
||||
libssh2_channel_setenv(channel, (char *)"FOO", (char *)"bar");
|
||||
|
||||
/* Request a terminal with 'vanilla' terminal emulation
|
||||
* See /etc/termcap for more options
|
||||
*/
|
||||
if (libssh2_channel_request_pty(channel, "vanilla")) {
|
||||
if (libssh2_channel_request_pty(channel, (char *)"vanilla")) {
|
||||
fprintf(stderr, "Failed requesting pty\n");
|
||||
goto skip_shell;
|
||||
}
|
||||
@@ -114,8 +140,13 @@ int main(int argc, char *argv[]) {
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
#else
|
||||
sleep(1);
|
||||
close(sock);
|
||||
|
||||
#endif
|
||||
printf("all done\n");
|
||||
return 0;
|
||||
}
|
||||
|
5
tests/.cvsignore
Normal file
5
tests/.cvsignore
Normal file
@@ -0,0 +1,5 @@
|
||||
.deps
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
simple
|
7
tests/Makefile.am
Normal file
7
tests/Makefile.am
Normal file
@@ -0,0 +1,7 @@
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
AM_LDFLAGS = -no-install
|
||||
LDADD = ../src/libssh2.la
|
||||
|
||||
ctests = simple$(EXEEXT)
|
||||
TESTS = $(ctests)
|
||||
check_PROGRAMS = $(ctests)
|
56
tests/simple.c
Normal file
56
tests/simple.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/* Copyright (C) 2007 The Written Word, Inc. All rights reserved.
|
||||
* Author: Simon Josefsson
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names
|
||||
* of any other contributors may be used to endorse or
|
||||
* promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libssh2.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
LIBSSH2_SESSION *session;
|
||||
|
||||
session = libssh2_session_init();
|
||||
if (!session)
|
||||
{
|
||||
fprintf (stderr, "libssh2_session_init() failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
libssh2_session_free(session);
|
||||
|
||||
return 0;
|
||||
}
|
12
win32/.cvsignore
Normal file
12
win32/.cvsignore
Normal file
@@ -0,0 +1,12 @@
|
||||
*.lib
|
||||
*.pdb
|
||||
*.dll
|
||||
*.exe
|
||||
*.obj
|
||||
.*.swp
|
||||
Debug
|
||||
Release
|
||||
*.exp
|
||||
*.ncb
|
||||
*.opt
|
||||
*.plg
|
29
win32/config.mk
Normal file
29
win32/config.mk
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
# Tweak these for your system
|
||||
OPENSSLINC=..\libssh2_build\include
|
||||
OPENSSLLIB=..\libssh2_build\lib
|
||||
|
||||
ZLIBINC=-DLIBSSH2_HAVE_ZLIB=1 /I..\libssh2_build\include
|
||||
ZLIBLIB=..\libssh2_build\lib
|
||||
|
||||
!if "$(TARGET)" == ""
|
||||
TARGET=Release
|
||||
!endif
|
||||
|
||||
!if "$(TARGET)" == "Debug"
|
||||
SUFFIX=_debug
|
||||
CPPFLAGS=/Od /MDd
|
||||
DLLFLAGS=/DEBUG /LDd
|
||||
!else
|
||||
CPPFLAGS=/Og /Oi /O2 /Oy /GF /Y- /MD /DNDEBUG
|
||||
DLLFLAGS=/DEBUG /LD
|
||||
!endif
|
||||
|
||||
CPPFLAGS=/nologo /GL /Zi /EHsc $(CPPFLAGS) /Iwin32 /Iinclude /I$(OPENSSLINC) $(ZLIBINC) -DLIBSSH2_WIN32
|
||||
CFLAGS=$(CPPFLAGS)
|
||||
DLLFLAGS=$(CFLAGS) $(DLLFLAGS)
|
||||
LIBS=$(OPENSSLLIB)\libeay32.lib $(OPENSSLLIB)\ssleay32.lib ws2_32.lib $(ZLIBLIB)\zlib.lib
|
||||
|
||||
INTDIR=$(TARGET)\$(SUBDIR)
|
||||
|
||||
|
156
win32/libssh2.dsp
Normal file
156
win32/libssh2.dsp
Normal file
@@ -0,0 +1,156 @@
|
||||
# Microsoft Developer Studio Project File - Name="libssh2" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
||||
|
||||
CFG=libssh2 - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "libssh2.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "libssh2.mak" CFG="libssh2 - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "libssh2 - Win32 Release" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "libssh2 - Win32 Debug" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "libssh2 - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "libssh2___Win32_Release"
|
||||
# PROP BASE Intermediate_Dir "libssh2___Win32_Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "LIBSSH2_WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\include" /I "..\win32" /D "WIN32" /D "NDEBUG" /D "LIBSSH2_WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ELSEIF "$(CFG)" == "libssh2 - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "LIBSSH2_WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\include" /I "..\win32" /D "WIN32" /D "_DEBUG" /D "LIBSSH2_WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo /out:"Debug\libssh2d.lib"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "libssh2 - Win32 Release"
|
||||
# Name "libssh2 - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\channel.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\comp.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\crypt.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\hostkey.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\kex.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\mac.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\misc.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\packet.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\scp.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\session.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\sftp.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\userauth.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\include\libssh2.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libssh2_config.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\include\libssh2_priv.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\include\libssh2_sftp.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
41
win32/libssh2.dsw
Normal file
41
win32/libssh2.dsw
Normal file
@@ -0,0 +1,41 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "libssh2"=.\libssh2.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "ssh2_sample"=.\ssh2_sample.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
38
win32/libssh2_config.h
Normal file
38
win32/libssh2_config.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef WIN32
|
||||
#define WIN32
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#include <mswsock.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
/* same as WSABUF */
|
||||
struct iovec {
|
||||
u_long iov_len;
|
||||
char *iov_base;
|
||||
};
|
||||
|
||||
#define inline __inline
|
||||
|
||||
static inline int writev(int sock, struct iovec *iov, int nvecs)
|
||||
{
|
||||
DWORD ret;
|
||||
if (WSASend(sock, (LPWSABUF)iov, nvecs, &ret, 0, NULL, NULL) == 0) {
|
||||
return ret;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* not really usleep, but safe for the way we use it in this lib */
|
||||
static inline int usleep(int udelay)
|
||||
{
|
||||
Sleep(udelay / 1000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define snprintf _snprintf
|
||||
|
||||
/* Compile in zlib support */
|
||||
#define LIBSSH2_HAVE_ZLIB 1
|
||||
|
||||
/* Enable newer diffie-hellman-group-exchange-sha1 syntax */
|
||||
#define LIBSSH2_DH_GEX_NEW 1
|
15
win32/rules.mk
Normal file
15
win32/rules.mk
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
all-sub: $(INTDIR) all
|
||||
|
||||
clean-sub: clean
|
||||
|
||||
$(INTDIR):
|
||||
!if "$(SRCDIR)" == ""
|
||||
@if not exist $(TARGET) mkdir $(TARGET)
|
||||
!endif
|
||||
@if not exist $(INTDIR) mkdir $(INTDIR)
|
||||
|
||||
{$(SUBDIR)}.c{$(INTDIR)}.obj::
|
||||
$(CC) -c $(CFLAGS) /Fo"$(INTDIR)\\" $<
|
||||
|
||||
|
102
win32/ssh2_sample.dsp
Normal file
102
win32/ssh2_sample.dsp
Normal file
@@ -0,0 +1,102 @@
|
||||
# Microsoft Developer Studio Project File - Name="ssh2_sample" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=ssh2_sample - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "ssh2_sample.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "ssh2_sample.mak" CFG="ssh2_sample - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "ssh2_sample - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "ssh2_sample - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "ssh2_sample - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "ssh2_sample___Win32_Release"
|
||||
# PROP BASE Intermediate_Dir "ssh2_sample___Win32_Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "LIBSSH2_WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\include" /I "..\win32" /D "WIN32" /D "NDEBUG" /D "LIBSSH2_WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSSH2_LIBRARY" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libeay32.lib ssleay32.lib ws2_32.lib zlib.lib libssh2.lib /nologo /subsystem:console /machine:I386 /libpath:"Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ssh2_sample - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "ssh2_sample___Win32_Debug"
|
||||
# PROP BASE Intermediate_Dir "ssh2_sample___Win32_Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "LIBSSH2_WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\include" /I "..\win32" /D "WIN32" /D "_DEBUG" /D "LIBSSH2_WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSSH2_LIBRARY" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libeay32.lib ssleay32.lib ws2_32.lib zlib.lib libssh2d.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /pdbtype:sept /libpath:"Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "ssh2_sample - Win32 Release"
|
||||
# Name "ssh2_sample - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\ssh2_sample.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
Reference in New Issue
Block a user