mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 20:30:38 +09:00
Compare commits
403 Commits
release-0-
...
release-0-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
254a166c02 | ||
|
|
3e938cb901 | ||
|
|
452b16ede2 | ||
|
|
bd47ff75ba | ||
|
|
0016ded7f9 | ||
|
|
d725b31752 | ||
|
|
c2e86c876c | ||
|
|
028516ba6a | ||
|
|
344b27ac6c | ||
|
|
a700259b01 | ||
|
|
14da14db05 | ||
|
|
474d63f24e | ||
|
|
b3589fbf6c | ||
|
|
dd68bae776 | ||
|
|
4768cf3e85 | ||
|
|
5a95681f01 | ||
|
|
13a3619102 | ||
|
|
c7636edf84 | ||
|
|
27e332b623 | ||
|
|
ebc8544c56 | ||
|
|
0f8e9b839c | ||
|
|
0c02d6effe | ||
|
|
7199b196b0 | ||
|
|
ca83b66066 | ||
|
|
d978f9b58a | ||
|
|
e539eaf9e0 | ||
|
|
b728f44ce9 | ||
|
|
2f0b671a61 | ||
|
|
1fadec37d6 | ||
|
|
2aabbd6245 | ||
|
|
fd6823691b | ||
|
|
b174ad8ae4 | ||
|
|
176778bb1c | ||
|
|
e5bf645010 | ||
|
|
d1c6fa9261 | ||
|
|
b00e2ad40e | ||
|
|
ca9f42a20f | ||
|
|
e939786836 | ||
|
|
11cc5f5815 | ||
|
|
d60b1ec1a2 | ||
|
|
ae11589205 | ||
|
|
70b9475449 | ||
|
|
02aecc1278 | ||
|
|
3e90a11599 | ||
|
|
b4095189d7 | ||
|
|
c0b4c4d60c | ||
|
|
12da24c056 | ||
|
|
d821117033 | ||
|
|
30266f7627 | ||
|
|
10b625e180 | ||
|
|
10f27457d3 | ||
|
|
af1f431364 | ||
|
|
272a4d1e45 | ||
|
|
3a95ecfe74 | ||
|
|
14ae9a7f0c | ||
|
|
51f1918109 | ||
|
|
fa27956daf | ||
|
|
ab0d8a3828 | ||
|
|
efded18724 | ||
|
|
f52bc064e9 | ||
|
|
75f066dfcd | ||
|
|
535ff07f0f | ||
|
|
5e002635fc | ||
|
|
e71c28f6a0 | ||
|
|
c0e091a52f | ||
|
|
8ab0f8e51f | ||
|
|
cce34a6176 | ||
|
|
89f0311927 | ||
|
|
e455f6f756 | ||
|
|
17f2645a32 | ||
|
|
9f034aca9c | ||
|
|
22bdfa3886 | ||
|
|
ef8246a592 | ||
|
|
110d201e02 | ||
|
|
be4f695c5c | ||
|
|
792def7a65 | ||
|
|
840cecbe0e | ||
|
|
27d25752e9 | ||
|
|
a479b30298 | ||
|
|
86620fc991 | ||
|
|
b3dfd5cffc | ||
|
|
f0858ff6b2 | ||
|
|
7b7280e728 | ||
|
|
2523ed0779 | ||
|
|
e736b1a40e | ||
|
|
cbf012c337 | ||
|
|
c360ed1d9a | ||
|
|
22e74e3bab | ||
|
|
02b3104215 | ||
|
|
26a5294116 | ||
|
|
5e4c78e114 | ||
|
|
e74305c5eb | ||
|
|
499f9aa707 | ||
|
|
4dee9a3e68 | ||
|
|
399041180f | ||
|
|
3f55fb5b22 | ||
|
|
37a4a65d60 | ||
|
|
ccd886feb4 | ||
|
|
b1bc283e9a | ||
|
|
be75fac7ff | ||
|
|
6ec65c6f9d | ||
|
|
71ab0cf6cc | ||
|
|
1e0e8a5493 | ||
|
|
4b65aea401 | ||
|
|
98ff6fbbce | ||
|
|
43e0d73b63 | ||
|
|
58294442d3 | ||
|
|
2e9c13dad0 | ||
|
|
9c667ebc26 | ||
|
|
d1b772f1bc | ||
|
|
876f843f23 | ||
|
|
0e2e0983f3 | ||
|
|
6063a8d09c | ||
|
|
40778d4ba9 | ||
|
|
60d6954b75 | ||
|
|
bf376b6d4f | ||
|
|
ff52e3630f | ||
|
|
f1f17f18dc | ||
|
|
7c759b9615 | ||
|
|
d54e9550da | ||
|
|
d7c0270c89 | ||
|
|
7a37f9faf7 | ||
|
|
149a2b4a18 | ||
|
|
ab5b4c7cfe | ||
|
|
e78334688f | ||
|
|
566fda70a5 | ||
|
|
62cebe23d9 | ||
|
|
42aacc7106 | ||
|
|
8ed9cdce80 | ||
|
|
a3a7f17d0f | ||
|
|
571dd56eca | ||
|
|
f6f0988d10 | ||
|
|
f9d1542542 | ||
|
|
d32fe11da3 | ||
|
|
cd7f6bea57 | ||
|
|
c3dc60103f | ||
|
|
2a2616f65c | ||
|
|
f643c34ee8 | ||
|
|
0f77578ee2 | ||
|
|
3e314e863c | ||
|
|
adbb087221 | ||
|
|
3a8d839e86 | ||
|
|
358647f5d9 | ||
|
|
5e76118512 | ||
|
|
e3bdc393cb | ||
|
|
04b49d46c1 | ||
|
|
74b7fb7bba | ||
|
|
c70694c594 | ||
|
|
fef87793a0 | ||
|
|
79c475c917 | ||
|
|
3dd03fec21 | ||
|
|
e8e07f7376 | ||
|
|
1c5ae7dd97 | ||
|
|
f65e3566a2 | ||
|
|
6b0a89a288 | ||
|
|
f84ebc2e27 | ||
|
|
b359229a2e | ||
|
|
496a8e12d9 | ||
|
|
0e8e124d20 | ||
|
|
9a8d4cd0fd | ||
|
|
ffed8b03bb | ||
|
|
5bd38a5f37 | ||
|
|
ab60d1d678 | ||
|
|
5223fa5740 | ||
|
|
95558d54b0 | ||
|
|
068a7dfc49 | ||
|
|
abd8b17a04 | ||
|
|
343e6e482a | ||
|
|
aae1df0589 | ||
|
|
0a57ebb3a9 | ||
|
|
9afad28255 | ||
|
|
8b21b51a78 | ||
|
|
2003a81b44 | ||
|
|
abe6c7c728 | ||
|
|
f78045dfd3 | ||
|
|
39729bd3de | ||
|
|
f6d2a66de2 | ||
|
|
7de3122b42 | ||
|
|
88f4e9ea24 | ||
|
|
4133f484ae | ||
|
|
041aff8060 | ||
|
|
7c7096d8f8 | ||
|
|
fd7b7bc3b5 | ||
|
|
bb034e8e1d | ||
|
|
d37a475816 | ||
|
|
4845642611 | ||
|
|
de8808cb47 | ||
|
|
ca978a9e81 | ||
|
|
ffca268bee | ||
|
|
6a3d31acb7 | ||
|
|
f28352707a | ||
|
|
4b363928f6 | ||
|
|
929f5ca25b | ||
|
|
7ff80a2666 | ||
|
|
480dfd9050 | ||
|
|
bdb32afa20 | ||
|
|
f90ae73b6d | ||
|
|
7fed54b1e5 | ||
|
|
d5840aa1f0 | ||
|
|
6f2225e8fb | ||
|
|
07a9e6b7c6 | ||
|
|
86e6444656 | ||
|
|
8ef62cf784 | ||
|
|
8051ab044c | ||
|
|
18bce13617 | ||
|
|
2a10019f82 | ||
|
|
df4c62212c | ||
|
|
97b6036cbf | ||
|
|
df4f7ed5b8 | ||
|
|
0792c015d6 | ||
|
|
8344598910 | ||
|
|
16870abed7 | ||
|
|
65850a1bad | ||
|
|
1137f0d48c | ||
|
|
d9a50f04e7 | ||
|
|
4aa7d73b43 | ||
|
|
3804e72e24 | ||
|
|
b8508020e5 | ||
|
|
324be0eabd | ||
|
|
cfe5f83cf8 | ||
|
|
a1ad0deb32 | ||
|
|
7c575a2418 | ||
|
|
47cac13c0a | ||
|
|
16d1ef8933 | ||
|
|
b500d76929 | ||
|
|
aef9471217 | ||
|
|
f3454d571e | ||
|
|
1df1f86f7e | ||
|
|
f9db9c5a9c | ||
|
|
96bafeca4c | ||
|
|
626d8ec637 | ||
|
|
f3b36af50e | ||
|
|
385b640d1d | ||
|
|
d4bc6fa954 | ||
|
|
8bae43876f | ||
|
|
fbfea94559 | ||
|
|
6a04b43a45 | ||
|
|
049c62098c | ||
|
|
6801959989 | ||
|
|
8463d9d7c6 | ||
|
|
c497f057a0 | ||
|
|
fc0af0f0d8 | ||
|
|
330c2004a1 | ||
|
|
0b10493e90 | ||
|
|
d23e64fc52 | ||
|
|
fd83d69440 | ||
|
|
461e46b814 | ||
|
|
4f95146151 | ||
|
|
3eb21053d0 | ||
|
|
92db6f8c6d | ||
|
|
0fd0c6d293 | ||
|
|
b49973f17b | ||
|
|
978d265da8 | ||
|
|
cf6dddce34 | ||
|
|
2c4bbe51dd | ||
|
|
756d441f8c | ||
|
|
db6aa88bc4 | ||
|
|
e707af1cd7 | ||
|
|
380a70d650 | ||
|
|
2dc3b5c675 | ||
|
|
63011c29a0 | ||
|
|
e68c3b09a6 | ||
|
|
0793bf5aa6 | ||
|
|
d9b7e4cb7a | ||
|
|
8e6ab1809f | ||
|
|
86418bfbbe | ||
|
|
1e1c13f756 | ||
|
|
8dae851836 | ||
|
|
db284d60b9 | ||
|
|
bfc6c7e606 | ||
|
|
9b13390ad0 | ||
|
|
81fe4299f7 | ||
|
|
5e4bc6ec79 | ||
|
|
f3612879a8 | ||
|
|
57088c4375 | ||
|
|
011ab7c8fe | ||
|
|
e4422d6605 | ||
|
|
14e1d015ee | ||
|
|
3da1c17acb | ||
|
|
7e9f0803c5 | ||
|
|
f989452b3e | ||
|
|
a2780d1dd4 | ||
|
|
ddca45804b | ||
|
|
f92e12c7b0 | ||
|
|
e4da8b99fe | ||
|
|
b993579079 | ||
|
|
807cb635c1 | ||
|
|
3ad559cc23 | ||
|
|
ec02ce0ec2 | ||
|
|
1b9676a0cc | ||
|
|
f4b3ef7604 | ||
|
|
e9974c2053 | ||
|
|
de532ee550 | ||
|
|
67b44e4417 | ||
|
|
83f65031c0 | ||
|
|
63053541e6 | ||
|
|
a040e2e3db | ||
|
|
678d445075 | ||
|
|
3558b9e6b6 | ||
|
|
590c3e2f51 | ||
|
|
28a7343320 | ||
|
|
766bae9d76 | ||
|
|
94a57df0c9 | ||
|
|
5f93742c5e | ||
|
|
9457c770df | ||
|
|
bccb9b16a5 | ||
|
|
1355029ec9 | ||
|
|
5dc8d6069d | ||
|
|
60837b1538 | ||
|
|
debfd1f3a3 | ||
|
|
4f70cc13e2 | ||
|
|
b4111c5c18 | ||
|
|
b9b7174d85 | ||
|
|
69ceaae9a9 | ||
|
|
1abdb28995 | ||
|
|
81dab99afc | ||
|
|
291522772d | ||
|
|
26d1ac325b | ||
|
|
1311d03415 | ||
|
|
549fd32574 | ||
|
|
9f14bbd6ad | ||
|
|
e8f7801540 | ||
|
|
cdde79418a | ||
|
|
9b97da65e6 | ||
|
|
1dcaebe1ce | ||
|
|
28b5d0f875 | ||
|
|
ba217dec1c | ||
|
|
3b8c4dc750 | ||
|
|
5d1fa1be24 | ||
|
|
c8e82528fc | ||
|
|
104e6d39ab | ||
|
|
3f778d9a31 | ||
|
|
a935ad1857 | ||
|
|
7abb3941c8 | ||
|
|
194880b869 | ||
|
|
737f588b3b | ||
|
|
6d5b36fb79 | ||
|
|
8ce6bd3459 | ||
|
|
5b8338d115 | ||
|
|
e73cbbe18c | ||
|
|
69a01b3657 | ||
|
|
e406b81d34 | ||
|
|
fdc2751952 | ||
|
|
fa11083fcb | ||
|
|
2bc8819e8f | ||
|
|
23b6c95e04 | ||
|
|
c041bcc6d9 | ||
|
|
fc5dd23afa | ||
|
|
91d0660cc3 | ||
|
|
fb5769b4be | ||
|
|
56ee212641 | ||
|
|
8f3891e968 | ||
|
|
958a775afa | ||
|
|
e776dc16c9 | ||
|
|
9450a3c987 | ||
|
|
1939a55c3c | ||
|
|
2a116bb291 | ||
|
|
d01c7320f9 | ||
|
|
ea0315ed88 | ||
|
|
85a5eb9499 | ||
|
|
3cd06a1f26 | ||
|
|
19c3d02805 | ||
|
|
b534bfc520 | ||
|
|
ef2c8d66f1 | ||
|
|
1a6038baa5 | ||
|
|
41a8fb5810 | ||
|
|
8843d8b68d | ||
|
|
2aec79ce36 | ||
|
|
bbcbc8425c | ||
|
|
ed8178f3c3 | ||
|
|
933527fc77 | ||
|
|
bf8d139b2d | ||
|
|
093983b804 | ||
|
|
103292dd99 | ||
|
|
76b6b1c694 | ||
|
|
1301864f92 | ||
|
|
d5b6f6cc37 | ||
|
|
052073c36d | ||
|
|
60c778ad7f | ||
|
|
71100dadcd | ||
|
|
5ba33438f3 | ||
|
|
708c0d32a2 | ||
|
|
3659e8c04a | ||
|
|
c4cf349729 | ||
|
|
2c99566697 | ||
|
|
42470857e2 | ||
|
|
8724f97a19 | ||
|
|
8960992267 | ||
|
|
730af24de8 | ||
|
|
a3fa6f3099 | ||
|
|
4dafc25927 | ||
|
|
e671ebcd99 | ||
|
|
bab8508eba | ||
|
|
77cd4795c5 | ||
|
|
dc83f36a00 | ||
|
|
8336c91e9c | ||
|
|
1bea53375b | ||
|
|
3af55a4f49 | ||
|
|
cf482ae3bf | ||
|
|
916958a2bb | ||
|
|
e2af94289f | ||
|
|
fa4c81cfb9 | ||
|
|
7dbc66e4a3 |
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
.*
|
||||
*.swp
|
||||
*~$
|
||||
build
|
||||
cscope.*
|
||||
tags
|
||||
@@ -6,14 +6,16 @@ cmake_minimum_required(VERSION 2.6.0)
|
||||
# global needed variables
|
||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
|
||||
set(APPLICATION_VERSION "0.3.0")
|
||||
set(APPLICATION_VERSION "0.4.0")
|
||||
|
||||
set(APPLICATION_VERSION_MAJOR "0")
|
||||
set(APPLICATION_VERSION_MINOR "3")
|
||||
set(APPLICATION_VERSION_MINOR "4")
|
||||
set(APPLICATION_VERSION_PATCH "1")
|
||||
|
||||
set(LIBRARY_VERSION "3.1.0")
|
||||
set(LIBRARY_SOVERSION "3")
|
||||
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}${APPLICATION_VERSION_MINOR}${APPLICATION_VERSION_PATCH}")
|
||||
|
||||
set(LIBRARY_VERSION "4.0.1")
|
||||
set(LIBRARY_SOVERSION "4")
|
||||
|
||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||
set(CMAKE_MODULE_PATH
|
||||
@@ -38,14 +40,20 @@ include(MacroCopyFile)
|
||||
# search for libraries
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
find_package(OpenSSL)
|
||||
|
||||
if (NOT CRYPTO_FOUND)
|
||||
find_package(GCrypt)
|
||||
if (WITH_GCRYPT)
|
||||
find_package(GCrypt REQUIRED)
|
||||
if (NOT GCRYPT_FOUND)
|
||||
message(FATAL_ERROR "Could not find OpenSSL or GCrypt")
|
||||
message(FATAL_ERROR "Could not find GCrypt")
|
||||
endif (NOT GCRYPT_FOUND)
|
||||
endif (NOT CRYPTO_FOUND)
|
||||
else (WITH_GCRYPT)
|
||||
find_package(OpenSSL)
|
||||
if (NOT CRYPTO_FOUND)
|
||||
find_package(GCrypt)
|
||||
if (NOT GCRYPT_FOUND)
|
||||
message(FATAL_ERROR "Could not find OpenSSL or GCrypt")
|
||||
endif (NOT GCRYPT_FOUND)
|
||||
endif (NOT CRYPTO_FOUND)
|
||||
endif(WITH_GCRYPT)
|
||||
|
||||
# config.h checks
|
||||
include(ConfigureChecks.cmake)
|
||||
@@ -60,11 +68,6 @@ add_subdirectory(libssh)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
if (UNIX AND NOT WIN32)
|
||||
if (WITH_SFTP AND WITH_SERVER)
|
||||
add_executable(samplessh sample.c)
|
||||
add_executable(samplesshd samplesshd.c)
|
||||
add_subdirectory(examples)
|
||||
|
||||
target_link_libraries(samplessh ${LIBSSH_SHARED_LIBRARY})
|
||||
target_link_libraries(samplesshd ${LIBSSH_SHARED_LIBRARY})
|
||||
endif (WITH_SFTP AND WITH_SERVER)
|
||||
endif (UNIX AND NOT WIN32)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
# For help take a look at:
|
||||
# http://www.cmake.org/Wiki/CMake:CPackConfiguration
|
||||
|
||||
@@ -14,7 +12,7 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
|
||||
|
||||
### versions
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "0")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "3")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "4")
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "1")
|
||||
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
|
||||
|
||||
|
||||
71
ChangeLog
71
ChangeLog
@@ -1,6 +1,77 @@
|
||||
ChangeLog
|
||||
==========
|
||||
|
||||
version 0.4.1 (released 2010-02-13)
|
||||
* Added support for aes128-ctr, aes192-ctr and aes256-ctr encryption.
|
||||
* Added an example for exec.
|
||||
* Added private key type detection feature in privatekey_from_file().
|
||||
* Fixed zlib compression fallback.
|
||||
* Fixed kex bug that client preference should be prioritary
|
||||
* Fixed known_hosts file set by the user.
|
||||
* Fixed a memleak in channel_accept().
|
||||
* Fixed underflow when leave_function() are unbalanced
|
||||
* Fixed memory corruption in handle_channel_request_open().
|
||||
* Fixed closing of a file handle case of errors in privatekey_from_file().
|
||||
* Fixed ssh_get_user_home_dir() to be thread safe.
|
||||
* Fixed the doxygen documentation.
|
||||
|
||||
version 0.4.0 (released 2009-12-10)
|
||||
* Added scp support.
|
||||
* Added support for sending signals (RFC 4254, section 6.9).
|
||||
* Added MSVC support.
|
||||
* Added support for ~/.ssh/config.
|
||||
* Added sftp extension support.
|
||||
* Added X11 forwarding support for client.
|
||||
* Added forward listening.
|
||||
* Added support for openssh extensions (statvfs, fstatvfs).
|
||||
* Added a cleaned up interface for setting options.
|
||||
* Added a generic way to handle sockets asynchronously.
|
||||
* Added logging of the sftp flags used to open a file.
|
||||
* Added full poll() support and poll-emulation for win32.
|
||||
* Added missing 64bit functions in sftp.
|
||||
* Added support for ~/ and SSH_DIR/ in filenames instead of %s/.
|
||||
* Fixed Fix channel_get_exit_status bug.
|
||||
* Fixed calltrace logging to make it optional.
|
||||
* Fixed compilation on Solaris.
|
||||
* Fixed resolving of ip addresses.
|
||||
* Fixed libssh compilation without server support.
|
||||
* Fixed possible memory corruptions (ticket #14).
|
||||
|
||||
version 0.3.4 (released 2009-09-14)
|
||||
* Added ssh_basename and ssh_dirname.
|
||||
* Added a portable ssh_mkdir function.
|
||||
* Added a sftp_tell64() function.
|
||||
* Added missing NULL pointer checks to crypt_set_algorithms_server.
|
||||
* Fixed ssh_write_knownhost if ~/.ssh doesn't exist.
|
||||
* Fixed a possible integer overflow in buffer_get_data().
|
||||
* Fixed possible security bug in packet_decrypt().
|
||||
* Fixed a possible stack overflow in agent code.
|
||||
|
||||
version 0.3.3 (released 2009-08-18)
|
||||
* Fixed double free pointer crash in dsa_public_to_string.
|
||||
* Fixed channel_get_exit_status bug.
|
||||
* Fixed ssh_finalize which didn't clear the flag.
|
||||
* Fixed memory leak introduced by previous bugfix.
|
||||
* Fixed channel_poll broken when delayed EOF recvd.
|
||||
* Fixed stupid "can't parse known host key" bug.
|
||||
* Fixed possible memory corruption (ticket #14).
|
||||
|
||||
version 0.3.2 (released 2009-08-05)
|
||||
* Added ssh_init() function.
|
||||
* Added sftp_readlink() function.
|
||||
* Added sftp_symlink() function.
|
||||
* Fixed ssh_write_knownhost().
|
||||
* Fixed compilation on Solaris.
|
||||
* Fixed SSHv1 compilation.
|
||||
|
||||
version 0.3.1 (released 2009-07-14)
|
||||
* Added return code SSH_SERVER_FILE_NOT_FOUND.
|
||||
* Fixed compilation of SSHv1.
|
||||
* Fixed several memory leaks.
|
||||
* Fixed possible infinite loops.
|
||||
* Fixed a possible crash bug.
|
||||
* Fixed build warnings.
|
||||
* Fixed cmake on BSD.
|
||||
version 0.3.1 (released 2009-07-14)
|
||||
* Added return code SSH_SERVER_FILE_NOT_FOUND.
|
||||
* Fixed compilation of SSHv1.
|
||||
|
||||
@@ -4,6 +4,7 @@ include(CheckFunctionExists)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckTypeSize)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(TestBigEndian)
|
||||
|
||||
set(PACKAGE ${APPLICATION_NAME})
|
||||
set(VERSION ${APPLICATION_VERSION})
|
||||
@@ -15,26 +16,70 @@ set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
|
||||
set(BINARYDIR ${CMAKE_BINARY_DIR})
|
||||
set(SOURCEDIR ${CMAKE_SOURCE_DIR})
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUC)
|
||||
check_c_compiler_flag("-fvisibility=hidden" WITH_VISIBILITY_HIDDEN)
|
||||
endif(CMAKE_COMPILER_IS_GNUC)
|
||||
|
||||
# HEADER FILES
|
||||
check_include_file(argp.h HAVE_ARGP_H)
|
||||
check_include_file(pty.h HAVE_PTY_H)
|
||||
check_include_file(terminos.h HAVE_TERMIOS_H)
|
||||
if (WIN32)
|
||||
check_include_file(wspiapi.h HAVE_WSPIAPI_H)
|
||||
if (NOT HAVE_WSPIAPI_H)
|
||||
message(STATUS "WARNING: Without wspiapi.h, this build will only work on Windows XP and newer versions")
|
||||
endif (NOT HAVE_WSPIAPI_H)
|
||||
check_include_file(ws2tcpip.h HAVE_WS2TCPIP_H)
|
||||
if (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
|
||||
set(HAVE_GETADDRINFO TRUE)
|
||||
set(HAVE_GETHOSTBYNAME TRUE)
|
||||
endif (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
|
||||
|
||||
set(HAVE_SELECT TRUE)
|
||||
endif (WIN32)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/aes.h HAVE_OPENSSL_AES_H)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/blowfish.h HAVE_OPENSSL_BLOWFISH_H)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/des.h HAVE_OPENSSL_DES_H)
|
||||
|
||||
# FUNCTIONS
|
||||
check_function_exists(cfmakeraw HAVE_CFMAKERAW)
|
||||
if (WIN32)
|
||||
set(HAVE_GETADDRINFO TRUE)
|
||||
set(HAVE_GETHOSTBYNAME TRUE)
|
||||
set(HAVE_SELECT TRUE)
|
||||
else (WIN32)
|
||||
|
||||
if (UNIX)
|
||||
# libsocket (Solaris)
|
||||
check_library_exists(socket getaddrinfo "" HAVE_LIBSOCKET)
|
||||
if (HAVE_LIBSOCKET)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} socket)
|
||||
endif (HAVE_LIBSOCKET)
|
||||
# libnsl (Solaris)
|
||||
check_library_exists(nsl gethostbyname "" HAVE_LIBNSL)
|
||||
if (HAVE_LIBNSL)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} nsl)
|
||||
endif (HAVE_LIBNSL)
|
||||
# libresolv
|
||||
check_library_exists(resolv hstrerror "" HAVE_LIBRESOLV)
|
||||
if (HAVE_LIBRESOLV)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} resolv)
|
||||
endif (HAVE_LIBRESOLV)
|
||||
check_library_exists(rt nanosleep "" HAVE_LIBRT)
|
||||
# librt
|
||||
if (HAVE_LIBRT)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} rt)
|
||||
endif (HAVE_LIBRT)
|
||||
|
||||
check_function_exists(getaddrinfo HAVE_GETADDRINFO)
|
||||
check_function_exists(gethostbyname HAVE_GETHOSTBYNAME)
|
||||
check_function_exists(poll HAVE_POLL)
|
||||
check_function_exists(select HAVE_SELECT)
|
||||
endif (WIN32)
|
||||
check_function_exists(cfmakeraw HAVE_CFMAKERAW)
|
||||
check_function_exists(regcomp HAVE_REGCOMP)
|
||||
endif (UNIX)
|
||||
|
||||
set(LIBSSH_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "libssh required system libraries")
|
||||
|
||||
# LIBRARIES
|
||||
if (CRYPTO_FOUND)
|
||||
@@ -54,3 +99,9 @@ if (WITH_DEBUG_CRYPTO)
|
||||
set(DEBUG_CRYPTO 1)
|
||||
endif (WITH_DEBUG_CRYPTO)
|
||||
|
||||
if (WITH_DEBUG_CALLTRACE)
|
||||
set(DEBUG_CALLTRACE 1)
|
||||
endif (WITH_DEBUG_CALLTRACE)
|
||||
|
||||
# ENDIAN
|
||||
test_big_endian(WORDS_BIGENDIAN)
|
||||
|
||||
@@ -3,4 +3,7 @@ option(WITH_SSH1 "Build with SSH1 support" OFF)
|
||||
option(WITH_SFTP "Build with SFTP support" ON)
|
||||
option(WITH_SERVER "Build with SSH server support" ON)
|
||||
option(WITH_STATIC_LIB "Build with a static library" OFF)
|
||||
option(WITH_DEBUG_CRYPTO "Build with cryto debut output" OFF)
|
||||
option(WITH_DEBUG_CRYPTO "Build with cryto debug output" OFF)
|
||||
option(WITH_DEBUG_CALLTRACE "Build with calltrace debug output" ON)
|
||||
option(WITH_GCRYPT "Compile against libgcrypt" OFF)
|
||||
option(WITH_PCAP "Compile with Pcap generation support" OFF)
|
||||
|
||||
49
README
49
README
@@ -1,14 +1,14 @@
|
||||
The libSSH and its client
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-Aris Adamantiadis
|
||||
libssh: the SSH library
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
1* Why ?
|
||||
-_-_-_-_-_
|
||||
|
||||
Why not ? :) I've began to work on my own implementation of the ssh protocol
|
||||
because i didn't like the currently public ones.
|
||||
Not any allow you to import and use the functions as a library, and so i
|
||||
worked on a library-based SSH implementation.
|
||||
Not any allowed you to import and use the functions as a powerful library,
|
||||
and so i worked on a library-based SSH implementation which was non-existing
|
||||
in the free and open source software world.
|
||||
|
||||
|
||||
2* How/Who ?
|
||||
@@ -16,24 +16,33 @@ worked on a library-based SSH implementation.
|
||||
|
||||
If you downloaded this file, you must know what it is : a library for
|
||||
accessing ssh client services through C libraries calls in a simple manner.
|
||||
The client is there as a programming example and isn't at all doing its job
|
||||
correctly (doesn't verify public key hashes with the ones in ~/.ssh/
|
||||
and doesn't handle TERM - yet)
|
||||
Everybody can use this software under the terms of the LGPL - see the COPYING
|
||||
file
|
||||
|
||||
3* What ?
|
||||
-_-_-_-_-_
|
||||
If you ask yourself how to compile libssh, please read INSTALL before anything.
|
||||
|
||||
The SSH library features :
|
||||
-Full C library functions for manipulating a client-side SSH connection
|
||||
-Fully configurable sessions
|
||||
-Support for AES-128,AES-192,AES-256,blowfish, in cbc mode
|
||||
-use multiple SSH connections in a same process, at same time.
|
||||
-usable SFTP implementation
|
||||
-Public key and password authentication
|
||||
|
||||
4* Where ?
|
||||
3* Where ?
|
||||
-_-_-_-_-_-_
|
||||
|
||||
http://0xbadc0de.be/?part=libssh
|
||||
http://www.libssh.org
|
||||
|
||||
4* API Changes !
|
||||
-_-_-_-_-_-_-_-_-_
|
||||
|
||||
Changes between 0.3 and 0.4
|
||||
---------------------------
|
||||
|
||||
We changed libssh to be typesafe now:
|
||||
|
||||
SSH_SESSION *session -> ssh_session session
|
||||
SFTP_SESSION *sftp -> sftp_session sftp
|
||||
CHANNEL *channel -> ssh_channel channel
|
||||
STRING *string -> ssh_string string
|
||||
...
|
||||
|
||||
The options structure has been removed and there is a new function. This
|
||||
function can set all available options now. You can find the enum in the
|
||||
header file and it is documented. Example:
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
|
||||
|
||||
@@ -34,15 +34,26 @@ cleanup_and_exit () {
|
||||
}
|
||||
|
||||
function configure() {
|
||||
cmake "$@" ${SOURCE_DIR} || cleanup_and_exit $?
|
||||
if [ -n "${CMAKEDIR}" ]; then
|
||||
${CMAKEDIR}/bin/cmake "$@" ${SOURCE_DIR} || cleanup_and_exit $?
|
||||
else
|
||||
cmake "$@" ${SOURCE_DIR} || cleanup_and_exit $?
|
||||
fi
|
||||
}
|
||||
|
||||
function compile() {
|
||||
CPUCOUNT=$(grep -c processor /proc/cpuinfo)
|
||||
if [ "${CPUCOUNT}" -gt "1" ]; then
|
||||
make -j${CPUCOUNT} $1 || cleanup_and_exit $?
|
||||
if [ -f /proc/cpuinfo ]; then
|
||||
CPUCOUNT=$(grep -c processor /proc/cpuinfo)
|
||||
elif test `uname` = "SunOS" ; then
|
||||
CPUCOUNT=$(psrinfo -p)
|
||||
else
|
||||
make $1 || exit $?
|
||||
CPUCOUNT="1"
|
||||
fi
|
||||
|
||||
if [ "${CPUCOUNT}" -gt "1" ]; then
|
||||
${MAKE} -j${CPUCOUNT} $1 || cleanup_and_exit $?
|
||||
else
|
||||
${MAKE} $1 || exit $?
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -51,13 +62,18 @@ function clean_build_dir() {
|
||||
}
|
||||
|
||||
function usage () {
|
||||
echo "Usage: `basename $0` [--prefix /install_prefix|--build [debug|final]|--clean|--verbose|--libsuffix (32|64)|--help]"
|
||||
echo "Usage: `basename $0` [--prefix /install_prefix|--build [debug|final]|--clean|--verbose|--libsuffix (32|64)|--help|--cmakedir /directory|--make
|
||||
(gmake|make)|--ccompiler (gcc|cc)|--withstaticlib|--unittesting|--withss1|--withserver]"
|
||||
cleanup_and_exit
|
||||
}
|
||||
|
||||
cd ${BUILDDIR}
|
||||
|
||||
OPTIONS="--graphviz=${BUILDDIR}/libssh.dot -DUNIT_TESTING=ON -DWITH_SSH1=ON -DWITH_SERVER=ON"
|
||||
# the default CMake options:
|
||||
OPTIONS="--graphviz=${BUILDDIR}/libssh.dot"
|
||||
|
||||
# the default 'make' utility:
|
||||
MAKE="make"
|
||||
|
||||
while test -n "$1"; do
|
||||
PARAM="$1"
|
||||
@@ -102,6 +118,34 @@ while test -n "$1"; do
|
||||
OPTIONS="${OPTIONS} -DSYSCONF_INSTALL_DIR=${ARG}"
|
||||
shift
|
||||
;;
|
||||
*-cmakedir)
|
||||
CMAKEDIR="${ARG}"
|
||||
shift
|
||||
;;
|
||||
*-make)
|
||||
MAKE="${ARG}"
|
||||
shift
|
||||
;;
|
||||
*-ccompiler)
|
||||
OPTIONS="${OPTIONS} -DCMAKE_C_COMPILER=${ARG}"
|
||||
shift
|
||||
;;
|
||||
*-withstaticlib)
|
||||
OPTIONS="${OPTIONS} -DWITH_STATIC_LIB=ON"
|
||||
shift
|
||||
;;
|
||||
*-unittesting)
|
||||
OPTIONS="${OPTIONS} -DUNIT_TESTING=ON"
|
||||
shift
|
||||
;;
|
||||
*-withssh1)
|
||||
OPTIONS="${OPTIONS} -DWITH_SSH1=ON"
|
||||
shift
|
||||
;;
|
||||
*-withserver)
|
||||
OPTIONS="${OPTIONS} -DWITH_SERVER=ON"
|
||||
shift
|
||||
;;
|
||||
----noarg)
|
||||
echo "$ARG does not take an argument"
|
||||
cleanup_and_exit
|
||||
@@ -116,7 +160,7 @@ while test -n "$1"; do
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ${DOMAKE} -eq 1 ]; then
|
||||
if [ "${DOMAKE}" == "1" ]; then
|
||||
OPTIONS="${OPTIONS} -DCMAKE_BUILD_TYPE=${BUILD_TYPE}"
|
||||
fi
|
||||
|
||||
@@ -149,4 +193,3 @@ exec >&0 2>&0 # so that the logging tee finishes
|
||||
sleep 1 # wait till tee terminates
|
||||
|
||||
cleanup_and_exit 0
|
||||
|
||||
|
||||
@@ -3,47 +3,57 @@
|
||||
include(CheckCCompilerFlag)
|
||||
|
||||
if (UNIX AND NOT WIN32)
|
||||
# with -fPIC
|
||||
check_c_compiler_flag("-fPIC" WITH_FPIC)
|
||||
if (WITH_FPIC)
|
||||
add_definitions(-fPIC)
|
||||
endif (WITH_FPIC)
|
||||
if (${CMAKE_C_COMPILER_ID} MATCHES GNU)
|
||||
# add -Wconversion ?
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -pedantic -Wall -Wextra -Wshadow -Wmissing-prototypes -Wdeclaration-after-statement -Wunused -Wfloat-equal -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute")
|
||||
|
||||
# with -fPIC
|
||||
check_c_compiler_flag("-fPIC" WITH_FPIC)
|
||||
if (WITH_FPIC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
|
||||
endif (WITH_FPIC)
|
||||
|
||||
check_c_compiler_flag("-fstack-protector" WITH_STACK_PROTECTOR)
|
||||
if (WITH_STACK_PROTECTOR)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector")
|
||||
endif (WITH_STACK_PROTECTOR)
|
||||
|
||||
check_c_compiler_flag("-D_FORTIFY_SOURCE=2" WITH_FORTIFY_SOURCE)
|
||||
if (WITH_FORTIFY_SOURCE)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2")
|
||||
endif (WITH_FORTIFY_SOURCE)
|
||||
|
||||
endif (${CMAKE_C_COMPILER_ID} MATCHES GNU)
|
||||
|
||||
if (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
# with large file support
|
||||
execute_process(
|
||||
COMMAND
|
||||
getconf LFS64_CFLAGS
|
||||
OUTPUT_VARIABLE
|
||||
_lfs_CFLAGS
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
else (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
# with large file support
|
||||
execute_process(
|
||||
COMMAND
|
||||
getconf LFS_CFLAGS
|
||||
OUTPUT_VARIABLE
|
||||
_lfs_CFLAGS
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
string(REGEX REPLACE "[\r\n]" " " "${_lfs_CFLAGS}" "${${_lfs_CFLAGS}}")
|
||||
|
||||
add_definitions(${_lfs_CFLAGS})
|
||||
endif (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
|
||||
add_definitions(-Wall -Wextra -Wmissing-prototypes -Wdeclaration-after-statement -Wunused)
|
||||
|
||||
check_c_compiler_flag("-fstack-protector" WITH_STACK_PROTECTOR)
|
||||
if (WITH_STACK_PROTECTOR)
|
||||
add_definitions(-fstack-protector)
|
||||
endif (WITH_STACK_PROTECTOR)
|
||||
|
||||
check_c_compiler_flag("-D_FORTIFY_SOURCE=2" WITH_FORTIFY_SOURCE)
|
||||
if (WITH_FORTIFY_SOURCE)
|
||||
add_definitions(-D_FORTIFY_SOURCE=2)
|
||||
endif (WITH_FORTIFY_SOURCE)
|
||||
# with large file support
|
||||
execute_process(
|
||||
COMMAND
|
||||
getconf LFS64_CFLAGS
|
||||
OUTPUT_VARIABLE
|
||||
_lfs_CFLAGS
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
else (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
# with large file support
|
||||
execute_process(
|
||||
COMMAND
|
||||
getconf LFS_CFLAGS
|
||||
OUTPUT_VARIABLE
|
||||
_lfs_CFLAGS
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
endif (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
if (_lfs_CFLAGS)
|
||||
string(REGEX REPLACE "[\r\n]" " " "${_lfs_CFLAGS}" "${${_lfs_CFLAGS}}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_lfs_CFLAGS}")
|
||||
endif (_lfs_CFLAGS)
|
||||
|
||||
endif (UNIX AND NOT WIN32)
|
||||
|
||||
# suppress warning about "deprecated" functions
|
||||
if (MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS")
|
||||
endif (MSVC)
|
||||
|
||||
@@ -94,7 +94,7 @@ endif (UNIX)
|
||||
|
||||
if (WIN32)
|
||||
# Same same
|
||||
set(BIN_INSTALL_DIR "." CACHE PATH "-")
|
||||
set(BIN_INSTALL_DIR "bin" CACHE PATH "-")
|
||||
set(SBIN_INSTALL_DIR "." CACHE PATH "-")
|
||||
set(LIB_INSTALL_DIR "lib" CACHE PATH "-")
|
||||
set(INCLUDE_INSTALL_DIR "include" CACHE PATH "-")
|
||||
|
||||
@@ -37,20 +37,26 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
||||
${_OPENSSL_INCLUDEDIR}
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/usr/local/ssl/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
/usr/lib/sfw/include
|
||||
)
|
||||
mark_as_advanced(OPENSSL_INCLUDE_DIR)
|
||||
|
||||
find_library(SSL_LIBRARY
|
||||
NAMES
|
||||
ssl
|
||||
libssl
|
||||
PATHS
|
||||
${_OPENSSL_LIBDIR}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/usr/local/ssl/lib
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
/usr/sfw/lib/64
|
||||
/usr/sfw/lib
|
||||
)
|
||||
mark_as_advanced(SSL_LIBRARY)
|
||||
|
||||
@@ -61,8 +67,11 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
||||
${_OPENSSL_LIBDIR}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/usr/local/ssl/lib
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
/usr/sfw/lib/64
|
||||
/usr/sfw/lib
|
||||
)
|
||||
mark_as_advanced(SSLEAY32_LIBRARY)
|
||||
|
||||
@@ -73,20 +82,32 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
||||
${_OPENSSL_LIBDIR}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/usr/local/ssl/lib
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
/usr/sfw/lib/64
|
||||
/usr/sfw/lib
|
||||
)
|
||||
mark_as_advanced(SSLEAY32MD_LIBRARY)
|
||||
|
||||
find_library(CRYPTO_LIBRARY
|
||||
NAMES
|
||||
crypto
|
||||
libcrypto
|
||||
eay
|
||||
eay32
|
||||
libeay
|
||||
libeay32
|
||||
PATHS
|
||||
${_OPENSSL_LIBDIR}
|
||||
/lib
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/usr/local/ssl/lib
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
/usr/sfw/lib/64
|
||||
/usr/sfw/lib
|
||||
)
|
||||
mark_as_advanced(CRYPTO_LIBRARY)
|
||||
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
|
||||
/************************** HEADER FILES *************************/
|
||||
|
||||
/* Define to 1 if you have the <argp.h> header file. */
|
||||
#cmakedefine HAVE_ARGP_H 1
|
||||
|
||||
/* Define to 1 if you have the <pty.h> header file. */
|
||||
#cmakedefine HAVE_PTY_H 1
|
||||
|
||||
@@ -23,6 +26,9 @@
|
||||
/* Define to 1 if you have the <openssl/aes.h> header file. */
|
||||
#cmakedefine HAVE_OPENSSL_AES_H 1
|
||||
|
||||
/* Define to 1 if you have the <wspiapi.h> header file. */
|
||||
#cmakedefine HAVE_WSPIAPI_H 1
|
||||
|
||||
/* Define to 1 if you have the <openssl/blowfish.h> header file. */
|
||||
#cmakedefine HAVE_OPENSSL_BLOWFISH_H 1
|
||||
|
||||
@@ -46,6 +52,9 @@
|
||||
/* Define to 1 if you have the `select' function. */
|
||||
#cmakedefine HAVE_SELECT 1
|
||||
|
||||
/* Define to 1 if you have the `regcomp' function. */
|
||||
#cmakedefine HAVE_REGCOMP 1
|
||||
|
||||
/*************************** LIBRARIES ***************************/
|
||||
|
||||
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
||||
@@ -62,7 +71,7 @@
|
||||
/* Define to 1 if you want to enable ZLIB */
|
||||
#cmakedefine WITH_LIBZ 1
|
||||
|
||||
/* Define to 1 if you want to enable SSH1 */
|
||||
/* Define to 1 if you want to enable SFTP */
|
||||
#cmakedefine WITH_SFTP 1
|
||||
|
||||
/* Define to 1 if you want to enable SSH1 */
|
||||
@@ -74,14 +83,28 @@
|
||||
/* Define to 1 if you want to enable debug output for crypto functions */
|
||||
#cmakedefine DEBUG_CRYPTO 1
|
||||
|
||||
/* Define to 1 if you want to enable pcap output support (experimental) */
|
||||
#cmakedefine WITH_PCAP 1
|
||||
|
||||
/* Define to 1 if you want to enable calltrace debug output */
|
||||
#cmakedefine DEBUG_CALLTRACE 1
|
||||
|
||||
/*************************** ENDIAN *****************************/
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
/* # undef WORDS_BIGENDIAN */
|
||||
# endif
|
||||
#endif
|
||||
#cmakedefine WORDS_BIGENDIAN 1
|
||||
|
||||
/************************* MS Windows ***************************/
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef _MSC_VER
|
||||
/* On Microsoft compilers define inline to __inline on all others use inline */
|
||||
# undef inline
|
||||
# define inline __inline
|
||||
|
||||
# undef strdup
|
||||
# define strdup _strdup
|
||||
# endif // _MSC_VER
|
||||
#endif /* _WIN32 */
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Doxyfile 1.5.8
|
||||
# Doxyfile 1.5.6
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# doxygen (www.doxygen.org) for a project
|
||||
@@ -57,8 +57,8 @@ CREATE_SUBDIRS = NO
|
||||
# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
|
||||
# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
|
||||
# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
|
||||
# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene,
|
||||
# Spanish, Swedish, and Ukrainian.
|
||||
# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
|
||||
# and Ukrainian.
|
||||
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
@@ -165,6 +165,13 @@ QT_AUTOBRIEF = NO
|
||||
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
|
||||
# If the DETAILS_AT_TOP tag is set to YES then Doxygen
|
||||
# will output the detailed description near the top, like JavaDoc.
|
||||
# If set to NO, the detailed description appears after the member
|
||||
# documentation.
|
||||
|
||||
DETAILS_AT_TOP = YES
|
||||
|
||||
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
|
||||
# member inherits the documentation from any documented member that it
|
||||
# re-implements.
|
||||
@@ -217,17 +224,6 @@ OPTIMIZE_FOR_FORTRAN = NO
|
||||
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
|
||||
# Doxygen selects the parser to use depending on the extension of the files it parses.
|
||||
# With this tag you can assign which parser to use for a given extension.
|
||||
# Doxygen has a built-in mapping, but you can override or extend it using this tag.
|
||||
# The format is ext=language, where ext is a file extension, and language is one of
|
||||
# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
|
||||
# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
|
||||
# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
|
||||
# use: inc=Fortran f=C
|
||||
|
||||
EXTENSION_MAPPING =
|
||||
|
||||
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
|
||||
# to include (a tag file for) the STL sources as input, then you should
|
||||
# set this tag to YES in order to let doxygen match functions declarations and
|
||||
@@ -237,7 +233,7 @@ EXTENSION_MAPPING =
|
||||
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
|
||||
# If you use Microsoft's C++/CLI language, you should set this option to YES to
|
||||
# If you use Microsoft's C++/CLI language, you should set this option to YES to
|
||||
# enable parsing support.
|
||||
|
||||
CPP_CLI_SUPPORT = NO
|
||||
@@ -280,23 +276,7 @@ SUBGROUPING = YES
|
||||
# be useful for C code in case the coding convention dictates that all compound
|
||||
# types are typedef'ed and only the typedef is referenced, never the tag name.
|
||||
|
||||
TYPEDEF_HIDES_STRUCT = NO
|
||||
|
||||
# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
|
||||
# determine which symbols to keep in memory and which to flush to disk.
|
||||
# When the cache is full, less often used symbols will be written to disk.
|
||||
# For small to medium size projects (<1000 input files) the default value is
|
||||
# probably good enough. For larger projects a too small cache size can cause
|
||||
# doxygen to be busy swapping symbols to and from disk most of the time
|
||||
# causing a significant performance penality.
|
||||
# If the system has enough physical memory increasing the cache will improve the
|
||||
# performance by keeping more symbols in memory. Note that the value works on
|
||||
# a logarithmic scale so increasing the size by one will rougly double the
|
||||
# memory usage. The cache size is given by this formula:
|
||||
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
|
||||
# corresponding to a cache size of 2^16 = 65536 symbols
|
||||
|
||||
SYMBOL_CACHE_SIZE = 0
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
@@ -425,7 +405,7 @@ SORT_GROUP_NAMES = NO
|
||||
# sorted by fully-qualified names, including namespaces. If set to
|
||||
# NO (the default), the class list will be sorted only by class name,
|
||||
# not including the namespace part.
|
||||
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
|
||||
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
|
||||
# Note: This option applies only to the class list, not to the
|
||||
# alphabetical list.
|
||||
|
||||
@@ -482,15 +462,14 @@ SHOW_USED_FILES = YES
|
||||
|
||||
SHOW_DIRECTORIES = NO
|
||||
|
||||
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
|
||||
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
|
||||
# This will remove the Files entry from the Quick Index and from the
|
||||
# Folder Tree View (if specified). The default is YES.
|
||||
|
||||
SHOW_FILES = YES
|
||||
|
||||
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
|
||||
# Namespaces page.
|
||||
# This will remove the Namespaces entry from the Quick Index
|
||||
# Namespaces page. This will remove the Namespaces entry from the Quick Index
|
||||
# and from the Folder Tree View (if specified). The default is YES.
|
||||
|
||||
SHOW_NAMESPACES = YES
|
||||
@@ -505,15 +484,6 @@ SHOW_NAMESPACES = YES
|
||||
|
||||
FILE_VERSION_FILTER =
|
||||
|
||||
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
|
||||
# doxygen. The layout file controls the global structure of the generated output files
|
||||
# in an output format independent way. The create the layout file that represents
|
||||
# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
|
||||
# file name after the option, if omitted DoxygenLayout.xml will be used as the name
|
||||
# of the layout file.
|
||||
|
||||
LAYOUT_FILE =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -575,7 +545,8 @@ WARN_LOGFILE = @CMAKE_CURRENT_BINARY_DIR@/doxy.log
|
||||
# with spaces.
|
||||
|
||||
INPUT = @CMAKE_SOURCE_DIR@/include \
|
||||
@CMAKE_SOURCE_DIR@/libssh
|
||||
@CMAKE_SOURCE_DIR@/libssh \
|
||||
@CMAKE_SOURCE_DIR@/doc
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
||||
@@ -642,18 +613,15 @@ EXCLUDE_SYMBOLS =
|
||||
# directories that contain example code fragments that are included (see
|
||||
# the \include command).
|
||||
|
||||
EXAMPLE_PATH = @CMAKE_SOURCE_DIR@/tests \
|
||||
@CMAKE_SOURCE_DIR@
|
||||
EXAMPLE_PATH = @CMAKE_SOURCE_DIR@/examples
|
||||
|
||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||
# and *.h) to filter out the source-files in the directories. If left
|
||||
# blank all files are included.
|
||||
|
||||
EXAMPLE_PATTERNS = *.cpp \
|
||||
*.cc \
|
||||
EXAMPLE_PATTERNS = *.c \
|
||||
*.h \
|
||||
*.hh \
|
||||
INSTALL \
|
||||
DEPENDENCIES \
|
||||
CHANGELOG \
|
||||
@@ -678,17 +646,14 @@ IMAGE_PATH =
|
||||
# by executing (via popen()) the command <filter> <input-file>, where <filter>
|
||||
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
|
||||
# input file. Doxygen will then use the output that the filter program writes
|
||||
# to standard output.
|
||||
# If FILTER_PATTERNS is specified, this tag will be
|
||||
# to standard output. If FILTER_PATTERNS is specified, this tag will be
|
||||
# ignored.
|
||||
|
||||
INPUT_FILTER =
|
||||
|
||||
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
|
||||
# basis.
|
||||
# Doxygen will compare the file name with each pattern and apply the
|
||||
# filter if there is a match.
|
||||
# The filters are a list of the form:
|
||||
# basis. Doxygen will compare the file name with each pattern and apply the
|
||||
# filter if there is a match. The filters are a list of the form:
|
||||
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
|
||||
# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
|
||||
# is applied to all files.
|
||||
@@ -735,11 +700,10 @@ REFERENCED_BY_RELATION = YES
|
||||
|
||||
REFERENCES_RELATION = YES
|
||||
|
||||
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
|
||||
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
|
||||
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
|
||||
# link to the source code.
|
||||
# Otherwise they will link to the documentation.
|
||||
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
|
||||
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
|
||||
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
|
||||
# link to the source code. Otherwise they will link to the documentstion.
|
||||
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
|
||||
@@ -828,13 +792,12 @@ HTML_STYLESHEET =
|
||||
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
|
||||
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
|
||||
# documentation will contain sections that can be hidden and shown after the
|
||||
# page has loaded. For this to work a browser that supports
|
||||
# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
|
||||
# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
|
||||
# will be generated that can be used as input for tools like the
|
||||
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
|
||||
# of the generated HTML documentation.
|
||||
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
GENERATE_HTMLHELP = NO
|
||||
|
||||
# If the GENERATE_DOCSET tag is set to YES, additional index files
|
||||
# will be generated that can be used as input for Apple's Xcode 3
|
||||
@@ -843,8 +806,7 @@ HTML_DYNAMIC_SECTIONS = NO
|
||||
# HTML output directory. Running make will produce the docset in that
|
||||
# directory and running "make install" will install the docset in
|
||||
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
|
||||
# it at startup.
|
||||
# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
|
||||
# it at startup.
|
||||
|
||||
GENERATE_DOCSET = NO
|
||||
|
||||
@@ -862,12 +824,13 @@ DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
|
||||
# will be generated that can be used as input for tools like the
|
||||
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
|
||||
# of the generated HTML documentation.
|
||||
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
|
||||
# documentation will contain sections that can be hidden and shown after the
|
||||
# page has loaded. For this to work a browser that supports
|
||||
# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
|
||||
# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
|
||||
|
||||
GENERATE_HTMLHELP = NO
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
|
||||
# be used to specify the file name of the resulting .chm file. You
|
||||
@@ -889,8 +852,8 @@ HHC_LOCATION =
|
||||
|
||||
GENERATE_CHI = NO
|
||||
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
|
||||
# is used to encode HtmlHelp index (hhk), content (hhc) and project file
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
|
||||
# is used to encode HtmlHelp index (hhk), content (hhc) and project file
|
||||
# content.
|
||||
|
||||
CHM_INDEX_ENCODING =
|
||||
@@ -906,55 +869,6 @@ BINARY_TOC = NO
|
||||
|
||||
TOC_EXPAND = NO
|
||||
|
||||
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
|
||||
# are set, an additional index file will be generated that can be used as input for
|
||||
# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
|
||||
# HTML documentation.
|
||||
|
||||
GENERATE_QHP = NO
|
||||
|
||||
# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
|
||||
# be used to specify the file name of the resulting .qch file.
|
||||
# The path specified is relative to the HTML output folder.
|
||||
|
||||
QCH_FILE =
|
||||
|
||||
# The QHP_NAMESPACE tag specifies the namespace to use when generating
|
||||
# Qt Help Project output. For more information please see
|
||||
# http://doc.trolltech.com/qthelpproject.html#namespace
|
||||
|
||||
QHP_NAMESPACE =
|
||||
|
||||
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
|
||||
# Qt Help Project output. For more information please see
|
||||
# http://doc.trolltech.com/qthelpproject.html#virtual-folders
|
||||
|
||||
QHP_VIRTUAL_FOLDER = doc
|
||||
|
||||
# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
|
||||
# For more information please see
|
||||
# http://doc.trolltech.com/qthelpproject.html#custom-filters
|
||||
|
||||
QHP_CUST_FILTER_NAME =
|
||||
|
||||
# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
|
||||
# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
|
||||
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
|
||||
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
|
||||
# filter section matches.
|
||||
# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
|
||||
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
|
||||
# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
|
||||
# be used to specify the location of Qt's qhelpgenerator.
|
||||
# If non-empty doxygen will try to run qhelpgenerator on the generated
|
||||
# .qhp file.
|
||||
|
||||
QHG_LOCATION =
|
||||
|
||||
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
|
||||
# top of each HTML page. The value NO (the default) enables the index and
|
||||
# the value YES disables it.
|
||||
@@ -966,19 +880,19 @@ DISABLE_INDEX = NO
|
||||
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
|
||||
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
|
||||
# structure should be generated to display hierarchical information.
|
||||
# If the tag value is set to FRAME, a side panel will be generated
|
||||
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
|
||||
# structure should be generated to display hierarchical information.
|
||||
# If the tag value is set to FRAME, a side panel will be generated
|
||||
# containing a tree-like index structure (just like the one that
|
||||
# is generated for HTML Help). For this to work a browser that supports
|
||||
# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
|
||||
# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
|
||||
# probably better off using the HTML help feature. Other possible values
|
||||
# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
|
||||
# and Class Hierarchy pages using a tree view instead of an ordered list;
|
||||
# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
|
||||
# disables this behavior completely. For backwards compatibility with previous
|
||||
# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
|
||||
# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
|
||||
# and Class Hiererachy pages using a tree view instead of an ordered list;
|
||||
# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
|
||||
# disables this behavior completely. For backwards compatibility with previous
|
||||
# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
|
||||
# respectively.
|
||||
|
||||
GENERATE_TREEVIEW = NO
|
||||
@@ -1209,10 +1123,8 @@ GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
|
||||
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
|
||||
# nicely formatted so it can be parsed by a human reader.
|
||||
# This is useful
|
||||
# if you want to understand what is going on.
|
||||
# On the other hand, if this
|
||||
# nicely formatted so it can be parsed by a human reader. This is useful
|
||||
# if you want to understand what is going on. On the other hand, if this
|
||||
# tag is set to NO the size of the Perl module output will be much smaller
|
||||
# and Perl will parse it just the same.
|
||||
|
||||
@@ -1299,16 +1211,14 @@ SKIP_FUNCTION_MACROS = YES
|
||||
# Optionally an initial location of the external documentation
|
||||
# can be added for each tagfile. The format of a tag file without
|
||||
# this location is as follows:
|
||||
#
|
||||
# TAGFILES = file1 file2 ...
|
||||
# TAGFILES = file1 file2 ...
|
||||
# Adding location for the tag files is done as follows:
|
||||
#
|
||||
# TAGFILES = file1=loc1 "file2 = loc2" ...
|
||||
# TAGFILES = file1=loc1 "file2 = loc2" ...
|
||||
# where "loc1" and "loc2" can be relative or absolute paths or
|
||||
# URLs. If a location is present for each tag, the installdox tool
|
||||
# does not have to be run to correct the links.
|
||||
# Note that each tag file must have a unique name
|
||||
# (where the name does NOT include the path)
|
||||
# does not have to be run to correct the links.
|
||||
# Note that each tag file must have a unique name
|
||||
# (where the name does NOT include the path)
|
||||
# If a tag file is not located in the directory in which doxygen
|
||||
# is run, you must also specify the path to the tagfile here.
|
||||
|
||||
@@ -1382,11 +1292,6 @@ HAVE_DOT = @DOXYGEN_DOT_FOUND@
|
||||
|
||||
DOT_FONTNAME = FreeSans
|
||||
|
||||
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
|
||||
# The default size is 10pt.
|
||||
|
||||
DOT_FONTSIZE = 10
|
||||
|
||||
# By default doxygen will tell dot to use the output directory to look for the
|
||||
# FreeSans.ttf font (which doxygen will put there itself). If you specify a
|
||||
# different font using DOT_FONTNAME you can set the path where dot
|
||||
@@ -1429,7 +1334,7 @@ TEMPLATE_RELATIONS = YES
|
||||
# file showing the direct and indirect include dependencies of the file with
|
||||
# other documented files.
|
||||
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDE_GRAPH = NO
|
||||
|
||||
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
|
||||
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
|
||||
@@ -1444,7 +1349,7 @@ INCLUDED_BY_GRAPH = YES
|
||||
# the time of a run. So in most cases it will be better to enable call graphs
|
||||
# for selected functions only using the \callgraph command.
|
||||
|
||||
CALL_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
|
||||
# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
|
||||
# doxygen will generate a caller dependency graph for every global function
|
||||
@@ -1452,7 +1357,7 @@ CALL_GRAPH = YES
|
||||
# the time of a run. So in most cases it will be better to enable caller
|
||||
# graphs for selected functions only using the \callergraph command.
|
||||
|
||||
CALLER_GRAPH = YES
|
||||
CALLER_GRAPH = NO
|
||||
|
||||
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
|
||||
# will graphical hierarchy of all classes instead of a textual one.
|
||||
@@ -1461,13 +1366,13 @@ GRAPHICAL_HIERARCHY = YES
|
||||
|
||||
# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
|
||||
# then doxygen will show the dependencies a directory has on other directories
|
||||
# in a graphical way. The dependency relations are determined by the #include
|
||||
# in a graphical way. The dependency relations are determined by the #include
|
||||
# relations between the files in the directories.
|
||||
|
||||
DIRECTORY_GRAPH = YES
|
||||
|
||||
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
||||
# generated by dot. Possible values are png, jpg, or gif
|
||||
# generated by dot. Possible values are png, jpg, or gif
|
||||
# If left blank png will be used.
|
||||
|
||||
DOT_IMAGE_FORMAT = png
|
||||
@@ -1504,10 +1409,10 @@ DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
|
||||
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
|
||||
# background. This is disabled by default, because dot on Windows does not
|
||||
# seem to support this out of the box. Warning: Depending on the platform used,
|
||||
# enabling this option may lead to badly anti-aliased labels on the edges of
|
||||
# a graph (i.e. they become hard to read).
|
||||
# background. This is enabled by default, which results in a transparent
|
||||
# background. Warning: Depending on the platform used, enabling this option
|
||||
# may lead to badly anti-aliased labels on the edges of a graph (i.e. they
|
||||
# become hard to read).
|
||||
|
||||
DOT_TRANSPARENT = NO
|
||||
|
||||
@@ -1531,7 +1436,7 @@ GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Options related to the search engine
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The SEARCHENGINE tag specifies whether or not a search engine should be
|
||||
|
||||
12
doc/mainpage.dox
Normal file
12
doc/mainpage.dox
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @mainpage
|
||||
* This manual documents the libssh C API.
|
||||
*
|
||||
* There are several other places to look for libssh information, such as the
|
||||
* <a href="http://dev.libssh.org/wiki/Tutorial" target="_blank">tutorial</a>
|
||||
* and the specification; those can be found at the <a
|
||||
* href="http://www.libssh.org/" target="_blank">libssh website</a>.
|
||||
*
|
||||
* To be continued...
|
||||
*/
|
||||
|
||||
38
examples/CMakeLists.txt
Normal file
38
examples/CMakeLists.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
project(libssh-examples C)
|
||||
|
||||
set(examples_SRCS
|
||||
authentication.c
|
||||
knownhosts.c
|
||||
connect_ssh.c
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${LIBSSH_PUBLIC_INCLUDE_DIRS}
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_executable(libssh_scp libssh_scp.c ${examples_SRCS})
|
||||
add_executable(scp_download scp_download.c ${examples_SRCS})
|
||||
add_executable(samplessh sample.c ${examples_SRCS})
|
||||
add_executable(exec exec.c ${examples_SRCS})
|
||||
|
||||
target_link_libraries(libssh_scp ${LIBSSH_SHARED_LIBRARY})
|
||||
target_link_libraries(scp_download ${LIBSSH_SHARED_LIBRARY})
|
||||
target_link_libraries(samplessh ${LIBSSH_SHARED_LIBRARY})
|
||||
target_link_libraries(exec ${LIBSSH_SHARED_LIBRARY})
|
||||
|
||||
include_directories(
|
||||
${LIBSSH_PUBLIC_INCLUDE_DIRS}
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
if (WITH_SFTP)
|
||||
add_executable(samplesftp samplesftp.c ${examples_SRCS})
|
||||
target_link_libraries(samplesftp ${LIBSSH_SHARED_LIBRARY})
|
||||
endif (WITH_SFTP)
|
||||
|
||||
if (WITH_SERVER)
|
||||
add_executable(samplesshd samplesshd.c)
|
||||
target_link_libraries(samplesshd ${LIBSSH_SHARED_LIBRARY})
|
||||
endif (WITH_SERVER)
|
||||
|
||||
125
examples/authentication.c
Normal file
125
examples/authentication.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* authentication.c
|
||||
* This file contains an example of how to do an authentication to a
|
||||
* SSH server using libssh
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2003-2009 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include "examples_common.h"
|
||||
|
||||
int authenticate_kbdint(ssh_session session){
|
||||
int err=ssh_userauth_kbdint(session,NULL,NULL);
|
||||
const char *name, *instruction, *prompt;
|
||||
char *ptr;
|
||||
char buffer[128];
|
||||
int i,n;
|
||||
char echo;
|
||||
while (err==SSH_AUTH_INFO){
|
||||
name=ssh_userauth_kbdint_getname(session);
|
||||
instruction=ssh_userauth_kbdint_getinstruction(session);
|
||||
n=ssh_userauth_kbdint_getnprompts(session);
|
||||
if(strlen(name)>0)
|
||||
printf("%s\n",name);
|
||||
if(strlen(instruction)>0)
|
||||
printf("%s\n",instruction);
|
||||
for(i=0;i<n;++i){
|
||||
prompt=ssh_userauth_kbdint_getprompt(session,i,&echo);
|
||||
if(echo){
|
||||
printf("%s",prompt);
|
||||
fgets(buffer,sizeof(buffer),stdin);
|
||||
buffer[sizeof(buffer)-1]=0;
|
||||
if((ptr=strchr(buffer,'\n')))
|
||||
*ptr=0;
|
||||
if (ssh_userauth_kbdint_setanswer(session,i,buffer) < 0) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
memset(buffer,0,strlen(buffer));
|
||||
} else {
|
||||
ptr=getpass(prompt);
|
||||
if (ssh_userauth_kbdint_setanswer(session,i,ptr) < 0) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
err=ssh_userauth_kbdint(session,NULL,NULL);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int authenticate_console(ssh_session session){
|
||||
int rc;
|
||||
int method;
|
||||
char *password;
|
||||
char *banner;
|
||||
|
||||
// Try to authenticate
|
||||
rc = ssh_userauth_none(session, NULL);
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
perror("Authentication failed.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
method = ssh_auth_list(session);
|
||||
while (rc != SSH_AUTH_SUCCESS) {
|
||||
|
||||
// Try to authenticate with public key first
|
||||
if (method & SSH_AUTH_METHOD_PUBLICKEY) {
|
||||
rc = ssh_userauth_autopubkey(session, NULL);
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
perror("Authentication failed.");
|
||||
return rc;
|
||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to authenticate with keyboard interactive";
|
||||
if (method & SSH_AUTH_METHOD_INTERACTIVE) {
|
||||
rc = authenticate_kbdint(session);
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
perror("Authentication failed.");
|
||||
return rc;
|
||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
password=getpass("Password: ");
|
||||
// Try to authenticate with password
|
||||
if (method & SSH_AUTH_METHOD_PASSWORD) {
|
||||
rc = ssh_userauth_password(session, NULL, password);
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
perror("Authentication failed.");
|
||||
return rc;
|
||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
banner = ssh_get_issue_banner(session);
|
||||
if (banner) {
|
||||
printf("%s\n",banner);
|
||||
free(banner);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
63
examples/connect_ssh.c
Normal file
63
examples/connect_ssh.c
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* connect_ssh.c
|
||||
* This file contains an example of how to connect to a
|
||||
* SSH server using libssh
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
*/
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include "examples_common.h"
|
||||
#include <stdio.h>
|
||||
|
||||
ssh_session connect_ssh(const char *host, const char *user,int verbosity){
|
||||
ssh_session session;
|
||||
int auth=0;
|
||||
|
||||
session=ssh_new();
|
||||
if (session == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(user != NULL){
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
|
||||
ssh_disconnect(session);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||
if(ssh_connect(session)){
|
||||
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
return NULL;
|
||||
}
|
||||
if(verify_knownhost(session)<0){
|
||||
ssh_disconnect(session);
|
||||
return NULL;
|
||||
}
|
||||
auth=authenticate_console(session);
|
||||
if(auth==SSH_AUTH_SUCCESS){
|
||||
return session;
|
||||
} else if(auth==SSH_AUTH_DENIED){
|
||||
fprintf(stderr,"Authentication failed\n");
|
||||
} else {
|
||||
fprintf(stderr,"Error while authenticating : %s\n",ssh_get_error(session));
|
||||
}
|
||||
ssh_disconnect(session);
|
||||
return NULL;
|
||||
}
|
||||
22
examples/examples_common.h
Normal file
22
examples/examples_common.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright 2009 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
*/
|
||||
#ifndef EXAMPLES_COMMON_H_
|
||||
#define EXAMPLES_COMMON_H_
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
int authenticate_console(ssh_session session);
|
||||
int authenticate_kbdint(ssh_session session);
|
||||
int verify_knownhost(ssh_session session);
|
||||
ssh_session connect_ssh(const char *hostname, const char *user, int verbosity);
|
||||
|
||||
#endif /* EXAMPLES_COMMON_H_ */
|
||||
67
examples/exec.c
Normal file
67
examples/exec.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/* simple exec example */
|
||||
#include <stdio.h>
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include "examples_common.h"
|
||||
|
||||
int main(void) {
|
||||
ssh_session session;
|
||||
ssh_channel channel;
|
||||
ssh_buffer buf;
|
||||
int rc;
|
||||
|
||||
session = connect_ssh("localhost", NULL, 0);
|
||||
if (session == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
channel = channel_new(session);;
|
||||
if (channel == NULL) {
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = channel_open_session(channel);
|
||||
if (rc < 0) {
|
||||
channel_close(channel);
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = channel_request_exec(channel, "ps aux");
|
||||
if (rc < 0) {
|
||||
channel_close(channel);
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if (channel_is_open(channel)) {
|
||||
while (channel_poll(channel, 0) >= 0) {
|
||||
buf = buffer_new();
|
||||
rc = channel_read_buffer(channel, buf, 0, 0);
|
||||
if (rc < 0) {
|
||||
buffer_free(buf);
|
||||
channel_close(channel);
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("%s\n", (char *) buffer_get(buf));
|
||||
|
||||
buffer_free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
channel_send_eof(channel);
|
||||
channel_close(channel);
|
||||
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
88
examples/knownhosts.c
Normal file
88
examples/knownhosts.c
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* knownhosts.c
|
||||
* This file contains an example of how verify the identity of a
|
||||
* SSH server using libssh
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2003-2009 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include "examples_common.h"
|
||||
|
||||
int verify_knownhost(ssh_session session){
|
||||
char *hexa;
|
||||
int state;
|
||||
char buf[10];
|
||||
unsigned char *hash = NULL;
|
||||
int hlen;
|
||||
|
||||
state=ssh_is_server_known(session);
|
||||
|
||||
hlen = ssh_get_pubkey_hash(session, &hash);
|
||||
if (hlen < 0) {
|
||||
return -1;
|
||||
}
|
||||
switch(state){
|
||||
case SSH_SERVER_KNOWN_OK:
|
||||
break; /* ok */
|
||||
case SSH_SERVER_KNOWN_CHANGED:
|
||||
fprintf(stderr,"Host key for server changed : server's one is now :\n");
|
||||
ssh_print_hexa("Public key hash",hash, hlen);
|
||||
free(hash);
|
||||
fprintf(stderr,"For security reason, connection will be stopped\n");
|
||||
return -1;
|
||||
case SSH_SERVER_FOUND_OTHER:
|
||||
fprintf(stderr,"The host key for this server was not found but an other type of key exists.\n");
|
||||
fprintf(stderr,"An attacker might change the default server key to confuse your client"
|
||||
"into thinking the key does not exist\n"
|
||||
"We advise you to rerun the client with -d or -r for more safety.\n");
|
||||
return -1;
|
||||
case SSH_SERVER_FILE_NOT_FOUND:
|
||||
fprintf(stderr,"Could not find known host file. If you accept the host key here,\n");
|
||||
fprintf(stderr,"the file will be automatically created.\n");
|
||||
/* fallback to SSH_SERVER_NOT_KNOWN behavior */
|
||||
case SSH_SERVER_NOT_KNOWN:
|
||||
hexa = ssh_get_hexa(hash, hlen);
|
||||
fprintf(stderr,"The server is unknown. Do you trust the host key ?\n");
|
||||
fprintf(stderr, "Public key hash: %s\n", hexa);
|
||||
free(hexa);
|
||||
fgets(buf,sizeof(buf),stdin);
|
||||
if(strncasecmp(buf,"yes",3)!=0){
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr,"This new key will be written on disk for further usage. do you agree ?\n");
|
||||
fgets(buf,sizeof(buf),stdin);
|
||||
if(strncasecmp(buf,"yes",3)==0){
|
||||
if (ssh_write_knownhost(session) < 0) {
|
||||
free(hash);
|
||||
fprintf(stderr, "error %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case SSH_SERVER_ERROR:
|
||||
free(hash);
|
||||
fprintf(stderr,"%s",ssh_get_error(session));
|
||||
return -1;
|
||||
}
|
||||
free(hash);
|
||||
return 0;
|
||||
}
|
||||
304
examples/libssh_scp.c
Normal file
304
examples/libssh_scp.c
Normal file
@@ -0,0 +1,304 @@
|
||||
/* libssh_scp.c
|
||||
* Sample implementation of a SCP client
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include "examples_common.h"
|
||||
|
||||
char **sources;
|
||||
int nsources;
|
||||
char *destination;
|
||||
int verbosity=0;
|
||||
|
||||
struct location {
|
||||
int is_ssh;
|
||||
char *user;
|
||||
char *host;
|
||||
char *path;
|
||||
ssh_session session;
|
||||
ssh_scp scp;
|
||||
FILE *file;
|
||||
};
|
||||
|
||||
enum {
|
||||
READ,
|
||||
WRITE
|
||||
};
|
||||
|
||||
static void usage(const char *argv0){
|
||||
fprintf(stderr,"Usage : %s [options] [[user@]host1:]file1 ... \n"
|
||||
" [[user@]host2:]destination\n"
|
||||
"sample scp client - libssh-%s\n",
|
||||
// "Options :\n",
|
||||
// " -r : use RSA to verify host public key\n",
|
||||
argv0,
|
||||
ssh_version(0));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int opts(int argc, char **argv){
|
||||
int i;
|
||||
while((i=getopt(argc,argv,"v"))!=-1){
|
||||
switch(i){
|
||||
case 'v':
|
||||
verbosity++;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"unknown option %c\n",optopt);
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
nsources=argc-optind-1;
|
||||
if(nsources < 1){
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
sources=malloc((nsources + 1) * sizeof(char *));
|
||||
if(sources == NULL)
|
||||
return -1;
|
||||
for(i=0;i<nsources;++i){
|
||||
sources[i] = argv[optind];
|
||||
optind++;
|
||||
}
|
||||
sources[i]=NULL;
|
||||
destination=argv[optind];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct location *parse_location(char *loc){
|
||||
struct location *location=malloc(sizeof(struct location));
|
||||
char *ptr;
|
||||
|
||||
location->host=location->user=NULL;
|
||||
ptr=strchr(loc,':');
|
||||
if(ptr != NULL){
|
||||
location->is_ssh=1;
|
||||
location->path=strdup(ptr+1);
|
||||
*ptr='\0';
|
||||
ptr=strchr(loc,'@');
|
||||
if(ptr != NULL){
|
||||
location->host=strdup(ptr+1);
|
||||
*ptr='\0';
|
||||
location->user=strdup(loc);
|
||||
} else {
|
||||
location->host=strdup(loc);
|
||||
}
|
||||
} else {
|
||||
location->is_ssh=0;
|
||||
location->path=strdup(loc);
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
static int open_location(struct location *loc, int flag){
|
||||
if(loc->is_ssh && flag==WRITE){
|
||||
loc->session=connect_ssh(loc->host,loc->user,verbosity);
|
||||
if(!loc->session){
|
||||
fprintf(stderr,"Couldn't connect to %s\n",loc->host);
|
||||
return -1;
|
||||
}
|
||||
loc->scp=ssh_scp_new(loc->session,SSH_SCP_WRITE,loc->path);
|
||||
if(!loc->scp){
|
||||
fprintf(stderr,"error : %s\n",ssh_get_error(loc->session));
|
||||
return -1;
|
||||
}
|
||||
if(ssh_scp_init(loc->scp)==SSH_ERROR){
|
||||
fprintf(stderr,"error : %s\n",ssh_get_error(loc->session));
|
||||
ssh_scp_free(loc->scp);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
} else if(loc->is_ssh && flag==READ){
|
||||
loc->session=connect_ssh(loc->host, loc->user,verbosity);
|
||||
if(!loc->session){
|
||||
fprintf(stderr,"Couldn't connect to %s\n",loc->host);
|
||||
return -1;
|
||||
}
|
||||
loc->scp=ssh_scp_new(loc->session,SSH_SCP_READ,loc->path);
|
||||
if(!loc->scp){
|
||||
fprintf(stderr,"error : %s\n",ssh_get_error(loc->session));
|
||||
return -1;
|
||||
}
|
||||
if(ssh_scp_init(loc->scp)==SSH_ERROR){
|
||||
fprintf(stderr,"error : %s\n",ssh_get_error(loc->session));
|
||||
ssh_scp_free(loc->scp);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
loc->file=fopen(loc->path,flag==READ ? "r":"w");
|
||||
if(!loc->file){
|
||||
if(errno==EISDIR){
|
||||
if(chdir(loc->path)){
|
||||
fprintf(stderr,"Error changing directory to %s: %s\n",loc->path,strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr,"Error opening %s: %s\n",loc->path,strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** @brief copies files from source location to destination
|
||||
* @param src source location
|
||||
* @param dest destination location
|
||||
* @param recursive Copy also directories
|
||||
*/
|
||||
static int do_copy(struct location *src, struct location *dest, int recursive){
|
||||
int size;
|
||||
socket_t fd;
|
||||
struct stat s;
|
||||
int w,r;
|
||||
char buffer[16384];
|
||||
int total=0;
|
||||
int mode;
|
||||
char *filename;
|
||||
/* recursive mode doesn't work yet */
|
||||
(void)recursive;
|
||||
/* Get the file name and size*/
|
||||
if(!src->is_ssh){
|
||||
fd=fileno(src->file);
|
||||
fstat(fd,&s);
|
||||
size=s.st_size;
|
||||
mode=s.st_mode;
|
||||
filename=ssh_basename(src->path);
|
||||
} else {
|
||||
size=0;
|
||||
do {
|
||||
r=ssh_scp_pull_request(src->scp);
|
||||
if(r==SSH_SCP_REQUEST_NEWDIR){
|
||||
ssh_scp_deny_request(src->scp,"Not in recursive mode");
|
||||
continue;
|
||||
}
|
||||
if(r==SSH_SCP_REQUEST_NEWFILE){
|
||||
size=ssh_scp_request_get_size(src->scp);
|
||||
filename=strdup(ssh_scp_request_get_filename(src->scp));
|
||||
mode=ssh_scp_request_get_permissions(src->scp);
|
||||
//ssh_scp_accept_request(src->scp);
|
||||
break;
|
||||
}
|
||||
if(r==SSH_ERROR){
|
||||
fprintf(stderr,"Error: %s\n",ssh_get_error(src->session));
|
||||
return -1;
|
||||
}
|
||||
} while(r != SSH_SCP_REQUEST_NEWFILE);
|
||||
}
|
||||
|
||||
if(dest->is_ssh){
|
||||
r=ssh_scp_push_file(dest->scp,src->path,size,0644);
|
||||
// snprintf(buffer,sizeof(buffer),"C0644 %d %s\n",size,src->path);
|
||||
if(r==SSH_ERROR){
|
||||
fprintf(stderr,"error: %s\n",ssh_get_error(dest->session));
|
||||
ssh_scp_free(dest->scp);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if(!dest->file){
|
||||
dest->file=fopen(filename,"w");
|
||||
if(!dest->file){
|
||||
fprintf(stderr,"Cannot open %s for writing: %s\n",filename,strerror(errno));
|
||||
if(src->is_ssh)
|
||||
ssh_scp_deny_request(src->scp,"Cannot open local file");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(src->is_ssh){
|
||||
ssh_scp_accept_request(src->scp);
|
||||
}
|
||||
}
|
||||
do {
|
||||
if(src->is_ssh){
|
||||
r=ssh_scp_read(src->scp,buffer,sizeof(buffer));
|
||||
if(r==SSH_ERROR){
|
||||
fprintf(stderr,"Error reading scp: %s\n",ssh_get_error(src->session));
|
||||
return -1;
|
||||
}
|
||||
if(r==0)
|
||||
break;
|
||||
} else {
|
||||
r=fread(buffer,1,sizeof(buffer),src->file);
|
||||
if(r==0)
|
||||
break;
|
||||
if(r<0){
|
||||
fprintf(stderr,"Error reading file: %s\n",strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(dest->is_ssh){
|
||||
w=ssh_scp_write(dest->scp,buffer,r);
|
||||
if(w == SSH_ERROR){
|
||||
fprintf(stderr,"Error writing in scp: %s\n",ssh_get_error(dest->session));
|
||||
ssh_scp_free(dest->scp);
|
||||
dest->scp=NULL;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
w=fwrite(buffer,r,1,dest->file);
|
||||
if(w<=0){
|
||||
fprintf(stderr,"Error writing in local file: %s\n",strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
total+=r;
|
||||
|
||||
} while(total < size);
|
||||
printf("wrote %d bytes\n",total);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
struct location *dest, *src;
|
||||
int i;
|
||||
int r;
|
||||
if(opts(argc,argv)<0)
|
||||
return EXIT_FAILURE;
|
||||
dest=parse_location(destination);
|
||||
if(open_location(dest,WRITE)<0)
|
||||
return EXIT_FAILURE;
|
||||
for(i=0;i<nsources;++i){
|
||||
src=parse_location(sources[i]);
|
||||
if(open_location(src,READ)<0){
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if(do_copy(src,dest,0) < 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(dest->is_ssh){
|
||||
r=ssh_scp_close(dest->scp);
|
||||
if(r == SSH_ERROR){
|
||||
fprintf(stderr,"Error closing scp: %s\n",ssh_get_error(dest->session));
|
||||
ssh_scp_free(dest->scp);
|
||||
dest->scp=NULL;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
fclose(dest->file);
|
||||
dest->file=NULL;
|
||||
}
|
||||
ssh_disconnect(dest->session);
|
||||
ssh_finalize();
|
||||
return 0;
|
||||
}
|
||||
515
examples/sample.c
Normal file
515
examples/sample.c
Normal file
@@ -0,0 +1,515 @@
|
||||
/* client.c */
|
||||
/*
|
||||
Copyright 2003-2009 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef HAVE_PTY_H
|
||||
#include <pty.h>
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <libssh/callbacks.h>
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/sftp.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "examples_common.h"
|
||||
#define MAXCMD 10
|
||||
char *host;
|
||||
char *user;
|
||||
char *cmds[MAXCMD];
|
||||
struct termios terminal;
|
||||
|
||||
#ifdef WITH_PCAP
|
||||
/* this header file won't be necessary in the future */
|
||||
#include <libssh/pcap.h>
|
||||
char *pcap_file=NULL;
|
||||
#endif
|
||||
|
||||
static int auth_callback(const char *prompt, char *buf, size_t len,
|
||||
int echo, int verify, void *userdata) {
|
||||
char *answer = NULL;
|
||||
char *ptr;
|
||||
|
||||
(void) verify;
|
||||
(void) userdata;
|
||||
|
||||
if (echo) {
|
||||
while ((answer = fgets(buf, len, stdin)) == NULL);
|
||||
if ((ptr = strchr(buf, '\n'))) {
|
||||
ptr = '\0';
|
||||
}
|
||||
} else {
|
||||
answer = getpass(prompt);
|
||||
}
|
||||
|
||||
if (answer == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(buf, answer, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ssh_callbacks_struct cb = {
|
||||
.auth_function=auth_callback,
|
||||
.userdata=NULL
|
||||
};
|
||||
|
||||
static void add_cmd(char *cmd){
|
||||
int n;
|
||||
for(n=0;cmds[n] && (n<MAXCMD);n++);
|
||||
if(n==MAXCMD)
|
||||
return;
|
||||
cmds[n]=strdup(cmd);
|
||||
}
|
||||
|
||||
static void usage(){
|
||||
fprintf(stderr,"Usage : ssh [options] [login@]hostname\n"
|
||||
"sample client - libssh-%s\n"
|
||||
"Options :\n"
|
||||
" -l user : log in as user\n"
|
||||
" -p port : connect to port\n"
|
||||
" -d : use DSS to verify host public key\n"
|
||||
" -r : use RSA to verify host public key\n"
|
||||
#ifdef WITH_PCAP
|
||||
" -P file : create a pcap debugging file\n"
|
||||
#endif
|
||||
,
|
||||
ssh_version(0));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int opts(int argc, char **argv){
|
||||
int i;
|
||||
// for(i=0;i<argc;i++)
|
||||
// printf("%d : %s\n",i,argv[i]);
|
||||
/* insert your own arguments here */
|
||||
while((i=getopt(argc,argv,"P:"))!=-1){
|
||||
switch(i){
|
||||
#ifdef WITH_PCAP
|
||||
case 'P':
|
||||
pcap_file=optarg;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
fprintf(stderr,"unknown option %c\n",optopt);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
if(optind < argc)
|
||||
host=argv[optind++];
|
||||
while(optind < argc)
|
||||
add_cmd(argv[optind++]);
|
||||
if(host==NULL)
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_CFMAKERAW
|
||||
static void cfmakeraw(struct termios *termios_p){
|
||||
termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
|
||||
termios_p->c_oflag &= ~OPOST;
|
||||
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
||||
termios_p->c_cflag &= ~(CSIZE|PARENB);
|
||||
termios_p->c_cflag |= CS8;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void do_cleanup(int i) {
|
||||
/* unused variable */
|
||||
(void) i;
|
||||
|
||||
tcsetattr(0,TCSANOW,&terminal);
|
||||
}
|
||||
|
||||
static void do_exit(int i) {
|
||||
/* unused variable */
|
||||
(void) i;
|
||||
|
||||
do_cleanup(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ssh_channel chan;
|
||||
int signal_delayed=0;
|
||||
|
||||
static void sigwindowchanged(int i){
|
||||
(void) i;
|
||||
signal_delayed=1;
|
||||
}
|
||||
|
||||
static void setsignal(void){
|
||||
signal(SIGWINCH, sigwindowchanged);
|
||||
signal_delayed=0;
|
||||
}
|
||||
|
||||
static void sizechanged(void){
|
||||
struct winsize win = { 0, 0, 0, 0 };
|
||||
ioctl(1, TIOCGWINSZ, &win);
|
||||
channel_change_pty_size(chan,win.ws_col, win.ws_row);
|
||||
// printf("Changed pty size\n");
|
||||
setsignal();
|
||||
}
|
||||
|
||||
/* There are two flavors of select loop: the one based on
|
||||
* ssh_select and the one based on channel_select.
|
||||
* The ssh_select one permits you to give your own file descriptors to
|
||||
* follow. It is thus a complete select loop.
|
||||
* The second one only selects on channels. It is simplier to use
|
||||
* but doesn't permit you to fill in your own file descriptor. It is
|
||||
* more adapted if you can't use ssh_select as a main loop (because
|
||||
* you already have another main loop system).
|
||||
*/
|
||||
|
||||
#ifdef USE_CHANNEL_SELECT
|
||||
|
||||
/* channel_select base main loop, with a standard select(2)
|
||||
*/
|
||||
static void select_loop(ssh_session session,ssh_channel channel){
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
char buffer[4096];
|
||||
ssh_buffer readbuf=buffer_new();
|
||||
ssh_channel channels[2];
|
||||
int lus;
|
||||
int eof=0;
|
||||
int maxfd;
|
||||
int ret;
|
||||
while(channel){
|
||||
/* when a signal is caught, ssh_select will return
|
||||
* with SSH_EINTR, which means it should be started
|
||||
* again. It lets you handle the signal the faster you
|
||||
* can, like in this window changed example. Of course, if
|
||||
* your signal handler doesn't call libssh at all, you're
|
||||
* free to handle signals directly in sighandler.
|
||||
*/
|
||||
do{
|
||||
FD_ZERO(&fds);
|
||||
if(!eof)
|
||||
FD_SET(0,&fds);
|
||||
timeout.tv_sec=30;
|
||||
timeout.tv_usec=0;
|
||||
FD_SET(ssh_get_fd(session),&fds);
|
||||
maxfd=ssh_get_fd(session)+1;
|
||||
ret=select(maxfd,&fds,NULL,NULL,&timeout);
|
||||
if(ret==EINTR)
|
||||
continue;
|
||||
if(FD_ISSET(0,&fds)){
|
||||
lus=read(0,buffer,sizeof(buffer));
|
||||
if(lus)
|
||||
channel_write(channel,buffer,lus);
|
||||
else {
|
||||
eof=1;
|
||||
channel_send_eof(channel);
|
||||
}
|
||||
}
|
||||
if(FD_ISSET(ssh_get_fd(session),&fds)){
|
||||
ssh_set_fd_toread(session);
|
||||
}
|
||||
channels[0]=channel; // set the first channel we want to read from
|
||||
channels[1]=NULL;
|
||||
ret=channel_select(channels,NULL,NULL,NULL); // no specific timeout - just poll
|
||||
if(signal_delayed)
|
||||
sizechanged();
|
||||
} while (ret==EINTR || ret==SSH_EINTR);
|
||||
|
||||
// we already looked for input from stdin. Now, we are looking for input from the channel
|
||||
|
||||
if(channel && channel_is_closed(channel)){
|
||||
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
|
||||
|
||||
channel_free(channel);
|
||||
channel=NULL;
|
||||
channels[0]=NULL;
|
||||
}
|
||||
if(channels[0]){
|
||||
while(channel && channel_is_open(channel) && channel_poll(channel,0)){
|
||||
lus=channel_read_buffer(channel,readbuf,0,0);
|
||||
if(lus==-1){
|
||||
fprintf(stderr, "Error reading channel: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(lus==0){
|
||||
ssh_log(session,SSH_LOG_RARE,"EOF received\n");
|
||||
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
|
||||
|
||||
channel_free(channel);
|
||||
channel=channels[0]=NULL;
|
||||
} else
|
||||
write(1,buffer_get(readbuf),lus);
|
||||
}
|
||||
while(channel && channel_is_open(channel) && channel_poll(channel,1)){ /* stderr */
|
||||
lus=channel_read_buffer(channel,readbuf,0,1);
|
||||
if(lus==-1){
|
||||
fprintf(stderr, "Error reading channel: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(lus==0){
|
||||
ssh_log(session,SSH_LOG_RARE,"EOF received\n");
|
||||
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
|
||||
channel_free(channel);
|
||||
channel=channels[0]=NULL;
|
||||
} else
|
||||
write(2,buffer_get(readbuf),lus);
|
||||
}
|
||||
}
|
||||
if(channel && channel_is_closed(channel)){
|
||||
channel_free(channel);
|
||||
channel=NULL;
|
||||
}
|
||||
}
|
||||
buffer_free(readbuf);
|
||||
}
|
||||
#else /* CHANNEL_SELECT */
|
||||
|
||||
static void select_loop(ssh_session session,ssh_channel channel){
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
char buffer[4096];
|
||||
/* channels will be set to the channels to poll.
|
||||
* outchannels will contain the result of the poll
|
||||
*/
|
||||
ssh_channel channels[2], outchannels[2];
|
||||
int lus;
|
||||
int eof=0;
|
||||
int maxfd;
|
||||
int ret;
|
||||
while(channel){
|
||||
do{
|
||||
FD_ZERO(&fds);
|
||||
if(!eof)
|
||||
FD_SET(0,&fds);
|
||||
timeout.tv_sec=30;
|
||||
timeout.tv_usec=0;
|
||||
FD_SET(ssh_get_fd(session),&fds);
|
||||
maxfd=ssh_get_fd(session)+1;
|
||||
channels[0]=channel; // set the first channel we want to read from
|
||||
channels[1]=NULL;
|
||||
ret=ssh_select(channels,outchannels,maxfd,&fds,&timeout);
|
||||
if(signal_delayed)
|
||||
sizechanged();
|
||||
if(ret==EINTR)
|
||||
continue;
|
||||
if(FD_ISSET(0,&fds)){
|
||||
lus=read(0,buffer,sizeof(buffer));
|
||||
if(lus)
|
||||
channel_write(channel,buffer,lus);
|
||||
else {
|
||||
eof=1;
|
||||
channel_send_eof(channel);
|
||||
}
|
||||
}
|
||||
if(channel && channel_is_closed(channel)){
|
||||
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
|
||||
|
||||
channel_free(channel);
|
||||
channel=NULL;
|
||||
channels[0]=NULL;
|
||||
}
|
||||
if(outchannels[0]){
|
||||
while(channel && channel_is_open(channel) && channel_poll(channel,0)){
|
||||
lus=channel_read(channel,buffer,sizeof(buffer),0);
|
||||
if(lus==-1){
|
||||
fprintf(stderr, "Error reading channel: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(lus==0){
|
||||
ssh_log(session,SSH_LOG_RARE,"EOF received\n");
|
||||
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
|
||||
|
||||
channel_free(channel);
|
||||
channel=channels[0]=NULL;
|
||||
} else
|
||||
write(1,buffer,lus);
|
||||
}
|
||||
while(channel && channel_is_open(channel) && channel_poll(channel,1)){ /* stderr */
|
||||
lus=channel_read(channel,buffer,sizeof(buffer),1);
|
||||
if(lus==-1){
|
||||
fprintf(stderr, "Error reading channel: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(lus==0){
|
||||
ssh_log(session,SSH_LOG_RARE,"EOF received\n");
|
||||
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
|
||||
channel_free(channel);
|
||||
channel=channels[0]=NULL;
|
||||
} else
|
||||
write(2,buffer,lus);
|
||||
}
|
||||
}
|
||||
if(channel && channel_is_closed(channel)){
|
||||
channel_free(channel);
|
||||
channel=NULL;
|
||||
}
|
||||
} while (ret==EINTR || ret==SSH_EINTR);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void shell(ssh_session session){
|
||||
ssh_channel channel;
|
||||
struct termios terminal_local;
|
||||
int interactive=isatty(0);
|
||||
channel = channel_new(session);
|
||||
if(interactive){
|
||||
tcgetattr(0,&terminal_local);
|
||||
memcpy(&terminal,&terminal_local,sizeof(struct termios));
|
||||
}
|
||||
if(channel_open_session(channel)){
|
||||
printf("error opening channel : %s\n",ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
chan=channel;
|
||||
if(interactive){
|
||||
channel_request_pty(channel);
|
||||
sizechanged();
|
||||
}
|
||||
if(channel_request_shell(channel)){
|
||||
printf("Requesting shell : %s\n",ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(interactive){
|
||||
cfmakeraw(&terminal_local);
|
||||
tcsetattr(0,TCSANOW,&terminal_local);
|
||||
setsignal();
|
||||
}
|
||||
signal(SIGTERM,do_cleanup);
|
||||
select_loop(session,channel);
|
||||
if(interactive)
|
||||
do_cleanup(0);
|
||||
}
|
||||
|
||||
static void batch_shell(ssh_session session){
|
||||
ssh_channel channel;
|
||||
char buffer[1024];
|
||||
int i,s=0;
|
||||
for(i=0;i<MAXCMD && cmds[i];++i)
|
||||
s+=snprintf(buffer+s,sizeof(buffer)-s,"%s ",cmds[i]);
|
||||
channel=channel_new(session);
|
||||
channel_open_session(channel);
|
||||
if(channel_request_exec(channel,buffer)){
|
||||
printf("error executing \"%s\" : %s\n",buffer,ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
select_loop(session,channel);
|
||||
}
|
||||
|
||||
static int client(ssh_session session){
|
||||
int auth=0;
|
||||
char *banner;
|
||||
int state;
|
||||
if (user)
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0)
|
||||
return -1;
|
||||
if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0)
|
||||
return -1;
|
||||
|
||||
ssh_options_parse_config(session, NULL);
|
||||
|
||||
if(ssh_connect(session)){
|
||||
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
|
||||
return -1;
|
||||
}
|
||||
state=verify_knownhost(session);
|
||||
if (state != 0)
|
||||
return -1;
|
||||
ssh_userauth_none(session, NULL);
|
||||
banner=ssh_get_issue_banner(session);
|
||||
if(banner){
|
||||
printf("%s\n",banner);
|
||||
free(banner);
|
||||
}
|
||||
auth=authenticate_console(session);
|
||||
if(auth != SSH_AUTH_SUCCESS){
|
||||
return -1;
|
||||
}
|
||||
ssh_log(session, SSH_LOG_FUNCTIONS, "Authentication success");
|
||||
if(!cmds[0])
|
||||
shell(session);
|
||||
else
|
||||
batch_shell(session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WITH_PCAP
|
||||
ssh_pcap_file pcap;
|
||||
void set_pcap(ssh_session session);
|
||||
void set_pcap(ssh_session session){
|
||||
if(!pcap_file)
|
||||
return;
|
||||
pcap=ssh_pcap_file_new();
|
||||
if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){
|
||||
printf("Error opening pcap file\n");
|
||||
ssh_pcap_file_free(pcap);
|
||||
pcap=NULL;
|
||||
return;
|
||||
}
|
||||
ssh_set_pcap_file(session,pcap);
|
||||
}
|
||||
|
||||
void cleanup_pcap(void);
|
||||
void cleanup_pcap(){
|
||||
ssh_pcap_file_free(pcap);
|
||||
pcap=NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv){
|
||||
ssh_session session;
|
||||
|
||||
session = ssh_new();
|
||||
|
||||
ssh_callbacks_init(&cb);
|
||||
ssh_set_callbacks(session,&cb);
|
||||
|
||||
if(ssh_options_getopt(session, &argc, argv)) {
|
||||
fprintf(stderr, "error parsing command line :%s\n",
|
||||
ssh_get_error(session));
|
||||
usage();
|
||||
}
|
||||
opts(argc,argv);
|
||||
signal(SIGTERM, do_exit);
|
||||
#ifdef WITH_PCAP
|
||||
set_pcap(session);
|
||||
#endif
|
||||
client(session);
|
||||
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
#ifdef WITH_PCAP
|
||||
cleanup_pcap();
|
||||
#endif
|
||||
|
||||
ssh_finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
263
examples/samplesftp.c
Normal file
263
examples/samplesftp.c
Normal file
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
Copyright 2003-2009 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/statvfs.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/sftp.h>
|
||||
|
||||
#include "examples_common.h"
|
||||
#ifdef WITH_SFTP
|
||||
|
||||
int verbosity;
|
||||
char *destination;
|
||||
|
||||
static void do_sftp(ssh_session session){
|
||||
sftp_session sftp=sftp_new(session);
|
||||
sftp_dir dir;
|
||||
sftp_attributes file;
|
||||
sftp_statvfs_t sftpstatvfs;
|
||||
struct statvfs sysstatvfs;
|
||||
sftp_file fichier;
|
||||
sftp_file to;
|
||||
int len=1;
|
||||
unsigned int i;
|
||||
char data[8000]={0};
|
||||
char *lnk;
|
||||
|
||||
unsigned int count;
|
||||
|
||||
if(!sftp){
|
||||
fprintf(stderr, "sftp error initialising channel: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(sftp_init(sftp)){
|
||||
fprintf(stderr, "error initialising sftp: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Additional SFTP extensions provided by the server:\n");
|
||||
count = sftp_extensions_get_count(sftp);
|
||||
for (i = 0; i < count; i++) {
|
||||
printf("\t%s, version: %s\n",
|
||||
sftp_extensions_get_name(sftp, i),
|
||||
sftp_extensions_get_data(sftp, i));
|
||||
}
|
||||
|
||||
/* test symlink and readlink */
|
||||
if (sftp_symlink(sftp, "/tmp/this_is_the_link",
|
||||
"/tmp/sftp_symlink_test") < 0) {
|
||||
fprintf(stderr, "Could not create link (%s)\n", ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
|
||||
lnk = sftp_readlink(sftp, "/tmp/sftp_symlink_test");
|
||||
if (lnk == NULL) {
|
||||
fprintf(stderr, "Could not read link (%s)\n", ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
printf("readlink /tmp/sftp_symlink_test: %s\n", lnk);
|
||||
|
||||
sftp_unlink(sftp, "/tmp/sftp_symlink_test");
|
||||
|
||||
if (sftp_extension_supported(sftp, "statvfs@openssh.com", "2")) {
|
||||
sftpstatvfs = sftp_statvfs(sftp, "/tmp");
|
||||
if (sftpstatvfs == NULL) {
|
||||
fprintf(stderr, "statvfs failed (%s)\n", ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
|
||||
printf("sftp statvfs:\n"
|
||||
"\tfile system block size: %llu\n"
|
||||
"\tfundamental fs block size: %llu\n"
|
||||
"\tnumber of blocks (unit f_frsize): %llu\n"
|
||||
"\tfree blocks in file system: %llu\n"
|
||||
"\tfree blocks for non-root: %llu\n"
|
||||
"\ttotal file inodes: %llu\n"
|
||||
"\tfree file inodes: %llu\n"
|
||||
"\tfree file inodes for to non-root: %llu\n"
|
||||
"\tfile system id: %llu\n"
|
||||
"\tbit mask of f_flag values: %llu\n"
|
||||
"\tmaximum filename length: %llu\n",
|
||||
(unsigned long long) sftpstatvfs->f_bsize,
|
||||
(unsigned long long) sftpstatvfs->f_frsize,
|
||||
(unsigned long long) sftpstatvfs->f_blocks,
|
||||
(unsigned long long) sftpstatvfs->f_bfree,
|
||||
(unsigned long long) sftpstatvfs->f_bavail,
|
||||
(unsigned long long) sftpstatvfs->f_files,
|
||||
(unsigned long long) sftpstatvfs->f_ffree,
|
||||
(unsigned long long) sftpstatvfs->f_favail,
|
||||
(unsigned long long) sftpstatvfs->f_fsid,
|
||||
(unsigned long long) sftpstatvfs->f_flag,
|
||||
(unsigned long long) sftpstatvfs->f_namemax);
|
||||
|
||||
sftp_statvfs_free(sftpstatvfs);
|
||||
|
||||
if (statvfs("/tmp", &sysstatvfs) < 0) {
|
||||
fprintf(stderr, "statvfs failed (%s)\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
printf("sys statvfs:\n"
|
||||
"\tfile system block size: %llu\n"
|
||||
"\tfundamental fs block size: %llu\n"
|
||||
"\tnumber of blocks (unit f_frsize): %llu\n"
|
||||
"\tfree blocks in file system: %llu\n"
|
||||
"\tfree blocks for non-root: %llu\n"
|
||||
"\ttotal file inodes: %llu\n"
|
||||
"\tfree file inodes: %llu\n"
|
||||
"\tfree file inodes for to non-root: %llu\n"
|
||||
"\tfile system id: %llu\n"
|
||||
"\tbit mask of f_flag values: %llu\n"
|
||||
"\tmaximum filename length: %llu\n",
|
||||
(unsigned long long) sysstatvfs.f_bsize,
|
||||
(unsigned long long) sysstatvfs.f_frsize,
|
||||
(unsigned long long) sysstatvfs.f_blocks,
|
||||
(unsigned long long) sysstatvfs.f_bfree,
|
||||
(unsigned long long) sysstatvfs.f_bavail,
|
||||
(unsigned long long) sysstatvfs.f_files,
|
||||
(unsigned long long) sysstatvfs.f_ffree,
|
||||
(unsigned long long) sysstatvfs.f_favail,
|
||||
(unsigned long long) sysstatvfs.f_fsid,
|
||||
(unsigned long long) sysstatvfs.f_flag,
|
||||
(unsigned long long) sysstatvfs.f_namemax);
|
||||
}
|
||||
|
||||
/* the connection is made */
|
||||
/* opening a directory */
|
||||
dir=sftp_opendir(sftp,"./");
|
||||
if(!dir) {
|
||||
fprintf(stderr, "Directory not opened(%s)\n", ssh_get_error(session));
|
||||
return ;
|
||||
}
|
||||
/* reading the whole directory, file by file */
|
||||
while((file=sftp_readdir(sftp,dir))){
|
||||
fprintf(stderr, "%30s(%.8o) : %.5d.%.5d : %.10llu bytes\n",
|
||||
file->name,
|
||||
file->permissions,
|
||||
file->uid,
|
||||
file->gid,
|
||||
(long long unsigned int) file->size);
|
||||
sftp_attributes_free(file);
|
||||
}
|
||||
/* when file=NULL, an error has occured OR the directory listing is end of file */
|
||||
if(!sftp_dir_eof(dir)){
|
||||
fprintf(stderr, "Error: %s\n", ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(sftp_closedir(dir)){
|
||||
fprintf(stderr, "Error: %s\n", ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
/* this will open a file and copy it into your /home directory */
|
||||
/* the small buffer size was intended to stress the library. of course, you can use a buffer till 20kbytes without problem */
|
||||
|
||||
fichier=sftp_open(sftp,"/usr/bin/ssh",O_RDONLY, 0);
|
||||
if(!fichier){
|
||||
fprintf(stderr, "Error opening /usr/bin/ssh: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
/* open a file for writing... */
|
||||
to=sftp_open(sftp,"ssh-copy",O_WRONLY | O_CREAT, 0700);
|
||||
if(!to){
|
||||
fprintf(stderr, "Error opening ssh-copy for writing: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
while((len=sftp_read(fichier,data,4096)) > 0){
|
||||
if(sftp_write(to,data,len)!=len){
|
||||
fprintf(stderr, "Error writing %d bytes: %s\n",
|
||||
len, ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
}
|
||||
printf("finished\n");
|
||||
if(len<0)
|
||||
fprintf(stderr, "Error reading file: %s\n", ssh_get_error(session));
|
||||
sftp_close(fichier);
|
||||
sftp_close(to);
|
||||
printf("fichiers ferm\n");
|
||||
to=sftp_open(sftp,"/tmp/grosfichier",O_WRONLY|O_CREAT, 0644);
|
||||
for(i=0;i<1000;++i){
|
||||
len=sftp_write(to,data,8000);
|
||||
printf("wrote %d bytes\n",len);
|
||||
if(len != 8000){
|
||||
printf("chunk %d : %d (%s)\n",i,len,ssh_get_error(session));
|
||||
}
|
||||
}
|
||||
sftp_close(to);
|
||||
|
||||
/* close the sftp session */
|
||||
sftp_free(sftp);
|
||||
printf("sftp session terminated\n");
|
||||
}
|
||||
|
||||
static void usage(const char *argv0){
|
||||
fprintf(stderr,"Usage : %s [-v] remotehost\n"
|
||||
"sample sftp test client - libssh-%s\n"
|
||||
"Options :\n"
|
||||
" -v : increase log verbosity\n",
|
||||
argv0,
|
||||
ssh_version(0));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int opts(int argc, char **argv){
|
||||
int i;
|
||||
while((i=getopt(argc,argv,"v"))!=-1){
|
||||
switch(i){
|
||||
case 'v':
|
||||
verbosity++;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"unknown option %c\n",optopt);
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
destination=argv[optind];
|
||||
if(destination == NULL){
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
ssh_session session;
|
||||
if(opts(argc,argv)<0)
|
||||
return EXIT_FAILURE;
|
||||
session=connect_ssh(destination,NULL,verbosity);
|
||||
if(session == NULL)
|
||||
return EXIT_FAILURE;
|
||||
do_sftp(session);
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
269
examples/samplesshd.c
Normal file
269
examples/samplesshd.c
Normal file
@@ -0,0 +1,269 @@
|
||||
/* This is a sample implementation of a libssh based SSH server */
|
||||
/*
|
||||
Copyright 2003-2009 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/server.h>
|
||||
|
||||
#ifdef HAVE_ARGP_H
|
||||
#include <argp.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#ifndef KEYS_FOLDER
|
||||
#ifdef _WIN32
|
||||
#define KEYS_FOLDER
|
||||
#else
|
||||
#define KEYS_FOLDER "/etc/ssh/"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static int auth_password(char *user, char *password){
|
||||
if(strcmp(user,"aris"))
|
||||
return 0;
|
||||
if(strcmp(password,"lala"))
|
||||
return 0;
|
||||
return 1; // authenticated
|
||||
}
|
||||
#ifdef HAVE_ARGP_H
|
||||
const char *argp_program_version = "libssh server example "
|
||||
SSH_STRINGIFY(LIBSSH_VERSION);
|
||||
const char *argp_program_bug_address = "<libssh@libssh.org>";
|
||||
|
||||
/* Program documentation. */
|
||||
static char doc[] = "libssh -- a Secure Shell protocol implementation";
|
||||
|
||||
/* A description of the arguments we accept. */
|
||||
static char args_doc[] = "BINDADDR";
|
||||
|
||||
/* The options we understand. */
|
||||
static struct argp_option options[] = {
|
||||
{
|
||||
.name = "port",
|
||||
.key = 'p',
|
||||
.arg = "PORT",
|
||||
.flags = 0,
|
||||
.doc = "Set the port to bind.",
|
||||
.group = 0
|
||||
},
|
||||
{
|
||||
.name = "hostkey",
|
||||
.key = 'k',
|
||||
.arg = "FILE",
|
||||
.flags = 0,
|
||||
.doc = "Set the host key.",
|
||||
.group = 0
|
||||
},
|
||||
{
|
||||
.name = "dsakey",
|
||||
.key = 'd',
|
||||
.arg = "FILE",
|
||||
.flags = 0,
|
||||
.doc = "Set the dsa key.",
|
||||
.group = 0
|
||||
},
|
||||
{
|
||||
.name = "rsakey",
|
||||
.key = 'r',
|
||||
.arg = "FILE",
|
||||
.flags = 0,
|
||||
.doc = "Set the rsa key.",
|
||||
.group = 0
|
||||
},
|
||||
{
|
||||
.name = "verbose",
|
||||
.key = 'v',
|
||||
.arg = NULL,
|
||||
.flags = 0,
|
||||
.doc = "Get verbose output.",
|
||||
.group = 0
|
||||
},
|
||||
{NULL, 0, 0, 0, NULL, 0}
|
||||
};
|
||||
|
||||
/* Parse a single option. */
|
||||
static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
||||
/* Get the input argument from argp_parse, which we
|
||||
* know is a pointer to our arguments structure.
|
||||
*/
|
||||
ssh_bind sshbind = state->input;
|
||||
|
||||
switch (key) {
|
||||
case 'p':
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
||||
break;
|
||||
case 'd':
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg);
|
||||
break;
|
||||
case 'k':
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||
break;
|
||||
case 'r':
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg);
|
||||
break;
|
||||
case 'v':
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
if (state->arg_num >= 1) {
|
||||
/* Too many arguments. */
|
||||
argp_usage (state);
|
||||
}
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg);
|
||||
break;
|
||||
case ARGP_KEY_END:
|
||||
if (state->arg_num < 1) {
|
||||
/* Not enough arguments. */
|
||||
argp_usage (state);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Our argp parser. */
|
||||
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||
#endif /* HAVE_ARGP_H */
|
||||
|
||||
int main(int argc, char **argv){
|
||||
ssh_session session;
|
||||
ssh_bind sshbind;
|
||||
ssh_message message;
|
||||
ssh_channel chan=0;
|
||||
ssh_buffer buf;
|
||||
int auth=0;
|
||||
int sftp=0;
|
||||
int i;
|
||||
int r;
|
||||
|
||||
sshbind=ssh_bind_new();
|
||||
session=ssh_new();
|
||||
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, KEYS_FOLDER "ssh_host_dsa_key");
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, KEYS_FOLDER "ssh_host_rsa_key");
|
||||
|
||||
#ifdef HAVE_ARGP_H
|
||||
/*
|
||||
* Parse our arguments; every option seen by parse_opt will
|
||||
* be reflected in arguments.
|
||||
*/
|
||||
argp_parse (&argp, argc, argv, 0, 0, sshbind);
|
||||
#endif
|
||||
if(ssh_bind_listen(sshbind)<0){
|
||||
printf("Error listening to socket: %s\n",ssh_get_error(sshbind));
|
||||
return 1;
|
||||
}
|
||||
r=ssh_bind_accept(sshbind,session);
|
||||
if(r==SSH_ERROR){
|
||||
printf("error accepting a connection : %s\n",ssh_get_error(sshbind));
|
||||
return 1;
|
||||
}
|
||||
if(ssh_accept(session)){
|
||||
printf("ssh_accept: %s\n",ssh_get_error(session));
|
||||
return 1;
|
||||
}
|
||||
do {
|
||||
message=ssh_message_get(session);
|
||||
if(!message)
|
||||
break;
|
||||
switch(ssh_message_type(message)){
|
||||
case SSH_REQUEST_AUTH:
|
||||
switch(ssh_message_subtype(message)){
|
||||
case SSH_AUTH_METHOD_PASSWORD:
|
||||
printf("User %s wants to auth with pass %s\n",
|
||||
ssh_message_auth_user(message),
|
||||
ssh_message_auth_password(message));
|
||||
if(auth_password(ssh_message_auth_user(message),
|
||||
ssh_message_auth_password(message))){
|
||||
auth=1;
|
||||
ssh_message_auth_reply_success(message,0);
|
||||
break;
|
||||
}
|
||||
// not authenticated, send default message
|
||||
case SSH_AUTH_METHOD_NONE:
|
||||
default:
|
||||
ssh_message_auth_set_methods(message,SSH_AUTH_METHOD_PASSWORD);
|
||||
ssh_message_reply_default(message);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ssh_message_reply_default(message);
|
||||
}
|
||||
ssh_message_free(message);
|
||||
} while (!auth);
|
||||
if(!auth){
|
||||
printf("auth error: %s\n",ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
return 1;
|
||||
}
|
||||
do {
|
||||
message=ssh_message_get(session);
|
||||
if(message){
|
||||
switch(ssh_message_type(message)){
|
||||
case SSH_REQUEST_CHANNEL_OPEN:
|
||||
if(ssh_message_subtype(message)==SSH_CHANNEL_SESSION){
|
||||
chan=ssh_message_channel_request_open_reply_accept(message);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ssh_message_reply_default(message);
|
||||
}
|
||||
ssh_message_free(message);
|
||||
}
|
||||
} while(message && !chan);
|
||||
if(!chan){
|
||||
printf("error : %s\n",ssh_get_error(session));
|
||||
ssh_finalize();
|
||||
return 1;
|
||||
}
|
||||
do {
|
||||
message=ssh_message_get(session);
|
||||
if(message && ssh_message_type(message)==SSH_REQUEST_CHANNEL &&
|
||||
ssh_message_subtype(message)==SSH_CHANNEL_REQUEST_SHELL){
|
||||
// if(!strcmp(ssh_message_channel_request_subsystem(message),"sftp")){
|
||||
sftp=1;
|
||||
ssh_message_channel_request_reply_success(message);
|
||||
break;
|
||||
// }
|
||||
}
|
||||
if(!sftp){
|
||||
ssh_message_reply_default(message);
|
||||
}
|
||||
ssh_message_free(message);
|
||||
} while (message && !sftp);
|
||||
if(!sftp){
|
||||
printf("error : %s\n",ssh_get_error(session));
|
||||
return 1;
|
||||
}
|
||||
printf("it works !\n");
|
||||
buf=buffer_new();
|
||||
do{
|
||||
i=channel_read_buffer(chan,buf,0,0);
|
||||
if(i>0)
|
||||
write(1,buffer_get(buf),buffer_get_len(buf));
|
||||
} while (i>0);
|
||||
buffer_free(buf);
|
||||
ssh_disconnect(session);
|
||||
ssh_bind_free(sshbind);
|
||||
ssh_finalize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
149
examples/scp_download.c
Normal file
149
examples/scp_download.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/* scp_download.c
|
||||
* Sample implementation of a tiny SCP downloader client
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2009 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include "examples_common.h"
|
||||
|
||||
int verbosity=0;
|
||||
const char *createcommand="rm -fr /tmp/libssh_tests && mkdir /tmp/libssh_tests && cd /tmp/libssh_tests && date > a && date > b && mkdir c && date > d";
|
||||
char *host=NULL;
|
||||
static void usage(const char *argv0){
|
||||
fprintf(stderr,"Usage : %s [options] host\n"
|
||||
"sample tiny scp downloader client - libssh-%s\n"
|
||||
"This program will create files in /tmp and try to fetch them\n",
|
||||
// "Options :\n",
|
||||
// " -r : use RSA to verify host public key\n",
|
||||
argv0,
|
||||
ssh_version(0));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int opts(int argc, char **argv){
|
||||
int i;
|
||||
while((i=getopt(argc,argv,"v"))!=-1){
|
||||
switch(i){
|
||||
case 'v':
|
||||
verbosity++;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"unknown option %c\n",optopt);
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
host = argv[optind];
|
||||
if(host == NULL)
|
||||
usage(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void create_files(ssh_session session){
|
||||
ssh_channel channel=channel_new(session);
|
||||
char buffer[1];
|
||||
if(channel == NULL){
|
||||
fprintf(stderr,"Error creating channel: %s\n",ssh_get_error(session));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(channel_open_session(channel) != SSH_OK){
|
||||
fprintf(stderr,"Error creating channel: %s\n",ssh_get_error(session));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(channel_request_exec(channel,createcommand) != SSH_OK){
|
||||
fprintf(stderr,"Error executing command: %s\n",ssh_get_error(session));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
while(!channel_is_eof(channel)){
|
||||
channel_read(channel,buffer,1,1);
|
||||
write(1,buffer,1);
|
||||
}
|
||||
channel_close(channel);
|
||||
channel_free(channel);
|
||||
}
|
||||
|
||||
|
||||
static int fetch_files(ssh_session session){
|
||||
int size;
|
||||
char buffer[16384];
|
||||
int mode;
|
||||
char *filename;
|
||||
int r;
|
||||
ssh_scp scp=ssh_scp_new(session, SSH_SCP_READ | SSH_SCP_RECURSIVE, "/tmp/libssh_tests/*");
|
||||
if(ssh_scp_init(scp) != SSH_OK){
|
||||
fprintf(stderr,"error initializing scp: %s\n",ssh_get_error(session));
|
||||
return -1;
|
||||
}
|
||||
printf("Trying to download 3 files (a,b,d) and 1 directory (c)\n");
|
||||
do {
|
||||
|
||||
r=ssh_scp_pull_request(scp);
|
||||
switch(r){
|
||||
case SSH_SCP_REQUEST_NEWFILE:
|
||||
size=ssh_scp_request_get_size(scp);
|
||||
filename=strdup(ssh_scp_request_get_filename(scp));
|
||||
mode=ssh_scp_request_get_permissions(scp);
|
||||
printf("downloading file %s, size %d, perms 0%o\n",filename,size,mode);
|
||||
free(filename);
|
||||
ssh_scp_accept_request(scp);
|
||||
r=ssh_scp_read(scp,buffer,sizeof(buffer));
|
||||
if(r==SSH_ERROR){
|
||||
fprintf(stderr,"Error reading scp: %s\n",ssh_get_error(session));
|
||||
return -1;
|
||||
}
|
||||
printf("done\n");
|
||||
break;
|
||||
case SSH_ERROR:
|
||||
fprintf(stderr,"Error: %s\n",ssh_get_error(session));
|
||||
return -1;
|
||||
case SSH_SCP_REQUEST_WARNING:
|
||||
fprintf(stderr,"Warning: %s\n",ssh_scp_request_get_warning(scp));
|
||||
break;
|
||||
case SSH_SCP_REQUEST_NEWDIR:
|
||||
filename=strdup(ssh_scp_request_get_filename(scp));
|
||||
mode=ssh_scp_request_get_permissions(scp);
|
||||
printf("downloading directory %s, perms 0%o\n",filename,mode);
|
||||
free(filename);
|
||||
ssh_scp_accept_request(scp);
|
||||
break;
|
||||
case SSH_SCP_REQUEST_ENDDIR:
|
||||
printf("End of directory\n");
|
||||
break;
|
||||
case SSH_SCP_REQUEST_EOF:
|
||||
printf("End of requests\n");
|
||||
goto end;
|
||||
}
|
||||
} while (1);
|
||||
end:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
ssh_session session;
|
||||
if(opts(argc,argv)<0)
|
||||
return EXIT_FAILURE;
|
||||
session=connect_ssh(host,NULL,verbosity);
|
||||
if(session == NULL)
|
||||
return EXIT_FAILURE;
|
||||
create_files(session);
|
||||
fetch_files(session);
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
project(libssh-headers C)
|
||||
|
||||
set(libssh_HDRS
|
||||
callbacks.h
|
||||
libssh.h
|
||||
crypto.h
|
||||
ssh2.h
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef __AGENT_H
|
||||
#define __AGENT_H
|
||||
|
||||
#include "libssh/libssh.h"
|
||||
|
||||
/* Messages for the authentication agent connection. */
|
||||
#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
|
||||
#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2
|
||||
@@ -45,5 +47,51 @@
|
||||
|
||||
#define SSH_AGENT_OLD_SIGNATURE 0x01
|
||||
|
||||
struct ssh_agent_struct {
|
||||
struct socket *sock;
|
||||
ssh_buffer ident;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
/* agent.c */
|
||||
/**
|
||||
* @brief Create a new ssh agent structure.
|
||||
*
|
||||
* @return An allocated ssh agent structure or NULL on error.
|
||||
*/
|
||||
struct ssh_agent_struct *agent_new(struct ssh_session_struct *session);
|
||||
|
||||
void agent_close(struct ssh_agent_struct *agent);
|
||||
|
||||
/**
|
||||
* @brief Free an allocated ssh agent structure.
|
||||
*
|
||||
* @param agent The ssh agent structure to free.
|
||||
*/
|
||||
void agent_free(struct ssh_agent_struct *agent);
|
||||
|
||||
/**
|
||||
* @brief Check if the ssh agent is running.
|
||||
*
|
||||
* @param session The ssh session to check for the agent.
|
||||
*
|
||||
* @return 1 if it is running, 0 if not.
|
||||
*/
|
||||
int agent_is_running(struct ssh_session_struct *session);
|
||||
|
||||
int agent_get_ident_count(struct ssh_session_struct *session);
|
||||
|
||||
struct ssh_public_key_struct *agent_get_next_ident(struct ssh_session_struct *session,
|
||||
char **comment);
|
||||
|
||||
struct ssh_public_key_struct *agent_get_first_ident(struct ssh_session_struct *session,
|
||||
char **comment);
|
||||
|
||||
ssh_string agent_sign_data(struct ssh_session_struct *session,
|
||||
struct ssh_buffer_struct *data,
|
||||
struct ssh_public_key_struct *pubkey);
|
||||
#endif
|
||||
|
||||
#endif /* __AGENT_H */
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
|
||||
62
include/libssh/buffer.h
Normal file
62
include/libssh/buffer.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef BUFFER_H_
|
||||
#define BUFFER_H_
|
||||
|
||||
/* Describes a buffer state */
|
||||
struct ssh_buffer_struct {
|
||||
char *data;
|
||||
uint32_t used;
|
||||
uint32_t allocated;
|
||||
uint32_t pos;
|
||||
};
|
||||
|
||||
int buffer_add_ssh_string(ssh_buffer buffer, ssh_string string);
|
||||
int buffer_add_u8(ssh_buffer buffer, uint8_t data);
|
||||
int buffer_add_u16(ssh_buffer buffer, uint16_t data);
|
||||
int buffer_add_u32(ssh_buffer buffer, uint32_t data);
|
||||
int buffer_add_u64(ssh_buffer buffer, uint64_t data);
|
||||
int buffer_add_data(ssh_buffer buffer, const void *data, uint32_t len);
|
||||
int buffer_prepend_data(ssh_buffer buffer, const void *data, uint32_t len);
|
||||
int buffer_add_buffer(ssh_buffer buffer, ssh_buffer source);
|
||||
int buffer_reinit(ssh_buffer buffer);
|
||||
|
||||
/* buffer_get_rest returns a pointer to the current position into the buffer */
|
||||
void *buffer_get_rest(ssh_buffer buffer);
|
||||
/* buffer_get_rest_len returns the number of bytes which can be read */
|
||||
uint32_t buffer_get_rest_len(ssh_buffer buffer);
|
||||
|
||||
/* buffer_read_*() returns the number of bytes read, except for ssh strings */
|
||||
int buffer_get_u8(ssh_buffer buffer, uint8_t *data);
|
||||
int buffer_get_u32(ssh_buffer buffer, uint32_t *data);
|
||||
int buffer_get_u64(ssh_buffer buffer, uint64_t *data);
|
||||
|
||||
uint32_t buffer_get_data(ssh_buffer buffer, void *data, uint32_t requestedlen);
|
||||
/* buffer_get_ssh_string() is an exception. if the String read is too large or invalid, it will answer NULL. */
|
||||
ssh_string buffer_get_ssh_string(ssh_buffer buffer);
|
||||
/* gets a string out of a SSH-1 mpint */
|
||||
ssh_string buffer_get_mpint(ssh_buffer buffer);
|
||||
/* buffer_pass_bytes acts as if len bytes have been read (used for padding) */
|
||||
uint32_t buffer_pass_bytes_end(ssh_buffer buffer, uint32_t len);
|
||||
uint32_t buffer_pass_bytes(ssh_buffer buffer, uint32_t len);
|
||||
|
||||
#endif /* BUFFER_H_ */
|
||||
113
include/libssh/callbacks.h
Normal file
113
include/libssh/callbacks.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 Aris Adamantiadis <aris@0xbadc0de.be>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* callback.h
|
||||
* This file includes the public declarations for the libssh callback mechanism
|
||||
*/
|
||||
|
||||
#ifndef _SSH_CALLBACK_H
|
||||
#define _SSH_CALLBACK_H
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SSH authentication callback.
|
||||
*
|
||||
* @param prompt Prompt to be displayed.
|
||||
* @param buf Buffer to save the password. You should null-terminate it.
|
||||
* @param len Length of the buffer.
|
||||
* @param echo Enable or disable the echo of what you type.
|
||||
* @param verify Should the password be verified?
|
||||
* @param userdata Userdata to be passed to the callback function. Useful
|
||||
* for GUI applications.
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
typedef int (*ssh_auth_callback) (const char *prompt, char *buf, size_t len,
|
||||
int echo, int verify, void *userdata);
|
||||
typedef void (*ssh_log_callback) (ssh_session session, int priority,
|
||||
const char *message, void *userdata);
|
||||
/** this callback will be called with status going from 0.0 to 1.0 during
|
||||
* connection */
|
||||
typedef void (*ssh_status_callback) (ssh_session session, float status,
|
||||
void *userdata);
|
||||
|
||||
struct ssh_callbacks_struct {
|
||||
/** size of this structure. internal, shoud be set with ssh_callbacks_init()*/
|
||||
size_t size;
|
||||
/** User-provided data. User is free to set anything he wants here */
|
||||
void *userdata;
|
||||
/** this functions will be called if e.g. a keyphrase is needed. */
|
||||
ssh_auth_callback auth_function;
|
||||
/** this function will be called each time a loggable event happens. */
|
||||
ssh_log_callback log_function;
|
||||
/** this function gets called during connection time to indicate the percentage
|
||||
* of connection steps completed.
|
||||
*/
|
||||
void (*connect_status_function)(void *userdata, float status);
|
||||
};
|
||||
|
||||
typedef struct ssh_callbacks_struct * ssh_callbacks;
|
||||
|
||||
/** Initializes an ssh_callbacks_struct
|
||||
* A call to this macro is mandatory when you have set a new
|
||||
* ssh_callback_struct structure. Its goal is to maintain the binary
|
||||
* compatibility with future versions of libssh as the structure
|
||||
* evolves with time.
|
||||
*/
|
||||
#define ssh_callbacks_init(p) do {\
|
||||
(p)->size=sizeof(*(p)); \
|
||||
} while(0);
|
||||
|
||||
/**
|
||||
* @brief Set the callback functions.
|
||||
*
|
||||
* This functions sets the callback structure to use your own callback
|
||||
* functions for auth, logging and status.
|
||||
*
|
||||
* @code
|
||||
* struct ssh_callbacks_struct cb;
|
||||
* memset(&cb, 0, sizeof(struct ssh_callbacks_struct));
|
||||
* cb.userdata = data;
|
||||
* cb.auth_function = my_auth_function;
|
||||
*
|
||||
* ssh_callbacks_init(&cb);
|
||||
* ssh_set_callbacks(session, &cb);
|
||||
* @endcode
|
||||
*
|
||||
* @param session The session to set the callback structure.
|
||||
*
|
||||
* @param cb The callback itself.
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
LIBSSH_API int ssh_set_callbacks(ssh_session session, ssh_callbacks cb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*_SSH_CALLBACK_H */
|
||||
58
include/libssh/channels.h
Normal file
58
include/libssh/channels.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef CHANNELS_H_
|
||||
#define CHANNELS_H_
|
||||
#include "libssh/priv.h"
|
||||
|
||||
struct ssh_channel_struct {
|
||||
struct ssh_channel_struct *prev;
|
||||
struct ssh_channel_struct *next;
|
||||
ssh_session session; /* SSH_SESSION pointer */
|
||||
uint32_t local_channel;
|
||||
uint32_t local_window;
|
||||
int local_eof;
|
||||
uint32_t local_maxpacket;
|
||||
|
||||
uint32_t remote_channel;
|
||||
uint32_t remote_window;
|
||||
int remote_eof; /* end of file received */
|
||||
uint32_t remote_maxpacket;
|
||||
int open; /* shows if the channel is still opened */
|
||||
int delayed_close;
|
||||
ssh_buffer stdout_buffer;
|
||||
ssh_buffer stderr_buffer;
|
||||
void *userarg;
|
||||
int version;
|
||||
int blocking;
|
||||
int exit_status;
|
||||
};
|
||||
|
||||
void channel_handle(ssh_session session, int type);
|
||||
ssh_channel channel_new(ssh_session session);
|
||||
int channel_default_bufferize(ssh_channel channel, void *data, int len,
|
||||
int is_stderr);
|
||||
uint32_t ssh_channel_new_id(ssh_session session);
|
||||
ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id);
|
||||
int channel_write_common(ssh_channel channel, const void *data,
|
||||
uint32_t len, int is_stderr);
|
||||
|
||||
#endif /* CHANNELS_H_ */
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003 by Aris Adamantiadis
|
||||
* Copyright (c) 2003,2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
@@ -20,11 +20,19 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* crypto.h is an include file for internal structures of libssh
|
||||
* It hasn't to be into the final development set of files (and btw
|
||||
* the filename would cause problems on most systems).
|
||||
* crypto.h is an include file for internal cryptographic structures of libssh
|
||||
*/
|
||||
|
||||
#ifndef _CRYPTO_H_
|
||||
#define _CRYPTO_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#include <gcrypt.h>
|
||||
#endif
|
||||
#include "libssh/wrapper.h"
|
||||
|
||||
#ifdef cbc_encrypt
|
||||
#undef cbc_encrypt
|
||||
#endif
|
||||
@@ -32,9 +40,27 @@
|
||||
#undef cbc_decrypt
|
||||
#endif
|
||||
|
||||
#ifdef GCRYPT
|
||||
#include <gcrypt.h>
|
||||
#endif
|
||||
struct ssh_crypto_struct {
|
||||
bignum e,f,x,k,y;
|
||||
unsigned char session_id[SHA_DIGEST_LEN];
|
||||
|
||||
unsigned char encryptIV[SHA_DIGEST_LEN*2];
|
||||
unsigned char decryptIV[SHA_DIGEST_LEN*2];
|
||||
|
||||
unsigned char decryptkey[SHA_DIGEST_LEN*2];
|
||||
unsigned char encryptkey[SHA_DIGEST_LEN*2];
|
||||
|
||||
unsigned char encryptMAC[SHA_DIGEST_LEN];
|
||||
unsigned char decryptMAC[SHA_DIGEST_LEN];
|
||||
unsigned char hmacbuf[EVP_MAX_MD_SIZE];
|
||||
struct crypto_struct *in_cipher, *out_cipher; /* the cipher structures/objects */
|
||||
ssh_string server_pubkey;
|
||||
const char *server_pubkey_type;
|
||||
int do_compress_out; /* idem */
|
||||
int do_compress_in; /* don't set them, set the option instead */
|
||||
void *compress_out_ctx; /* don't touch it */
|
||||
void *compress_in_ctx; /* really, don't */
|
||||
};
|
||||
|
||||
struct crypto_struct {
|
||||
const char *name; /* ssh name of the algorithm */
|
||||
@@ -66,3 +92,4 @@ struct crypto_struct {
|
||||
};
|
||||
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
#endif /* _CRYPTO_H_ */
|
||||
|
||||
57
include/libssh/dh.h
Normal file
57
include/libssh/dh.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef DH_H_
|
||||
#define DH_H_
|
||||
#include "config.h"
|
||||
|
||||
/* DH key generation */
|
||||
#include "libssh/keys.h"
|
||||
|
||||
void ssh_print_bignum(const char *which,bignum num);
|
||||
int dh_generate_e(ssh_session session);
|
||||
int dh_generate_f(ssh_session session);
|
||||
int dh_generate_x(ssh_session session);
|
||||
int dh_generate_y(ssh_session session);
|
||||
|
||||
int ssh_crypto_init(void);
|
||||
void ssh_crypto_finalize(void);
|
||||
|
||||
ssh_string dh_get_e(ssh_session session);
|
||||
ssh_string dh_get_f(ssh_session session);
|
||||
int dh_import_f(ssh_session session,ssh_string f_string);
|
||||
int dh_import_e(ssh_session session, ssh_string e_string);
|
||||
void dh_import_pubkey(ssh_session session,ssh_string pubkey_string);
|
||||
int dh_build_k(ssh_session session);
|
||||
int make_sessionid(ssh_session session);
|
||||
/* add data for the final cookie */
|
||||
int hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
|
||||
int hashbufout_add_cookie(ssh_session session);
|
||||
int generate_session_keys(ssh_session session);
|
||||
int sig_verify(ssh_session session, ssh_public_key pubkey,
|
||||
SIGNATURE *signature, unsigned char *digest, int size);
|
||||
/* returns 1 if server signature ok, 0 otherwise. The NEXT crypto is checked, not the current one */
|
||||
int signature_verify(ssh_session session,ssh_string signature);
|
||||
bignum make_string_bn(ssh_string string);
|
||||
ssh_string make_bignum_string(bignum num);
|
||||
|
||||
|
||||
#endif /* DH_H_ */
|
||||
33
include/libssh/keyfiles.h
Normal file
33
include/libssh/keyfiles.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef KEYFILES_H_
|
||||
#define KEYFILES_H_
|
||||
|
||||
/* in keyfiles.c */
|
||||
|
||||
ssh_private_key _privatekey_from_file(void *session, const char *filename,
|
||||
int type);
|
||||
ssh_string try_publickey_from_file(ssh_session session,
|
||||
struct ssh_keys_struct keytab,
|
||||
char **privkeyfile, int *type);
|
||||
|
||||
#endif /* KEYFILES_H_ */
|
||||
84
include/libssh/keys.h
Normal file
84
include/libssh/keys.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef KEYS_H_
|
||||
#define KEYS_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/wrapper.h"
|
||||
|
||||
struct ssh_public_key_struct {
|
||||
int type;
|
||||
const char *type_c; /* Don't free it ! it is static */
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_t dsa_pub;
|
||||
gcry_sexp_t rsa_pub;
|
||||
#elif HAVE_LIBCRYPTO
|
||||
DSA *dsa_pub;
|
||||
RSA *rsa_pub;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ssh_private_key_struct {
|
||||
int type;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_t dsa_priv;
|
||||
gcry_sexp_t rsa_priv;
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
DSA *dsa_priv;
|
||||
RSA *rsa_priv;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct signature_struct {
|
||||
int type;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_t dsa_sign;
|
||||
gcry_sexp_t rsa_sign;
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
DSA_SIG *dsa_sign;
|
||||
ssh_string rsa_sign;
|
||||
#endif
|
||||
} SIGNATURE;
|
||||
|
||||
const char *ssh_type_to_char(int type);
|
||||
int ssh_type_from_name(const char *name);
|
||||
ssh_buffer ssh_userauth_build_digest(ssh_session session, ssh_message msg, char *service);
|
||||
|
||||
ssh_private_key privatekey_make_dss(ssh_session session, ssh_buffer buffer);
|
||||
ssh_private_key privatekey_make_rsa(ssh_session session, ssh_buffer buffer,
|
||||
const char *type);
|
||||
ssh_private_key privatekey_from_string(ssh_session session, ssh_string privkey_s);
|
||||
|
||||
ssh_public_key publickey_make_dss(ssh_session session, ssh_buffer buffer);
|
||||
ssh_public_key publickey_make_rsa(ssh_session session, ssh_buffer buffer, int type);
|
||||
ssh_public_key publickey_from_string(ssh_session session, ssh_string pubkey_s);
|
||||
SIGNATURE *signature_from_string(ssh_session session, ssh_string signature,ssh_public_key pubkey,int needed_type);
|
||||
void signature_free(SIGNATURE *sign);
|
||||
ssh_string ssh_do_sign_with_agent(struct ssh_session_struct *session,
|
||||
struct ssh_buffer_struct *buf, struct ssh_public_key_struct *publickey);
|
||||
ssh_string ssh_do_sign(ssh_session session,ssh_buffer sigbuf,
|
||||
ssh_private_key privatekey);
|
||||
ssh_string ssh_sign_session_id(ssh_session session, ssh_private_key privatekey);
|
||||
ssh_string ssh_encrypt_rsa1(ssh_session session, ssh_string data, ssh_public_key key);
|
||||
|
||||
#endif /* KEYS_H_ */
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
@@ -22,22 +22,50 @@
|
||||
#ifndef _LIBSSH_H
|
||||
#define _LIBSSH_H
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#ifdef LIBSSH_STATIC
|
||||
#define LIBSSH_API
|
||||
#else
|
||||
#if defined _WIN32 || defined __CYGWIN__
|
||||
#ifdef LIBSSH_EXPORTS
|
||||
#ifdef __GNUC__
|
||||
#define LIBSSH_API __attribute__((dllexport))
|
||||
#else
|
||||
#define LIBSSH_API __declspec(dllexport)
|
||||
#endif
|
||||
#else
|
||||
#ifdef __GNUC__
|
||||
#define LIBSSH_API __attribute__((dllimport))
|
||||
#else
|
||||
#define LIBSSH_API __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#if __GNUC__ >= 4
|
||||
#define LIBSSH_API __attribute__((visibility("default")))
|
||||
#else
|
||||
#define LIBSSH_API
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* Visual Studio hasn't inttypes.h so it doesn't know uint32_t */
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef int mode_t;
|
||||
#else /* _MSC_VER */
|
||||
//visual studio hasn't inttypes.h so it doesn't know uint32_t
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <sys/select.h> /* for fd_set * */
|
||||
#include <netdb.h>
|
||||
#include <winsock2.h>
|
||||
#else /* _WIN32 */
|
||||
#include <sys/select.h> /* for fd_set * */
|
||||
#include <netdb.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#define SSH_STRINGIFY(s) SSH_TOSTRING(s)
|
||||
@@ -50,7 +78,7 @@ typedef unsigned long long uint64_t;
|
||||
|
||||
/* libssh version */
|
||||
#define LIBSSH_VERSION_MAJOR 0
|
||||
#define LIBSSH_VERSION_MINOR 3
|
||||
#define LIBSSH_VERSION_MINOR 4
|
||||
#define LIBSSH_VERSION_MICRO 1
|
||||
|
||||
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
|
||||
@@ -67,26 +95,27 @@ typedef unsigned long long uint64_t;
|
||||
#define PRINTF_ATTRIBUTE(a,b)
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define SSH_DEPRECATED __attribute__ ((deprecated))
|
||||
#else
|
||||
#define SSH_DEPRECATED
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct string_struct STRING;
|
||||
typedef struct buffer_struct BUFFER;
|
||||
typedef struct public_key_struct PUBLIC_KEY;
|
||||
typedef struct private_key_struct PRIVATE_KEY;
|
||||
typedef struct ssh_options_struct SSH_OPTIONS;
|
||||
typedef struct channel_struct CHANNEL;
|
||||
typedef struct agent_struct AGENT;
|
||||
typedef struct ssh_session SSH_SESSION;
|
||||
typedef struct ssh_kbdint SSH_KBDINT;
|
||||
struct keys_struct;
|
||||
|
||||
/* integer values */
|
||||
typedef uint32_t u32;
|
||||
typedef uint16_t u16;
|
||||
typedef uint64_t u64;
|
||||
typedef uint8_t u8;
|
||||
typedef struct ssh_agent_struct* ssh_agent;
|
||||
typedef struct ssh_buffer_struct* ssh_buffer;
|
||||
typedef struct ssh_channel_struct* ssh_channel;
|
||||
typedef struct ssh_message_struct* ssh_message;
|
||||
typedef struct ssh_pcap_file_struct* ssh_pcap_file;
|
||||
typedef struct ssh_private_key_struct* ssh_private_key;
|
||||
typedef struct ssh_public_key_struct* ssh_public_key;
|
||||
typedef struct ssh_scp_struct* ssh_scp;
|
||||
typedef struct ssh_session_struct* ssh_session;
|
||||
typedef struct ssh_string_struct* ssh_string;
|
||||
|
||||
/* Socket type */
|
||||
#ifdef _WIN32
|
||||
@@ -96,55 +125,92 @@ typedef int socket_t;
|
||||
#endif
|
||||
|
||||
/* the offsets of methods */
|
||||
#define SSH_KEX 0
|
||||
#define SSH_HOSTKEYS 1
|
||||
#define SSH_CRYPT_C_S 2
|
||||
#define SSH_CRYPT_S_C 3
|
||||
#define SSH_MAC_C_S 4
|
||||
#define SSH_MAC_S_C 5
|
||||
#define SSH_COMP_C_S 6
|
||||
#define SSH_COMP_S_C 7
|
||||
#define SSH_LANG_C_S 8
|
||||
#define SSH_LANG_S_C 9
|
||||
enum ssh_kex_types_e {
|
||||
SSH_KEX=0,
|
||||
SSH_HOSTKEYS,
|
||||
SSH_CRYPT_C_S,
|
||||
SSH_CRYPT_S_C,
|
||||
SSH_MAC_C_S,
|
||||
SSH_MAC_S_C,
|
||||
SSH_COMP_C_S,
|
||||
SSH_COMP_S_C,
|
||||
SSH_LANG_C_S,
|
||||
SSH_LANG_S_C
|
||||
};
|
||||
|
||||
#define SSH_CRYPT 2
|
||||
#define SSH_MAC 3
|
||||
#define SSH_COMP 4
|
||||
#define SSH_LANG 5
|
||||
|
||||
#define SSH_AUTH_SUCCESS 0
|
||||
#define SSH_AUTH_DENIED 1
|
||||
#define SSH_AUTH_PARTIAL 2
|
||||
#define SSH_AUTH_INFO 3
|
||||
#define SSH_AUTH_ERROR -1
|
||||
enum ssh_auth_e {
|
||||
SSH_AUTH_SUCCESS=0,
|
||||
SSH_AUTH_DENIED,
|
||||
SSH_AUTH_PARTIAL,
|
||||
SSH_AUTH_INFO,
|
||||
SSH_AUTH_ERROR=-1
|
||||
};
|
||||
|
||||
#define SSH_AUTH_METHOD_PASSWORD 0x0001
|
||||
#define SSH_AUTH_METHOD_PUBLICKEY 0x0002
|
||||
#define SSH_AUTH_METHOD_HOSTBASED 0x0004
|
||||
#define SSH_AUTH_METHOD_INTERACTIVE 0x0008
|
||||
/* auth flags */
|
||||
#define SSH_AUTH_METHOD_UNKNOWN 0
|
||||
#define SSH_AUTH_METHOD_NONE 0x0001
|
||||
#define SSH_AUTH_METHOD_PASSWORD 0x0002
|
||||
#define SSH_AUTH_METHOD_PUBLICKEY 0x0004
|
||||
#define SSH_AUTH_METHOD_HOSTBASED 0x0008
|
||||
#define SSH_AUTH_METHOD_INTERACTIVE 0x0010
|
||||
|
||||
/* messages */
|
||||
enum ssh_requests_e {
|
||||
SSH_REQUEST_AUTH=1,
|
||||
SSH_REQUEST_CHANNEL_OPEN,
|
||||
SSH_REQUEST_CHANNEL,
|
||||
SSH_REQUEST_SERVICE,
|
||||
SSH_REQUEST_GLOBAL,
|
||||
};
|
||||
|
||||
enum ssh_channel_type_e {
|
||||
SSH_CHANNEL_UNKNOWN=0,
|
||||
SSH_CHANNEL_SESSION,
|
||||
SSH_CHANNEL_DIRECT_TCPIP,
|
||||
SSH_CHANNEL_FORWARDED_TCPIP,
|
||||
SSH_CHANNEL_X11
|
||||
};
|
||||
|
||||
enum ssh_channel_requests_e {
|
||||
SSH_CHANNEL_REQUEST_UNKNOWN=0,
|
||||
SSH_CHANNEL_REQUEST_PTY,
|
||||
SSH_CHANNEL_REQUEST_EXEC,
|
||||
SSH_CHANNEL_REQUEST_SHELL,
|
||||
SSH_CHANNEL_REQUEST_ENV,
|
||||
SSH_CHANNEL_REQUEST_SUBSYSTEM,
|
||||
SSH_CHANNEL_REQUEST_WINDOW_CHANGE,
|
||||
};
|
||||
|
||||
/* status flags */
|
||||
#define SSH_CLOSED 0x01
|
||||
#define SSH_READ_PENDING 0x02
|
||||
#define SSH_CLOSED_ERROR 0x04
|
||||
|
||||
#define SSH_CLOSED (1<<0)
|
||||
#define SSH_READ_PENDING (1<<1)
|
||||
#define SSH_CLOSED_ERROR (1<<2)
|
||||
|
||||
#define SSH_SERVER_ERROR -1
|
||||
#define SSH_SERVER_NOT_KNOWN 0
|
||||
#define SSH_SERVER_KNOWN_OK 1
|
||||
#define SSH_SERVER_KNOWN_CHANGED 2
|
||||
#define SSH_SERVER_FOUND_OTHER 3
|
||||
#define SSH_SERVER_FILE_NOT_FOUND 4
|
||||
enum ssh_server_known_e {
|
||||
SSH_SERVER_ERROR=-1,
|
||||
SSH_SERVER_NOT_KNOWN=0,
|
||||
SSH_SERVER_KNOWN_OK,
|
||||
SSH_SERVER_KNOWN_CHANGED,
|
||||
SSH_SERVER_FOUND_OTHER,
|
||||
SSH_SERVER_FILE_NOT_FOUND,
|
||||
};
|
||||
|
||||
#ifndef MD5_DIGEST_LEN
|
||||
#define MD5_DIGEST_LEN 16
|
||||
#endif
|
||||
/* errors */
|
||||
|
||||
#define SSH_NO_ERROR 0
|
||||
#define SSH_REQUEST_DENIED 1
|
||||
#define SSH_FATAL 2
|
||||
#define SSH_EINTR 3
|
||||
enum ssh_error_types_e {
|
||||
SSH_NO_ERROR=0,
|
||||
SSH_REQUEST_DENIED,
|
||||
SSH_FATAL,
|
||||
SSH_EINTR
|
||||
};
|
||||
|
||||
/* Error return codes */
|
||||
#define SSH_OK 0 /* No error */
|
||||
@@ -152,16 +218,10 @@ typedef int socket_t;
|
||||
#define SSH_AGAIN -2 /* The nonblocking call must be repeated */
|
||||
#define SSH_EOF -127 /* We have already a eof */
|
||||
|
||||
const char *ssh_get_error(void *error);
|
||||
int ssh_get_error_code(void *error);
|
||||
|
||||
/* version checks */
|
||||
const char *ssh_version(int req_version);
|
||||
|
||||
/** \addtogroup ssh_log
|
||||
* @{
|
||||
*/
|
||||
/** \brief Verbosity level for logging and help to debugging
|
||||
/** \brief Verbosity level for logging and help to debugging
|
||||
*/
|
||||
|
||||
enum {
|
||||
@@ -171,214 +231,214 @@ enum {
|
||||
/** Only rare and noteworthy events
|
||||
*/
|
||||
SSH_LOG_RARE,
|
||||
/** High level protocol informations
|
||||
/** High level protocol informations
|
||||
*/
|
||||
SSH_LOG_PROTOCOL,
|
||||
/** Lower level protocol infomations, packet level
|
||||
*/
|
||||
SSH_LOG_PACKET,
|
||||
SSH_LOG_PACKET,
|
||||
/** Every function path
|
||||
*/
|
||||
SSH_LOG_FUNCTIONS
|
||||
SSH_LOG_FUNCTIONS
|
||||
};
|
||||
/** @}
|
||||
*/
|
||||
/*#define SSH_LOG_NOLOG 0 // no log
|
||||
#define SSH_LOG_RARE 1 // rare conditions
|
||||
#define SSH_LOG_ENTRY 2 // user-accessible entrypoints
|
||||
#define SSH_LOG_PACKET 3 // packet id and size
|
||||
#define SSH_LOG_FUNCTIONS 4 // every function in and return
|
||||
*/
|
||||
/* log.c */
|
||||
void ssh_log(SSH_SESSION *session, int prioriry, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
|
||||
|
||||
/* session.c */
|
||||
SSH_SESSION *ssh_new(void);
|
||||
socket_t ssh_get_fd(SSH_SESSION *session);
|
||||
int ssh_get_version(SSH_SESSION *session);
|
||||
int ssh_get_status(SSH_SESSION *session);
|
||||
const char *ssh_get_disconnect_message(SSH_SESSION *session);
|
||||
void ssh_set_options(SSH_SESSION *session, SSH_OPTIONS *options);
|
||||
void ssh_set_fd_toread(SSH_SESSION *session);
|
||||
void ssh_set_fd_towrite(SSH_SESSION *session);
|
||||
void ssh_set_fd_except(SSH_SESSION *session);
|
||||
void ssh_set_blocking(SSH_SESSION *session, int blocking);
|
||||
void ssh_silent_disconnect(SSH_SESSION *session);
|
||||
enum ssh_options_e {
|
||||
SSH_OPTIONS_HOST,
|
||||
SSH_OPTIONS_PORT,
|
||||
SSH_OPTIONS_PORT_STR,
|
||||
SSH_OPTIONS_FD,
|
||||
SSH_OPTIONS_USER,
|
||||
SSH_OPTIONS_SSH_DIR,
|
||||
SSH_OPTIONS_IDENTITY,
|
||||
SSH_OPTIONS_KNOWNHOSTS,
|
||||
SSH_OPTIONS_TIMEOUT,
|
||||
SSH_OPTIONS_TIMEOUT_USEC,
|
||||
SSH_OPTIONS_SSH1,
|
||||
SSH_OPTIONS_SSH2,
|
||||
SSH_OPTIONS_LOG_VERBOSITY,
|
||||
SSH_OPTIONS_LOG_VERBOSITY_STR,
|
||||
|
||||
SSH_OPTIONS_CIPHERS_C_S,
|
||||
SSH_OPTIONS_CIPHERS_S_C,
|
||||
SSH_OPTIONS_COMPRESSION_C_S,
|
||||
SSH_OPTIONS_COMPRESSION_S_C
|
||||
};
|
||||
|
||||
/* client.c */
|
||||
int ssh_connect(SSH_SESSION *session);
|
||||
void ssh_disconnect(SSH_SESSION *session);
|
||||
int ssh_service_request(SSH_SESSION *session, const char *service);
|
||||
char *ssh_get_issue_banner(SSH_SESSION *session);
|
||||
/* get copyright informations */
|
||||
const char *ssh_copyright(void);
|
||||
enum {
|
||||
/** Code is going to write/create remote files */
|
||||
SSH_SCP_WRITE,
|
||||
/** Code is going to read remote files */
|
||||
SSH_SCP_READ,
|
||||
SSH_SCP_RECURSIVE=0x10
|
||||
};
|
||||
|
||||
/* string.h */
|
||||
enum ssh_scp_request_types {
|
||||
/** A new directory is going to be pulled */
|
||||
SSH_SCP_REQUEST_NEWDIR=1,
|
||||
/** A new file is going to be pulled */
|
||||
SSH_SCP_REQUEST_NEWFILE,
|
||||
/** End of requests */
|
||||
SSH_SCP_REQUEST_EOF,
|
||||
/** End of directory */
|
||||
SSH_SCP_REQUEST_ENDDIR,
|
||||
/** Warning received */
|
||||
SSH_SCP_REQUEST_WARNING
|
||||
};
|
||||
|
||||
/* You can use these functions, they won't change */
|
||||
/* string_from_char returns a newly allocated string from a char *ptr */
|
||||
STRING *string_from_char(const char *what);
|
||||
/* it returns the string len in host byte orders. str->size is big endian warning ! */
|
||||
size_t string_len(STRING *str);
|
||||
STRING *string_new(size_t size);
|
||||
/* string_fill copies the data in the string. */
|
||||
int string_fill(STRING *str, const void *data, size_t len);
|
||||
/* returns a newly allocated char array with the str string and a final nul caracter */
|
||||
char *string_to_char(STRING *str);
|
||||
STRING *string_copy(STRING *str);
|
||||
/* burns the data inside a string */
|
||||
void string_burn(STRING *str);
|
||||
void *string_data(STRING *str);
|
||||
void string_free(STRING *str);
|
||||
LIBSSH_API void buffer_free(ssh_buffer buffer);
|
||||
LIBSSH_API void *buffer_get(ssh_buffer buffer);
|
||||
LIBSSH_API uint32_t buffer_get_len(ssh_buffer buffer);
|
||||
LIBSSH_API ssh_buffer buffer_new(void);
|
||||
|
||||
/* useful for debug */
|
||||
char *ssh_get_hexa(const unsigned char *what, size_t len);
|
||||
void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len);
|
||||
int ssh_get_random(void *where,int len,int strong);
|
||||
|
||||
/* this one can be called by the client to see the hash of the public key before accepting it */
|
||||
int ssh_get_pubkey_hash(SSH_SESSION *session, unsigned char **hash);
|
||||
STRING *ssh_get_pubkey(SSH_SESSION *session);
|
||||
|
||||
/* in connect.c */
|
||||
int ssh_fd_poll(SSH_SESSION *session,int *write, int *except);
|
||||
int ssh_select(CHANNEL **channels, CHANNEL **outchannels, socket_t maxfd,
|
||||
fd_set *readfds, struct timeval *timeout);
|
||||
|
||||
void publickey_free(PUBLIC_KEY *key);
|
||||
|
||||
/* in keyfiles.c */
|
||||
|
||||
PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session, const char *filename,
|
||||
int type, const char *passphrase);
|
||||
STRING *publickey_to_string(PUBLIC_KEY *key);
|
||||
PUBLIC_KEY *publickey_from_privatekey(PRIVATE_KEY *prv);
|
||||
void privatekey_free(PRIVATE_KEY *prv);
|
||||
STRING *publickey_from_file(SSH_SESSION *session, const char *filename,
|
||||
int *type);
|
||||
STRING *try_publickey_from_file(SSH_SESSION *session,
|
||||
struct keys_struct keytab,
|
||||
char **privkeyfile, int *type);
|
||||
int ssh_is_server_known(SSH_SESSION *session);
|
||||
int ssh_write_knownhost(SSH_SESSION *session);
|
||||
|
||||
/* in channels.c */
|
||||
|
||||
CHANNEL *channel_new(SSH_SESSION *session);
|
||||
int channel_open_forward(CHANNEL *channel, const char *remotehost,
|
||||
LIBSSH_API ssh_channel channel_accept_x11(ssh_channel channel, int timeout_ms);
|
||||
LIBSSH_API int channel_change_pty_size(ssh_channel channel,int cols,int rows);
|
||||
LIBSSH_API ssh_channel channel_forward_accept(ssh_session session, int timeout_ms);
|
||||
LIBSSH_API int channel_close(ssh_channel channel);
|
||||
LIBSSH_API int channel_forward_cancel(ssh_session session, const char *address, int port);
|
||||
LIBSSH_API int channel_forward_listen(ssh_session session, const char *address, int port, int *bound_port);
|
||||
LIBSSH_API void channel_free(ssh_channel channel);
|
||||
LIBSSH_API int channel_get_exit_status(ssh_channel channel);
|
||||
LIBSSH_API ssh_session channel_get_session(ssh_channel channel);
|
||||
LIBSSH_API int channel_is_closed(ssh_channel channel);
|
||||
LIBSSH_API int channel_is_eof(ssh_channel channel);
|
||||
LIBSSH_API int channel_is_open(ssh_channel channel);
|
||||
LIBSSH_API ssh_channel channel_new(ssh_session session);
|
||||
LIBSSH_API int channel_open_forward(ssh_channel channel, const char *remotehost,
|
||||
int remoteport, const char *sourcehost, int localport);
|
||||
int channel_open_session(CHANNEL *channel);
|
||||
void channel_free(CHANNEL *channel);
|
||||
int channel_request_pty(CHANNEL *channel);
|
||||
int channel_request_pty_size(CHANNEL *channel, const char *term,
|
||||
LIBSSH_API int channel_open_session(ssh_channel channel);
|
||||
LIBSSH_API int channel_poll(ssh_channel channel, int is_stderr);
|
||||
LIBSSH_API int channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr);
|
||||
LIBSSH_API int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count,
|
||||
int is_stderr);
|
||||
LIBSSH_API int channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count,
|
||||
int is_stderr);
|
||||
LIBSSH_API int channel_request_env(ssh_channel channel, const char *name, const char *value);
|
||||
LIBSSH_API int channel_request_exec(ssh_channel channel, const char *cmd);
|
||||
LIBSSH_API int channel_request_pty(ssh_channel channel);
|
||||
LIBSSH_API int channel_request_pty_size(ssh_channel channel, const char *term,
|
||||
int cols, int rows);
|
||||
int channel_change_pty_size(CHANNEL *channel,int cols,int rows);
|
||||
int channel_request_shell(CHANNEL *channel);
|
||||
int channel_request_subsystem(CHANNEL *channel, const char *system);
|
||||
int channel_request_env(CHANNEL *channel, const char *name, const char *value);
|
||||
int channel_request_exec(CHANNEL *channel, const char *cmd);
|
||||
int channel_request_sftp(CHANNEL *channel);
|
||||
int channel_write(CHANNEL *channel, const void *data, u32 len);
|
||||
int channel_send_eof(CHANNEL *channel);
|
||||
int channel_is_eof(CHANNEL *channel);
|
||||
int channel_read(CHANNEL *channel, void *dest, u32 count, int is_stderr);
|
||||
int channel_read_buffer(CHANNEL *channel, BUFFER *buffer, u32 count,
|
||||
int is_stderr);
|
||||
int channel_poll(CHANNEL *channel, int is_stderr);
|
||||
int channel_close(CHANNEL *channel);
|
||||
void channel_set_blocking(CHANNEL *channel, int blocking);
|
||||
int channel_read_nonblocking(CHANNEL *channel, void *dest, u32 count,
|
||||
int is_stderr);
|
||||
int channel_is_open(CHANNEL *channel);
|
||||
int channel_is_closed(CHANNEL *channel);
|
||||
int channel_select(CHANNEL **readchans, CHANNEL **writechans, CHANNEL **exceptchans, struct
|
||||
LIBSSH_API int channel_request_shell(ssh_channel channel);
|
||||
LIBSSH_API int channel_request_send_signal(ssh_channel channel, const char *signum);
|
||||
LIBSSH_API int channel_request_sftp(ssh_channel channel);
|
||||
LIBSSH_API int channel_request_subsystem(ssh_channel channel, const char *subsystem);
|
||||
LIBSSH_API int channel_request_x11(ssh_channel channel, int single_connection, const char *protocol,
|
||||
const char *cookie, int screen_number);
|
||||
LIBSSH_API int channel_send_eof(ssh_channel channel);
|
||||
LIBSSH_API int channel_select(ssh_channel *readchans, ssh_channel *writechans, ssh_channel *exceptchans, struct
|
||||
timeval * timeout);
|
||||
SSH_SESSION *channel_get_session(CHANNEL *channel);
|
||||
int channel_get_exit_status(CHANNEL *channel);
|
||||
/* in options.c */
|
||||
LIBSSH_API void channel_set_blocking(ssh_channel channel, int blocking);
|
||||
LIBSSH_API int channel_write(ssh_channel channel, const void *data, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief SSH authentication callback.
|
||||
*
|
||||
* @param prompt Prompt to be displayed.
|
||||
* @param buf Buffer to save the password. You should null-terminate it.
|
||||
* @param len Length of the buffer.
|
||||
* @param echo Enable or disable the echo of what you type.
|
||||
* @param verify Should the password be verified?
|
||||
* @param userdata Userdata to be passed to the callback function. Useful
|
||||
* for GUI applications.
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
typedef int (*ssh_auth_callback) (const char *prompt, char *buf, size_t len,
|
||||
int echo, int verify, void *userdata);
|
||||
LIBSSH_API void privatekey_free(ssh_private_key prv);
|
||||
LIBSSH_API ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
|
||||
int type, const char *passphrase);
|
||||
LIBSSH_API void publickey_free(ssh_public_key key);
|
||||
LIBSSH_API ssh_string publickey_from_file(ssh_session session, const char *filename,
|
||||
int *type);
|
||||
LIBSSH_API ssh_public_key publickey_from_privatekey(ssh_private_key prv);
|
||||
LIBSSH_API ssh_string publickey_to_string(ssh_public_key key);
|
||||
|
||||
SSH_OPTIONS *ssh_options_new(void);
|
||||
SSH_OPTIONS *ssh_options_copy(SSH_OPTIONS *opt);
|
||||
void ssh_options_free(SSH_OPTIONS *opt);
|
||||
int ssh_options_set_wanted_algos(SSH_OPTIONS *opt, int algo, const char *list);
|
||||
int ssh_options_set_username(SSH_OPTIONS *opt, const char *username);
|
||||
int ssh_options_set_port(SSH_OPTIONS *opt, unsigned int port);
|
||||
int ssh_options_getopt(SSH_OPTIONS *options, int *argcptr, char **argv);
|
||||
int ssh_options_set_host(SSH_OPTIONS *opt, const char *host);
|
||||
int ssh_options_set_fd(SSH_OPTIONS *opt, socket_t fd);
|
||||
int ssh_options_set_bind(SSH_OPTIONS *opt, const char *bindaddr, int port);
|
||||
int ssh_options_set_ssh_dir(SSH_OPTIONS *opt, const char *dir);
|
||||
int ssh_options_set_known_hosts_file(SSH_OPTIONS *opt, const char *dir);
|
||||
int ssh_options_set_identity(SSH_OPTIONS *opt, const char *identity);
|
||||
int ssh_options_set_banner(SSH_OPTIONS *opt, const char *banner);
|
||||
int ssh_options_set_status_callback(SSH_OPTIONS *opt, void (*callback)
|
||||
(void *arg, float status), void *arg);
|
||||
int ssh_options_set_timeout(SSH_OPTIONS *opt, long seconds, long usec);
|
||||
int ssh_options_allow_ssh1(SSH_OPTIONS *opt, int allow);
|
||||
int ssh_options_allow_ssh2(SSH_OPTIONS *opt, int allow);
|
||||
int ssh_options_set_log_function(SSH_OPTIONS *opt,
|
||||
void (*callback)(const char *message, SSH_SESSION *session, int verbosity));
|
||||
int ssh_options_set_log_verbosity(SSH_OPTIONS *opt, int verbosity);
|
||||
int ssh_options_set_dsa_server_key(SSH_OPTIONS *opt, const char *dsakey);
|
||||
int ssh_options_set_rsa_server_key(SSH_OPTIONS *opt, const char *rsakey);
|
||||
int ssh_options_set_auth_callback(SSH_OPTIONS *opt, ssh_auth_callback cb,
|
||||
void *userdata);
|
||||
LIBSSH_API int ssh_auth_list(ssh_session session);
|
||||
LIBSSH_API char *ssh_basename (const char *path);
|
||||
LIBSSH_API void ssh_clean_pubkey_hash(unsigned char **hash);
|
||||
LIBSSH_API int ssh_connect(ssh_session session);
|
||||
LIBSSH_API const char *ssh_copyright(void);
|
||||
LIBSSH_API void ssh_disconnect(ssh_session session);
|
||||
LIBSSH_API char *ssh_dirname (const char *path);
|
||||
LIBSSH_API int ssh_finalize(void);
|
||||
LIBSSH_API void ssh_free(ssh_session session);
|
||||
LIBSSH_API const char *ssh_get_disconnect_message(ssh_session session);
|
||||
LIBSSH_API const char *ssh_get_error(void *error);
|
||||
LIBSSH_API int ssh_get_error_code(void *error);
|
||||
LIBSSH_API socket_t ssh_get_fd(ssh_session session);
|
||||
LIBSSH_API char *ssh_get_hexa(const unsigned char *what, size_t len);
|
||||
LIBSSH_API char *ssh_get_issue_banner(ssh_session session);
|
||||
LIBSSH_API int ssh_get_openssh_version(ssh_session session);
|
||||
LIBSSH_API ssh_string ssh_get_pubkey(ssh_session session);
|
||||
LIBSSH_API int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash);
|
||||
LIBSSH_API int ssh_get_random(void *where,int len,int strong);
|
||||
LIBSSH_API int ssh_get_version(ssh_session session);
|
||||
LIBSSH_API int ssh_get_status(ssh_session session);
|
||||
LIBSSH_API int ssh_init(void);
|
||||
LIBSSH_API int ssh_is_server_known(ssh_session session);
|
||||
LIBSSH_API void ssh_log(ssh_session session, int prioriry, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
|
||||
LIBSSH_API ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg);
|
||||
LIBSSH_API int ssh_message_channel_request_reply_success(ssh_message msg);
|
||||
LIBSSH_API void ssh_message_free(ssh_message msg);
|
||||
LIBSSH_API ssh_message ssh_message_get(ssh_session session);
|
||||
LIBSSH_API ssh_message ssh_message_retrieve(ssh_session session, uint32_t packettype);
|
||||
LIBSSH_API int ssh_message_subtype(ssh_message msg);
|
||||
LIBSSH_API int ssh_message_type(ssh_message msg);
|
||||
LIBSSH_API int ssh_mkdir (const char *pathname, mode_t mode);
|
||||
LIBSSH_API ssh_session ssh_new(void);
|
||||
|
||||
|
||||
/* buffer.c */
|
||||
|
||||
/** creates a new buffer
|
||||
*/
|
||||
BUFFER *buffer_new(void);
|
||||
void buffer_free(BUFFER *buffer);
|
||||
/* buffer_get returns a pointer to the begining of the buffer. no position is taken into account */
|
||||
void *buffer_get(BUFFER *buffer);
|
||||
/* same here */
|
||||
u32 buffer_get_len(BUFFER *buffer);
|
||||
|
||||
|
||||
/* in auth.c */
|
||||
int ssh_auth_list(SSH_SESSION *session);
|
||||
/* these functions returns AUTH_ERROR is some serious error has happened,
|
||||
AUTH_SUCCESS if success,
|
||||
AUTH_PARTIAL if partial success,
|
||||
AUTH_DENIED if refused */
|
||||
int ssh_userauth_list(SSH_SESSION *session, const char *username);
|
||||
int ssh_userauth_none(SSH_SESSION *session, const char *username);
|
||||
int ssh_userauth_password(SSH_SESSION *session, const char *username, const char *password);
|
||||
int ssh_userauth_offer_pubkey(SSH_SESSION *session, const char *username, int type, STRING *publickey);
|
||||
int ssh_userauth_pubkey(SSH_SESSION *session, const char *username, STRING *publickey, PRIVATE_KEY *privatekey);
|
||||
int ssh_userauth_agent_pubkey(SSH_SESSION *session, const char *username,
|
||||
PUBLIC_KEY *publickey);
|
||||
int ssh_userauth_autopubkey(SSH_SESSION *session, const char *passphrase);
|
||||
int ssh_userauth_kbdint(SSH_SESSION *session, const char *user, const char *submethods);
|
||||
int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session);
|
||||
char *ssh_userauth_kbdint_getname(SSH_SESSION *session);
|
||||
char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session);
|
||||
char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, unsigned int i, char *echo);
|
||||
int ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i,
|
||||
LIBSSH_API int ssh_options_copy(ssh_session src, ssh_session *dest);
|
||||
LIBSSH_API int ssh_options_getopt(ssh_session session, int *argcptr, char **argv);
|
||||
LIBSSH_API int ssh_options_parse_config(ssh_session session, const char *filename);
|
||||
LIBSSH_API int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
||||
const void *value);
|
||||
LIBSSH_API int ssh_pcap_file_close(ssh_pcap_file pcap);
|
||||
LIBSSH_API void ssh_pcap_file_free(ssh_pcap_file pcap);
|
||||
LIBSSH_API ssh_pcap_file ssh_pcap_file_new(void);
|
||||
LIBSSH_API int ssh_pcap_file_open(ssh_pcap_file pcap, const char *filename);
|
||||
LIBSSH_API void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len);
|
||||
LIBSSH_API int ssh_scp_accept_request(ssh_scp scp);
|
||||
LIBSSH_API int ssh_scp_close(ssh_scp scp);
|
||||
LIBSSH_API int ssh_scp_deny_request(ssh_scp scp, const char *reason);
|
||||
LIBSSH_API void ssh_scp_free(ssh_scp scp);
|
||||
LIBSSH_API int ssh_scp_init(ssh_scp scp);
|
||||
LIBSSH_API int ssh_scp_leave_directory(ssh_scp scp);
|
||||
LIBSSH_API ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location);
|
||||
LIBSSH_API int ssh_scp_pull_request(ssh_scp scp);
|
||||
LIBSSH_API int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode);
|
||||
LIBSSH_API int ssh_scp_push_file(ssh_scp scp, const char *filename, size_t size, int perms);
|
||||
LIBSSH_API int ssh_scp_read(ssh_scp scp, void *buffer, size_t size);
|
||||
LIBSSH_API const char *ssh_scp_request_get_filename(ssh_scp scp);
|
||||
LIBSSH_API int ssh_scp_request_get_permissions(ssh_scp scp);
|
||||
LIBSSH_API size_t ssh_scp_request_get_size(ssh_scp scp);
|
||||
LIBSSH_API const char *ssh_scp_request_get_warning(ssh_scp scp);
|
||||
LIBSSH_API int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len);
|
||||
LIBSSH_API int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
||||
fd_set *readfds, struct timeval *timeout);
|
||||
LIBSSH_API int ssh_service_request(ssh_session session, const char *service);
|
||||
LIBSSH_API void ssh_set_blocking(ssh_session session, int blocking);
|
||||
LIBSSH_API void ssh_set_fd_except(ssh_session session);
|
||||
LIBSSH_API void ssh_set_fd_toread(ssh_session session);
|
||||
LIBSSH_API void ssh_set_fd_towrite(ssh_session session);
|
||||
LIBSSH_API void ssh_silent_disconnect(ssh_session session);
|
||||
LIBSSH_API int ssh_set_pcap_file(ssh_session session, ssh_pcap_file pcapfile);
|
||||
#ifndef _WIN32
|
||||
LIBSSH_API int ssh_userauth_agent_pubkey(ssh_session session, const char *username,
|
||||
ssh_public_key publickey);
|
||||
#endif
|
||||
LIBSSH_API int ssh_userauth_autopubkey(ssh_session session, const char *passphrase);
|
||||
LIBSSH_API int ssh_userauth_kbdint(ssh_session session, const char *user, const char *submethods);
|
||||
LIBSSH_API const char *ssh_userauth_kbdint_getinstruction(ssh_session session);
|
||||
LIBSSH_API const char *ssh_userauth_kbdint_getname(ssh_session session);
|
||||
LIBSSH_API int ssh_userauth_kbdint_getnprompts(ssh_session session);
|
||||
LIBSSH_API const char *ssh_userauth_kbdint_getprompt(ssh_session session, unsigned int i, char *echo);
|
||||
LIBSSH_API int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i,
|
||||
const char *answer);
|
||||
LIBSSH_API int ssh_userauth_list(ssh_session session, const char *username);
|
||||
LIBSSH_API int ssh_userauth_none(ssh_session session, const char *username);
|
||||
LIBSSH_API int ssh_userauth_offer_pubkey(ssh_session session, const char *username, int type, ssh_string publickey);
|
||||
LIBSSH_API int ssh_userauth_password(ssh_session session, const char *username, const char *password);
|
||||
LIBSSH_API int ssh_userauth_pubkey(ssh_session session, const char *username, ssh_string publickey, ssh_private_key privatekey);
|
||||
LIBSSH_API const char *ssh_version(int req_version);
|
||||
LIBSSH_API int ssh_write_knownhost(ssh_session session);
|
||||
|
||||
LIBSSH_API void string_burn(ssh_string str);
|
||||
LIBSSH_API ssh_string string_copy(ssh_string str);
|
||||
LIBSSH_API void *string_data(ssh_string str);
|
||||
LIBSSH_API int string_fill(ssh_string str, const void *data, size_t len);
|
||||
LIBSSH_API void string_free(ssh_string str);
|
||||
LIBSSH_API ssh_string string_from_char(const char *what);
|
||||
LIBSSH_API size_t string_len(ssh_string str);
|
||||
LIBSSH_API ssh_string string_new(size_t size);
|
||||
LIBSSH_API char *string_to_char(ssh_string str);
|
||||
|
||||
/* init.c */
|
||||
int ssh_finalize(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
84
include/libssh/messages.h
Normal file
84
include/libssh/messages.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef MESSAGES_H_
|
||||
#define MESSAGES_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
struct ssh_auth_request {
|
||||
char *username;
|
||||
int method;
|
||||
char *password;
|
||||
struct ssh_public_key_struct *public_key;
|
||||
char signature_state;
|
||||
};
|
||||
|
||||
struct ssh_channel_request_open {
|
||||
int type;
|
||||
uint32_t sender;
|
||||
uint32_t window;
|
||||
uint32_t packet_size;
|
||||
char *originator;
|
||||
uint16_t originator_port;
|
||||
char *destination;
|
||||
uint16_t destination_port;
|
||||
};
|
||||
|
||||
struct ssh_service_request {
|
||||
char *service;
|
||||
};
|
||||
|
||||
struct ssh_channel_request {
|
||||
int type;
|
||||
ssh_channel channel;
|
||||
uint8_t want_reply;
|
||||
/* pty-req type specifics */
|
||||
char *TERM;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t pxwidth;
|
||||
uint32_t pxheight;
|
||||
ssh_string modes;
|
||||
|
||||
/* env type request */
|
||||
char *var_name;
|
||||
char *var_value;
|
||||
/* exec type request */
|
||||
char *command;
|
||||
/* subsystem */
|
||||
char *subsystem;
|
||||
};
|
||||
|
||||
struct ssh_message_struct {
|
||||
ssh_session session;
|
||||
int type;
|
||||
struct ssh_auth_request auth_request;
|
||||
struct ssh_channel_request_open channel_request_open;
|
||||
struct ssh_channel_request channel_request;
|
||||
struct ssh_service_request service_request;
|
||||
};
|
||||
|
||||
|
||||
void message_handle(ssh_session session, uint32_t type);
|
||||
int ssh_execute_message_callbacks(ssh_session session);
|
||||
|
||||
#endif /* MESSAGES_H_ */
|
||||
69
include/libssh/misc.h
Normal file
69
include/libssh/misc.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef MISC_H_
|
||||
#define MISC_H_
|
||||
|
||||
/* in misc.c */
|
||||
/* gets the user home dir. */
|
||||
char *ssh_get_user_home_dir(void);
|
||||
int ssh_file_readaccess_ok(const char *file);
|
||||
|
||||
/* macro for byte ordering */
|
||||
uint64_t ntohll(uint64_t);
|
||||
#define htonll(x) ntohll(x)
|
||||
|
||||
/* list processing */
|
||||
|
||||
struct ssh_list {
|
||||
struct ssh_iterator *root;
|
||||
struct ssh_iterator *end;
|
||||
};
|
||||
|
||||
struct ssh_iterator {
|
||||
struct ssh_iterator *next;
|
||||
const void *data;
|
||||
};
|
||||
|
||||
struct ssh_list *ssh_list_new(void);
|
||||
void ssh_list_free(struct ssh_list *list);
|
||||
struct ssh_iterator *ssh_list_get_iterator(const struct ssh_list *list);
|
||||
int ssh_list_add(struct ssh_list *list, const void *data);
|
||||
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator);
|
||||
|
||||
/** @brief fetch the head element of a list and remove it from list
|
||||
* @param list the ssh_list to use
|
||||
* @return the first element of the list
|
||||
*/
|
||||
const void *_ssh_list_get_head(struct ssh_list *list);
|
||||
|
||||
#define ssh_iterator_value(type, iterator)\
|
||||
((type)((iterator)->data))
|
||||
|
||||
/** @brief fetch the head element of a list and remove it from list
|
||||
* @param type type of the element to return
|
||||
* @param list the ssh_list to use
|
||||
* @return the first element of the list
|
||||
*/
|
||||
#define ssh_list_get_head(type, ssh_list)\
|
||||
((type)_ssh_list_get_head(ssh_list))
|
||||
|
||||
#endif /* MISC_H_ */
|
||||
41
include/libssh/packet.h
Normal file
41
include/libssh/packet.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef PACKET_H_
|
||||
#define PACKET_H_
|
||||
|
||||
/* this structure should go someday */
|
||||
typedef struct packet_struct {
|
||||
int valid;
|
||||
uint32_t len;
|
||||
uint8_t type;
|
||||
} PACKET;
|
||||
|
||||
void packet_parse(ssh_session session);
|
||||
int packet_send(ssh_session session);
|
||||
|
||||
int packet_read(ssh_session session);
|
||||
int packet_translate(ssh_session session);
|
||||
int packet_wait(ssh_session session,int type,int blocking);
|
||||
int packet_flush(ssh_session session, int enforce_blocking);
|
||||
|
||||
|
||||
#endif /* PACKET_H_ */
|
||||
26
include/libssh/pcap.h
Normal file
26
include/libssh/pcap.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef PCAP_H_
|
||||
#define PCAP_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/libssh.h"
|
||||
|
||||
#ifdef WITH_PCAP
|
||||
typedef struct ssh_pcap_context_struct* ssh_pcap_context;
|
||||
|
||||
int ssh_pcap_file_write_packet(ssh_pcap_file pcap, ssh_buffer packet, uint32_t original_len);
|
||||
|
||||
ssh_pcap_context ssh_pcap_context_new(ssh_session session);
|
||||
void ssh_pcap_context_free(ssh_pcap_context ctx);
|
||||
|
||||
enum ssh_pcap_direction{
|
||||
SSH_PCAP_DIR_IN,
|
||||
SSH_PCAP_DIR_OUT
|
||||
};
|
||||
void ssh_pcap_context_set_file(ssh_pcap_context, ssh_pcap_file);
|
||||
int ssh_pcap_context_write(ssh_pcap_context,enum ssh_pcap_direction direction, void *data,
|
||||
uint32_t len, uint32_t origlen);
|
||||
|
||||
|
||||
#endif /* WITH_PCAP */
|
||||
#endif /* PCAP_H_ */
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
102
include/libssh/poll.h
Normal file
102
include/libssh/poll.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef POLL_H_
|
||||
#define POLL_H_
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
|
||||
#include <poll.h>
|
||||
typedef struct pollfd ssh_pollfd_t;
|
||||
|
||||
#else /* HAVE_POLL */
|
||||
|
||||
/* poll emulation support */
|
||||
|
||||
typedef struct ssh_pollfd_struct {
|
||||
socket_t fd; /* file descriptor */
|
||||
short events; /* requested events */
|
||||
short revents; /* returned events */
|
||||
} ssh_pollfd_t;
|
||||
|
||||
/* poll.c */
|
||||
#ifndef POLLIN
|
||||
# define POLLIN 0x001 /* There is data to read. */
|
||||
#endif
|
||||
#ifndef POLLPRI
|
||||
#define POLLPRI 0x002 /* There is urgent data to read. */
|
||||
#endif
|
||||
#ifndef POLLOUT
|
||||
#define POLLOUT 0x004 /* Writing now will not block. */
|
||||
#endif
|
||||
|
||||
#ifndef POLLERR
|
||||
#define POLLERR 0x008 /* Error condition. */
|
||||
#endif
|
||||
#ifndef POLLHUP
|
||||
#define POLLHUP 0x010 /* Hung up. */
|
||||
#endif
|
||||
#ifndef POLLNVAL
|
||||
#define POLLNVAL 0x020 /* Invalid polling request. */
|
||||
#endif
|
||||
|
||||
typedef unsigned long int nfds_t;
|
||||
#endif /* HAVE_POLL */
|
||||
|
||||
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout);
|
||||
typedef struct ssh_poll_ctx_struct *ssh_poll_ctx;
|
||||
typedef struct ssh_poll_handle_struct *ssh_poll_handle;
|
||||
|
||||
/**
|
||||
* @brief SSH poll callback.
|
||||
*
|
||||
* @param p Poll object this callback belongs to.
|
||||
* @param fd The raw socket.
|
||||
* @param revents The current poll events on the socket.
|
||||
* @param userdata Userdata to be passed to the callback function.
|
||||
*
|
||||
* @return 0 on success, < 0 if you removed the poll object from
|
||||
* it's poll context.
|
||||
*/
|
||||
typedef int (*ssh_poll_callback)(ssh_poll_handle p, int fd, int revents,
|
||||
void *userdata);
|
||||
|
||||
|
||||
ssh_poll_handle ssh_poll_new(socket_t fd, short events, ssh_poll_callback cb,
|
||||
void *userdata);
|
||||
void ssh_poll_free(ssh_poll_handle p);
|
||||
ssh_poll_ctx ssh_poll_get_ctx(ssh_poll_handle p);
|
||||
short ssh_poll_get_events(ssh_poll_handle p);
|
||||
void ssh_poll_set_events(ssh_poll_handle p, short events);
|
||||
void ssh_poll_add_events(ssh_poll_handle p, short events);
|
||||
void ssh_poll_remove_events(ssh_poll_handle p, short events);
|
||||
socket_t ssh_poll_get_fd(ssh_poll_handle p);
|
||||
void ssh_poll_set_callback(ssh_poll_handle p, ssh_poll_callback cb, void *userdata);
|
||||
ssh_poll_ctx ssh_poll_ctx_new(size_t chunk_size);
|
||||
void ssh_poll_ctx_free(ssh_poll_ctx ctx);
|
||||
int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p);
|
||||
void ssh_poll_ctx_remove(ssh_poll_ctx ctx, ssh_poll_handle p);
|
||||
int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout);
|
||||
|
||||
|
||||
|
||||
#endif /* POLL_H_ */
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
@@ -29,15 +29,25 @@
|
||||
|
||||
#ifndef _LIBSSH_PRIV_H
|
||||
#define _LIBSSH_PRIV_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
/** Imitate define of inttypes.h */
|
||||
#define PRIdS "Id"
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#define strtoull _strtoui64
|
||||
#define isblank(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r')
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#define PRIdS "zd"
|
||||
#endif
|
||||
|
||||
#include "libssh/libssh.h"
|
||||
|
||||
/* Debugging constants */
|
||||
|
||||
/* Define this if you want to debug crypto systems */
|
||||
/* it's usefull when you are debugging the lib */
|
||||
/*#define DEBUG_CRYPTO */
|
||||
|
||||
#include "libssh/callbacks.h"
|
||||
#include "libssh/crypto.h"
|
||||
/* some constants */
|
||||
#define MAX_PACKET_LEN 262144
|
||||
#define ERROR_BUFFERLEN 1024
|
||||
@@ -45,680 +55,147 @@
|
||||
#define CLIENTBANNER2 "SSH-2.0-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
|
||||
#define KBDINT_MAX_PROMPT 256 /* more than openssh's :) */
|
||||
/* some types for public keys */
|
||||
#define TYPE_DSS 1
|
||||
#define TYPE_RSA 2
|
||||
#define TYPE_RSA1 3
|
||||
|
||||
/* profiling constants. Don't touch them unless you know what you do */
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
#define OPENSSL_BIGNUMS
|
||||
#endif
|
||||
enum public_key_types_e{
|
||||
TYPE_DSS=1,
|
||||
TYPE_RSA,
|
||||
TYPE_RSA1
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* wrapper things */
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#include <gcrypt.h>
|
||||
typedef gcry_md_hd_t SHACTX;
|
||||
typedef gcry_md_hd_t MD5CTX;
|
||||
typedef gcry_md_hd_t HMACCTX;
|
||||
#ifdef MD5_DIGEST_LEN
|
||||
#undef MD5_DIGEST_LEN
|
||||
#endif
|
||||
#define SHA_DIGEST_LEN 20
|
||||
#define MD5_DIGEST_LEN 16
|
||||
#define EVP_MAX_MD_SIZE 36
|
||||
|
||||
typedef gcry_mpi_t bignum;
|
||||
|
||||
#define bignum_new() gcry_mpi_new(0)
|
||||
#define bignum_free(num) gcry_mpi_release(num)
|
||||
#define bignum_set_word(bn,n) gcry_mpi_set_ui(bn,n)
|
||||
#define bignum_bin2bn(bn,datalen,data) gcry_mpi_scan(data,GCRYMPI_FMT_USG,bn,datalen,NULL)
|
||||
#define bignum_bn2dec(num) my_gcry_bn2dec(num)
|
||||
#define bignum_dec2bn(num, data) my_gcry_dec2bn(data, num)
|
||||
#define bignum_bn2hex(num,data) gcry_mpi_aprint(GCRYMPI_FMT_HEX,data,NULL,num)
|
||||
#define bignum_hex2bn(num,datalen,data) gcry_mpi_scan(num,GCRYMPI_FMT_HEX,data,datalen,NULL)
|
||||
#define bignum_rand(num,bits) gcry_mpi_randomize(num,bits,GCRY_STRONG_RANDOM),gcry_mpi_set_bit(num,bits-1),gcry_mpi_set_bit(num,0)
|
||||
#define bignum_mod_exp(dest,generator,exp,modulo) gcry_mpi_powm(dest,generator,exp,modulo)
|
||||
#define bignum_num_bits(num) gcry_mpi_get_nbits(num)
|
||||
#define bignum_num_bytes(num) ((gcry_mpi_get_nbits(num)+7)/8)
|
||||
#define bignum_is_bit_set(num,bit) gcry_mpi_test_bit(num,bit)
|
||||
#define bignum_bn2bin(num,datalen,data) gcry_mpi_print(GCRYMPI_FMT_USG,data,datalen,NULL,num)
|
||||
#define bignum_cmp(num1,num2) gcry_mpi_cmp(num1,num2)
|
||||
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/hmac.h>
|
||||
typedef SHA_CTX* SHACTX;
|
||||
typedef MD5_CTX* MD5CTX;
|
||||
typedef HMAC_CTX* HMACCTX;
|
||||
#ifdef MD5_DIGEST_LEN
|
||||
#undef MD5_DIGEST_LEN
|
||||
#endif
|
||||
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
|
||||
#define MD5_DIGEST_LEN MD5_DIGEST_LENGTH
|
||||
|
||||
#endif /* OPENSSL_CRYPTO */
|
||||
#ifdef OPENSSL_BIGNUMS
|
||||
#include <openssl/bn.h>
|
||||
typedef BIGNUM* bignum;
|
||||
typedef BN_CTX* bignum_CTX;
|
||||
|
||||
#define bignum_new() BN_new()
|
||||
#define bignum_free(num) BN_clear_free(num)
|
||||
#define bignum_set_word(bn,n) BN_set_word(bn,n)
|
||||
#define bignum_bin2bn(bn,datalen,data) BN_bin2bn(bn,datalen,data)
|
||||
#define bignum_bn2dec(num) BN_bn2dec(num)
|
||||
#define bignum_dec2bn(bn,data) BN_dec2bn(data,bn)
|
||||
#define bignum_bn2hex(num) BN_bn2hex(num)
|
||||
#define bignum_rand(rnd, bits, top, bottom) BN_rand(rnd,bits,top,bottom)
|
||||
#define bignum_ctx_new() BN_CTX_new()
|
||||
#define bignum_ctx_free(num) BN_CTX_free(num)
|
||||
#define bignum_mod_exp(dest,generator,exp,modulo,ctx) BN_mod_exp(dest,generator,exp,modulo,ctx)
|
||||
#define bignum_num_bytes(num) BN_num_bytes(num)
|
||||
#define bignum_num_bits(num) BN_num_bits(num)
|
||||
#define bignum_is_bit_set(num,bit) BN_is_bit_set(num,bit)
|
||||
#define bignum_bn2bin(num,ptr) BN_bn2bin(num,ptr)
|
||||
#define bignum_cmp(num1,num2) BN_cmp(num1,num2)
|
||||
|
||||
#endif /* OPENSSL_BIGNUMS */
|
||||
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
/* poll support */
|
||||
#ifdef HAVE_POLL
|
||||
#include <poll.h>
|
||||
typedef struct pollfd pollfd_t;
|
||||
#else /* HAVE_POLL */
|
||||
typedef struct pollfd_s {
|
||||
socket_t fd; /* file descriptor */
|
||||
short events; /* requested events */
|
||||
short revents; /* returned events */
|
||||
} pollfd_t;
|
||||
|
||||
#define POLLIN 0x001 /* There is data to read. */
|
||||
#define POLLPRI 0x002 /* There is urgent data to read. */
|
||||
#define POLLOUT 0x004 /* Writing now will not block. */
|
||||
|
||||
#define POLLERR 0x008 /* Error condition. */
|
||||
#define POLLHUP 0x010 /* Hung up. */
|
||||
#define POLLNVAL 0x020 /* Invalid polling request. */
|
||||
|
||||
typedef unsigned long int nfds_t;
|
||||
#endif /* HAVE_POLL */
|
||||
|
||||
/* wrapper.c */
|
||||
MD5CTX md5_init(void);
|
||||
void md5_update(MD5CTX c, const void *data, unsigned long len);
|
||||
void md5_final(unsigned char *md,MD5CTX c);
|
||||
SHACTX sha1_init(void);
|
||||
void sha1_update(SHACTX c, const void *data, unsigned long len);
|
||||
void sha1_final(unsigned char *md,SHACTX c);
|
||||
void sha1(unsigned char *digest,int len,unsigned char *hash);
|
||||
#define HMAC_SHA1 1
|
||||
#define HMAC_MD5 2
|
||||
HMACCTX hmac_init(const void *key,int len,int type);
|
||||
void hmac_update(HMACCTX c, const void *data, unsigned long len);
|
||||
void hmac_final(HMACCTX ctx,unsigned char *hashmacbuf,unsigned int *len);
|
||||
|
||||
/* strings and buffers */
|
||||
/* must be 32 bits number + immediatly our data */
|
||||
struct string_struct {
|
||||
u32 size;
|
||||
unsigned char string[MAX_PACKET_LEN];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/** Describes a buffer state at a moment
|
||||
*/
|
||||
struct buffer_struct {
|
||||
char *data;
|
||||
u32 used;
|
||||
u32 allocated;
|
||||
u32 pos;
|
||||
};
|
||||
|
||||
/* i should remove it one day */
|
||||
typedef struct packet_struct {
|
||||
int valid;
|
||||
u32 len;
|
||||
u8 type;
|
||||
} PACKET;
|
||||
|
||||
typedef struct kex_struct {
|
||||
unsigned char cookie[16];
|
||||
char **methods;
|
||||
} KEX;
|
||||
|
||||
struct public_key_struct {
|
||||
int type;
|
||||
const char *type_c; /* Don't free it ! it is static */
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_t dsa_pub;
|
||||
gcry_sexp_t rsa_pub;
|
||||
#elif HAVE_LIBCRYPTO
|
||||
DSA *dsa_pub;
|
||||
RSA *rsa_pub;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct private_key_struct {
|
||||
int type;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_t dsa_priv;
|
||||
gcry_sexp_t rsa_priv;
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
DSA *dsa_priv;
|
||||
RSA *rsa_priv;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct signature_struct {
|
||||
int type;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_t dsa_sign;
|
||||
gcry_sexp_t rsa_sign;
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
DSA_SIG *dsa_sign;
|
||||
STRING *rsa_sign;
|
||||
#endif
|
||||
} SIGNATURE;
|
||||
|
||||
|
||||
struct error_struct {
|
||||
/* error handling */
|
||||
int error_code;
|
||||
unsigned int error_code;
|
||||
char error_buffer[ERROR_BUFFERLEN];
|
||||
};
|
||||
|
||||
struct ssh_options_struct {
|
||||
struct error_struct error;
|
||||
char *banner; /* explicit banner to send */
|
||||
char *username;
|
||||
char *host;
|
||||
char *bindaddr;
|
||||
int bindport;
|
||||
char *identity;
|
||||
char *ssh_dir;
|
||||
char *known_hosts_file;
|
||||
socket_t fd; /* specificaly wanted file descriptor, don't connect host */
|
||||
int port;
|
||||
int dont_verify_hostkey; /* Don't spare time, don't check host key ! unneeded to say it's dangerous and not safe */
|
||||
int use_nonexisting_algo; /* if user sets a not supported algorithm for kex, don't complain */
|
||||
char *wanted_methods[10]; /* the kex methods can be choosed. better use the kex fonctions to do that */
|
||||
void *wanted_cookie; /* wants a specific cookie to be sent ? if null, generate a new one */
|
||||
ssh_auth_callback auth_function; /* this functions will be called if e.g. a keyphrase is needed. */
|
||||
void *auth_userdata;
|
||||
void (*connect_status_function)(void *arg, float status); /* status callback function */
|
||||
void *connect_status_arg; /* arbitrary argument */
|
||||
long timeout; /* seconds */
|
||||
long timeout_usec;
|
||||
int ssh2allowed;
|
||||
int ssh1allowed;
|
||||
char *dsakey;
|
||||
char *rsakey; /* host key for server implementation */
|
||||
int log_verbosity;
|
||||
void (*log_function)(const char *message, SSH_SESSION *session, int verbosity); //log callback
|
||||
};
|
||||
/* TODO: remove that include */
|
||||
#include "libssh/wrapper.h"
|
||||
|
||||
typedef struct ssh_crypto_struct {
|
||||
bignum e,f,x,k,y;
|
||||
unsigned char session_id[SHA_DIGEST_LEN];
|
||||
|
||||
unsigned char encryptIV[SHA_DIGEST_LEN*2];
|
||||
unsigned char decryptIV[SHA_DIGEST_LEN*2];
|
||||
|
||||
unsigned char decryptkey[SHA_DIGEST_LEN*2];
|
||||
unsigned char encryptkey[SHA_DIGEST_LEN*2];
|
||||
|
||||
unsigned char encryptMAC[SHA_DIGEST_LEN];
|
||||
unsigned char decryptMAC[SHA_DIGEST_LEN];
|
||||
unsigned char hmacbuf[EVP_MAX_MD_SIZE];
|
||||
struct crypto_struct *in_cipher, *out_cipher; /* the cipher structures/objects */
|
||||
STRING *server_pubkey;
|
||||
const char *server_pubkey_type;
|
||||
int do_compress_out; /* idem */
|
||||
int do_compress_in; /* don't set them, set the option instead */
|
||||
void *compress_out_ctx; /* don't touch it */
|
||||
void *compress_in_ctx; /* really, don't */
|
||||
} CRYPTO;
|
||||
|
||||
struct channel_struct {
|
||||
struct channel_struct *prev;
|
||||
struct channel_struct *next;
|
||||
SSH_SESSION *session; /* SSH_SESSION pointer */
|
||||
u32 local_channel;
|
||||
u32 local_window;
|
||||
int local_eof;
|
||||
u32 local_maxpacket;
|
||||
|
||||
u32 remote_channel;
|
||||
u32 remote_window;
|
||||
int remote_eof; /* end of file received */
|
||||
u32 remote_maxpacket;
|
||||
int open; /* shows if the channel is still opened */
|
||||
int delayed_close;
|
||||
BUFFER *stdout_buffer;
|
||||
BUFFER *stderr_buffer;
|
||||
void *userarg;
|
||||
int version;
|
||||
int blocking;
|
||||
int exit_status;
|
||||
};
|
||||
|
||||
struct agent_struct {
|
||||
struct socket *sock;
|
||||
BUFFER *ident;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
struct keys_struct {
|
||||
struct ssh_keys_struct {
|
||||
const char *privatekey;
|
||||
const char *publickey;
|
||||
};
|
||||
|
||||
struct ssh_session {
|
||||
struct error_struct error;
|
||||
struct socket *socket;
|
||||
SSH_OPTIONS *options;
|
||||
char *serverbanner;
|
||||
char *clientbanner;
|
||||
int protoversion;
|
||||
int server;
|
||||
int client;
|
||||
u32 send_seq;
|
||||
u32 recv_seq;
|
||||
/* status flags */
|
||||
int closed;
|
||||
int closed_by_except;
|
||||
struct ssh_message_struct;
|
||||
|
||||
int connected;
|
||||
/* !=0 when the user got a session handle */
|
||||
int alive;
|
||||
/* two previous are deprecated */
|
||||
int auth_service_asked;
|
||||
|
||||
/* socket status */
|
||||
int blocking; // functions should block
|
||||
|
||||
STRING *banner; /* that's the issue banner from
|
||||
the server */
|
||||
char *remotebanner; /* that's the SSH- banner from
|
||||
remote host. */
|
||||
char *discon_msg; /* disconnect message from
|
||||
the remote host */
|
||||
BUFFER *in_buffer;
|
||||
PACKET in_packet;
|
||||
BUFFER *out_buffer;
|
||||
|
||||
/* the states are used by the nonblocking stuff to remember */
|
||||
/* where it was before being interrupted */
|
||||
int packet_state;
|
||||
int dh_handshake_state;
|
||||
STRING *dh_server_signature; //information used by dh_handshake.
|
||||
|
||||
KEX server_kex;
|
||||
KEX client_kex;
|
||||
BUFFER *in_hashbuf;
|
||||
BUFFER *out_hashbuf;
|
||||
CRYPTO *current_crypto;
|
||||
CRYPTO *next_crypto; /* next_crypto is going to be used after a SSH2_MSG_NEWKEYS */
|
||||
|
||||
CHANNEL *channels; /* linked list of channels */
|
||||
int maxchannel;
|
||||
int exec_channel_opened; /* version 1 only. more
|
||||
info in channels1.c */
|
||||
AGENT *agent; /* ssh agent */
|
||||
|
||||
/* keyb interactive data */
|
||||
struct ssh_kbdint *kbdint;
|
||||
int version; /* 1 or 2 */
|
||||
/* server host keys */
|
||||
PRIVATE_KEY *rsa_key;
|
||||
PRIVATE_KEY *dsa_key;
|
||||
/* auths accepted by server */
|
||||
int auth_methods;
|
||||
int hostkeys; /* contains type of host key wanted by client, in server impl */
|
||||
struct ssh_message *ssh_message; /* ssh message */
|
||||
int log_verbosity; /*cached copy of the option structure */
|
||||
int log_indent; /* indentation level in enter_function logs */
|
||||
};
|
||||
|
||||
struct ssh_kbdint {
|
||||
u32 nprompts;
|
||||
char *name;
|
||||
char *instruction;
|
||||
char **prompts;
|
||||
unsigned char *echo; /* bool array */
|
||||
char **answers;
|
||||
};
|
||||
|
||||
/* server data */
|
||||
|
||||
struct ssh_bind_struct {
|
||||
struct error_struct error;
|
||||
socket_t bindfd;
|
||||
SSH_OPTIONS *options;
|
||||
int blocking;
|
||||
int toaccept;
|
||||
struct error_struct error;
|
||||
|
||||
ssh_callbacks callbacks; /* Callbacks to user functions */
|
||||
|
||||
/* options */
|
||||
char *wanted_methods[10];
|
||||
char *banner;
|
||||
char *dsakey;
|
||||
char *rsakey;
|
||||
char *bindaddr;
|
||||
socket_t bindfd;
|
||||
unsigned int bindport;
|
||||
unsigned int log_verbosity;
|
||||
|
||||
int blocking;
|
||||
int toaccept;
|
||||
};
|
||||
|
||||
struct ssh_auth_request {
|
||||
char *username;
|
||||
int method;
|
||||
char *password;
|
||||
};
|
||||
|
||||
struct ssh_channel_request_open {
|
||||
int type;
|
||||
u32 sender;
|
||||
u32 window;
|
||||
u32 packet_size;
|
||||
char *originator;
|
||||
u16 orignator_port;
|
||||
char *destination;
|
||||
u16 destination_port;
|
||||
};
|
||||
|
||||
struct ssh_channel_request {
|
||||
int type;
|
||||
CHANNEL *channel;
|
||||
u8 want_reply;
|
||||
/* pty-req type specifics */
|
||||
char *TERM;
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 pxwidth;
|
||||
u32 pxheight;
|
||||
STRING *modes;
|
||||
|
||||
/* env type request */
|
||||
char *var_name;
|
||||
char *var_value;
|
||||
/* exec type request */
|
||||
char *command;
|
||||
/* subsystem */
|
||||
char *subsystem;
|
||||
};
|
||||
|
||||
struct ssh_message {
|
||||
SSH_SESSION *session;
|
||||
int type;
|
||||
struct ssh_auth_request auth_request;
|
||||
struct ssh_channel_request_open channel_request_open;
|
||||
struct ssh_channel_request channel_request;
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
/* agent.c */
|
||||
/**
|
||||
* @brief Create a new ssh agent structure.
|
||||
*
|
||||
* @return An allocated ssh agent structure or NULL on error.
|
||||
*/
|
||||
struct agent_struct *agent_new(struct ssh_session *session);
|
||||
|
||||
void agent_close(struct agent_struct *agent);
|
||||
|
||||
/**
|
||||
* @brief Free an allocated ssh agent structure.
|
||||
*
|
||||
* @param agent The ssh agent structure to free.
|
||||
*/
|
||||
void agent_free(struct agent_struct *agent);
|
||||
|
||||
/**
|
||||
* @brief Check if the ssh agent is running.
|
||||
*
|
||||
* @param session The ssh session to check for the agent.
|
||||
*
|
||||
* @return 1 if it is running, 0 if not.
|
||||
*/
|
||||
int agent_is_running(struct ssh_session *session);
|
||||
|
||||
int agent_get_ident_count(struct ssh_session *session);
|
||||
|
||||
struct public_key_struct *agent_get_next_ident(struct ssh_session *session,
|
||||
char **comment);
|
||||
|
||||
struct public_key_struct *agent_get_first_ident(struct ssh_session *session,
|
||||
char **comment);
|
||||
|
||||
STRING *agent_sign_data(struct ssh_session *session,
|
||||
struct buffer_struct *data,
|
||||
struct public_key_struct *pubkey);
|
||||
#endif
|
||||
|
||||
/* poll.c */
|
||||
int ssh_poll(pollfd_t *fds, nfds_t nfds, int timeout);
|
||||
|
||||
/* socket.c */
|
||||
|
||||
struct socket;
|
||||
int ssh_socket_init(void);
|
||||
struct socket *ssh_socket_new(SSH_SESSION *session);
|
||||
void ssh_socket_free(struct socket *s);
|
||||
void ssh_socket_set_fd(struct socket *s, socket_t fd);
|
||||
socket_t ssh_socket_get_fd(struct socket *s);
|
||||
#ifndef _WIN32
|
||||
int ssh_socket_unix(struct socket *s, const char *path);
|
||||
#endif
|
||||
void ssh_socket_close(struct socket *s);
|
||||
int ssh_socket_read(struct socket *s, void *buffer, int len);
|
||||
int ssh_socket_write(struct socket *s,const void *buffer, int len);
|
||||
int ssh_socket_is_open(struct socket *s);
|
||||
int ssh_socket_fd_isset(struct socket *s, fd_set *set);
|
||||
void ssh_socket_fd_set(struct socket *s, fd_set *set, int *fd_max);
|
||||
int ssh_socket_completeread(struct socket *s, void *buffer, u32 len);
|
||||
int ssh_socket_completewrite(struct socket *s, const void *buffer, u32 len);
|
||||
int ssh_socket_wait_for_data(struct socket *s, SSH_SESSION *session, u32 len);
|
||||
int ssh_socket_nonblocking_flush(struct socket *s);
|
||||
int ssh_socket_blocking_flush(struct socket *s);
|
||||
int ssh_socket_poll(struct socket *s, int *writeable, int *except);
|
||||
void ssh_socket_set_towrite(struct socket *s);
|
||||
void ssh_socket_set_toread(struct socket *s);
|
||||
void ssh_socket_set_except(struct socket *s);
|
||||
int ssh_socket_get_status(struct socket *s);
|
||||
int ssh_socket_data_available(struct socket *s);
|
||||
int ssh_socket_data_writable(struct socket *s);
|
||||
/* session.c */
|
||||
|
||||
void ssh_cleanup(SSH_SESSION *session);
|
||||
|
||||
/* client.c */
|
||||
|
||||
int ssh_send_banner(SSH_SESSION *session, int is_server);
|
||||
char *ssh_get_banner(SSH_SESSION *session);
|
||||
int ssh_send_banner(ssh_session session, int is_server);
|
||||
char *ssh_get_banner(ssh_session session);
|
||||
|
||||
/* config.c */
|
||||
int ssh_config_parse_file(ssh_session session, const char *filename);
|
||||
|
||||
/* errors.c */
|
||||
void ssh_set_error(void *error, int code, const char *descr, ...) PRINTF_ATTRIBUTE(3, 4);
|
||||
|
||||
/* in dh.c */
|
||||
/* DH key generation */
|
||||
void ssh_print_bignum(const char *which,bignum num);
|
||||
int dh_generate_e(SSH_SESSION *session);
|
||||
int dh_generate_f(SSH_SESSION *session);
|
||||
int dh_generate_x(SSH_SESSION *session);
|
||||
int dh_generate_y(SSH_SESSION *session);
|
||||
|
||||
int ssh_crypto_init(void);
|
||||
void ssh_crypto_finalize(void);
|
||||
|
||||
STRING *dh_get_e(SSH_SESSION *session);
|
||||
STRING *dh_get_f(SSH_SESSION *session);
|
||||
int dh_import_f(SSH_SESSION *session,STRING *f_string);
|
||||
int dh_import_e(SSH_SESSION *session, STRING *e_string);
|
||||
void dh_import_pubkey(SSH_SESSION *session,STRING *pubkey_string);
|
||||
int dh_build_k(SSH_SESSION *session);
|
||||
int make_sessionid(SSH_SESSION *session);
|
||||
/* add data for the final cookie */
|
||||
int hashbufin_add_cookie(SSH_SESSION *session, unsigned char *cookie);
|
||||
int hashbufout_add_cookie(SSH_SESSION *session);
|
||||
int generate_session_keys(SSH_SESSION *session);
|
||||
/* returns 1 if server signature ok, 0 otherwise. The NEXT crypto is checked, not the current one */
|
||||
int signature_verify(SSH_SESSION *session,STRING *signature);
|
||||
bignum make_string_bn(STRING *string);
|
||||
STRING *make_bignum_string(bignum num);
|
||||
void ssh_set_error_oom(void *);
|
||||
void ssh_set_error_invalid(void *, const char *);
|
||||
|
||||
/* in crypt.c */
|
||||
u32 packet_decrypt_len(SSH_SESSION *session,char *crypted);
|
||||
int packet_decrypt(SSH_SESSION *session, void *packet,unsigned int len);
|
||||
unsigned char *packet_encrypt(SSH_SESSION *session,void *packet,unsigned int len);
|
||||
uint32_t packet_decrypt_len(ssh_session session,char *crypted);
|
||||
int packet_decrypt(ssh_session session, void *packet,unsigned int len);
|
||||
unsigned char *packet_encrypt(ssh_session session,void *packet,unsigned int len);
|
||||
/* it returns the hmac buffer if exists*/
|
||||
int packet_hmac_verify(SSH_SESSION *session,BUFFER *buffer,unsigned char *mac);
|
||||
int packet_hmac_verify(ssh_session session,ssh_buffer buffer,unsigned char *mac);
|
||||
|
||||
/* in packet.c */
|
||||
|
||||
void packet_parse(SSH_SESSION *session);
|
||||
int packet_send(SSH_SESSION *session);
|
||||
|
||||
int packet_read(SSH_SESSION *session);
|
||||
int packet_translate(SSH_SESSION *session);
|
||||
int packet_wait(SSH_SESSION *session,int type,int blocking);
|
||||
int packet_flush(SSH_SESSION *session, int enforce_blocking);
|
||||
/* connect.c */
|
||||
SSH_SESSION *ssh_session_new();
|
||||
socket_t ssh_connect_host(SSH_SESSION *session, const char *host,const char
|
||||
int ssh_regex_init(void);
|
||||
void ssh_regex_finalize(void);
|
||||
ssh_session ssh_session_new(void);
|
||||
socket_t ssh_connect_host(ssh_session session, const char *host,const char
|
||||
*bind_addr, int port, long timeout, long usec);
|
||||
|
||||
/* in kex.c */
|
||||
extern const char *ssh_kex_nums[];
|
||||
int ssh_send_kex(SSH_SESSION *session, int server_kex);
|
||||
void ssh_list_kex(SSH_SESSION *session, KEX *kex);
|
||||
int set_kex(SSH_SESSION *session);
|
||||
int ssh_get_kex(SSH_SESSION *session, int server_kex);
|
||||
int ssh_send_kex(ssh_session session, int server_kex);
|
||||
void ssh_list_kex(ssh_session session, KEX *kex);
|
||||
int set_kex(ssh_session session);
|
||||
int ssh_get_kex(ssh_session session, int server_kex);
|
||||
int verify_existing_algo(int algo, const char *name);
|
||||
char **space_tokenize(const char *chain);
|
||||
int ssh_get_kex1(SSH_SESSION *session);
|
||||
int ssh_get_kex1(ssh_session session);
|
||||
char *ssh_find_matching(const char *in_d, const char *what_d);
|
||||
|
||||
/* in keyfiles.c */
|
||||
|
||||
PRIVATE_KEY *_privatekey_from_file(void *session, const char *filename,
|
||||
int type);
|
||||
|
||||
/* in keys.c */
|
||||
const char *ssh_type_to_char(int type);
|
||||
int ssh_type_from_name(const char *name);
|
||||
|
||||
PRIVATE_KEY *privatekey_make_dss(SSH_SESSION *session, BUFFER *buffer);
|
||||
PRIVATE_KEY *privatekey_make_rsa(SSH_SESSION *session, BUFFER *buffer,
|
||||
const char *type);
|
||||
PRIVATE_KEY *privatekey_from_string(SSH_SESSION *session, STRING *privkey_s);
|
||||
|
||||
PUBLIC_KEY *publickey_make_dss(SSH_SESSION *session, BUFFER *buffer);
|
||||
PUBLIC_KEY *publickey_make_rsa(SSH_SESSION *session, BUFFER *buffer, int type);
|
||||
PUBLIC_KEY *publickey_from_string(SSH_SESSION *session, STRING *pubkey_s);
|
||||
SIGNATURE *signature_from_string(SSH_SESSION *session, STRING *signature,PUBLIC_KEY *pubkey,int needed_type);
|
||||
void signature_free(SIGNATURE *sign);
|
||||
STRING *ssh_do_sign_with_agent(struct ssh_session *session,
|
||||
struct buffer_struct *buf, struct public_key_struct *publickey);
|
||||
STRING *ssh_do_sign(SSH_SESSION *session,BUFFER *sigbuf,
|
||||
PRIVATE_KEY *privatekey);
|
||||
STRING *ssh_sign_session_id(SSH_SESSION *session, PRIVATE_KEY *privatekey);
|
||||
STRING *ssh_encrypt_rsa1(SSH_SESSION *session, STRING *data, PUBLIC_KEY *key);
|
||||
/* channel.c */
|
||||
void channel_handle(SSH_SESSION *session, int type);
|
||||
CHANNEL *channel_new(SSH_SESSION *session);
|
||||
int channel_default_bufferize(CHANNEL *channel, void *data, int len,
|
||||
int is_stderr);
|
||||
u32 ssh_channel_new_id(SSH_SESSION *session);
|
||||
CHANNEL *ssh_channel_from_local(SSH_SESSION *session, u32 id);
|
||||
|
||||
/* options.c */
|
||||
|
||||
/* this function must be called when no specific username has been asked. it has to guess it */
|
||||
int ssh_options_default_username(SSH_OPTIONS *opt);
|
||||
int ssh_options_default_ssh_dir(SSH_OPTIONS *opt);
|
||||
int ssh_options_default_known_hosts_file(SSH_OPTIONS *opt);
|
||||
|
||||
/* buffer.c */
|
||||
int buffer_add_ssh_string(BUFFER *buffer, STRING *string);
|
||||
int buffer_add_u8(BUFFER *buffer, u8 data);
|
||||
int buffer_add_u32(BUFFER *buffer, u32 data);
|
||||
int buffer_add_u64(BUFFER *buffer, u64 data);
|
||||
int buffer_add_data(BUFFER *buffer, const void *data, u32 len);
|
||||
int buffer_prepend_data(BUFFER *buffer, const void *data, u32 len);
|
||||
int buffer_add_buffer(BUFFER *buffer, BUFFER *source);
|
||||
int buffer_reinit(BUFFER *buffer);
|
||||
|
||||
/* buffer_get_rest returns a pointer to the current position into the buffer */
|
||||
void *buffer_get_rest(BUFFER *buffer);
|
||||
/* buffer_get_rest_len returns the number of bytes which can be read */
|
||||
u32 buffer_get_rest_len(BUFFER *buffer);
|
||||
|
||||
/* buffer_read_*() returns the number of bytes read, except for ssh strings */
|
||||
int buffer_get_u8(BUFFER *buffer, u8 *data);
|
||||
int buffer_get_u32(BUFFER *buffer, u32 *data);
|
||||
int buffer_get_u64(BUFFER *buffer, u64 *data);
|
||||
|
||||
u32 buffer_get_data(BUFFER *buffer, void *data, u32 requestedlen);
|
||||
/* buffer_get_ssh_string() is an exception. if the String read is too large or invalid, it will answer NULL. */
|
||||
STRING *buffer_get_ssh_string(BUFFER *buffer);
|
||||
/* gets a string out of a SSH-1 mpint */
|
||||
STRING *buffer_get_mpint(BUFFER *buffer);
|
||||
/* buffer_pass_bytes acts as if len bytes have been read (used for padding) */
|
||||
u32 buffer_pass_bytes_end(BUFFER *buffer, u32 len);
|
||||
u32 buffer_pass_bytes(BUFFER *buffer, u32 len);
|
||||
|
||||
/* in base64.c */
|
||||
BUFFER *base64_to_bin(const char *source);
|
||||
ssh_buffer base64_to_bin(const char *source);
|
||||
unsigned char *bin_to_base64(const unsigned char *source, int len);
|
||||
|
||||
/* gzip.c */
|
||||
int compress_buffer(SSH_SESSION *session,BUFFER *buf);
|
||||
int decompress_buffer(SSH_SESSION *session,BUFFER *buf);
|
||||
|
||||
/* wrapper.c */
|
||||
int crypt_set_algorithms(SSH_SESSION *);
|
||||
int crypt_set_algorithms_server(SSH_SESSION *session);
|
||||
CRYPTO *crypto_new(void);
|
||||
void crypto_free(CRYPTO *crypto);
|
||||
int compress_buffer(ssh_session session,ssh_buffer buf);
|
||||
int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen);
|
||||
|
||||
/* crc32.c */
|
||||
u32 ssh_crc32(const char *buf, u32 len);
|
||||
uint32_t ssh_crc32(const char *buf, uint32_t len);
|
||||
|
||||
/* auth1.c */
|
||||
int ssh_userauth1_none(SSH_SESSION *session, const char *username);
|
||||
int ssh_userauth1_offer_pubkey(SSH_SESSION *session, const char *username,
|
||||
int type, STRING *pubkey);
|
||||
int ssh_userauth1_password(SSH_SESSION *session, const char *username,
|
||||
int ssh_userauth1_none(ssh_session session, const char *username);
|
||||
int ssh_userauth1_offer_pubkey(ssh_session session, const char *username,
|
||||
int type, ssh_string pubkey);
|
||||
int ssh_userauth1_password(ssh_session session, const char *username,
|
||||
const char *password);
|
||||
/* in misc.c */
|
||||
/* gets the user home dir. */
|
||||
char *ssh_get_user_home_dir(void);
|
||||
int ssh_file_readaccess_ok(const char *file);
|
||||
|
||||
/* macro for byte ordering */
|
||||
u64 ntohll(u64);
|
||||
#define htonll(x) ntohll(x)
|
||||
|
||||
/* channels1.c */
|
||||
int channel_open_session1(CHANNEL *channel);
|
||||
int channel_request_pty_size1(CHANNEL *channel, const char *terminal,
|
||||
int channel_open_session1(ssh_channel channel);
|
||||
int channel_request_pty_size1(ssh_channel channel, const char *terminal,
|
||||
int cols, int rows);
|
||||
int channel_change_pty_size1(CHANNEL *channel, int cols, int rows);
|
||||
int channel_request_shell1(CHANNEL *channel);
|
||||
int channel_request_exec1(CHANNEL *channel, const char *cmd);
|
||||
int channel_handle1(SSH_SESSION *session, int type);
|
||||
int channel_write1(CHANNEL *channel, const void *data, int len);
|
||||
|
||||
/* session.c */
|
||||
|
||||
int ssh_handle_packets(SSH_SESSION *session);
|
||||
int channel_change_pty_size1(ssh_channel channel, int cols, int rows);
|
||||
int channel_request_shell1(ssh_channel channel);
|
||||
int channel_request_exec1(ssh_channel channel, const char *cmd);
|
||||
int channel_handle1(ssh_session session, int type);
|
||||
int channel_write1(ssh_channel channel, const void *data, int len);
|
||||
|
||||
/* match.c */
|
||||
int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
|
||||
/* log.c */
|
||||
|
||||
/* misc.c */
|
||||
#ifdef _WIN32
|
||||
int gettimeofday(struct timeval *__p, void *__t);
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifndef __FUNCTION__
|
||||
#if defined(__SUNPRO_C)
|
||||
#define __FUNCTION__ __func__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define _enter_function(sess) \
|
||||
do {\
|
||||
if((sess)->log_verbosity >= SSH_LOG_FUNCTIONS){ \
|
||||
@@ -735,8 +212,18 @@ int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
}\
|
||||
} while(0)
|
||||
|
||||
#ifdef DEBUG_CALLTRACE
|
||||
#define enter_function() _enter_function(session)
|
||||
#define leave_function() _leave_function(session)
|
||||
#else
|
||||
#define enter_function() (void)session
|
||||
#define leave_function() (void)session
|
||||
#endif
|
||||
|
||||
/* options.c */
|
||||
|
||||
char *dir_expand_dup(ssh_session session, const char *value, int allowsshdir);
|
||||
int ssh_options_set_algo(ssh_session session, int algo, const char *list);
|
||||
|
||||
/** Free memory space */
|
||||
#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
|
||||
|
||||
56
include/libssh/scp.h
Normal file
56
include/libssh/scp.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _SCP_H
|
||||
#define _SCP_H
|
||||
|
||||
enum ssh_scp_states {
|
||||
SSH_SCP_NEW, //Data structure just created
|
||||
SSH_SCP_WRITE_INITED, //Gave our intention to write
|
||||
SSH_SCP_WRITE_WRITING,//File was opened and currently writing
|
||||
SSH_SCP_READ_INITED, //Gave our intention to read
|
||||
SSH_SCP_READ_REQUESTED, //We got a read request
|
||||
SSH_SCP_READ_READING, //File is opened and reading
|
||||
SSH_SCP_ERROR, //Something bad happened
|
||||
SSH_SCP_TERMINATED //Transfer finished
|
||||
};
|
||||
|
||||
struct ssh_scp_struct {
|
||||
ssh_session session;
|
||||
int mode;
|
||||
int recursive;
|
||||
ssh_channel channel;
|
||||
char *location;
|
||||
enum ssh_scp_states state;
|
||||
size_t filelen;
|
||||
size_t processed;
|
||||
enum ssh_scp_request_types request_type;
|
||||
char *request_name;
|
||||
char *warning;
|
||||
int request_mode;
|
||||
};
|
||||
|
||||
int ssh_scp_read_string(ssh_scp scp, char *buffer, size_t len);
|
||||
int ssh_scp_integer_mode(const char *mode);
|
||||
char *ssh_scp_string_mode(int mode);
|
||||
int ssh_scp_response(ssh_scp scp, char **response);
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,4 @@
|
||||
/* Public include file for server support */
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
@@ -35,14 +36,27 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ssh_bind_struct SSH_BIND;
|
||||
enum ssh_bind_options_e {
|
||||
SSH_BIND_OPTIONS_BINDADDR,
|
||||
SSH_BIND_OPTIONS_BINDPORT,
|
||||
SSH_BIND_OPTIONS_BINDPORT_STR,
|
||||
SSH_BIND_OPTIONS_HOSTKEY,
|
||||
SSH_BIND_OPTIONS_DSAKEY,
|
||||
SSH_BIND_OPTIONS_RSAKEY,
|
||||
SSH_BIND_OPTIONS_BANNER,
|
||||
SSH_BIND_OPTIONS_LOG_VERBOSITY,
|
||||
SSH_BIND_OPTIONS_LOG_VERBOSITY_STR
|
||||
};
|
||||
|
||||
//typedef struct ssh_bind_struct SSH_BIND;
|
||||
typedef struct ssh_bind_struct* ssh_bind;
|
||||
|
||||
/**
|
||||
* @brief Creates a new SSH server bind.
|
||||
*
|
||||
* @return A newly allocated ssh_bind session pointer.
|
||||
*/
|
||||
SSH_BIND *ssh_bind_new(void);
|
||||
LIBSSH_API ssh_bind ssh_bind_new(void);
|
||||
|
||||
/**
|
||||
* @brief Set the opitons for the current SSH server bind.
|
||||
@@ -51,66 +65,68 @@ SSH_BIND *ssh_bind_new(void);
|
||||
*
|
||||
* @param options The option structure to set.
|
||||
*/
|
||||
void ssh_bind_set_options(SSH_BIND *ssh_bind, SSH_OPTIONS *options);
|
||||
LIBSSH_API int ssh_bind_options_set(ssh_bind sshbind,
|
||||
enum ssh_bind_options_e type, const void *value);
|
||||
|
||||
/**
|
||||
* @brief Start listening to the socket.
|
||||
*
|
||||
* @param ssh_bind The ssh server bind to use.
|
||||
* @param ssh_bind_o The ssh server bind to use.
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
int ssh_bind_listen(SSH_BIND *ssh_bind);
|
||||
LIBSSH_API int ssh_bind_listen(ssh_bind ssh_bind_o);
|
||||
|
||||
/**
|
||||
* @brief Set the session to blocking/nonblocking mode.
|
||||
*
|
||||
* @param ssh_bind The ssh server bind to use.
|
||||
* @param ssh_bind_o The ssh server bind to use.
|
||||
*
|
||||
* @param blocking Zero for nonblocking mode.
|
||||
*/
|
||||
void ssh_bind_set_blocking(SSH_BIND *ssh_bind, int blocking);
|
||||
LIBSSH_API void ssh_bind_set_blocking(ssh_bind ssh_bind_o, int blocking);
|
||||
|
||||
/**
|
||||
* @brief Recover the file descriptor from the session.
|
||||
*
|
||||
* @param ssh_bind The ssh server bind to get the fd from.
|
||||
* @param ssh_bind_o The ssh server bind to get the fd from.
|
||||
*
|
||||
* @return The file descriptor.
|
||||
*/
|
||||
socket_t ssh_bind_get_fd(SSH_BIND *ssh_bind);
|
||||
LIBSSH_API socket_t ssh_bind_get_fd(ssh_bind ssh_bind_o);
|
||||
|
||||
/**
|
||||
* @brief Set the file descriptor for a session.
|
||||
*
|
||||
* @param ssh_bind The ssh server bind to set the fd.
|
||||
* @param ssh_bind_o The ssh server bind to set the fd.
|
||||
*
|
||||
* @param fd The file descriptor.
|
||||
* @param fd The file descriptssh_bind B
|
||||
*/
|
||||
void ssh_bind_set_fd(SSH_BIND *ssh_bind, socket_t fd);
|
||||
LIBSSH_API void ssh_bind_set_fd(ssh_bind ssh_bind_o, socket_t fd);
|
||||
|
||||
/**
|
||||
* @brief Allow the file descriptor to accept new sessions.
|
||||
*
|
||||
* @param ssh_bind The ssh server bind to use.
|
||||
* @param ssh_bind_o The ssh server bind to use.
|
||||
*/
|
||||
void ssh_bind_fd_toaccept(SSH_BIND *ssh_bind);
|
||||
LIBSSH_API void ssh_bind_fd_toaccept(ssh_bind ssh_bind_o);
|
||||
|
||||
/**
|
||||
* @brief Accept an incoming ssh connection and initialize the session.
|
||||
*
|
||||
* @param ssh_bind The ssh server bind to accept a connection.
|
||||
*
|
||||
* @param ssh_bind_o The ssh server bind to accept a connection.
|
||||
* @param session A preallocated ssh session
|
||||
* @see ssh_new
|
||||
* @return A newly allocated ssh session, NULL on error.
|
||||
*/
|
||||
SSH_SESSION *ssh_bind_accept(SSH_BIND *ssh_bind);
|
||||
LIBSSH_API int ssh_bind_accept(ssh_bind ssh_bind_o, ssh_session session);
|
||||
|
||||
/**
|
||||
* @brief Free a ssh servers bind.
|
||||
*
|
||||
* @param ssh_bind The ssh server bind to free.
|
||||
* @param ssh_bind_o The ssh server bind to free.
|
||||
*/
|
||||
void ssh_bind_free(SSH_BIND *ssh_bind);
|
||||
LIBSSH_API void ssh_bind_free(ssh_bind ssh_bind_o);
|
||||
|
||||
/**
|
||||
* @brief Exchange the banner and cryptographic keys.
|
||||
@@ -119,54 +135,45 @@ void ssh_bind_free(SSH_BIND *ssh_bind);
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
int ssh_accept(SSH_SESSION *session);
|
||||
LIBSSH_API int ssh_accept(ssh_session session);
|
||||
|
||||
LIBSSH_API int channel_write_stderr(ssh_channel channel, const void *data, uint32_t len);
|
||||
|
||||
/* messages.c */
|
||||
LIBSSH_API int ssh_message_reply_default(ssh_message msg);
|
||||
|
||||
#define SSH_AUTH_REQUEST 1
|
||||
#define SSH_CHANNEL_REQUEST_OPEN 2
|
||||
#define SSH_CHANNEL_REQUEST 3
|
||||
LIBSSH_API char *ssh_message_auth_user(ssh_message msg);
|
||||
LIBSSH_API char *ssh_message_auth_password(ssh_message msg);
|
||||
LIBSSH_API ssh_public_key ssh_message_auth_publickey(ssh_message msg);
|
||||
LIBSSH_API int ssh_message_auth_reply_success(ssh_message msg,int partial);
|
||||
LIBSSH_API int ssh_message_auth_reply_pk_ok(ssh_message msg, ssh_string algo, ssh_string pubkey);
|
||||
LIBSSH_API int ssh_message_auth_set_methods(ssh_message msg, int methods);
|
||||
|
||||
#define SSH_AUTH_NONE (1<<0)
|
||||
#define SSH_AUTH_PASSWORD (1<<1)
|
||||
#define SSH_AUTH_HOSTBASED (1<<2)
|
||||
#define SSH_AUTH_PUBLICKEY (1<<3)
|
||||
#define SSH_AUTH_KEYBINT (1<<4)
|
||||
#define SSH_AUTH_UNKNOWN 0
|
||||
LIBSSH_API int ssh_message_service_reply_success(ssh_message msg);
|
||||
LIBSSH_API char *ssh_message_service_service(ssh_message msg);
|
||||
|
||||
#define SSH_CHANNEL_SESSION 1
|
||||
#define SSH_CHANNEL_TCPIP 2
|
||||
#define SSH_CHANNEL_X11 3
|
||||
#define SSH_CHANNEL_UNKNOWN 4
|
||||
LIBSSH_API void ssh_set_message_callback(ssh_session session,
|
||||
int(*ssh_message_callback)(ssh_session session, ssh_message msg));
|
||||
|
||||
#define SSH_CHANNEL_REQUEST_PTY 1
|
||||
#define SSH_CHANNEL_REQUEST_EXEC 2
|
||||
#define SSH_CHANNEL_REQUEST_SHELL 3
|
||||
#define SSH_CHANNEL_REQUEST_ENV 4
|
||||
#define SSH_CHANNEL_REQUEST_SUBSYSTEM 5
|
||||
#define SSH_CHANNEL_REQUEST_WINDOW_CHANGE 6
|
||||
#define SSH_CHANNEL_REQUEST_UNKNOWN 7
|
||||
LIBSSH_API char *ssh_message_channel_request_open_originator(ssh_message msg);
|
||||
LIBSSH_API int ssh_message_channel_request_open_originator_port(ssh_message msg);
|
||||
LIBSSH_API char *ssh_message_channel_request_open_destination(ssh_message msg);
|
||||
LIBSSH_API int ssh_message_channel_request_open_destination_port(ssh_message msg);
|
||||
|
||||
typedef struct ssh_message SSH_MESSAGE;
|
||||
LIBSSH_API ssh_channel ssh_message_channel_request_channel(ssh_message msg);
|
||||
|
||||
SSH_MESSAGE *ssh_message_get(SSH_SESSION *session);
|
||||
int ssh_message_type(SSH_MESSAGE *msg);
|
||||
int ssh_message_subtype(SSH_MESSAGE *msg);
|
||||
int ssh_message_reply_default(SSH_MESSAGE *msg);
|
||||
void ssh_message_free(SSH_MESSAGE *msg);
|
||||
LIBSSH_API char *ssh_message_channel_request_pty_term(ssh_message msg);
|
||||
LIBSSH_API int ssh_message_channel_request_pty_width(ssh_message msg);
|
||||
LIBSSH_API int ssh_message_channel_request_pty_height(ssh_message msg);
|
||||
LIBSSH_API int ssh_message_channel_request_pty_pxwidth(ssh_message msg);
|
||||
LIBSSH_API int ssh_message_channel_request_pty_pxheight(ssh_message msg);
|
||||
|
||||
char *ssh_message_auth_user(SSH_MESSAGE *msg);
|
||||
char *ssh_message_auth_password(SSH_MESSAGE *msg);
|
||||
int ssh_message_auth_reply_success(SSH_MESSAGE *msg,int partial);
|
||||
int ssh_message_auth_set_methods(SSH_MESSAGE *msg, int methods);
|
||||
LIBSSH_API char *ssh_message_channel_request_env_name(ssh_message msg);
|
||||
LIBSSH_API char *ssh_message_channel_request_env_value(ssh_message msg);
|
||||
|
||||
CHANNEL *ssh_message_channel_request_open_reply_accept(SSH_MESSAGE *msg);
|
||||
LIBSSH_API char *ssh_message_channel_request_command(ssh_message msg);
|
||||
|
||||
CHANNEL *ssh_message_channel_request_channel(SSH_MESSAGE *msg);
|
||||
// returns the TERM env variable
|
||||
char *ssh_message_channel_request_pty_term(SSH_MESSAGE *msg);
|
||||
char *ssh_message_channel_request_subsystem(SSH_MESSAGE *msg);
|
||||
int ssh_message_channel_request_reply_success(SSH_MESSAGE *msg);
|
||||
LIBSSH_API char *ssh_message_channel_request_subsystem(ssh_message msg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
121
include/libssh/session.h
Normal file
121
include/libssh/session.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef SESSION_H_
|
||||
#define SESSION_H_
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/pcap.h"
|
||||
|
||||
typedef struct ssh_kbdint_struct* ssh_kbdint;
|
||||
|
||||
struct ssh_session_struct {
|
||||
struct error_struct error;
|
||||
struct socket *socket;
|
||||
char *serverbanner;
|
||||
char *clientbanner;
|
||||
int protoversion;
|
||||
int server;
|
||||
int client;
|
||||
int openssh;
|
||||
uint32_t send_seq;
|
||||
uint32_t recv_seq;
|
||||
/* status flags */
|
||||
int closed;
|
||||
int closed_by_except;
|
||||
|
||||
int connected;
|
||||
/* !=0 when the user got a session handle */
|
||||
int alive;
|
||||
/* two previous are deprecated */
|
||||
int auth_service_asked;
|
||||
|
||||
/* socket status */
|
||||
int blocking; // functions should block
|
||||
|
||||
ssh_string banner; /* that's the issue banner from
|
||||
the server */
|
||||
char *remotebanner; /* that's the SSH- banner from
|
||||
remote host. */
|
||||
char *discon_msg; /* disconnect message from
|
||||
the remote host */
|
||||
ssh_buffer in_buffer;
|
||||
PACKET in_packet;
|
||||
ssh_buffer out_buffer;
|
||||
|
||||
/* the states are used by the nonblocking stuff to remember */
|
||||
/* where it was before being interrupted */
|
||||
int packet_state;
|
||||
int dh_handshake_state;
|
||||
ssh_string dh_server_signature; //information used by dh_handshake.
|
||||
|
||||
KEX server_kex;
|
||||
KEX client_kex;
|
||||
ssh_buffer in_hashbuf;
|
||||
ssh_buffer out_hashbuf;
|
||||
struct ssh_crypto_struct *current_crypto;
|
||||
struct ssh_crypto_struct *next_crypto; /* next_crypto is going to be used after a SSH2_MSG_NEWKEYS */
|
||||
|
||||
ssh_channel channels; /* linked list of channels */
|
||||
int maxchannel;
|
||||
int exec_channel_opened; /* version 1 only. more
|
||||
info in channels1.c */
|
||||
ssh_agent agent; /* ssh agent */
|
||||
|
||||
/* keyb interactive data */
|
||||
struct ssh_kbdint_struct *kbdint;
|
||||
int version; /* 1 or 2 */
|
||||
/* server host keys */
|
||||
ssh_private_key rsa_key;
|
||||
ssh_private_key dsa_key;
|
||||
/* auths accepted by server */
|
||||
int auth_methods;
|
||||
int hostkeys; /* contains type of host key wanted by client, in server impl */
|
||||
struct ssh_list *ssh_message_list; /* list of delayed SSH messages */
|
||||
int (*ssh_message_callback)( struct ssh_session_struct *session, ssh_message msg);
|
||||
int log_verbosity; /*cached copy of the option structure */
|
||||
int log_indent; /* indentation level in enter_function logs */
|
||||
|
||||
ssh_callbacks callbacks; /* Callbacks to user functions */
|
||||
|
||||
/* options */
|
||||
#ifdef WITH_PCAP
|
||||
ssh_pcap_context pcap_ctx; /* pcap debugging context */
|
||||
#endif
|
||||
char *username;
|
||||
char *host;
|
||||
char *bindaddr; /* TODO: check if needed */
|
||||
char *xbanner; /* TODO: looks like it is not needed */
|
||||
char *identity;
|
||||
char *sshdir;
|
||||
char *knownhosts;
|
||||
char *wanted_methods[10];
|
||||
unsigned long timeout; /* seconds */
|
||||
unsigned long timeout_usec;
|
||||
unsigned int port;
|
||||
socket_t fd;
|
||||
int ssh2;
|
||||
int ssh1;
|
||||
};
|
||||
|
||||
int ssh_handle_packets(ssh_session session);
|
||||
|
||||
#endif /* SESSION_H_ */
|
||||
@@ -25,12 +25,12 @@
|
||||
* @brief SFTP handling functions
|
||||
*
|
||||
* SFTP commands are channeled by the ssh sftp subsystem. Every packet is
|
||||
* sent/read using a SFTP_PACKET type structure. Related to these packets,
|
||||
* sent/read using a sftp_packet type structure. Related to these packets,
|
||||
* most of the server answers are messages having an ID and a message
|
||||
* specific part. It is described by SFTP_MESSAGE when reading a message,
|
||||
* specific part. It is described by sftp_message when reading a message,
|
||||
* the sftp system puts it into the queue, so the process having asked for
|
||||
* it can fetch it, while continuing to read for other messages (it is
|
||||
* inspecified in which order messages may be sent back to the client
|
||||
* unspecified in which order messages may be sent back to the client
|
||||
*
|
||||
* @defgroup ssh_sftp SFTP Functions
|
||||
* @{
|
||||
@@ -38,126 +38,156 @@
|
||||
|
||||
#ifndef SFTP_H
|
||||
#define SFTP_H
|
||||
#include <libssh/libssh.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "libssh.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define SFTP_DEPRECATED __attribute__ ((deprecated))
|
||||
#else
|
||||
#define SFTP_DEPRECATED
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef uid_t
|
||||
typedef long uid_t;
|
||||
typedef uint32_t uid_t;
|
||||
#endif /* uid_t */
|
||||
#ifndef gid_t
|
||||
typedef long gid_t;
|
||||
typedef uint32_t gid_t;
|
||||
#endif /* gid_t */
|
||||
#ifdef _MSC_VER
|
||||
#ifndef ssize_t
|
||||
typedef _W64 SSIZE_T ssize_t;
|
||||
#endif /* ssize_t */
|
||||
#endif /* _MSC_VER */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
typedef struct sftp_session_struct {
|
||||
SSH_SESSION *session;
|
||||
CHANNEL *channel;
|
||||
typedef struct sftp_attributes_struct* sftp_attributes;
|
||||
typedef struct sftp_client_message_struct* sftp_client_message;
|
||||
typedef struct sftp_dir_struct* sftp_dir;
|
||||
typedef struct sftp_ext_struct *sftp_ext;
|
||||
typedef struct sftp_file_struct* sftp_file;
|
||||
typedef struct sftp_message_struct* sftp_message;
|
||||
typedef struct sftp_packet_struct* sftp_packet;
|
||||
typedef struct sftp_request_queue_struct* sftp_request_queue;
|
||||
typedef struct sftp_session_struct* sftp_session;
|
||||
typedef struct sftp_status_message_struct* sftp_status_message;
|
||||
typedef struct sftp_statvfs_struct* sftp_statvfs_t;
|
||||
|
||||
struct sftp_session_struct {
|
||||
ssh_session session;
|
||||
ssh_channel channel;
|
||||
int server_version;
|
||||
int client_version;
|
||||
int version;
|
||||
struct request_queue *queue;
|
||||
u32 id_counter;
|
||||
sftp_request_queue queue;
|
||||
uint32_t id_counter;
|
||||
int errnum;
|
||||
void **handles;
|
||||
} SFTP_SESSION ;
|
||||
sftp_ext ext;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
SFTP_SESSION *sftp;
|
||||
u8 type;
|
||||
BUFFER *payload;
|
||||
} SFTP_PACKET;
|
||||
struct sftp_packet_struct {
|
||||
sftp_session sftp;
|
||||
uint8_t type;
|
||||
ssh_buffer payload;
|
||||
};
|
||||
|
||||
/* file handler */
|
||||
typedef struct sftp_file{
|
||||
SFTP_SESSION *sftp;
|
||||
struct sftp_file_struct {
|
||||
sftp_session sftp;
|
||||
char *name;
|
||||
u64 offset;
|
||||
STRING *handle;
|
||||
uint64_t offset;
|
||||
ssh_string handle;
|
||||
int eof;
|
||||
int nonblocking;
|
||||
} SFTP_FILE ;
|
||||
};
|
||||
|
||||
typedef struct sftp_dir {
|
||||
SFTP_SESSION *sftp;
|
||||
struct sftp_dir_struct {
|
||||
sftp_session sftp;
|
||||
char *name;
|
||||
STRING *handle; /* handle to directory */
|
||||
BUFFER *buffer; /* contains raw attributes from server which haven't been parsed */
|
||||
u32 count; /* counts the number of following attributes structures into buffer */
|
||||
ssh_string handle; /* handle to directory */
|
||||
ssh_buffer buffer; /* contains raw attributes from server which haven't been parsed */
|
||||
uint32_t count; /* counts the number of following attributes structures into buffer */
|
||||
int eof; /* end of directory listing */
|
||||
} SFTP_DIR;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
SFTP_SESSION *sftp;
|
||||
u8 packet_type;
|
||||
BUFFER *payload;
|
||||
u32 id;
|
||||
} SFTP_MESSAGE;
|
||||
struct sftp_message_struct {
|
||||
sftp_session sftp;
|
||||
uint8_t packet_type;
|
||||
ssh_buffer payload;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
/* this is a bunch of all data that could be into a message */
|
||||
typedef struct sftp_client_message{
|
||||
SFTP_SESSION *sftp;
|
||||
u8 type;
|
||||
u32 id;
|
||||
struct sftp_client_message_struct {
|
||||
sftp_session sftp;
|
||||
uint8_t type;
|
||||
uint32_t id;
|
||||
char *filename; /* can be "path" */
|
||||
u32 flags;
|
||||
struct sftp_attributes *attr;
|
||||
STRING *handle;
|
||||
u64 offset;
|
||||
u32 len;
|
||||
uint32_t flags;
|
||||
sftp_attributes attr;
|
||||
ssh_string handle;
|
||||
uint64_t offset;
|
||||
uint32_t len;
|
||||
int attr_num;
|
||||
BUFFER *attrbuf; /* used by sftp_reply_attrs */
|
||||
STRING *data; /* can be newpath of rename() */
|
||||
} SFTP_CLIENT_MESSAGE;
|
||||
ssh_buffer attrbuf; /* used by sftp_reply_attrs */
|
||||
ssh_string data; /* can be newpath of rename() */
|
||||
};
|
||||
|
||||
typedef struct request_queue{
|
||||
struct request_queue *next;
|
||||
SFTP_MESSAGE *message;
|
||||
} REQUEST_QUEUE;
|
||||
struct sftp_request_queue_struct {
|
||||
sftp_request_queue next;
|
||||
sftp_message message;
|
||||
};
|
||||
|
||||
/* SSH_FXP_MESSAGE described into .7 page 26 */
|
||||
typedef struct {
|
||||
u32 id;
|
||||
u32 status;
|
||||
STRING *error;
|
||||
STRING *lang;
|
||||
struct sftp_status_message_struct {
|
||||
uint32_t id;
|
||||
uint32_t status;
|
||||
ssh_string error;
|
||||
ssh_string lang;
|
||||
char *errormsg;
|
||||
char *langmsg;
|
||||
} STATUS_MESSAGE;
|
||||
};
|
||||
|
||||
/* don't worry much of these aren't really used */
|
||||
typedef struct sftp_attributes{
|
||||
struct sftp_attributes_struct {
|
||||
char *name;
|
||||
char *longname; /* some weird stuff */
|
||||
u32 flags;
|
||||
u8 type;
|
||||
u64 size;
|
||||
u32 uid;
|
||||
u32 gid;
|
||||
uint32_t flags;
|
||||
uint8_t type;
|
||||
uint64_t size;
|
||||
uint32_t uid;
|
||||
uint32_t gid;
|
||||
char *owner;
|
||||
char *group;
|
||||
u32 permissions;
|
||||
u64 atime64;
|
||||
u32 atime;
|
||||
u32 atime_nseconds;
|
||||
u64 createtime;
|
||||
u32 createtime_nseconds;
|
||||
u64 mtime64;
|
||||
u32 mtime;
|
||||
u32 mtime_nseconds;
|
||||
STRING *acl;
|
||||
u32 extended_count;
|
||||
STRING *extended_type;
|
||||
STRING *extended_data;
|
||||
} SFTP_ATTRIBUTES;
|
||||
uint32_t permissions;
|
||||
uint64_t atime64;
|
||||
uint32_t atime;
|
||||
uint32_t atime_nseconds;
|
||||
uint64_t createtime;
|
||||
uint32_t createtime_nseconds;
|
||||
uint64_t mtime64;
|
||||
uint32_t mtime;
|
||||
uint32_t mtime_nseconds;
|
||||
ssh_string acl;
|
||||
uint32_t extended_count;
|
||||
ssh_string extended_type;
|
||||
ssh_string extended_data;
|
||||
};
|
||||
|
||||
struct sftp_statvfs_struct {
|
||||
uint64_t f_bsize; /* file system block size */
|
||||
uint64_t f_frsize; /* fundamental fs block size */
|
||||
uint64_t f_blocks; /* number of blocks (unit f_frsize) */
|
||||
uint64_t f_bfree; /* free blocks in file system */
|
||||
uint64_t f_bavail; /* free blocks for non-root */
|
||||
uint64_t f_files; /* total file inodes */
|
||||
uint64_t f_ffree; /* free file inodes */
|
||||
uint64_t f_favail; /* free file inodes for to non-root */
|
||||
uint64_t f_fsid; /* file system id */
|
||||
uint64_t f_flag; /* bit mask of f_flag values */
|
||||
uint64_t f_namemax; /* maximum filename length */
|
||||
};
|
||||
|
||||
#define LIBSFTP_VERSION 3
|
||||
|
||||
@@ -168,14 +198,14 @@ typedef struct sftp_attributes{
|
||||
*
|
||||
* @return A new sftp session or NULL on error.
|
||||
*/
|
||||
SFTP_SESSION *sftp_new(SSH_SESSION *session);
|
||||
LIBSSH_API sftp_session sftp_new(ssh_session session);
|
||||
|
||||
/**
|
||||
* @brief Close and deallocate a sftp session.
|
||||
*
|
||||
* @param sftp The sftp session handle to free.
|
||||
*/
|
||||
void sftp_free(SFTP_SESSION *sftp);
|
||||
LIBSSH_API void sftp_free(sftp_session sftp);
|
||||
|
||||
/**
|
||||
* @brief Initialize the sftp session with the server.
|
||||
@@ -184,7 +214,7 @@ void sftp_free(SFTP_SESSION *sftp);
|
||||
*
|
||||
* @return 0 on success, < 0 on error with ssh error set.
|
||||
*/
|
||||
int sftp_init(SFTP_SESSION *sftp);
|
||||
LIBSSH_API int sftp_init(sftp_session sftp);
|
||||
|
||||
/**
|
||||
* @brief Get the last sftp error.
|
||||
@@ -196,11 +226,65 @@ int sftp_init(SFTP_SESSION *sftp);
|
||||
* @return The saved error (see server responses), < 0 if an error
|
||||
* in the function occured.
|
||||
*/
|
||||
int sftp_get_error(SFTP_SESSION *sftp);
|
||||
LIBSSH_API int sftp_get_error(sftp_session sftp);
|
||||
|
||||
/**
|
||||
* @brief Get the count of extensions provided by the server.
|
||||
*
|
||||
* @param sftp The sftp session to use.
|
||||
*
|
||||
* @return The count of extensions provided by the server, 0 on error or
|
||||
* not available.
|
||||
*/
|
||||
LIBSSH_API unsigned int sftp_extensions_get_count(sftp_session sftp);
|
||||
|
||||
/**
|
||||
* @brief Get the name of the extension provided by the server.
|
||||
*
|
||||
* @param sftp The sftp session to use.
|
||||
*
|
||||
* @param indexn The index number of the extension name you want.
|
||||
*
|
||||
* @return The name of the extension.
|
||||
*/
|
||||
LIBSSH_API const char *sftp_extensions_get_name(sftp_session sftp, unsigned int indexn);
|
||||
|
||||
/**
|
||||
* @brief Get the data of the extension provided by the server.
|
||||
*
|
||||
* This is normally the version number of the extension.
|
||||
*
|
||||
* @param sftp The sftp session to use.
|
||||
*
|
||||
* @param indexn The index number of the extension data you want.
|
||||
*
|
||||
* @return The data of the extension.
|
||||
*/
|
||||
LIBSSH_API const char *sftp_extensions_get_data(sftp_session sftp, unsigned int indexn);
|
||||
|
||||
/**
|
||||
* @brief Check if the given extension is supported.
|
||||
*
|
||||
* @param sftp The sftp session to use.
|
||||
*
|
||||
* @param name The name of the extension.
|
||||
*
|
||||
* @param data The data of the extension.
|
||||
*
|
||||
* @return 1 if supported, 0 if not.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* @code
|
||||
* sftp_extension_supported(sftp, "statvfs@openssh.com", "2");
|
||||
* @endcode
|
||||
*/
|
||||
LIBSSH_API int sftp_extension_supported(sftp_session sftp, const char *name,
|
||||
const char *data);
|
||||
|
||||
/**
|
||||
* @brief Open a directory used to obtain directory entries.
|
||||
*
|
||||
|
||||
* @param session The sftp session handle to open the directory.
|
||||
* @param path The path of the directory to open.
|
||||
*
|
||||
@@ -210,7 +294,7 @@ int sftp_get_error(SFTP_SESSION *sftp);
|
||||
* @see sftp_readdir
|
||||
* @see sftp_closedir
|
||||
*/
|
||||
SFTP_DIR *sftp_opendir(SFTP_SESSION *session, const char *path);
|
||||
LIBSSH_API sftp_dir sftp_opendir(sftp_session session, const char *path);
|
||||
|
||||
/**
|
||||
* @brief Get a single file attributes structure of a directory.
|
||||
@@ -225,7 +309,7 @@ SFTP_DIR *sftp_opendir(SFTP_SESSION *session, const char *path);
|
||||
* @see sftp_attribute_free()
|
||||
* @see sftp_closedir()
|
||||
*/
|
||||
SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *session, SFTP_DIR *dir);
|
||||
LIBSSH_API sftp_attributes sftp_readdir(sftp_session session, sftp_dir dir);
|
||||
|
||||
/**
|
||||
* @brief Tell if the directory has reached EOF (End Of File).
|
||||
@@ -236,7 +320,7 @@ SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *session, SFTP_DIR *dir);
|
||||
*
|
||||
* @see sftp_readdir()
|
||||
*/
|
||||
int sftp_dir_eof(SFTP_DIR *dir);
|
||||
LIBSSH_API int sftp_dir_eof(sftp_dir dir);
|
||||
|
||||
/**
|
||||
* @brief Get information about a file or directory.
|
||||
@@ -248,7 +332,7 @@ int sftp_dir_eof(SFTP_DIR *dir);
|
||||
* @return The sftp attributes structure of the file or directory,
|
||||
* NULL on error with ssh and sftp error set.
|
||||
*/
|
||||
SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, const char *path);
|
||||
LIBSSH_API sftp_attributes sftp_stat(sftp_session session, const char *path);
|
||||
|
||||
/**
|
||||
* @brief Get information about a file or directory.
|
||||
@@ -263,7 +347,7 @@ SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, const char *path);
|
||||
* @return The sftp attributes structure of the file or directory,
|
||||
* NULL on error with ssh and sftp error set.
|
||||
*/
|
||||
SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, const char *path);
|
||||
LIBSSH_API sftp_attributes sftp_lstat(sftp_session session, const char *path);
|
||||
|
||||
/**
|
||||
* @brief Get information about a file or directory from a file handle.
|
||||
@@ -273,14 +357,14 @@ SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, const char *path);
|
||||
* @return The sftp attributes structure of the file or directory,
|
||||
* NULL on error with ssh and sftp error set.
|
||||
*/
|
||||
SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file);
|
||||
LIBSSH_API sftp_attributes sftp_fstat(sftp_file file);
|
||||
|
||||
/**
|
||||
* @brief Free a sftp attribute structure.
|
||||
*
|
||||
* @param file The sftp attribute structure to free.
|
||||
*/
|
||||
void sftp_attributes_free(SFTP_ATTRIBUTES *file);
|
||||
LIBSSH_API void sftp_attributes_free(sftp_attributes file);
|
||||
|
||||
/**
|
||||
* @brief Close a directory handle opened by sftp_opendir().
|
||||
@@ -289,12 +373,7 @@ void sftp_attributes_free(SFTP_ATTRIBUTES *file);
|
||||
*
|
||||
* @return Returns SSH_NO_ERROR or SSH_ERROR if an error occured.
|
||||
*/
|
||||
int sftp_closedir(SFTP_DIR *dir);
|
||||
|
||||
/**
|
||||
* @deprecated Use sftp_closedir() instead.
|
||||
*/
|
||||
int sftp_dir_close(SFTP_DIR *dir) SFTP_DEPRECATED;
|
||||
LIBSSH_API int sftp_closedir(sftp_dir dir);
|
||||
|
||||
/**
|
||||
* @brief Close an open file handle.
|
||||
@@ -305,12 +384,7 @@ int sftp_dir_close(SFTP_DIR *dir) SFTP_DEPRECATED;
|
||||
*
|
||||
* @see sftp_open()
|
||||
*/
|
||||
int sftp_close(SFTP_FILE *file);
|
||||
|
||||
/**
|
||||
* @deprecated Use sftp_close() instead.
|
||||
*/
|
||||
int sftp_file_close(SFTP_FILE *file) SFTP_DEPRECATED;
|
||||
LIBSSH_API int sftp_close(sftp_file file);
|
||||
|
||||
/**
|
||||
* @brief Open a file on the server.
|
||||
@@ -319,7 +393,7 @@ int sftp_file_close(SFTP_FILE *file) SFTP_DEPRECATED;
|
||||
*
|
||||
* @param file The file to be opened.
|
||||
*
|
||||
* @param access Is one of O_RDONLY, O_WRONLY or O_RDWR which request
|
||||
* @param accesstype Is one of O_RDONLY, O_WRONLY or O_RDWR which request
|
||||
* opening the file read-only,write-only or read/write.
|
||||
* Acesss may also be bitwise-or'd with one or more of
|
||||
* the following:
|
||||
@@ -338,12 +412,12 @@ int sftp_file_close(SFTP_FILE *file) SFTP_DEPRECATED;
|
||||
* @return A sftp file handle, NULL on error with ssh and sftp
|
||||
* error set.
|
||||
*/
|
||||
SFTP_FILE *sftp_open(SFTP_SESSION *session, const char *file, int flags,
|
||||
LIBSSH_API sftp_file sftp_open(sftp_session session, const char *file, int accesstype,
|
||||
mode_t mode);
|
||||
|
||||
void sftp_file_set_nonblocking(SFTP_FILE *handle);
|
||||
LIBSSH_API void sftp_file_set_nonblocking(sftp_file handle);
|
||||
|
||||
void sftp_file_set_blocking(SFTP_FILE *handle);
|
||||
LIBSSH_API void sftp_file_set_blocking(sftp_file handle);
|
||||
|
||||
/**
|
||||
* @brief Read from a file using an opened sftp file handle.
|
||||
@@ -357,7 +431,7 @@ void sftp_file_set_blocking(SFTP_FILE *handle);
|
||||
* @return Number of bytes written, < 0 on error with ssh and sftp
|
||||
* error set.
|
||||
*/
|
||||
ssize_t sftp_read(SFTP_FILE *file, void *buf, size_t count);
|
||||
LIBSSH_API ssize_t sftp_read(sftp_file file, void *buf, size_t count);
|
||||
|
||||
/**
|
||||
* @brief Start an asynchronous read from a file using an opened sftp file handle.
|
||||
@@ -390,7 +464,7 @@ ssize_t sftp_read(SFTP_FILE *file, void *buf, size_t count);
|
||||
* @see sftp_async_read()
|
||||
* @see sftp_open()
|
||||
*/
|
||||
int sftp_async_read_begin(SFTP_FILE *file, u32 len);
|
||||
LIBSSH_API int sftp_async_read_begin(sftp_file file, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief Wait for an asynchronous read to complete and save the data.
|
||||
@@ -415,7 +489,7 @@ int sftp_async_read_begin(SFTP_FILE *file, u32 len);
|
||||
*
|
||||
* @see sftp_async_read_begin()
|
||||
*/
|
||||
int sftp_async_read(SFTP_FILE *file, void *data, u32 len, u32 id);
|
||||
LIBSSH_API int sftp_async_read(sftp_file file, void *data, uint32_t len, uint32_t id);
|
||||
|
||||
/**
|
||||
* @brief Write to a file using an opened sftp file handle.
|
||||
@@ -433,7 +507,7 @@ int sftp_async_read(SFTP_FILE *file, void *data, u32 len, u32 id);
|
||||
* @see sftp_read()
|
||||
* @see sftp_close()
|
||||
*/
|
||||
ssize_t sftp_write(SFTP_FILE *file, const void *buf, size_t count);
|
||||
LIBSSH_API ssize_t sftp_write(sftp_file file, const void *buf, size_t count);
|
||||
|
||||
/**
|
||||
* @brief Seek to a specific location in a file.
|
||||
@@ -444,7 +518,7 @@ ssize_t sftp_write(SFTP_FILE *file, const void *buf, size_t count);
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
int sftp_seek(SFTP_FILE *file, u32 new_offset);
|
||||
LIBSSH_API int sftp_seek(sftp_file file, uint32_t new_offset);
|
||||
|
||||
/**
|
||||
* @brief Seek to a specific location in a file. This is the
|
||||
@@ -456,7 +530,7 @@ int sftp_seek(SFTP_FILE *file, u32 new_offset);
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
int sftp_seek64(SFTP_FILE *file, u64 new_offset);
|
||||
LIBSSH_API int sftp_seek64(sftp_file file, uint64_t new_offset);
|
||||
|
||||
/**
|
||||
* @brief Report current byte position in file.
|
||||
@@ -467,7 +541,18 @@ int sftp_seek64(SFTP_FILE *file, u64 new_offset);
|
||||
* of the file associated with the file descriptor. < 0 on
|
||||
* error.
|
||||
*/
|
||||
unsigned long sftp_tell(SFTP_FILE *file);
|
||||
LIBSSH_API unsigned long sftp_tell(sftp_file file);
|
||||
|
||||
/**
|
||||
* @brief Report current byte position in file.
|
||||
*
|
||||
* @param file Open sftp file handle.
|
||||
*
|
||||
* @return The offset of the current byte relative to the beginning
|
||||
* of the file associated with the file descriptor. < 0 on
|
||||
* error.
|
||||
*/
|
||||
LIBSSH_API uint64_t sftp_tell64(sftp_file file);
|
||||
|
||||
/**
|
||||
* @brief Rewinds the position of the file pointer to the beginning of the
|
||||
@@ -475,12 +560,7 @@ unsigned long sftp_tell(SFTP_FILE *file);
|
||||
*
|
||||
* @param file Open sftp file handle.
|
||||
*/
|
||||
void sftp_rewind(SFTP_FILE *file);
|
||||
|
||||
/**
|
||||
* @deprecated Use sftp_unlink() instead.
|
||||
*/
|
||||
int sftp_rm(SFTP_SESSION *sftp, const char *file) SFTP_DEPRECATED;
|
||||
LIBSSH_API void sftp_rewind(sftp_file file);
|
||||
|
||||
/**
|
||||
* @brief Unlink (delete) a file.
|
||||
@@ -491,7 +571,7 @@ int sftp_rm(SFTP_SESSION *sftp, const char *file) SFTP_DEPRECATED;
|
||||
*
|
||||
* @return 0 on success, < 0 on error with ssh and sftp error set.
|
||||
*/
|
||||
int sftp_unlink(SFTP_SESSION *sftp, const char *file);
|
||||
LIBSSH_API int sftp_unlink(sftp_session sftp, const char *file);
|
||||
|
||||
/**
|
||||
* @brief Remove a directoy.
|
||||
@@ -502,7 +582,7 @@ int sftp_unlink(SFTP_SESSION *sftp, const char *file);
|
||||
*
|
||||
* @return 0 on success, < 0 on error with ssh and sftp error set.
|
||||
*/
|
||||
int sftp_rmdir(SFTP_SESSION *sftp, const char *directory);
|
||||
LIBSSH_API int sftp_rmdir(sftp_session sftp, const char *directory);
|
||||
|
||||
/**
|
||||
* @brief Create a directory.
|
||||
@@ -517,7 +597,7 @@ int sftp_rmdir(SFTP_SESSION *sftp, const char *directory);
|
||||
*
|
||||
* @return 0 on success, < 0 on error with ssh and sftp error set.
|
||||
*/
|
||||
int sftp_mkdir(SFTP_SESSION *sftp, const char *directory, mode_t mode);
|
||||
LIBSSH_API int sftp_mkdir(sftp_session sftp, const char *directory, mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Rename or move a file or directory.
|
||||
@@ -532,7 +612,7 @@ int sftp_mkdir(SFTP_SESSION *sftp, const char *directory, mode_t mode);
|
||||
*
|
||||
* @return 0 on success, < 0 on error with ssh and sftp error set.
|
||||
*/
|
||||
int sftp_rename(SFTP_SESSION *sftp, const char *original, const char *newname);
|
||||
LIBSSH_API int sftp_rename(sftp_session sftp, const char *original, const char *newname);
|
||||
|
||||
/**
|
||||
* @brief Set file attributes on a file, directory or symbolic link.
|
||||
@@ -546,7 +626,7 @@ int sftp_rename(SFTP_SESSION *sftp, const char *original, const char *newname);
|
||||
*
|
||||
* @return 0 on success, < 0 on error with ssh and sftp error set.
|
||||
*/
|
||||
int sftp_setstat(SFTP_SESSION *sftp, const char *file, SFTP_ATTRIBUTES *attr);
|
||||
LIBSSH_API int sftp_setstat(sftp_session sftp, const char *file, sftp_attributes attr);
|
||||
|
||||
/**
|
||||
* @brief Change the file owner and group
|
||||
@@ -561,7 +641,7 @@ int sftp_setstat(SFTP_SESSION *sftp, const char *file, SFTP_ATTRIBUTES *attr);
|
||||
*
|
||||
* @return 0 on success, < 0 on error with ssh and sftp error set.
|
||||
*/
|
||||
int sftp_chown(SFTP_SESSION *sftp, const char *file, uid_t owner, gid_t group);
|
||||
LIBSSH_API int sftp_chown(sftp_session sftp, const char *file, uid_t owner, gid_t group);
|
||||
|
||||
/**
|
||||
* @brief Change permissions of a file
|
||||
@@ -576,7 +656,7 @@ int sftp_chown(SFTP_SESSION *sftp, const char *file, uid_t owner, gid_t group);
|
||||
*
|
||||
* @return 0 on success, < 0 on error with ssh and sftp error set.
|
||||
*/
|
||||
int sftp_chmod(SFTP_SESSION *sftp, const char *file, mode_t mode);
|
||||
LIBSSH_API int sftp_chmod(sftp_session sftp, const char *file, mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Change the last modification and access time of a file.
|
||||
@@ -590,7 +670,58 @@ int sftp_chmod(SFTP_SESSION *sftp, const char *file, mode_t mode);
|
||||
*
|
||||
* @return 0 on success, < 0 on error with ssh and sftp error set.
|
||||
*/
|
||||
int sftp_utimes(SFTP_SESSION *sftp, const char *file, const struct timeval *times);
|
||||
LIBSSH_API int sftp_utimes(sftp_session sftp, const char *file, const struct timeval *times);
|
||||
|
||||
/**
|
||||
* @brief Create a symbolic link.
|
||||
*
|
||||
* @param sftp The sftp session handle.
|
||||
*
|
||||
* @param target Specifies the target of the symlink.
|
||||
*
|
||||
* @param dest Specifies the path name of the symlink to be created.
|
||||
*
|
||||
* @return 0 on success, < 0 on error with ssh and sftp error set.
|
||||
*/
|
||||
LIBSSH_API int sftp_symlink(sftp_session sftp, const char *target, const char *dest);
|
||||
|
||||
/**
|
||||
* @brief Read the value of a symbolic link.
|
||||
*
|
||||
* @param sftp The sftp session handle.
|
||||
*
|
||||
* @param path Specifies the path name of the symlink to be read.
|
||||
*
|
||||
* @return The target of the link, NULL on error.
|
||||
*/
|
||||
LIBSSH_API char *sftp_readlink(sftp_session sftp, const char *path);
|
||||
|
||||
/**
|
||||
* @brief Get information about a mounted file system.
|
||||
*
|
||||
* @param sftp The sftp session handle.
|
||||
*
|
||||
* @param path The pathname of any file within the mounted file system.
|
||||
*
|
||||
* @return A statvfs structure or NULL on error.
|
||||
*/
|
||||
LIBSSH_API sftp_statvfs_t sftp_statvfs(sftp_session sftp, const char *path);
|
||||
|
||||
/**
|
||||
* @brief Get information about a mounted file system.
|
||||
*
|
||||
* @param file An opened file.
|
||||
*
|
||||
* @return A statvfs structure or NULL on error.
|
||||
*/
|
||||
LIBSSH_API sftp_statvfs_t sftp_fstatvfs(sftp_file file);
|
||||
|
||||
/**
|
||||
* @brief Free the memory of an allocated statvfs.
|
||||
*
|
||||
* @param statvfs_o The statvfs to free.
|
||||
*/
|
||||
LIBSSH_API void sftp_statvfs_free(sftp_statvfs_t statvfs_o);
|
||||
|
||||
/**
|
||||
* @brief Canonicalize a sftp path.
|
||||
@@ -601,7 +732,7 @@ int sftp_utimes(SFTP_SESSION *sftp, const char *file, const struct timeval *time
|
||||
*
|
||||
* @return The canonicalize path, NULL on error.
|
||||
*/
|
||||
char *sftp_canonicalize_path(SFTP_SESSION *sftp, const char *path);
|
||||
LIBSSH_API char *sftp_canonicalize_path(sftp_session sftp, const char *path);
|
||||
|
||||
/**
|
||||
* @brief Get the version of the SFTP protocol supported by the server
|
||||
@@ -610,7 +741,7 @@ char *sftp_canonicalize_path(SFTP_SESSION *sftp, const char *path);
|
||||
*
|
||||
* @return The server version.
|
||||
*/
|
||||
int sftp_server_version(SFTP_SESSION *sftp);
|
||||
LIBSSH_API int sftp_server_version(sftp_session sftp);
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
/**
|
||||
@@ -622,7 +753,7 @@ int sftp_server_version(SFTP_SESSION *sftp);
|
||||
*
|
||||
* @return A new sftp server session.
|
||||
*/
|
||||
SFTP_SESSION *sftp_server_new(SSH_SESSION *session, CHANNEL *chan);
|
||||
LIBSSH_API sftp_session sftp_server_new(ssh_session session, ssh_channel chan);
|
||||
|
||||
/**
|
||||
* @brief Intialize the sftp server.
|
||||
@@ -631,32 +762,32 @@ SFTP_SESSION *sftp_server_new(SSH_SESSION *session, CHANNEL *chan);
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
int sftp_server_init(SFTP_SESSION *sftp);
|
||||
LIBSSH_API int sftp_server_init(sftp_session sftp);
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
/* this is not a public interface */
|
||||
#define SFTP_HANDLES 256
|
||||
SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp);
|
||||
int sftp_packet_write(SFTP_SESSION *sftp,u8 type, BUFFER *payload);
|
||||
void sftp_packet_free(SFTP_PACKET *packet);
|
||||
int buffer_add_attributes(BUFFER *buffer, SFTP_ATTRIBUTES *attr);
|
||||
SFTP_ATTRIBUTES *sftp_parse_attr(SFTP_SESSION *session, BUFFER *buf,int expectname);
|
||||
sftp_packet sftp_packet_read(sftp_session sftp);
|
||||
int sftp_packet_write(sftp_session sftp,uint8_t type, ssh_buffer payload);
|
||||
void sftp_packet_free(sftp_packet packet);
|
||||
int buffer_add_attributes(ssh_buffer buffer, sftp_attributes attr);
|
||||
sftp_attributes sftp_parse_attr(sftp_session session, ssh_buffer buf,int expectname);
|
||||
/* sftpserver.c */
|
||||
|
||||
SFTP_CLIENT_MESSAGE *sftp_get_client_message(SFTP_SESSION *sftp);
|
||||
void sftp_client_message_free(SFTP_CLIENT_MESSAGE *msg);
|
||||
int sftp_reply_name(SFTP_CLIENT_MESSAGE *msg, const char *name,
|
||||
SFTP_ATTRIBUTES *attr);
|
||||
int sftp_reply_handle(SFTP_CLIENT_MESSAGE *msg, STRING *handle);
|
||||
STRING *sftp_handle_alloc(SFTP_SESSION *sftp, void *info);
|
||||
int sftp_reply_attr(SFTP_CLIENT_MESSAGE *msg, SFTP_ATTRIBUTES *attr);
|
||||
void *sftp_handle(SFTP_SESSION *sftp, STRING *handle);
|
||||
int sftp_reply_status(SFTP_CLIENT_MESSAGE *msg, u32 status, const char *message);
|
||||
int sftp_reply_names_add(SFTP_CLIENT_MESSAGE *msg, const char *file,
|
||||
const char *longname, SFTP_ATTRIBUTES *attr);
|
||||
int sftp_reply_names(SFTP_CLIENT_MESSAGE *msg);
|
||||
int sftp_reply_data(SFTP_CLIENT_MESSAGE *msg, const void *data, int len);
|
||||
void sftp_handle_remove(SFTP_SESSION *sftp, void *handle);
|
||||
sftp_client_message sftp_get_client_message(sftp_session sftp);
|
||||
void sftp_client_message_free(sftp_client_message msg);
|
||||
int sftp_reply_name(sftp_client_message msg, const char *name,
|
||||
sftp_attributes attr);
|
||||
int sftp_reply_handle(sftp_client_message msg, ssh_string handle);
|
||||
ssh_string sftp_handle_alloc(sftp_session sftp, void *info);
|
||||
int sftp_reply_attr(sftp_client_message msg, sftp_attributes attr);
|
||||
void *sftp_handle(sftp_session sftp, ssh_string handle);
|
||||
int sftp_reply_status(sftp_client_message msg, uint32_t status, const char *message);
|
||||
int sftp_reply_names_add(sftp_client_message msg, const char *file,
|
||||
const char *longname, sftp_attributes attr);
|
||||
int sftp_reply_names(sftp_client_message msg);
|
||||
int sftp_reply_data(sftp_client_message msg, const void *data, int len);
|
||||
void sftp_handle_remove(sftp_session sftp, void *handle);
|
||||
|
||||
/* SFTP commands and constants */
|
||||
#define SSH_FXP_INIT 1
|
||||
@@ -762,7 +893,9 @@ void sftp_handle_remove(SFTP_SESSION *sftp, void *handle);
|
||||
#define SFTP_READLINK SSH_FXP_READLINK
|
||||
#define SFTP_SYMLINK SSH_FXP_SYMLINK
|
||||
|
||||
|
||||
/* openssh flags */
|
||||
#define SSH_FXE_STATVFS_ST_RDONLY 0x1 /* read-only */
|
||||
#define SSH_FXE_STATVFS_ST_NOSUID 0x2 /* no setuid */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} ;
|
||||
|
||||
55
include/libssh/socket.h
Normal file
55
include/libssh/socket.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef SOCKET_H_
|
||||
#define SOCKET_H_
|
||||
|
||||
/* socket.c */
|
||||
|
||||
struct socket;
|
||||
int ssh_socket_init(void);
|
||||
struct socket *ssh_socket_new(ssh_session session);
|
||||
void ssh_socket_free(struct socket *s);
|
||||
void ssh_socket_set_fd(struct socket *s, socket_t fd);
|
||||
socket_t ssh_socket_get_fd(struct socket *s);
|
||||
#ifndef _WIN32
|
||||
int ssh_socket_unix(struct socket *s, const char *path);
|
||||
#endif
|
||||
void ssh_socket_close(struct socket *s);
|
||||
int ssh_socket_read(struct socket *s, void *buffer, int len);
|
||||
int ssh_socket_write(struct socket *s,const void *buffer, int len);
|
||||
int ssh_socket_is_open(struct socket *s);
|
||||
int ssh_socket_fd_isset(struct socket *s, fd_set *set);
|
||||
void ssh_socket_fd_set(struct socket *s, fd_set *set, int *fd_max);
|
||||
int ssh_socket_completeread(struct socket *s, void *buffer, uint32_t len);
|
||||
int ssh_socket_completewrite(struct socket *s, const void *buffer, uint32_t len);
|
||||
int ssh_socket_wait_for_data(struct socket *s, ssh_session session, uint32_t len);
|
||||
int ssh_socket_nonblocking_flush(struct socket *s);
|
||||
int ssh_socket_blocking_flush(struct socket *s);
|
||||
int ssh_socket_poll(struct socket *s, int *writeable, int *except);
|
||||
void ssh_socket_set_towrite(struct socket *s);
|
||||
void ssh_socket_set_toread(struct socket *s);
|
||||
void ssh_socket_set_except(struct socket *s);
|
||||
int ssh_socket_get_status(struct socket *s);
|
||||
int ssh_socket_data_available(struct socket *s);
|
||||
int ssh_socket_data_writable(struct socket *s);
|
||||
|
||||
#endif /* SOCKET_H_ */
|
||||
42
include/libssh/string.h
Normal file
42
include/libssh/string.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef STRING_H_
|
||||
#define STRING_H_
|
||||
#include "libssh/priv.h"
|
||||
|
||||
/* must be 32 bits number + immediately our data */
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
struct ssh_string_struct {
|
||||
uint32_t size;
|
||||
unsigned char string[MAX_PACKET_LEN];
|
||||
}
|
||||
#if !defined(__SUNPRO_C) && !defined(_MSC_VER)
|
||||
__attribute__ ((packed))
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack()
|
||||
#endif
|
||||
;
|
||||
|
||||
#endif /* STRING_H_ */
|
||||
114
include/libssh/wrapper.h
Normal file
114
include/libssh/wrapper.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef WRAPPER_H_
|
||||
#define WRAPPER_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef MD5_DIGEST_LEN
|
||||
#undef MD5_DIGEST_LEN
|
||||
#endif
|
||||
/* wrapper things */
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#include <gcrypt.h>
|
||||
typedef gcry_md_hd_t SHACTX;
|
||||
typedef gcry_md_hd_t MD5CTX;
|
||||
typedef gcry_md_hd_t HMACCTX;
|
||||
#define SHA_DIGEST_LEN 20
|
||||
#define MD5_DIGEST_LEN 16
|
||||
#define EVP_MAX_MD_SIZE 36
|
||||
|
||||
typedef gcry_mpi_t bignum;
|
||||
|
||||
#define bignum_new() gcry_mpi_new(0)
|
||||
#define bignum_free(num) gcry_mpi_release(num)
|
||||
#define bignum_set_word(bn,n) gcry_mpi_set_ui(bn,n)
|
||||
#define bignum_bin2bn(bn,datalen,data) gcry_mpi_scan(data,GCRYMPI_FMT_USG,bn,datalen,NULL)
|
||||
#define bignum_bn2dec(num) my_gcry_bn2dec(num)
|
||||
#define bignum_dec2bn(num, data) my_gcry_dec2bn(data, num)
|
||||
#define bignum_bn2hex(num,data) gcry_mpi_aprint(GCRYMPI_FMT_HEX,data,NULL,num)
|
||||
#define bignum_hex2bn(num,datalen,data) gcry_mpi_scan(num,GCRYMPI_FMT_HEX,data,datalen,NULL)
|
||||
#define bignum_rand(num,bits) gcry_mpi_randomize(num,bits,GCRY_STRONG_RANDOM),gcry_mpi_set_bit(num,bits-1),gcry_mpi_set_bit(num,0)
|
||||
#define bignum_mod_exp(dest,generator,exp,modulo) gcry_mpi_powm(dest,generator,exp,modulo)
|
||||
#define bignum_num_bits(num) gcry_mpi_get_nbits(num)
|
||||
#define bignum_num_bytes(num) ((gcry_mpi_get_nbits(num)+7)/8)
|
||||
#define bignum_is_bit_set(num,bit) gcry_mpi_test_bit(num,bit)
|
||||
#define bignum_bn2bin(num,datalen,data) gcry_mpi_print(GCRYMPI_FMT_USG,data,datalen,NULL,num)
|
||||
#define bignum_cmp(num1,num2) gcry_mpi_cmp(num1,num2)
|
||||
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/hmac.h>
|
||||
typedef SHA_CTX* SHACTX;
|
||||
typedef MD5_CTX* MD5CTX;
|
||||
typedef HMAC_CTX* HMACCTX;
|
||||
|
||||
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
|
||||
#define MD5_DIGEST_LEN MD5_DIGEST_LENGTH
|
||||
|
||||
#include <openssl/bn.h>
|
||||
typedef BIGNUM* bignum;
|
||||
typedef BN_CTX* bignum_CTX;
|
||||
|
||||
#define bignum_new() BN_new()
|
||||
#define bignum_free(num) BN_clear_free(num)
|
||||
#define bignum_set_word(bn,n) BN_set_word(bn,n)
|
||||
#define bignum_bin2bn(bn,datalen,data) BN_bin2bn(bn,datalen,data)
|
||||
#define bignum_bn2dec(num) BN_bn2dec(num)
|
||||
#define bignum_dec2bn(bn,data) BN_dec2bn(data,bn)
|
||||
#define bignum_bn2hex(num) BN_bn2hex(num)
|
||||
#define bignum_rand(rnd, bits, top, bottom) BN_rand(rnd,bits,top,bottom)
|
||||
#define bignum_ctx_new() BN_CTX_new()
|
||||
#define bignum_ctx_free(num) BN_CTX_free(num)
|
||||
#define bignum_mod_exp(dest,generator,exp,modulo,ctx) BN_mod_exp(dest,generator,exp,modulo,ctx)
|
||||
#define bignum_num_bytes(num) BN_num_bytes(num)
|
||||
#define bignum_num_bits(num) BN_num_bits(num)
|
||||
#define bignum_is_bit_set(num,bit) BN_is_bit_set(num,bit)
|
||||
#define bignum_bn2bin(num,ptr) BN_bn2bin(num,ptr)
|
||||
#define bignum_cmp(num1,num2) BN_cmp(num1,num2)
|
||||
|
||||
#endif /* OPENSSL_CRYPTO */
|
||||
|
||||
MD5CTX md5_init(void);
|
||||
void md5_update(MD5CTX c, const void *data, unsigned long len);
|
||||
void md5_final(unsigned char *md,MD5CTX c);
|
||||
SHACTX sha1_init(void);
|
||||
void sha1_update(SHACTX c, const void *data, unsigned long len);
|
||||
void sha1_final(unsigned char *md,SHACTX c);
|
||||
void sha1(unsigned char *digest,int len,unsigned char *hash);
|
||||
#define HMAC_SHA1 1
|
||||
#define HMAC_MD5 2
|
||||
HMACCTX hmac_init(const void *key,int len,int type);
|
||||
void hmac_update(HMACCTX c, const void *data, unsigned long len);
|
||||
void hmac_final(HMACCTX ctx,unsigned char *hashmacbuf,unsigned int *len);
|
||||
|
||||
int crypt_set_algorithms(ssh_session );
|
||||
int crypt_set_algorithms_server(ssh_session session);
|
||||
struct ssh_crypto_struct *crypto_new(void);
|
||||
void crypto_free(struct ssh_crypto_struct *crypto);
|
||||
|
||||
|
||||
#endif /* WRAPPER_H_ */
|
||||
@@ -1,999 +0,0 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 2000, Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
wspiapi.h
|
||||
|
||||
Abstract:
|
||||
The file contains protocol independent API functions.
|
||||
|
||||
Revision History:
|
||||
Wed Jul 12 10:50:31 2000, Created
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _WSPIAPI_H_
|
||||
#define _WSPIAPI_H_
|
||||
|
||||
#include <stdio.h> // sprintf()
|
||||
#include <stdlib.h> // calloc(), strtoul()
|
||||
#include <malloc.h> // calloc()
|
||||
#include <string.h> // strlen(), strcmp(), strstr()
|
||||
|
||||
#define WspiapiMalloc(tSize) calloc(1, (tSize))
|
||||
#define WspiapiFree(p) free(p)
|
||||
#define WspiapiSwap(a, b, c) { (c) = (a); (a) = (b); (b) = (c); }
|
||||
#define getaddrinfo WspiapiGetAddrInfo
|
||||
#define getnameinfo WspiapiGetNameInfo
|
||||
#define freeaddrinfo WspiapiFreeAddrInfo
|
||||
|
||||
typedef int (WINAPI *WSPIAPI_PGETADDRINFO) (
|
||||
IN const char *nodename,
|
||||
IN const char *servname,
|
||||
IN const struct addrinfo *hints,
|
||||
OUT struct addrinfo **res);
|
||||
|
||||
typedef int (WINAPI *WSPIAPI_PGETNAMEINFO) (
|
||||
IN const struct sockaddr *sa,
|
||||
IN socklen_t salen,
|
||||
OUT char *host,
|
||||
IN size_t hostlen,
|
||||
OUT char *serv,
|
||||
IN size_t servlen,
|
||||
IN int flags);
|
||||
|
||||
typedef void (WINAPI *WSPIAPI_PFREEADDRINFO) (
|
||||
IN struct addrinfo *ai);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// v4 only versions of getaddrinfo and friends.
|
||||
// NOTE: gai_strerror is inlined in ws2tcpip.h
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
__inline
|
||||
char *
|
||||
WINAPI
|
||||
WspiapiStrdup (
|
||||
IN const char * pszString)
|
||||
/*++
|
||||
|
||||
Routine Description
|
||||
allocates enough storage via calloc() for a copy of the string,
|
||||
copies the string into the new memory, and returns a pointer to it.
|
||||
|
||||
Arguments
|
||||
pszString string to copy into new memory
|
||||
|
||||
Return Value
|
||||
a pointer to the newly allocated storage with the string in it.
|
||||
NULL if enough memory could not be allocated, or string was NULL.
|
||||
|
||||
--*/
|
||||
{
|
||||
char *pszMemory;
|
||||
|
||||
if (!pszString)
|
||||
return(NULL);
|
||||
|
||||
pszMemory = (char *) WspiapiMalloc(strlen(pszString) + 1);
|
||||
if (!pszMemory)
|
||||
return(NULL);
|
||||
|
||||
return(strcpy(pszMemory, pszString));
|
||||
}
|
||||
|
||||
|
||||
|
||||
__inline
|
||||
BOOL
|
||||
WINAPI
|
||||
WspiapiParseV4Address (
|
||||
IN const char * pszAddress,
|
||||
OUT PDWORD pdwAddress)
|
||||
/*++
|
||||
|
||||
Routine Description
|
||||
get the IPv4 address (in network byte order) from its string
|
||||
representation. the syntax should be a.b.c.d.
|
||||
|
||||
Arguments
|
||||
pszArgument string representation of the IPv4 address
|
||||
ptAddress pointer to the resulting IPv4 address
|
||||
|
||||
Return Value
|
||||
Returns FALSE if there is an error, TRUE for success.
|
||||
|
||||
--*/
|
||||
{
|
||||
DWORD dwAddress = 0;
|
||||
const char *pcNext = NULL;
|
||||
int iCount = 0;
|
||||
|
||||
// ensure there are 3 '.' (periods)
|
||||
for (pcNext = pszAddress; *pcNext != '\0'; pcNext++)
|
||||
if (*pcNext == '.')
|
||||
iCount++;
|
||||
if (iCount != 3)
|
||||
return FALSE;
|
||||
|
||||
// return an error if dwAddress is INADDR_NONE (255.255.255.255)
|
||||
// since this is never a valid argument to getaddrinfo.
|
||||
dwAddress = inet_addr(pszAddress);
|
||||
if (dwAddress == INADDR_NONE)
|
||||
return FALSE;
|
||||
|
||||
*pdwAddress = dwAddress;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
__inline
|
||||
struct addrinfo *
|
||||
WINAPI
|
||||
WspiapiNewAddrInfo (
|
||||
IN int iSocketType,
|
||||
IN int iProtocol,
|
||||
IN WORD wPort,
|
||||
IN DWORD dwAddress)
|
||||
/*++
|
||||
|
||||
Routine Description
|
||||
allocate an addrinfo structure and populate fields.
|
||||
IPv4 specific internal function, not exported.
|
||||
|
||||
Arguments
|
||||
iSocketType SOCK_*. can be wildcarded (zero).
|
||||
iProtocol IPPROTO_*. can be wildcarded (zero).
|
||||
wPort port number of service (in network order).
|
||||
dwAddress IPv4 address (in network order).
|
||||
|
||||
Return Value
|
||||
returns an addrinfo struct, or NULL if out of memory.
|
||||
|
||||
--*/
|
||||
{
|
||||
struct addrinfo *ptNew;
|
||||
struct sockaddr_in *ptAddress;
|
||||
|
||||
// allocate a new addrinfo structure.
|
||||
ptNew =
|
||||
(struct addrinfo *) WspiapiMalloc(sizeof(struct addrinfo));
|
||||
if (!ptNew)
|
||||
return NULL;
|
||||
|
||||
ptAddress =
|
||||
(struct sockaddr_in *) WspiapiMalloc(sizeof(struct sockaddr_in));
|
||||
if (!ptAddress)
|
||||
{
|
||||
WspiapiFree(ptNew);
|
||||
return NULL;
|
||||
}
|
||||
ptAddress->sin_family = AF_INET;
|
||||
ptAddress->sin_port = wPort;
|
||||
ptAddress->sin_addr.s_addr = dwAddress;
|
||||
|
||||
// fill in the fields...
|
||||
ptNew->ai_family = PF_INET;
|
||||
ptNew->ai_socktype = iSocketType;
|
||||
ptNew->ai_protocol = iProtocol;
|
||||
ptNew->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
ptNew->ai_addr = (struct sockaddr *) ptAddress;
|
||||
|
||||
return ptNew;
|
||||
}
|
||||
|
||||
|
||||
|
||||
__inline
|
||||
int
|
||||
WINAPI
|
||||
WspiapiQueryDNS(
|
||||
IN const char *pszNodeName,
|
||||
IN int iSocketType,
|
||||
IN int iProtocol,
|
||||
IN WORD wPort,
|
||||
OUT char *pszAlias,
|
||||
OUT struct addrinfo **pptResult)
|
||||
/*++
|
||||
|
||||
Routine Description
|
||||
helper routine for WspiapiLookupNode.
|
||||
performs name resolution by querying the DNS for A records.
|
||||
*pptResult would need to be freed if an error is returned.
|
||||
|
||||
Arguments
|
||||
pszNodeName name of node to resolve.
|
||||
iSocketType SOCK_*. can be wildcarded (zero).
|
||||
iProtocol IPPROTO_*. can be wildcarded (zero).
|
||||
wPort port number of service (in network order).
|
||||
pszAlias where to return the alias.
|
||||
pptResult where to return the result.
|
||||
|
||||
Return Value
|
||||
Returns 0 on success, an EAI_* style error value otherwise.
|
||||
|
||||
--*/
|
||||
{
|
||||
struct addrinfo **pptNext = pptResult;
|
||||
struct hostent *ptHost = NULL;
|
||||
char **ppAddresses;
|
||||
|
||||
*pptNext = NULL;
|
||||
pszAlias[0] = '\0';
|
||||
|
||||
ptHost = gethostbyname(pszNodeName);
|
||||
if (ptHost)
|
||||
{
|
||||
if ((ptHost->h_addrtype == AF_INET) &&
|
||||
(ptHost->h_length == sizeof(struct in_addr)))
|
||||
{
|
||||
for (ppAddresses = ptHost->h_addr_list;
|
||||
*ppAddresses != NULL;
|
||||
ppAddresses++)
|
||||
{
|
||||
// create an addrinfo structure...
|
||||
*pptNext = WspiapiNewAddrInfo(
|
||||
iSocketType,
|
||||
iProtocol,
|
||||
wPort,
|
||||
((struct in_addr *) *ppAddresses)->s_addr);
|
||||
if (!*pptNext)
|
||||
return EAI_MEMORY;
|
||||
|
||||
pptNext = &((*pptNext)->ai_next);
|
||||
}
|
||||
}
|
||||
|
||||
// pick up the canonical name.
|
||||
strcpy(pszAlias, ptHost->h_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (WSAGetLastError())
|
||||
{
|
||||
case WSAHOST_NOT_FOUND: return EAI_NONAME;
|
||||
case WSATRY_AGAIN: return EAI_AGAIN;
|
||||
case WSANO_RECOVERY: return EAI_FAIL;
|
||||
case WSANO_DATA: return EAI_NODATA;
|
||||
default: return EAI_NONAME;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
__inline
|
||||
int
|
||||
WINAPI
|
||||
WspiapiLookupNode(
|
||||
IN const char *pszNodeName,
|
||||
IN int iSocketType,
|
||||
IN int iProtocol,
|
||||
IN WORD wPort,
|
||||
IN BOOL bAI_CANONNAME,
|
||||
OUT struct addrinfo **pptResult)
|
||||
/*++
|
||||
|
||||
Routine Description
|
||||
resolve a nodename and return a list of addrinfo structures.
|
||||
IPv4 specific internal function, not exported.
|
||||
*pptResult would need to be freed if an error is returned.
|
||||
|
||||
NOTE: if bAI_CANONNAME is true, the canonical name should be
|
||||
returned in the first addrinfo structure.
|
||||
|
||||
Arguments
|
||||
pszNodeName name of node to resolve.
|
||||
iSocketType SOCK_*. can be wildcarded (zero).
|
||||
iProtocol IPPROTO_*. can be wildcarded (zero).
|
||||
wPort port number of service (in network order).
|
||||
bAI_CANONNAME whether the AI_CANONNAME flag is set.
|
||||
pptResult where to return result.
|
||||
|
||||
Return Value
|
||||
Returns 0 on success, an EAI_* style error value otherwise.
|
||||
|
||||
--*/
|
||||
{
|
||||
int iError = 0;
|
||||
int iAliasCount = 0;
|
||||
|
||||
char szFQDN1[NI_MAXHOST] = "";
|
||||
char szFQDN2[NI_MAXHOST] = "";
|
||||
char *pszName = szFQDN1;
|
||||
char *pszAlias = szFQDN2;
|
||||
char *pszScratch = NULL;
|
||||
strcpy(pszName, pszNodeName);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
iError = WspiapiQueryDNS(pszNodeName,
|
||||
iSocketType,
|
||||
iProtocol,
|
||||
wPort,
|
||||
pszAlias,
|
||||
pptResult);
|
||||
if (iError)
|
||||
break;
|
||||
|
||||
// if we found addresses, then we are done.
|
||||
if (*pptResult)
|
||||
break;
|
||||
|
||||
// stop infinite loops due to DNS misconfiguration. there appears
|
||||
// to be no particular recommended limit in RFCs 1034 and 1035.
|
||||
if ((!strlen(pszAlias)) ||
|
||||
(!strcmp(pszName, pszAlias)) ||
|
||||
(++iAliasCount == 16))
|
||||
{
|
||||
iError = EAI_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
// there was a new CNAME, look again.
|
||||
WspiapiSwap(pszName, pszAlias, pszScratch);
|
||||
}
|
||||
|
||||
if (!iError && bAI_CANONNAME)
|
||||
{
|
||||
(*pptResult)->ai_canonname = WspiapiStrdup(pszAlias);
|
||||
if (!(*pptResult)->ai_canonname)
|
||||
iError = EAI_MEMORY;
|
||||
}
|
||||
|
||||
return iError;
|
||||
}
|
||||
|
||||
|
||||
|
||||
__inline
|
||||
int
|
||||
WINAPI
|
||||
WspiapiClone (
|
||||
IN WORD wPort,
|
||||
IN struct addrinfo *ptResult)
|
||||
/*++
|
||||
|
||||
Routine Description
|
||||
clone every addrinfo structure in ptResult for the UDP service.
|
||||
ptResult would need to be freed if an error is returned.
|
||||
|
||||
Arguments
|
||||
wPort port number of UDP service.
|
||||
ptResult list of addrinfo structures, each
|
||||
of whose node needs to be cloned.
|
||||
|
||||
Return Value
|
||||
Returns 0 on success, an EAI_MEMORY on allocation failure.
|
||||
|
||||
--*/
|
||||
{
|
||||
struct addrinfo *ptNext = NULL;
|
||||
struct addrinfo *ptNew = NULL;
|
||||
|
||||
for (ptNext = ptResult; ptNext != NULL; )
|
||||
{
|
||||
// create an addrinfo structure...
|
||||
ptNew = WspiapiNewAddrInfo(
|
||||
SOCK_DGRAM,
|
||||
ptNext->ai_protocol,
|
||||
wPort,
|
||||
((struct sockaddr_in *) ptNext->ai_addr)->sin_addr.s_addr);
|
||||
if (!ptNew)
|
||||
break;
|
||||
|
||||
// link the cloned addrinfo
|
||||
ptNew->ai_next = ptNext->ai_next;
|
||||
ptNext->ai_next = ptNew;
|
||||
ptNext = ptNew->ai_next;
|
||||
}
|
||||
|
||||
if (ptNext != NULL)
|
||||
return EAI_MEMORY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
__inline
|
||||
void
|
||||
WINAPI
|
||||
WspiapiLegacyFreeAddrInfo (
|
||||
IN struct addrinfo *ptHead)
|
||||
/*++
|
||||
|
||||
Routine Description
|
||||
Free an addrinfo structure (or chain of structures).
|
||||
As specified in RFC 2553, Section 6.4.
|
||||
|
||||
Arguments
|
||||
ptHead structure (chain) to free
|
||||
|
||||
--*/
|
||||
{
|
||||
struct addrinfo *ptNext; // next strcture to free
|
||||
|
||||
for (ptNext = ptHead; ptNext != NULL; ptNext = ptHead)
|
||||
{
|
||||
if (ptNext->ai_canonname)
|
||||
WspiapiFree(ptNext->ai_canonname);
|
||||
|
||||
if (ptNext->ai_addr)
|
||||
WspiapiFree(ptNext->ai_addr);
|
||||
|
||||
ptHead = ptNext->ai_next;
|
||||
WspiapiFree(ptNext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
__inline
|
||||
int
|
||||
WINAPI
|
||||
WspiapiLegacyGetAddrInfo(
|
||||
IN const char *pszNodeName,
|
||||
IN const char *pszServiceName,
|
||||
IN const struct addrinfo *ptHints,
|
||||
OUT struct addrinfo **pptResult)
|
||||
/*++
|
||||
|
||||
Routine Description
|
||||
Protocol-independent name-to-address translation.
|
||||
As specified in RFC 2553, Section 6.4.
|
||||
This is the hacked version that only supports IPv4.
|
||||
|
||||
Arguments
|
||||
pszNodeName node name to lookup.
|
||||
pszServiceName service name to lookup.
|
||||
ptHints hints about how to process request.
|
||||
pptResult where to return result.
|
||||
|
||||
Return Value
|
||||
returns zero if successful, an EAI_* error code if not.
|
||||
|
||||
--*/
|
||||
{
|
||||
int iError = 0;
|
||||
int iFlags = 0;
|
||||
int iFamily = PF_UNSPEC;
|
||||
int iSocketType = 0;
|
||||
int iProtocol = 0;
|
||||
WORD wPort = 0;
|
||||
DWORD dwAddress = 0;
|
||||
|
||||
struct servent *ptService = NULL;
|
||||
char *pc = NULL;
|
||||
BOOL bClone = FALSE;
|
||||
WORD wTcpPort = 0;
|
||||
WORD wUdpPort = 0;
|
||||
|
||||
|
||||
// initialize pptResult with default return value.
|
||||
*pptResult = NULL;
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
// validate arguments...
|
||||
//
|
||||
|
||||
// both the node name and the service name can't be NULL.
|
||||
if ((!pszNodeName) && (!pszServiceName))
|
||||
return EAI_NONAME;
|
||||
|
||||
// validate hints.
|
||||
if (ptHints)
|
||||
{
|
||||
// all members other than ai_flags, ai_family, ai_socktype
|
||||
// and ai_protocol must be zero or a null pointer.
|
||||
if ((ptHints->ai_addrlen != 0) ||
|
||||
(ptHints->ai_canonname != NULL) ||
|
||||
(ptHints->ai_addr != NULL) ||
|
||||
(ptHints->ai_next != NULL))
|
||||
{
|
||||
return EAI_FAIL;
|
||||
}
|
||||
|
||||
// the spec has the "bad flags" error code, so presumably we
|
||||
// should check something here. insisting that there aren't
|
||||
// any unspecified flags set would break forward compatibility,
|
||||
// however. so we just check for non-sensical combinations.
|
||||
//
|
||||
// we cannot come up with a canonical name given a null node name.
|
||||
iFlags = ptHints->ai_flags;
|
||||
if ((iFlags & AI_CANONNAME) && !pszNodeName)
|
||||
return EAI_BADFLAGS;
|
||||
|
||||
// we only support a limited number of protocol families.
|
||||
iFamily = ptHints->ai_family;
|
||||
if ((iFamily != PF_UNSPEC) && (iFamily != PF_INET))
|
||||
return EAI_FAMILY;
|
||||
|
||||
// we only support only these socket types.
|
||||
iSocketType = ptHints->ai_socktype;
|
||||
if ((iSocketType != 0) &&
|
||||
(iSocketType != SOCK_STREAM) &&
|
||||
(iSocketType != SOCK_DGRAM) &&
|
||||
(iSocketType != SOCK_RAW))
|
||||
return EAI_SOCKTYPE;
|
||||
|
||||
// REVIEW: What if ai_socktype and ai_protocol are at odds?
|
||||
iProtocol = ptHints->ai_protocol;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
// do service lookup...
|
||||
|
||||
if (pszServiceName)
|
||||
{
|
||||
wPort = (WORD) strtoul(pszServiceName, &pc, 10);
|
||||
if (*pc == '\0') // numeric port string
|
||||
{
|
||||
wPort = wTcpPort = wUdpPort = htons(wPort);
|
||||
if (iSocketType == 0)
|
||||
{
|
||||
bClone = TRUE;
|
||||
iSocketType = SOCK_STREAM;
|
||||
}
|
||||
}
|
||||
else // non numeric port string
|
||||
{
|
||||
if ((iSocketType == 0) || (iSocketType == SOCK_DGRAM))
|
||||
{
|
||||
ptService = getservbyname(pszServiceName, "udp");
|
||||
if (ptService)
|
||||
wPort = wUdpPort = ptService->s_port;
|
||||
}
|
||||
|
||||
if ((iSocketType == 0) || (iSocketType == SOCK_STREAM))
|
||||
{
|
||||
ptService = getservbyname(pszServiceName, "tcp");
|
||||
if (ptService)
|
||||
wPort = wTcpPort = ptService->s_port;
|
||||
}
|
||||
|
||||
// assumes 0 is an invalid service port...
|
||||
if (wPort == 0) // no service exists
|
||||
return (iSocketType ? EAI_SERVICE : EAI_NONAME);
|
||||
|
||||
if (iSocketType == 0)
|
||||
{
|
||||
// if both tcp and udp, process tcp now & clone udp later.
|
||||
iSocketType = (wTcpPort) ? SOCK_STREAM : SOCK_DGRAM;
|
||||
bClone = (wTcpPort && wUdpPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
// do node name lookup...
|
||||
|
||||
// if we weren't given a node name,
|
||||
// return the wildcard or loopback address (depending on AI_PASSIVE).
|
||||
//
|
||||
// if we have a numeric host address string,
|
||||
// return the binary address.
|
||||
//
|
||||
if ((!pszNodeName) || (WspiapiParseV4Address(pszNodeName, &dwAddress)))
|
||||
{
|
||||
if (!pszNodeName)
|
||||
{
|
||||
dwAddress = htonl((iFlags & AI_PASSIVE)
|
||||
? INADDR_ANY
|
||||
: INADDR_LOOPBACK);
|
||||
}
|
||||
|
||||
// create an addrinfo structure...
|
||||
*pptResult =
|
||||
WspiapiNewAddrInfo(iSocketType, iProtocol, wPort, dwAddress);
|
||||
if (!(*pptResult))
|
||||
iError = EAI_MEMORY;
|
||||
|
||||
if (!iError && pszNodeName)
|
||||
{
|
||||
// implementation specific behavior: set AI_NUMERICHOST
|
||||
// to indicate that we got a numeric host address string.
|
||||
(*pptResult)->ai_flags |= AI_NUMERICHOST;
|
||||
|
||||
// return the numeric address string as the canonical name
|
||||
if (iFlags & AI_CANONNAME)
|
||||
{
|
||||
(*pptResult)->ai_canonname =
|
||||
WspiapiStrdup(inet_ntoa(*((struct in_addr *) &dwAddress)));
|
||||
if (!(*pptResult)->ai_canonname)
|
||||
iError = EAI_MEMORY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if we do not have a numeric host address string and
|
||||
// AI_NUMERICHOST flag is set, return an error!
|
||||
else if (iFlags & AI_NUMERICHOST)
|
||||
{
|
||||
iError = EAI_NONAME;
|
||||
}
|
||||
|
||||
|
||||
// since we have a non-numeric node name,
|
||||
// we have to do a regular node name lookup.
|
||||
else
|
||||
{
|
||||
iError = WspiapiLookupNode(pszNodeName,
|
||||
iSocketType,
|
||||
iProtocol,
|
||||
wPort,
|
||||
(iFlags & AI_CANONNAME),
|
||||
pptResult);
|
||||
}
|
||||
|
||||
if (!iError && bClone)
|
||||
{
|
||||
iError = WspiapiClone(wUdpPort, *pptResult);
|
||||
}
|
||||
|
||||
if (iError)
|
||||
{
|
||||
WspiapiLegacyFreeAddrInfo(*pptResult);
|
||||
*pptResult = NULL;
|
||||
}
|
||||
|
||||
return (iError);
|
||||
}
|
||||
|
||||
|
||||
|
||||
__inline
|
||||
int
|
||||
WINAPI
|
||||
WspiapiLegacyGetNameInfo(
|
||||
IN const struct sockaddr *ptSocketAddress,
|
||||
IN socklen_t tSocketLength,
|
||||
OUT char *pszNodeName,
|
||||
IN size_t tNodeLength,
|
||||
OUT char *pszServiceName,
|
||||
IN size_t tServiceLength,
|
||||
IN int iFlags)
|
||||
/*++
|
||||
|
||||
Routine Description
|
||||
protocol-independent address-to-name translation.
|
||||
as specified in RFC 2553, Section 6.5.
|
||||
this is the hacked version that only supports IPv4.
|
||||
|
||||
Arguments
|
||||
ptSocketAddress socket address to translate.
|
||||
tSocketLength length of above socket address.
|
||||
pszNodeName where to return the node name.
|
||||
tNodeLength size of above buffer.
|
||||
pszServiceName where to return the service name.
|
||||
tServiceLength size of above buffer.
|
||||
iFlags flags of type NI_*.
|
||||
|
||||
Return Value
|
||||
returns zero if successful, an EAI_* error code if not.
|
||||
|
||||
--*/
|
||||
{
|
||||
struct servent *ptService;
|
||||
WORD wPort;
|
||||
char szBuffer[] = "65535";
|
||||
char *pszService = szBuffer;
|
||||
|
||||
struct hostent *ptHost;
|
||||
struct in_addr tAddress;
|
||||
char *pszNode = NULL;
|
||||
char *pc = NULL;
|
||||
|
||||
|
||||
// sanity check ptSocketAddress and tSocketLength.
|
||||
if (!ptSocketAddress)
|
||||
return EAI_FAIL;
|
||||
|
||||
if ((ptSocketAddress->sa_family != AF_INET) ||
|
||||
(tSocketLength != sizeof(struct sockaddr_in)))
|
||||
{
|
||||
return EAI_FAMILY;
|
||||
}
|
||||
|
||||
if (!(pszNodeName && tNodeLength) &&
|
||||
!(pszServiceName && tServiceLength))
|
||||
{
|
||||
return EAI_NONAME;
|
||||
}
|
||||
|
||||
// the draft has the "bad flags" error code, so presumably we
|
||||
// should check something here. insisting that there aren't
|
||||
// any unspecified flags set would break forward compatibility,
|
||||
// however. so we just check for non-sensical combinations.
|
||||
if ((iFlags & NI_NUMERICHOST) && (iFlags & NI_NAMEREQD))
|
||||
{
|
||||
return EAI_BADFLAGS;
|
||||
}
|
||||
|
||||
// translate the port to a service name (if requested).
|
||||
if (pszServiceName && tServiceLength)
|
||||
{
|
||||
wPort = ((struct sockaddr_in *) ptSocketAddress)->sin_port;
|
||||
|
||||
if (iFlags & NI_NUMERICSERV)
|
||||
{
|
||||
// return numeric form of the address.
|
||||
sprintf(szBuffer, "%u", ntohs(wPort));
|
||||
}
|
||||
else
|
||||
{
|
||||
// return service name corresponding to port.
|
||||
ptService = getservbyport(wPort,
|
||||
(iFlags & NI_DGRAM) ? "udp" : NULL);
|
||||
if (ptService && ptService->s_name)
|
||||
{
|
||||
// lookup successful.
|
||||
pszService = ptService->s_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
// DRAFT: return numeric form of the port!
|
||||
sprintf(szBuffer, "%u", ntohs(wPort));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (tServiceLength > strlen(pszService))
|
||||
strcpy(pszServiceName, pszService);
|
||||
else
|
||||
return EAI_FAIL;
|
||||
}
|
||||
|
||||
|
||||
// translate the address to a node name (if requested).
|
||||
if (pszNodeName && tNodeLength)
|
||||
{
|
||||
// this is the IPv4-only version, so we have an IPv4 address.
|
||||
tAddress = ((struct sockaddr_in *) ptSocketAddress)->sin_addr;
|
||||
|
||||
if (iFlags & NI_NUMERICHOST)
|
||||
{
|
||||
// return numeric form of the address.
|
||||
pszNode = inet_ntoa(tAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
// return node name corresponding to address.
|
||||
ptHost = gethostbyaddr((char *) &tAddress,
|
||||
sizeof(struct in_addr),
|
||||
AF_INET);
|
||||
if (ptHost && ptHost->h_name)
|
||||
{
|
||||
// DNS lookup successful.
|
||||
// stop copying at a "." if NI_NOFQDN is specified.
|
||||
pszNode = ptHost->h_name;
|
||||
if ((iFlags & NI_NOFQDN) && (pc = strchr(pszNode, '.')))
|
||||
*pc = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
// DNS lookup failed. return numeric form of the address.
|
||||
if (iFlags & NI_NAMEREQD)
|
||||
{
|
||||
switch (WSAGetLastError())
|
||||
{
|
||||
case WSAHOST_NOT_FOUND: return EAI_NONAME;
|
||||
case WSATRY_AGAIN: return EAI_AGAIN;
|
||||
case WSANO_RECOVERY: return EAI_FAIL;
|
||||
default: return EAI_NONAME;
|
||||
}
|
||||
}
|
||||
else
|
||||
pszNode = inet_ntoa(tAddress);
|
||||
}
|
||||
}
|
||||
|
||||
if (tNodeLength > strlen(pszNode))
|
||||
strcpy(pszNodeName, pszNode);
|
||||
else
|
||||
return EAI_FAIL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char const *pszName;
|
||||
FARPROC pfAddress;
|
||||
} WSPIAPI_FUNCTION;
|
||||
|
||||
#define WSPIAPI_FUNCTION_ARRAY \
|
||||
{ \
|
||||
"getaddrinfo", (FARPROC) WspiapiLegacyGetAddrInfo, \
|
||||
"getnameinfo", (FARPROC) WspiapiLegacyGetNameInfo, \
|
||||
"freeaddrinfo", (FARPROC) WspiapiLegacyFreeAddrInfo, \
|
||||
}
|
||||
|
||||
|
||||
|
||||
__inline
|
||||
FARPROC
|
||||
WINAPI
|
||||
WspiapiLoad(
|
||||
IN WORD wFunction)
|
||||
/*++
|
||||
|
||||
Routine Description
|
||||
try to locate the address family independent name resolution routines
|
||||
(i.e. getaddrinfo, getnameinfo, freeaddrinfo, gai_strerror).
|
||||
|
||||
Locks
|
||||
this function call is not synchronized. hence the library containing
|
||||
the routines might be loaded multiple times. another option is to
|
||||
synchronize through a spin lock using a static local variable and the
|
||||
InterlockedExchange operation.
|
||||
|
||||
|
||||
Arguments
|
||||
wFunction ordinal # of the function to get the pointer to
|
||||
0 getaddrinfo
|
||||
1 getnameinfo
|
||||
2 freeaddrinfo
|
||||
|
||||
Return Value
|
||||
address of the library/legacy routine
|
||||
|
||||
--*/
|
||||
{
|
||||
HMODULE hLibrary = NULL;
|
||||
|
||||
// these static variables store state across calls, across threads.
|
||||
static BOOL bInitialized = FALSE;
|
||||
static WSPIAPI_FUNCTION rgtGlobal[] = WSPIAPI_FUNCTION_ARRAY;
|
||||
static const int iNumGlobal = (sizeof(rgtGlobal) /
|
||||
sizeof(WSPIAPI_FUNCTION));
|
||||
|
||||
// we overwrite rgtGlobal only if all routines exist in library.
|
||||
WSPIAPI_FUNCTION rgtLocal[] = WSPIAPI_FUNCTION_ARRAY;
|
||||
FARPROC fScratch = NULL;
|
||||
int i = 0;
|
||||
|
||||
|
||||
if (bInitialized) // WspiapiLoad has already been called once
|
||||
return (rgtGlobal[wFunction].pfAddress);
|
||||
|
||||
do // breakout loop
|
||||
{
|
||||
// in Whistler and beyond...
|
||||
// the routines are present in the WinSock 2 library (ws2_32.dll).
|
||||
// printf("Looking in ws2_32 for getaddrinfo...\n");
|
||||
hLibrary = LoadLibraryA("ws2_32");
|
||||
if (hLibrary != NULL)
|
||||
{
|
||||
fScratch = GetProcAddress(hLibrary, "getaddrinfo");
|
||||
if (fScratch == NULL)
|
||||
{
|
||||
FreeLibrary(hLibrary);
|
||||
hLibrary = NULL;
|
||||
}
|
||||
}
|
||||
if (hLibrary != NULL)
|
||||
break;
|
||||
|
||||
|
||||
// in the IPv6 Technology Preview...
|
||||
// the routines are present in the IPv6 WinSock library (wship6.dll).
|
||||
// printf("Looking in wship6 for getaddrinfo...\n");
|
||||
hLibrary = LoadLibraryA("wship6");
|
||||
if (hLibrary != NULL)
|
||||
{
|
||||
fScratch = GetProcAddress(hLibrary, "getaddrinfo");
|
||||
if (fScratch == NULL)
|
||||
{
|
||||
FreeLibrary(hLibrary);
|
||||
hLibrary = NULL;
|
||||
}
|
||||
}
|
||||
} while (FALSE);
|
||||
|
||||
|
||||
if (hLibrary != NULL)
|
||||
{
|
||||
// use routines from this library...
|
||||
// since getaddrinfo is here, we expect all routines to be here,
|
||||
// but will fall back to IPv4-only if any of them is missing.
|
||||
for (i = 0; i < iNumGlobal; i++)
|
||||
{
|
||||
rgtLocal[i].pfAddress
|
||||
= GetProcAddress(hLibrary, rgtLocal[i].pszName);
|
||||
if (rgtLocal[i].pfAddress == NULL)
|
||||
{
|
||||
FreeLibrary(hLibrary);
|
||||
hLibrary = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hLibrary != NULL)
|
||||
{
|
||||
// printf("found!\n");
|
||||
for (i = 0; i < iNumGlobal; i++)
|
||||
rgtGlobal[i].pfAddress = rgtLocal[i].pfAddress;
|
||||
}
|
||||
}
|
||||
|
||||
bInitialized = TRUE;
|
||||
return (rgtGlobal[wFunction].pfAddress);
|
||||
}
|
||||
|
||||
|
||||
|
||||
__inline
|
||||
int
|
||||
WINAPI
|
||||
WspiapiGetAddrInfo(
|
||||
IN const char *nodename,
|
||||
IN const char *servname,
|
||||
IN const struct addrinfo *hints,
|
||||
OUT struct addrinfo **res)
|
||||
{
|
||||
static WSPIAPI_PGETADDRINFO pfGetAddrInfo = NULL;
|
||||
|
||||
if (!pfGetAddrInfo)
|
||||
pfGetAddrInfo = (WSPIAPI_PGETADDRINFO) WspiapiLoad(0);
|
||||
return ((*pfGetAddrInfo)
|
||||
(nodename, servname, hints, res));
|
||||
}
|
||||
|
||||
|
||||
|
||||
__inline
|
||||
int
|
||||
WINAPI
|
||||
WspiapiGetNameInfo (
|
||||
IN const struct sockaddr *sa,
|
||||
IN socklen_t salen,
|
||||
OUT char *host,
|
||||
IN size_t hostlen,
|
||||
OUT char *serv,
|
||||
IN size_t servlen,
|
||||
IN int flags)
|
||||
{
|
||||
static WSPIAPI_PGETNAMEINFO pfGetNameInfo = NULL;
|
||||
|
||||
if (!pfGetNameInfo)
|
||||
pfGetNameInfo = (WSPIAPI_PGETNAMEINFO) WspiapiLoad(1);
|
||||
return ((*pfGetNameInfo)
|
||||
(sa, salen, host, hostlen, serv, servlen, flags));
|
||||
}
|
||||
|
||||
|
||||
|
||||
__inline
|
||||
void
|
||||
WINAPI
|
||||
WspiapiFreeAddrInfo (
|
||||
IN struct addrinfo *ai)
|
||||
{
|
||||
static WSPIAPI_PFREEADDRINFO pfFreeAddrInfo = NULL;
|
||||
|
||||
if (!pfFreeAddrInfo)
|
||||
pfFreeAddrInfo = (WSPIAPI_PFREEADDRINFO) WspiapiLoad(2);
|
||||
(*pfFreeAddrInfo)(ai);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _WSPIAPI_H_
|
||||
@@ -25,6 +25,7 @@ if (WITH_STATIC_LIB)
|
||||
endif (WITH_STATIC_LIB)
|
||||
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
${LIBSSH_REQUIRED_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
)
|
||||
|
||||
@@ -35,6 +36,13 @@ if (WIN32)
|
||||
)
|
||||
endif (WIN32)
|
||||
|
||||
if (HAVE_LIBSOCKET)
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
${LIBSSH_LINK_LIBRARIES}
|
||||
socket
|
||||
)
|
||||
endif (HAVE_LIBSOCKET)
|
||||
|
||||
if (CRYPTO_LIBRARY)
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
@@ -59,14 +67,15 @@ if (GCRYPT_LIBRARY)
|
||||
)
|
||||
endif (GCRYPT_LIBRARY)
|
||||
|
||||
|
||||
set(libssh_SRCS
|
||||
agent.c
|
||||
auth.c
|
||||
base64.c
|
||||
buffer.c
|
||||
callbacks.c
|
||||
channels.c
|
||||
client.c
|
||||
config.c
|
||||
connect.c
|
||||
crc32.c
|
||||
crypt.c
|
||||
@@ -86,12 +95,20 @@ set(libssh_SRCS
|
||||
packet.c
|
||||
poll.c
|
||||
session.c
|
||||
scp.c
|
||||
socket.c
|
||||
string.c
|
||||
wrapper.c
|
||||
libssh.map
|
||||
)
|
||||
|
||||
if (WITH_PCAP)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
pcap.c
|
||||
)
|
||||
|
||||
endif (WITH_PCAP)
|
||||
|
||||
if (WITH_SFTP)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
@@ -139,22 +156,27 @@ set_target_properties(
|
||||
${LIBRARY_SOVERSION}
|
||||
OUTPUT_NAME
|
||||
ssh
|
||||
DEFINE_SYMBOL
|
||||
LIBSSH_EXPORTS
|
||||
)
|
||||
|
||||
if (WITH_VISIBILITY_HIDDEN)
|
||||
set_target_properties(${LIBSSH_SHARED_LIBRARY} PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
|
||||
endif (WITH_VISIBILITY_HIDDEN)
|
||||
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
${LIBSSH_SHARED_LIBRARY}
|
||||
DESTINATION
|
||||
${LIB_INSTALL_DIR}
|
||||
COMPONENT
|
||||
libraries
|
||||
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
|
||||
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
|
||||
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
|
||||
COMPONENT libraries
|
||||
)
|
||||
|
||||
if (WITH_STATIC_LIB)
|
||||
add_library(${LIBSSH_STATIC_LIBRARY} STATIC ${libssh_SRCS})
|
||||
|
||||
target_link_libraries(${LIBSSH_STATIC_LIBRARY} ${LIBSSH_LINK_LIBRARIES})
|
||||
|
||||
set_target_properties(
|
||||
${LIBSSH_STATIC_LIBRARY}
|
||||
PROPERTIES
|
||||
@@ -162,8 +184,8 @@ if (WITH_STATIC_LIB)
|
||||
${LIBRARY_VERSION}
|
||||
SOVERSION
|
||||
${LIBRARY_SOVERSION}
|
||||
OUTPUT_NAME
|
||||
ssh
|
||||
COMPILE_FLAGS
|
||||
"-DLIBSSH_STATIC"
|
||||
)
|
||||
|
||||
install(
|
||||
|
||||
101
libssh/agent.c
101
libssh/agent.c
@@ -50,31 +50,35 @@
|
||||
|
||||
#include "libssh/agent.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/keys.h"
|
||||
|
||||
/* macro to check for "agent failure" message */
|
||||
#define agent_failed(x) \
|
||||
(((x) == SSH_AGENT_FAILURE) || ((x) == SSH_COM_AGENT2_FAILURE) || \
|
||||
((x) == SSH2_AGENT_FAILURE))
|
||||
|
||||
static u32 agent_get_u32(const void *vp) {
|
||||
const u8 *p = (const u8 *)vp;
|
||||
u32 v;
|
||||
static uint32_t agent_get_u32(const void *vp) {
|
||||
const uint8_t *p = (const uint8_t *)vp;
|
||||
uint32_t v;
|
||||
|
||||
v = (u32)p[0] << 24;
|
||||
v |= (u32)p[1] << 16;
|
||||
v |= (u32)p[2] << 8;
|
||||
v |= (u32)p[3];
|
||||
v = (uint32_t)p[0] << 24;
|
||||
v |= (uint32_t)p[1] << 16;
|
||||
v |= (uint32_t)p[2] << 8;
|
||||
v |= (uint32_t)p[3];
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static void agent_put_u32(void *vp, u32 v) {
|
||||
u8 *p = (u8 *)vp;
|
||||
static void agent_put_u32(void *vp, uint32_t v) {
|
||||
uint8_t *p = (uint8_t *)vp;
|
||||
|
||||
p[0] = (u8)(v >> 24) & 0xff;
|
||||
p[1] = (u8)(v >> 16) & 0xff;
|
||||
p[2] = (u8)(v >> 8) & 0xff;
|
||||
p[3] = (u8)v & 0xff;
|
||||
p[0] = (uint8_t)(v >> 24) & 0xff;
|
||||
p[1] = (uint8_t)(v >> 16) & 0xff;
|
||||
p[2] = (uint8_t)(v >> 8) & 0xff;
|
||||
p[3] = (uint8_t)v & 0xff;
|
||||
}
|
||||
|
||||
static size_t atomicio(struct socket *s, void *buf, size_t n, int do_read) {
|
||||
@@ -118,10 +122,10 @@ static size_t atomicio(struct socket *s, void *buf, size_t n, int do_read) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
AGENT *agent_new(struct ssh_session *session) {
|
||||
AGENT *agent = NULL;
|
||||
ssh_agent agent_new(struct ssh_session_struct *session) {
|
||||
ssh_agent agent = NULL;
|
||||
|
||||
agent = malloc(sizeof(AGENT));
|
||||
agent = malloc(sizeof(struct ssh_agent_struct));
|
||||
if (agent == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -137,7 +141,7 @@ AGENT *agent_new(struct ssh_session *session) {
|
||||
return agent;
|
||||
}
|
||||
|
||||
void agent_close(struct agent_struct *agent) {
|
||||
void agent_close(struct ssh_agent_struct *agent) {
|
||||
if (agent == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -147,7 +151,7 @@ void agent_close(struct agent_struct *agent) {
|
||||
}
|
||||
}
|
||||
|
||||
void agent_free(AGENT *agent) {
|
||||
void agent_free(ssh_agent agent) {
|
||||
if (agent) {
|
||||
if (agent->ident) {
|
||||
buffer_free(agent->ident);
|
||||
@@ -160,7 +164,7 @@ void agent_free(AGENT *agent) {
|
||||
}
|
||||
}
|
||||
|
||||
static int agent_connect(SSH_SESSION *session) {
|
||||
static int agent_connect(ssh_session session) {
|
||||
const char *auth_sock = NULL;
|
||||
|
||||
if (session == NULL || session->agent == NULL) {
|
||||
@@ -180,7 +184,7 @@ static int agent_connect(SSH_SESSION *session) {
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int agent_decode_reply(struct ssh_session *session, int type) {
|
||||
static int agent_decode_reply(struct ssh_session_struct *session, int type) {
|
||||
switch (type) {
|
||||
case SSH_AGENT_FAILURE:
|
||||
case SSH2_AGENT_FAILURE:
|
||||
@@ -199,10 +203,10 @@ static int agent_decode_reply(struct ssh_session *session, int type) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static int agent_talk(struct ssh_session *session,
|
||||
struct buffer_struct *request, struct buffer_struct *reply) {
|
||||
u32 len = 0;
|
||||
u8 payload[1024] = {0};
|
||||
static int agent_talk(struct ssh_session_struct *session,
|
||||
struct ssh_buffer_struct *request, struct ssh_buffer_struct *reply) {
|
||||
uint32_t len = 0;
|
||||
uint8_t payload[1024] = {0};
|
||||
|
||||
len = buffer_get_len(request);
|
||||
ssh_log(session, SSH_LOG_PACKET, "agent_talk - len of request: %u", len);
|
||||
@@ -210,10 +214,7 @@ static int agent_talk(struct ssh_session *session,
|
||||
|
||||
/* send length and then the request packet */
|
||||
if (atomicio(session->agent->sock, payload, 4, 0) == 4) {
|
||||
buffer_get_data(request, payload, len);
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"agent_talk - sending request, payload[0] = %u", payload[0]);
|
||||
if (atomicio(session->agent->sock, payload, len, 0)
|
||||
if (atomicio(session->agent->sock, buffer_get_rest(request), len, 0)
|
||||
!= len) {
|
||||
ssh_log(session, SSH_LOG_PACKET, "atomicio sending request failed: %s",
|
||||
strerror(errno));
|
||||
@@ -262,12 +263,12 @@ static int agent_talk(struct ssh_session *session,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int agent_get_ident_count(struct ssh_session *session) {
|
||||
BUFFER *request = NULL;
|
||||
BUFFER *reply = NULL;
|
||||
int agent_get_ident_count(struct ssh_session_struct *session) {
|
||||
ssh_buffer request = NULL;
|
||||
ssh_buffer reply = NULL;
|
||||
unsigned int type = 0;
|
||||
unsigned int c1 = 0, c2 = 0;
|
||||
u8 buf[4] = {0};
|
||||
uint8_t buf[4] = {0};
|
||||
|
||||
switch (session->version) {
|
||||
case 1:
|
||||
@@ -302,7 +303,7 @@ int agent_get_ident_count(struct ssh_session *session) {
|
||||
buffer_free(request);
|
||||
|
||||
/* get message type and verify the answer */
|
||||
buffer_get_u8(reply, (u8 *) &type);
|
||||
buffer_get_u8(reply, (uint8_t *) &type);
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"agent_ident_count - answer type: %d, expected answer: %d",
|
||||
type, c2);
|
||||
@@ -314,7 +315,7 @@ int agent_get_ident_count(struct ssh_session *session) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer_get_u32(reply, (u32 *) buf);
|
||||
buffer_get_u32(reply, (uint32_t *) buf);
|
||||
session->agent->count = agent_get_u32(buf);
|
||||
ssh_log(session, SSH_LOG_PACKET, "agent_ident_count - count: %d",
|
||||
session->agent->count);
|
||||
@@ -327,7 +328,7 @@ int agent_get_ident_count(struct ssh_session *session) {
|
||||
}
|
||||
|
||||
if (session->agent->ident) {
|
||||
buffer_free(session->agent->ident);
|
||||
buffer_reinit(session->agent->ident);
|
||||
}
|
||||
session->agent->ident = reply;
|
||||
|
||||
@@ -335,7 +336,7 @@ int agent_get_ident_count(struct ssh_session *session) {
|
||||
}
|
||||
|
||||
/* caller has to free commment */
|
||||
struct public_key_struct *agent_get_first_ident(struct ssh_session *session,
|
||||
struct ssh_public_key_struct *agent_get_first_ident(struct ssh_session_struct *session,
|
||||
char **comment) {
|
||||
if (agent_get_ident_count(session) > 0) {
|
||||
return agent_get_next_ident(session, comment);
|
||||
@@ -345,11 +346,11 @@ struct public_key_struct *agent_get_first_ident(struct ssh_session *session,
|
||||
}
|
||||
|
||||
/* caller has to free commment */
|
||||
struct public_key_struct *agent_get_next_ident(struct ssh_session *session,
|
||||
struct ssh_public_key_struct *agent_get_next_ident(struct ssh_session_struct *session,
|
||||
char **comment) {
|
||||
struct public_key_struct *pubkey = NULL;
|
||||
struct string_struct *blob = NULL;
|
||||
struct string_struct *tmp = NULL;
|
||||
struct ssh_public_key_struct *pubkey = NULL;
|
||||
struct ssh_string_struct *blob = NULL;
|
||||
struct ssh_string_struct *tmp = NULL;
|
||||
|
||||
if (session->agent->count == 0) {
|
||||
return NULL;
|
||||
@@ -394,16 +395,16 @@ struct public_key_struct *agent_get_next_ident(struct ssh_session *session,
|
||||
return pubkey;
|
||||
}
|
||||
|
||||
STRING *agent_sign_data(struct ssh_session *session,
|
||||
struct buffer_struct *data,
|
||||
struct public_key_struct *pubkey) {
|
||||
struct string_struct *blob = NULL;
|
||||
struct string_struct *sig = NULL;
|
||||
struct buffer_struct *request = NULL;
|
||||
struct buffer_struct *reply = NULL;
|
||||
ssh_string agent_sign_data(struct ssh_session_struct *session,
|
||||
struct ssh_buffer_struct *data,
|
||||
struct ssh_public_key_struct *pubkey) {
|
||||
struct ssh_string_struct *blob = NULL;
|
||||
struct ssh_string_struct *sig = NULL;
|
||||
struct ssh_buffer_struct *request = NULL;
|
||||
struct ssh_buffer_struct *reply = NULL;
|
||||
int type = SSH2_AGENT_FAILURE;
|
||||
int flags = 0;
|
||||
u32 dlen = 0;
|
||||
uint32_t dlen = 0;
|
||||
|
||||
/* create blob from the pubkey */
|
||||
blob = publickey_to_string(pubkey);
|
||||
@@ -451,7 +452,7 @@ STRING *agent_sign_data(struct ssh_session *session,
|
||||
buffer_free(request);
|
||||
|
||||
/* check if reply is valid */
|
||||
if (buffer_get_u8(reply, (u8 *) &type) < 0) {
|
||||
if (buffer_get_u8(reply, (uint8_t *) &type) != sizeof(uint8_t)) {
|
||||
goto error;
|
||||
}
|
||||
if (agent_failed(type)) {
|
||||
@@ -478,7 +479,7 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int agent_is_running(SSH_SESSION *session) {
|
||||
int agent_is_running(ssh_session session) {
|
||||
if (session == NULL || session->agent == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
258
libssh/auth.c
258
libssh/auth.c
@@ -32,6 +32,12 @@
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/agent.h"
|
||||
#include "libssh/keyfiles.h"
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/keys.h"
|
||||
|
||||
/** \defgroup ssh_auth SSH Authentication functions
|
||||
* \brief functions to authenticate to servers
|
||||
@@ -39,7 +45,7 @@
|
||||
/** \addtogroup ssh_auth
|
||||
* @{ */
|
||||
|
||||
static int ask_userauth(SSH_SESSION *session) {
|
||||
static int ask_userauth(ssh_session session) {
|
||||
int rc = 0;
|
||||
|
||||
enter_function();
|
||||
@@ -56,12 +62,12 @@ static int ask_userauth(SSH_SESSION *session) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wait_auth_status(SSH_SESSION *session, int kbdint) {
|
||||
static int wait_auth_status(ssh_session session, int kbdint) {
|
||||
char *auth_methods = NULL;
|
||||
STRING *auth;
|
||||
ssh_string auth;
|
||||
int rc = SSH_AUTH_ERROR;
|
||||
int cont = 1;
|
||||
u8 partial = 0;
|
||||
uint8_t partial = 0;
|
||||
|
||||
enter_function();
|
||||
|
||||
@@ -139,7 +145,7 @@ static int wait_auth_status(SSH_SESSION *session, int kbdint) {
|
||||
break;
|
||||
case SSH2_MSG_USERAUTH_BANNER:
|
||||
{
|
||||
STRING *banner;
|
||||
ssh_string banner;
|
||||
|
||||
banner = buffer_get_ssh_string(session->in_buffer);
|
||||
if (banner == NULL) {
|
||||
@@ -163,7 +169,7 @@ static int wait_auth_status(SSH_SESSION *session, int kbdint) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ssh_auth_list(SSH_SESSION *session) {
|
||||
int ssh_auth_list(ssh_session session) {
|
||||
if (session == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -171,7 +177,7 @@ int ssh_auth_list(SSH_SESSION *session) {
|
||||
return session->auth_methods;
|
||||
}
|
||||
|
||||
int ssh_userauth_list(SSH_SESSION *session, const char *username) {
|
||||
int ssh_userauth_list(ssh_session session, const char *username) {
|
||||
if (session == NULL || username == NULL) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
@@ -200,15 +206,15 @@ int ssh_userauth_list(SSH_SESSION *session, const char *username) {
|
||||
* have to use another method\n
|
||||
* SSH_AUTH_SUCCESS: Authentication success
|
||||
*/
|
||||
int ssh_userauth_none(SSH_SESSION *session, const char *username) {
|
||||
STRING *user = NULL;
|
||||
STRING *service = NULL;
|
||||
STRING *method = NULL;
|
||||
int ssh_userauth_none(ssh_session session, const char *username) {
|
||||
ssh_string user = NULL;
|
||||
ssh_string service = NULL;
|
||||
ssh_string method = NULL;
|
||||
int rc = SSH_AUTH_ERROR;
|
||||
|
||||
enter_function();
|
||||
|
||||
#ifdef HAVE_SSH1
|
||||
#ifdef WITH_SSH1
|
||||
if (session->version == 1) {
|
||||
ssh_userauth1_none(session, username);
|
||||
leave_function();
|
||||
@@ -217,13 +223,13 @@ int ssh_userauth_none(SSH_SESSION *session, const char *username) {
|
||||
#endif
|
||||
|
||||
if (username == NULL) {
|
||||
if (session->options->username == NULL) {
|
||||
if (ssh_options_default_username(session->options) < 0) {
|
||||
if (session->username == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
user = string_from_char(session->options->username);
|
||||
user = string_from_char(session->username);
|
||||
} else {
|
||||
user = string_from_char(username);
|
||||
}
|
||||
@@ -268,7 +274,7 @@ int ssh_userauth_none(SSH_SESSION *session, const char *username) {
|
||||
leave_function();
|
||||
return rc;
|
||||
error:
|
||||
buffer_free(session->out_buffer);
|
||||
buffer_reinit(session->out_buffer);
|
||||
string_free(service);
|
||||
string_free(method);
|
||||
string_free(user);
|
||||
@@ -304,17 +310,17 @@ error:
|
||||
* @see privatekey_from_file()
|
||||
* @see ssh_userauth_pubkey()
|
||||
*/
|
||||
int ssh_userauth_offer_pubkey(SSH_SESSION *session, const char *username,
|
||||
int type, STRING *publickey) {
|
||||
STRING *user = NULL;
|
||||
STRING *service = NULL;
|
||||
STRING *method = NULL;
|
||||
STRING *algo = NULL;
|
||||
int ssh_userauth_offer_pubkey(ssh_session session, const char *username,
|
||||
int type, ssh_string publickey) {
|
||||
ssh_string user = NULL;
|
||||
ssh_string service = NULL;
|
||||
ssh_string method = NULL;
|
||||
ssh_string algo = NULL;
|
||||
int rc = SSH_AUTH_ERROR;
|
||||
|
||||
enter_function();
|
||||
|
||||
#ifdef HAVE_SSH1
|
||||
#ifdef WITH_SSH1
|
||||
if (session->version == 1) {
|
||||
ssh_userauth1_offer_pubkey(session, username, type, publickey);
|
||||
leave_function();
|
||||
@@ -323,13 +329,13 @@ int ssh_userauth_offer_pubkey(SSH_SESSION *session, const char *username,
|
||||
#endif
|
||||
|
||||
if (username == NULL) {
|
||||
if (session->options->username == NULL) {
|
||||
if (ssh_options_default_username(session->options) < 0) {
|
||||
if (session->username == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
user = string_from_char(session->options->username);
|
||||
user = string_from_char(session->username);
|
||||
} else {
|
||||
user = string_from_char(username);
|
||||
}
|
||||
@@ -382,7 +388,7 @@ int ssh_userauth_offer_pubkey(SSH_SESSION *session, const char *username,
|
||||
leave_function();
|
||||
return rc;
|
||||
error:
|
||||
buffer_free(session->out_buffer);
|
||||
buffer_reinit(session->out_buffer);
|
||||
string_free(user);
|
||||
string_free(method);
|
||||
string_free(service);
|
||||
@@ -417,13 +423,13 @@ error:
|
||||
* @see privatekey_free()
|
||||
* @see ssh_userauth_offer_pubkey()
|
||||
*/
|
||||
int ssh_userauth_pubkey(SSH_SESSION *session, const char *username,
|
||||
STRING *publickey, PRIVATE_KEY *privatekey) {
|
||||
STRING *user = NULL;
|
||||
STRING *service = NULL;
|
||||
STRING *method = NULL;
|
||||
STRING *algo = NULL;
|
||||
STRING *sign = NULL;
|
||||
int ssh_userauth_pubkey(ssh_session session, const char *username,
|
||||
ssh_string publickey, ssh_private_key privatekey) {
|
||||
ssh_string user = NULL;
|
||||
ssh_string service = NULL;
|
||||
ssh_string method = NULL;
|
||||
ssh_string algo = NULL;
|
||||
ssh_string sign = NULL;
|
||||
int rc = SSH_AUTH_ERROR;
|
||||
|
||||
enter_function();
|
||||
@@ -435,13 +441,13 @@ int ssh_userauth_pubkey(SSH_SESSION *session, const char *username,
|
||||
#endif
|
||||
|
||||
if (username == NULL) {
|
||||
if (session->options->username == NULL) {
|
||||
if (ssh_options_default_username(session->options) < 0) {
|
||||
if (session->username == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
user = string_from_char(session->options->username);
|
||||
user = string_from_char(session->username);
|
||||
} else {
|
||||
user = string_from_char(username);
|
||||
}
|
||||
@@ -503,7 +509,7 @@ int ssh_userauth_pubkey(SSH_SESSION *session, const char *username,
|
||||
leave_function();
|
||||
return rc;
|
||||
error:
|
||||
buffer_free(session->out_buffer);
|
||||
buffer_reinit(session->out_buffer);
|
||||
string_free(user);
|
||||
string_free(service);
|
||||
string_free(method);
|
||||
@@ -536,14 +542,14 @@ error:
|
||||
* @see privatekey_free()
|
||||
* @see ssh_userauth_offer_pubkey()
|
||||
*/
|
||||
int ssh_userauth_agent_pubkey(SSH_SESSION *session, const char *username,
|
||||
PUBLIC_KEY *publickey) {
|
||||
STRING *user = NULL;
|
||||
STRING *service = NULL;
|
||||
STRING *method = NULL;
|
||||
STRING *algo = NULL;
|
||||
STRING *key = NULL;
|
||||
STRING *sign = NULL;
|
||||
int ssh_userauth_agent_pubkey(ssh_session session, const char *username,
|
||||
ssh_public_key publickey) {
|
||||
ssh_string user = NULL;
|
||||
ssh_string service = NULL;
|
||||
ssh_string method = NULL;
|
||||
ssh_string algo = NULL;
|
||||
ssh_string key = NULL;
|
||||
ssh_string sign = NULL;
|
||||
int rc = SSH_AUTH_ERROR;
|
||||
|
||||
enter_function();
|
||||
@@ -553,13 +559,13 @@ int ssh_userauth_agent_pubkey(SSH_SESSION *session, const char *username,
|
||||
}
|
||||
|
||||
if (username == NULL) {
|
||||
if (session->options->username == NULL) {
|
||||
if (ssh_options_default_username(session->options) < 0) {
|
||||
if (session->username == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
user = string_from_char(session->options->username);
|
||||
user = string_from_char(session->username);
|
||||
} else {
|
||||
user = string_from_char(username);
|
||||
}
|
||||
@@ -627,7 +633,7 @@ int ssh_userauth_agent_pubkey(SSH_SESSION *session, const char *username,
|
||||
|
||||
return rc;
|
||||
error:
|
||||
buffer_free(session->out_buffer);
|
||||
buffer_reinit(session->out_buffer);
|
||||
string_free(sign);
|
||||
string_free(user);
|
||||
string_free(service);
|
||||
@@ -661,17 +667,17 @@ error:
|
||||
* @see ssh_userauth_kbdint()
|
||||
* @see BURN_STRING
|
||||
*/
|
||||
int ssh_userauth_password(SSH_SESSION *session, const char *username,
|
||||
int ssh_userauth_password(ssh_session session, const char *username,
|
||||
const char *password) {
|
||||
STRING *user = NULL;
|
||||
STRING *service = NULL;
|
||||
STRING *method = NULL;
|
||||
STRING *pwd = NULL;
|
||||
ssh_string user = NULL;
|
||||
ssh_string service = NULL;
|
||||
ssh_string method = NULL;
|
||||
ssh_string pwd = NULL;
|
||||
int rc = SSH_AUTH_ERROR;
|
||||
|
||||
enter_function();
|
||||
|
||||
#ifdef HAVE_SSH1
|
||||
#ifdef WITH_SSH1
|
||||
if (session->version == 1) {
|
||||
rc = ssh_userauth1_password(session, username, password);
|
||||
leave_function();
|
||||
@@ -680,13 +686,13 @@ int ssh_userauth_password(SSH_SESSION *session, const char *username,
|
||||
#endif
|
||||
|
||||
if (username == NULL) {
|
||||
if (session->options->username == NULL) {
|
||||
if (ssh_options_default_username(session->options) < 0) {
|
||||
if (session->username == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
user = string_from_char(session->options->username);
|
||||
user = string_from_char(session->username);
|
||||
} else {
|
||||
user = string_from_char(username);
|
||||
}
|
||||
@@ -739,7 +745,7 @@ int ssh_userauth_password(SSH_SESSION *session, const char *username,
|
||||
leave_function();
|
||||
return rc;
|
||||
error:
|
||||
buffer_free(session->out_buffer);
|
||||
buffer_reinit(session->out_buffer);
|
||||
string_free(user);
|
||||
string_free(service);
|
||||
string_free(method);
|
||||
@@ -750,27 +756,41 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct keys_struct keytab[] = {
|
||||
#ifdef _MSC_VER
|
||||
static const char privKey_1[] = "SSH_DIR/identity";
|
||||
static const char pubKey_1[] = "SSH_DIR/identity.pub";
|
||||
static const char privKey_2[] = "SSH_DIR/id_dsa";
|
||||
static const char pubKey_2[] = "SSH_DIR/id_dsa.pub";
|
||||
static const char privKey_3[] = "SSH_DIR/id_rsa";
|
||||
static const char pubKey_3[] = "SSH_DIR/id_rsa.pub";
|
||||
/** Used different var to allow const char[] declaration */
|
||||
static struct ssh_keys_struct keytab[] = {
|
||||
{ privKey_1, pubKey_1},
|
||||
{ privKey_2, pubKey_2},
|
||||
{ privKey_3, pubKey_3},
|
||||
{0}
|
||||
};
|
||||
#else
|
||||
/* This requires GCC extensions */
|
||||
static struct ssh_keys_struct keytab[] = {
|
||||
{
|
||||
.privatekey = "%s/.ssh/identity",
|
||||
.publickey = "%s/.ssh/identity.pub"
|
||||
.privatekey = "SSH_DIR/identity",
|
||||
.publickey = "SSH_DIR/identity.pub"
|
||||
},
|
||||
{
|
||||
.privatekey = "%s/.ssh/id_dsa",
|
||||
.publickey = "%s/.ssh/id_dsa.pub",
|
||||
.privatekey = "SSH_DIR/id_dsa",
|
||||
.publickey = "SSH_DIR/id_dsa.pub",
|
||||
},
|
||||
{
|
||||
.privatekey = "%s/.ssh/id_rsa",
|
||||
.publickey = "%s/.ssh/id_rsa.pub",
|
||||
.privatekey = "SSH_DIR/id_rsa",
|
||||
.publickey = "SSH_DIR/id_rsa.pub",
|
||||
},
|
||||
{
|
||||
.privatekey = NULL,
|
||||
.publickey = NULL
|
||||
}
|
||||
};
|
||||
|
||||
/* this function initialy was in the client */
|
||||
/* but the fools are the ones who never change mind */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Tries to automaticaly authenticate with public key and "none"
|
||||
@@ -792,12 +812,12 @@ static struct keys_struct keytab[] = {
|
||||
*
|
||||
* @see ssh_userauth_kbdint()
|
||||
* @see ssh_userauth_password()
|
||||
* @see ssh_options_set_identity()
|
||||
* @see ssh_options_set()
|
||||
*/
|
||||
int ssh_userauth_autopubkey(SSH_SESSION *session, const char *passphrase) {
|
||||
struct public_key_struct *publickey;
|
||||
STRING *pubkey;
|
||||
PRIVATE_KEY *privkey;
|
||||
int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) {
|
||||
struct ssh_public_key_struct *publickey;
|
||||
ssh_string pubkey;
|
||||
ssh_private_key privkey;
|
||||
char *privkeyfile = NULL;
|
||||
char *id = NULL;
|
||||
size_t size;
|
||||
@@ -818,7 +838,8 @@ int ssh_userauth_autopubkey(SSH_SESSION *session, const char *passphrase) {
|
||||
#ifndef _WIN32
|
||||
if (agent_is_running(session)) {
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
"Trying to authenticate with SSH agent keys");
|
||||
"Trying to authenticate with SSH agent keys as user: %s",
|
||||
session->username);
|
||||
|
||||
for (publickey = agent_get_first_ident(session, &privkeyfile);
|
||||
publickey != NULL;
|
||||
@@ -882,18 +903,18 @@ int ssh_userauth_autopubkey(SSH_SESSION *session, const char *passphrase) {
|
||||
#endif
|
||||
|
||||
size = ARRAY_SIZE(keytab);
|
||||
if (session->options->identity) {
|
||||
if (session->identity) {
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
"Trying identity file %s\n", session->options->identity);
|
||||
"Trying identity file %s\n", session->identity);
|
||||
|
||||
id = malloc(strlen(session->options->identity) + 1 + 4);
|
||||
id = malloc(strlen(session->identity) + 1 + 4);
|
||||
if (id == NULL) {
|
||||
leave_function();
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
sprintf(id, "%s.pub", session->options->identity);
|
||||
sprintf(id, "%s.pub", session->identity);
|
||||
|
||||
keytab[size - 1].privatekey = session->options->identity;
|
||||
keytab[size - 1].privatekey = session->identity;
|
||||
keytab[size - 1].publickey = id;
|
||||
}
|
||||
|
||||
@@ -915,11 +936,12 @@ int ssh_userauth_autopubkey(SSH_SESSION *session, const char *passphrase) {
|
||||
}
|
||||
string_free(pubkey);
|
||||
SAFE_FREE(privkeyfile);
|
||||
ssh_log(session, SSH_LOG_RARE, "Publickey authentication error");
|
||||
leave_function();
|
||||
return rc;
|
||||
} else {
|
||||
if (rc != SSH_AUTH_SUCCESS){
|
||||
ssh_log(session, SSH_LOG_RARE, "Public key refused by server");
|
||||
ssh_log(session, SSH_LOG_RARE, "Publickey refused by server");
|
||||
string_free(pubkey);
|
||||
pubkey = NULL;
|
||||
SAFE_FREE(privkeyfile);
|
||||
@@ -929,6 +951,7 @@ int ssh_userauth_autopubkey(SSH_SESSION *session, const char *passphrase) {
|
||||
}
|
||||
|
||||
/* Public key accepted by server! */
|
||||
ssh_log(session, SSH_LOG_RARE, "Trying to read privatekey %s", privkeyfile);
|
||||
privkey = privatekey_from_file(session, privkeyfile, type, passphrase);
|
||||
if (privkey == NULL) {
|
||||
ssh_log(session, SSH_LOG_FUNCTIONS,
|
||||
@@ -995,10 +1018,19 @@ int ssh_userauth_autopubkey(SSH_SESSION *session, const char *passphrase) {
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
static struct ssh_kbdint *kbdint_new(void) {
|
||||
struct ssh_kbdint *kbd;
|
||||
struct ssh_kbdint_struct {
|
||||
uint32_t nprompts;
|
||||
char *name;
|
||||
char *instruction;
|
||||
char **prompts;
|
||||
unsigned char *echo; /* bool array */
|
||||
char **answers;
|
||||
};
|
||||
|
||||
kbd = malloc(sizeof (struct ssh_kbdint));
|
||||
static ssh_kbdint kbdint_new(void) {
|
||||
ssh_kbdint kbd;
|
||||
|
||||
kbd = malloc(sizeof (struct ssh_kbdint_struct));
|
||||
if (kbd == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -1008,7 +1040,7 @@ static struct ssh_kbdint *kbdint_new(void) {
|
||||
}
|
||||
|
||||
|
||||
static void kbdint_free(struct ssh_kbdint *kbd) {
|
||||
static void kbdint_free(ssh_kbdint kbd) {
|
||||
int i, n;
|
||||
|
||||
if (kbd == NULL) {
|
||||
@@ -1039,7 +1071,7 @@ static void kbdint_free(struct ssh_kbdint *kbd) {
|
||||
SAFE_FREE(kbd);
|
||||
}
|
||||
|
||||
static void kbdint_clean(struct ssh_kbdint *kbd) {
|
||||
static void kbdint_clean(ssh_kbdint kbd) {
|
||||
int i, n;
|
||||
|
||||
if (kbd == NULL) {
|
||||
@@ -1073,12 +1105,12 @@ static void kbdint_clean(struct ssh_kbdint *kbd) {
|
||||
|
||||
/* this function sends the first packet as explained in section 3.1
|
||||
* of the draft */
|
||||
static int kbdauth_init(SSH_SESSION *session, const char *user,
|
||||
static int kbdauth_init(ssh_session session, const char *user,
|
||||
const char *submethods) {
|
||||
STRING *usr = NULL;
|
||||
STRING *sub = NULL;
|
||||
STRING *service = NULL;
|
||||
STRING *method = NULL;
|
||||
ssh_string usr = NULL;
|
||||
ssh_string sub = NULL;
|
||||
ssh_string service = NULL;
|
||||
ssh_string method = NULL;
|
||||
int rc = SSH_AUTH_ERROR;
|
||||
|
||||
enter_function();
|
||||
@@ -1123,7 +1155,7 @@ static int kbdauth_init(SSH_SESSION *session, const char *user,
|
||||
leave_function();
|
||||
return rc;
|
||||
error:
|
||||
buffer_free(session->out_buffer);
|
||||
buffer_reinit(session->out_buffer);
|
||||
string_free(usr);
|
||||
string_free(service);
|
||||
string_free(method);
|
||||
@@ -1133,12 +1165,12 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int kbdauth_info_get(SSH_SESSION *session) {
|
||||
STRING *name; /* name of the "asking" window showed to client */
|
||||
STRING *instruction;
|
||||
STRING *tmp;
|
||||
u32 nprompts;
|
||||
u32 i;
|
||||
static int kbdauth_info_get(ssh_session session) {
|
||||
ssh_string name; /* name of the "asking" window showed to client */
|
||||
ssh_string instruction;
|
||||
ssh_string tmp;
|
||||
uint32_t nprompts;
|
||||
uint32_t i;
|
||||
|
||||
enter_function();
|
||||
|
||||
@@ -1250,10 +1282,10 @@ static int kbdauth_info_get(SSH_SESSION *session) {
|
||||
}
|
||||
|
||||
/* sends challenge back to the server */
|
||||
static int kbdauth_send(SSH_SESSION *session) {
|
||||
STRING *answer = NULL;
|
||||
static int kbdauth_send(ssh_session session) {
|
||||
ssh_string answer = NULL;
|
||||
int rc = SSH_AUTH_ERROR;
|
||||
u32 i;
|
||||
uint32_t i;
|
||||
|
||||
enter_function();
|
||||
|
||||
@@ -1290,7 +1322,7 @@ static int kbdauth_send(SSH_SESSION *session) {
|
||||
leave_function();
|
||||
return rc;
|
||||
error:
|
||||
buffer_free(session->out_buffer);
|
||||
buffer_reinit(session->out_buffer);
|
||||
string_burn(answer);
|
||||
string_free(answer);
|
||||
|
||||
@@ -1323,7 +1355,7 @@ error:
|
||||
* @see ssh_userauth_kbdint_getprompt()
|
||||
* @see ssh_userauth_kbdint_setanswer()
|
||||
*/
|
||||
int ssh_userauth_kbdint(SSH_SESSION *session, const char *user,
|
||||
int ssh_userauth_kbdint(ssh_session session, const char *user,
|
||||
const char *submethods) {
|
||||
int rc = SSH_AUTH_ERROR;
|
||||
|
||||
@@ -1337,12 +1369,12 @@ int ssh_userauth_kbdint(SSH_SESSION *session, const char *user,
|
||||
if (session->kbdint == NULL) {
|
||||
/* first time we call. we must ask for a challenge */
|
||||
if (user == NULL) {
|
||||
if ((user = session->options->username) == NULL) {
|
||||
if (ssh_options_default_username(session->options) < 0) {
|
||||
if ((user = session->username) == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
||||
leave_function();
|
||||
return SSH_AUTH_ERROR;
|
||||
} else {
|
||||
user = session->options->username;
|
||||
user = session->username;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1403,7 +1435,7 @@ int ssh_userauth_kbdint(SSH_SESSION *session, const char *user,
|
||||
*
|
||||
* @returns The number of prompts.
|
||||
*/
|
||||
int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session) {
|
||||
int ssh_userauth_kbdint_getnprompts(ssh_session session) {
|
||||
return session->kbdint->nprompts;
|
||||
}
|
||||
|
||||
@@ -1417,7 +1449,7 @@ int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session) {
|
||||
*
|
||||
* @returns The name of the message block. Do not free it.
|
||||
*/
|
||||
char *ssh_userauth_kbdint_getname(SSH_SESSION *session) {
|
||||
const char *ssh_userauth_kbdint_getname(ssh_session session) {
|
||||
return session->kbdint->name;
|
||||
}
|
||||
|
||||
@@ -1432,7 +1464,7 @@ char *ssh_userauth_kbdint_getname(SSH_SESSION *session) {
|
||||
* @returns The instruction of the message block.
|
||||
*/
|
||||
|
||||
char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session) {
|
||||
const char *ssh_userauth_kbdint_getinstruction(ssh_session session) {
|
||||
return session->kbdint->instruction;
|
||||
}
|
||||
|
||||
@@ -1452,7 +1484,7 @@ char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session) {
|
||||
*
|
||||
* @returns A pointer to the prompt. Do not free it.
|
||||
*/
|
||||
char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, unsigned int i,
|
||||
const char *ssh_userauth_kbdint_getprompt(ssh_session session, unsigned int i,
|
||||
char *echo) {
|
||||
if (i > session->kbdint->nprompts) {
|
||||
return NULL;
|
||||
@@ -1473,9 +1505,9 @@ char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, unsigned int i,
|
||||
* \param answer answer to give to server
|
||||
* \return 0 on success, < 0 on error.
|
||||
*/
|
||||
int ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i,
|
||||
int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i,
|
||||
const char *answer) {
|
||||
if (i > session->kbdint->nprompts) {
|
||||
if (session == NULL || answer == NULL || i > session->kbdint->nprompts) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,14 +21,20 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/ssh1.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/string.h"
|
||||
|
||||
#ifdef HAVE_SSH1
|
||||
static int wait_auth1_status(SSH_SESSION *session) {
|
||||
#ifdef WITH_SSH1
|
||||
static int wait_auth1_status(ssh_session session) {
|
||||
/* wait for a packet */
|
||||
if (packet_read(session) != SSH_OK) {
|
||||
return SSH_AUTH_ERROR;
|
||||
@@ -51,19 +57,19 @@ static int wait_auth1_status(SSH_SESSION *session) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
static int send_username(SSH_SESSION *session, const char *username) {
|
||||
STRING *user = NULL;
|
||||
static int send_username(ssh_session session, const char *username) {
|
||||
ssh_string user = NULL;
|
||||
/* returns SSH_AUTH_SUCCESS or SSH_AUTH_DENIED */
|
||||
if(session->auth_service_asked) {
|
||||
return session->auth_service_asked;
|
||||
}
|
||||
|
||||
if (!username) {
|
||||
if(!(username = session->options->username)) {
|
||||
if(ssh_options_default_username(session->options)) {
|
||||
if(!(username = session->username)) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
||||
return session->auth_service_asked = SSH_AUTH_ERROR;
|
||||
} else {
|
||||
username = session->options->username;
|
||||
username = session->username;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,16 +97,16 @@ static int send_username(SSH_SESSION *session, const char *username) {
|
||||
}
|
||||
|
||||
/* use the "none" authentication question */
|
||||
int ssh_userauth1_none(SSH_SESSION *session, const char *username){
|
||||
int ssh_userauth1_none(ssh_session session, const char *username){
|
||||
return send_username(session, username);
|
||||
}
|
||||
|
||||
/*
|
||||
int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STRING *publickey){
|
||||
STRING *user;
|
||||
STRING *service;
|
||||
STRING *method;
|
||||
STRING *algo;
|
||||
int ssh_userauth_offer_pubkey(ssh_session session, char *username,int type, ssh_string publickey){
|
||||
ssh_string user;
|
||||
ssh_string service;
|
||||
ssh_string method;
|
||||
ssh_string algo;
|
||||
int err=SSH_AUTH_ERROR;
|
||||
if(!username)
|
||||
if(!(username=session->options->username)){
|
||||
@@ -136,18 +142,22 @@ int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STR
|
||||
/** \internal
|
||||
* \todo implement ssh1 public key
|
||||
*/
|
||||
int ssh_userauth1_offer_pubkey(SSH_SESSION *session, const char *username,
|
||||
int type, STRING *pubkey) {
|
||||
return SSH_AUTH_DENIED;
|
||||
int ssh_userauth1_offer_pubkey(ssh_session session, const char *username,
|
||||
int type, ssh_string pubkey) {
|
||||
(void) session;
|
||||
(void) username;
|
||||
(void) type;
|
||||
(void) pubkey;
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
/*
|
||||
int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey, PRIVATE_KEY *privatekey){
|
||||
STRING *user;
|
||||
STRING *service;
|
||||
STRING *method;
|
||||
STRING *algo;
|
||||
STRING *sign;
|
||||
int ssh_userauth_pubkey(ssh_session session, char *username, ssh_string publickey, ssh_private_key privatekey){
|
||||
ssh_string user;
|
||||
ssh_string service;
|
||||
ssh_string method;
|
||||
ssh_string algo;
|
||||
ssh_string sign;
|
||||
int err=SSH_AUTH_ERROR;
|
||||
if(!username)
|
||||
if(!(username=session->options->username)){
|
||||
@@ -188,9 +198,9 @@ int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey,
|
||||
}
|
||||
*/
|
||||
|
||||
int ssh_userauth1_password(SSH_SESSION *session, const char *username,
|
||||
int ssh_userauth1_password(ssh_session session, const char *username,
|
||||
const char *password) {
|
||||
STRING *pwd = NULL;
|
||||
ssh_string pwd = NULL;
|
||||
int rc;
|
||||
|
||||
rc = send_username(session, username);
|
||||
@@ -247,5 +257,5 @@ int ssh_userauth1_password(SSH_SESSION *session, const char *username,
|
||||
return wait_auth1_status(session);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SSH1 */
|
||||
#endif /* WITH_SSH1 */
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/buffer.h"
|
||||
|
||||
static char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
@@ -55,8 +56,8 @@ static int get_equals(char *string);
|
||||
* @returns A buffer containing the decoded string, NULL if something went
|
||||
* wrong (e.g. incorrect char).
|
||||
*/
|
||||
BUFFER *base64_to_bin(const char *source) {
|
||||
BUFFER *buffer = NULL;
|
||||
ssh_buffer base64_to_bin(const char *source) {
|
||||
ssh_buffer buffer = NULL;
|
||||
unsigned char block[3];
|
||||
char *base64;
|
||||
char *ptr;
|
||||
|
||||
181
libssh/buffer.c
181
libssh/buffer.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
@@ -29,7 +29,7 @@
|
||||
#endif
|
||||
|
||||
#include "libssh/priv.h"
|
||||
|
||||
#include "libssh/buffer.h"
|
||||
/** \defgroup ssh_buffer SSH Buffers
|
||||
* \brief buffer handling
|
||||
*/
|
||||
@@ -38,27 +38,57 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** \brief checks that preconditions and postconditions are valid
|
||||
* \internal
|
||||
*/
|
||||
|
||||
#ifdef DEBUG_BUFFER
|
||||
static void buffer_verify(struct buffer_struct *buf){
|
||||
int doabort=0;
|
||||
if(buf->data == NULL)
|
||||
return;
|
||||
if(buf->used > buf->allocated){
|
||||
fprintf(stderr,"Buffer error : allocated %u, used %u\n",buf->allocated, buf->used);
|
||||
doabort=1;
|
||||
}
|
||||
if(buf->pos > buf->used){
|
||||
fprintf(stderr,"Buffer error : position %u, used %u\n",buf->pos, buf->used);
|
||||
doabort=1;
|
||||
}
|
||||
if(buf->pos > buf->allocated){
|
||||
fprintf(stderr,"Buffer error : position %u, allocated %u\n",buf->pos, buf->allocated);
|
||||
doabort=1;
|
||||
}
|
||||
if(doabort)
|
||||
abort();
|
||||
}
|
||||
|
||||
#else
|
||||
#define buffer_verify(x)
|
||||
#endif
|
||||
|
||||
/** \brief creates a new buffer
|
||||
* \return a new initialized buffer, NULL on error.
|
||||
*/
|
||||
struct buffer_struct *buffer_new(void) {
|
||||
struct buffer_struct *buf = malloc(sizeof(struct buffer_struct));
|
||||
struct ssh_buffer_struct *buffer_new(void) {
|
||||
struct ssh_buffer_struct *buf = malloc(sizeof(struct ssh_buffer_struct));
|
||||
|
||||
if (buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset(buf, 0, sizeof(struct buffer_struct));
|
||||
|
||||
memset(buf, 0, sizeof(struct ssh_buffer_struct));
|
||||
buffer_verify(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/** \brief deallocate a buffer
|
||||
* \param buffer buffer to free
|
||||
*/
|
||||
void buffer_free(struct buffer_struct *buffer) {
|
||||
void buffer_free(struct ssh_buffer_struct *buffer) {
|
||||
if (buffer == NULL) {
|
||||
return;
|
||||
}
|
||||
buffer_verify(buffer);
|
||||
|
||||
if (buffer->data) {
|
||||
/* burn the data */
|
||||
@@ -69,11 +99,12 @@ void buffer_free(struct buffer_struct *buffer) {
|
||||
SAFE_FREE(buffer);
|
||||
}
|
||||
|
||||
static int realloc_buffer(struct buffer_struct *buffer, int needed) {
|
||||
static int realloc_buffer(struct ssh_buffer_struct *buffer, int needed) {
|
||||
int smallest = 1;
|
||||
char *new = NULL;
|
||||
buffer_verify(buffer);
|
||||
/* Find the smallest power of two which is greater or equal to needed */
|
||||
while(smallest <= needed) {
|
||||
while(smallest < needed) {
|
||||
smallest <<= 1;
|
||||
}
|
||||
needed = smallest;
|
||||
@@ -83,7 +114,7 @@ static int realloc_buffer(struct buffer_struct *buffer, int needed) {
|
||||
}
|
||||
buffer->data = new;
|
||||
buffer->allocated = needed;
|
||||
|
||||
buffer_verify(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -92,7 +123,8 @@ static int realloc_buffer(struct buffer_struct *buffer, int needed) {
|
||||
* \param buffer buffer
|
||||
* \return 0 on sucess, < 0 on error
|
||||
*/
|
||||
int buffer_reinit(struct buffer_struct *buffer) {
|
||||
int buffer_reinit(struct ssh_buffer_struct *buffer) {
|
||||
buffer_verify(buffer);
|
||||
memset(buffer->data, 0, buffer->used);
|
||||
buffer->used = 0;
|
||||
buffer->pos = 0;
|
||||
@@ -101,6 +133,7 @@ int buffer_reinit(struct buffer_struct *buffer) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
buffer_verify(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -110,7 +143,8 @@ int buffer_reinit(struct buffer_struct *buffer) {
|
||||
* \param data data pointer
|
||||
* \param len length of data
|
||||
*/
|
||||
int buffer_add_data(struct buffer_struct *buffer, const void *data, u32 len) {
|
||||
int buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint32_t len) {
|
||||
buffer_verify(buffer);
|
||||
if (buffer->allocated < (buffer->used + len)) {
|
||||
if (realloc_buffer(buffer, buffer->used + len) < 0) {
|
||||
return -1;
|
||||
@@ -119,6 +153,7 @@ int buffer_add_data(struct buffer_struct *buffer, const void *data, u32 len) {
|
||||
|
||||
memcpy(buffer->data+buffer->used, data, len);
|
||||
buffer->used+=len;
|
||||
buffer_verify(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -128,24 +163,39 @@ int buffer_add_data(struct buffer_struct *buffer, const void *data, u32 len) {
|
||||
* \param string SSH String to add
|
||||
* \return 0 on success, -1 on error.
|
||||
*/
|
||||
int buffer_add_ssh_string(struct buffer_struct *buffer,
|
||||
struct string_struct *string) {
|
||||
u32 len = 0;
|
||||
int buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
|
||||
struct ssh_string_struct *string) {
|
||||
uint32_t len = 0;
|
||||
|
||||
len = ntohl(string->size);
|
||||
if (buffer_add_data(buffer, string, len + sizeof(u32)) < 0) {
|
||||
len = string_len(string);
|
||||
if (buffer_add_data(buffer, string, len + sizeof(uint32_t)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* \brief add a 32 bits unsigned integer to the tail of buffer
|
||||
* \param buffer buffer
|
||||
* \param data 32 bits integer
|
||||
* \return 0 on success, -1 on error.
|
||||
*/
|
||||
int buffer_add_u32(struct buffer_struct *buffer,u32 data){
|
||||
int buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data){
|
||||
if (buffer_add_data(buffer, &data, sizeof(data)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* \brief add a 16 bits unsigned integer to the tail of buffer
|
||||
* \param buffer buffer
|
||||
* \param data 16 bits integer
|
||||
* \return 0 on success, -1 on error.
|
||||
*/
|
||||
int buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data){
|
||||
if (buffer_add_data(buffer, &data, sizeof(data)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -159,7 +209,7 @@ int buffer_add_u32(struct buffer_struct *buffer,u32 data){
|
||||
* \param data 64 bits integer
|
||||
* \return 0 on success, -1 on error.
|
||||
*/
|
||||
int buffer_add_u64(struct buffer_struct *buffer, u64 data){
|
||||
int buffer_add_u64(struct ssh_buffer_struct *buffer, uint64_t data){
|
||||
if (buffer_add_data(buffer, &data, sizeof(data)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -172,8 +222,8 @@ int buffer_add_u64(struct buffer_struct *buffer, u64 data){
|
||||
* \param data 8 bits integer
|
||||
* \return 0 on success, -1 on error.
|
||||
*/
|
||||
int buffer_add_u8(struct buffer_struct *buffer,u8 data){
|
||||
if (buffer_add_data(buffer, &data, sizeof(u8)) < 0) {
|
||||
int buffer_add_u8(struct ssh_buffer_struct *buffer,uint8_t data){
|
||||
if (buffer_add_data(buffer, &data, sizeof(uint8_t)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -187,8 +237,9 @@ int buffer_add_u8(struct buffer_struct *buffer,u8 data){
|
||||
* \param len length of data
|
||||
* \return 0 on success, -1 on error.
|
||||
*/
|
||||
int buffer_prepend_data(struct buffer_struct *buffer, const void *data,
|
||||
u32 len) {
|
||||
int buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data,
|
||||
uint32_t len) {
|
||||
buffer_verify(buffer);
|
||||
if (buffer->allocated < (buffer->used + len)) {
|
||||
if (realloc_buffer(buffer, buffer->used + len) < 0) {
|
||||
return -1;
|
||||
@@ -197,7 +248,7 @@ int buffer_prepend_data(struct buffer_struct *buffer, const void *data,
|
||||
memmove(buffer->data + len, buffer->data, buffer->used);
|
||||
memcpy(buffer->data, data, len);
|
||||
buffer->used += len;
|
||||
|
||||
buffer_verify(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -207,8 +258,8 @@ int buffer_prepend_data(struct buffer_struct *buffer, const void *data,
|
||||
* \param source source buffer. Doesn't take position in buffer into account
|
||||
* \return 0 on success, -1 on error.
|
||||
*/
|
||||
int buffer_add_buffer(struct buffer_struct *buffer,
|
||||
struct buffer_struct *source) {
|
||||
int buffer_add_buffer(struct ssh_buffer_struct *buffer,
|
||||
struct ssh_buffer_struct *source) {
|
||||
if (buffer_add_data(buffer, buffer_get(source), buffer_get_len(source)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -223,7 +274,7 @@ int buffer_add_buffer(struct buffer_struct *buffer,
|
||||
* \see buffer_get_rest()
|
||||
* \see buffer_get_len()
|
||||
*/
|
||||
void *buffer_get(struct buffer_struct *buffer){
|
||||
void *buffer_get(struct ssh_buffer_struct *buffer){
|
||||
return buffer->data;
|
||||
}
|
||||
|
||||
@@ -234,7 +285,7 @@ void *buffer_get(struct buffer_struct *buffer){
|
||||
* \see buffer_get_rest_len()
|
||||
* \see buffer_get()
|
||||
*/
|
||||
void *buffer_get_rest(struct buffer_struct *buffer){
|
||||
void *buffer_get_rest(struct ssh_buffer_struct *buffer){
|
||||
return buffer->data + buffer->pos;
|
||||
}
|
||||
|
||||
@@ -243,7 +294,7 @@ void *buffer_get_rest(struct buffer_struct *buffer){
|
||||
* \return length of the buffer
|
||||
* \see buffer_get()
|
||||
*/
|
||||
u32 buffer_get_len(struct buffer_struct *buffer){
|
||||
uint32_t buffer_get_len(struct ssh_buffer_struct *buffer){
|
||||
return buffer->used;
|
||||
}
|
||||
|
||||
@@ -253,8 +304,9 @@ u32 buffer_get_len(struct buffer_struct *buffer){
|
||||
* \return length of the buffer
|
||||
* \see buffer_get_rest()
|
||||
*/
|
||||
u32 buffer_get_rest_len(struct buffer_struct *buffer){
|
||||
return buffer->used - buffer->pos;
|
||||
uint32_t buffer_get_rest_len(struct ssh_buffer_struct *buffer){
|
||||
buffer_verify(buffer);
|
||||
return buffer->used - buffer->pos;
|
||||
}
|
||||
|
||||
/** \internal
|
||||
@@ -264,7 +316,8 @@ u32 buffer_get_rest_len(struct buffer_struct *buffer){
|
||||
* \param len number of bytes to eat
|
||||
* \return new size of the buffer
|
||||
*/
|
||||
u32 buffer_pass_bytes(struct buffer_struct *buffer, u32 len){
|
||||
uint32_t buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
|
||||
buffer_verify(buffer);
|
||||
if(buffer->used < buffer->pos+len)
|
||||
return 0;
|
||||
buffer->pos+=len;
|
||||
@@ -273,6 +326,7 @@ u32 buffer_pass_bytes(struct buffer_struct *buffer, u32 len){
|
||||
buffer->pos=0;
|
||||
buffer->used=0;
|
||||
}
|
||||
buffer_verify(buffer);
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -282,11 +336,13 @@ u32 buffer_pass_bytes(struct buffer_struct *buffer, u32 len){
|
||||
* \param len number of bytes to remove from tail
|
||||
* \return new size of the buffer
|
||||
*/
|
||||
u32 buffer_pass_bytes_end(struct buffer_struct *buffer, u32 len){
|
||||
if(buffer->used < buffer->pos + len)
|
||||
return 0;
|
||||
buffer->used-=len;
|
||||
return len;
|
||||
uint32_t buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){
|
||||
buffer_verify(buffer);
|
||||
if(buffer->used < buffer->pos + len)
|
||||
return 0;
|
||||
buffer->used-=len;
|
||||
buffer_verify(buffer);
|
||||
return len;
|
||||
}
|
||||
|
||||
/** \internal
|
||||
@@ -297,9 +353,14 @@ u32 buffer_pass_bytes_end(struct buffer_struct *buffer, u32 len){
|
||||
* \returns 0 if there is not enough data in buffer
|
||||
* \returns len otherwise.
|
||||
*/
|
||||
u32 buffer_get_data(struct buffer_struct *buffer, void *data, u32 len){
|
||||
if(buffer->pos+len>buffer->used)
|
||||
return 0; /*no enough data in buffer */
|
||||
uint32_t buffer_get_data(struct ssh_buffer_struct *buffer, void *data, uint32_t len){
|
||||
/*
|
||||
* Check for a integer overflow first, then check if not enough data is in
|
||||
* the buffer.
|
||||
*/
|
||||
if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(data,buffer->data+buffer->pos,len);
|
||||
buffer->pos+=len;
|
||||
return len; /* no yet support for partial reads (is it really needed ?? ) */
|
||||
@@ -307,33 +368,33 @@ u32 buffer_get_data(struct buffer_struct *buffer, void *data, u32 len){
|
||||
/** \internal
|
||||
* \brief gets a 8 bits unsigned int out of the buffer. Adjusts the read pointer.
|
||||
* \param buffer Buffer to read
|
||||
* \param data pointer to a u8 where to store the data
|
||||
* \param data pointer to a uint8_t where to store the data
|
||||
* \returns 0 if there is not enough data in buffer
|
||||
* \returns 1 otherwise.
|
||||
*/
|
||||
int buffer_get_u8(struct buffer_struct *buffer, u8 *data){
|
||||
return buffer_get_data(buffer,data,sizeof(u8));
|
||||
int buffer_get_u8(struct ssh_buffer_struct *buffer, uint8_t *data){
|
||||
return buffer_get_data(buffer,data,sizeof(uint8_t));
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* \brief gets a 32 bits unsigned int out of the buffer. Adjusts the read pointer.
|
||||
* \param buffer Buffer to read
|
||||
* \param data pointer to a u32 where to store the data
|
||||
* \param data pointer to a uint32_t where to store the data
|
||||
* \returns 0 if there is not enough data in buffer
|
||||
* \returns 4 otherwise.
|
||||
*/
|
||||
int buffer_get_u32(struct buffer_struct *buffer, u32 *data){
|
||||
return buffer_get_data(buffer,data,sizeof(u32));
|
||||
int buffer_get_u32(struct ssh_buffer_struct *buffer, uint32_t *data){
|
||||
return buffer_get_data(buffer,data,sizeof(uint32_t));
|
||||
}
|
||||
/** \internal
|
||||
* \brief gets a 64 bits unsigned int out of the buffer. Adjusts the read pointer.
|
||||
* \param buffer Buffer to read
|
||||
* \param data pointer to a u64 where to store the data
|
||||
* \param data pointer to a uint64_t where to store the data
|
||||
* \returns 0 if there is not enough data in buffer
|
||||
* \returns 8 otherwise.
|
||||
*/
|
||||
int buffer_get_u64(struct buffer_struct *buffer, u64 *data){
|
||||
return buffer_get_data(buffer,data,sizeof(u64));
|
||||
int buffer_get_u64(struct ssh_buffer_struct *buffer, uint64_t *data){
|
||||
return buffer_get_data(buffer,data,sizeof(uint64_t));
|
||||
}
|
||||
/** \internal
|
||||
* \brief gets a SSH String out of the buffer. Adjusts the read pointer.
|
||||
@@ -341,10 +402,10 @@ int buffer_get_u64(struct buffer_struct *buffer, u64 *data){
|
||||
* \returns The SSH String read
|
||||
* \returns NULL otherwise.
|
||||
*/
|
||||
struct string_struct *buffer_get_ssh_string(struct buffer_struct *buffer) {
|
||||
u32 stringlen;
|
||||
u32 hostlen;
|
||||
struct string_struct *str = NULL;
|
||||
struct ssh_string_struct *buffer_get_ssh_string(struct ssh_buffer_struct *buffer) {
|
||||
uint32_t stringlen;
|
||||
uint32_t hostlen;
|
||||
struct ssh_string_struct *str = NULL;
|
||||
|
||||
if (buffer_get_u32(buffer, &stringlen) == 0) {
|
||||
return NULL;
|
||||
@@ -358,7 +419,7 @@ struct string_struct *buffer_get_ssh_string(struct buffer_struct *buffer) {
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (buffer_get_data(buffer, str->string, hostlen) != hostlen) {
|
||||
if (buffer_get_data(buffer, string_data(str), hostlen) != hostlen) {
|
||||
/* should never happen */
|
||||
SAFE_FREE(str);
|
||||
return NULL;
|
||||
@@ -374,12 +435,12 @@ struct string_struct *buffer_get_ssh_string(struct buffer_struct *buffer) {
|
||||
* \returns NULL otherwise
|
||||
*/
|
||||
|
||||
struct string_struct *buffer_get_mpint(struct buffer_struct *buffer) {
|
||||
u16 bits;
|
||||
u32 len;
|
||||
struct string_struct *str = NULL;
|
||||
struct ssh_string_struct *buffer_get_mpint(struct ssh_buffer_struct *buffer) {
|
||||
uint16_t bits;
|
||||
uint32_t len;
|
||||
struct ssh_string_struct *str = NULL;
|
||||
|
||||
if (buffer_get_data(buffer, &bits, sizeof(u16)) != sizeof(u16)) {
|
||||
if (buffer_get_data(buffer, &bits, sizeof(uint16_t)) != sizeof(uint16_t)) {
|
||||
return NULL;
|
||||
}
|
||||
bits = ntohs(bits);
|
||||
@@ -391,7 +452,7 @@ struct string_struct *buffer_get_mpint(struct buffer_struct *buffer) {
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (buffer_get_data(buffer, str->string, len) != len) {
|
||||
if (buffer_get_data(buffer, string_data(str), len) != len) {
|
||||
SAFE_FREE(str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
37
libssh/callbacks.c
Normal file
37
libssh/callbacks.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* callbacks.c - callback functions
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "libssh/callbacks.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
int ssh_set_callbacks(ssh_session session, ssh_callbacks cb) {
|
||||
if (session == NULL || cb == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
session->callbacks = cb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,8 +28,12 @@
|
||||
#include <stdio.h>
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/ssh1.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/channels.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
#ifdef HAVE_SSH1
|
||||
#ifdef WITH_SSH1
|
||||
|
||||
/*
|
||||
* This is a big hack. In fact, SSH1 doesn't make a clever use of channels.
|
||||
@@ -40,12 +44,12 @@
|
||||
* protocol.
|
||||
*/
|
||||
|
||||
int channel_open_session1(CHANNEL *chan) {
|
||||
int channel_open_session1(ssh_channel chan) {
|
||||
/*
|
||||
* We guess we are requesting an *exec* channel. It can only have one exec
|
||||
* channel. So we abort with an error if we need more than one.
|
||||
*/
|
||||
SSH_SESSION *session = chan->session;
|
||||
ssh_session session = chan->session;
|
||||
if (session->exec_channel_opened) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"SSH1 supports only one execution channel. "
|
||||
@@ -73,10 +77,10 @@ int channel_open_session1(CHANNEL *chan) {
|
||||
* much simplier under ssh2. I just hope the defaults values are ok ...
|
||||
*/
|
||||
|
||||
int channel_request_pty_size1(CHANNEL *channel, const char *terminal, int col,
|
||||
int channel_request_pty_size1(ssh_channel channel, const char *terminal, int col,
|
||||
int row) {
|
||||
SSH_SESSION *session = channel->session;
|
||||
STRING *str = NULL;
|
||||
ssh_session session = channel->session;
|
||||
ssh_string str = NULL;
|
||||
|
||||
str = string_from_char(terminal);
|
||||
if (str == NULL) {
|
||||
@@ -126,8 +130,8 @@ int channel_request_pty_size1(CHANNEL *channel, const char *terminal, int col,
|
||||
return -1;
|
||||
}
|
||||
|
||||
int channel_change_pty_size1(CHANNEL *channel, int cols, int rows) {
|
||||
SSH_SESSION *session = channel->session;
|
||||
int channel_change_pty_size1(ssh_channel channel, int cols, int rows) {
|
||||
ssh_session session = channel->session;
|
||||
|
||||
if (buffer_add_u8(session->out_buffer, SSH_CMSG_WINDOW_SIZE) < 0 ||
|
||||
buffer_add_u32(session->out_buffer, ntohl(rows)) < 0 ||
|
||||
@@ -163,8 +167,8 @@ int channel_change_pty_size1(CHANNEL *channel, int cols, int rows) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int channel_request_shell1(CHANNEL *channel) {
|
||||
SSH_SESSION *session = channel->session;
|
||||
int channel_request_shell1(ssh_channel channel) {
|
||||
ssh_session session = channel->session;
|
||||
|
||||
if (buffer_add_u8(session->out_buffer,SSH_CMSG_EXEC_SHELL) < 0) {
|
||||
return -1;
|
||||
@@ -179,9 +183,9 @@ int channel_request_shell1(CHANNEL *channel) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int channel_request_exec1(CHANNEL *channel, const char *cmd) {
|
||||
SSH_SESSION *session = channel->session;
|
||||
STRING *command = NULL;
|
||||
int channel_request_exec1(ssh_channel channel, const char *cmd) {
|
||||
ssh_session session = channel->session;
|
||||
ssh_string command = NULL;
|
||||
|
||||
command = string_from_char(cmd);
|
||||
if (command == NULL) {
|
||||
@@ -204,9 +208,9 @@ int channel_request_exec1(CHANNEL *channel, const char *cmd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int channel_rcv_data1(SSH_SESSION *session, int is_stderr) {
|
||||
CHANNEL *channel = session->channels;
|
||||
STRING *str = NULL;
|
||||
static int channel_rcv_data1(ssh_session session, int is_stderr) {
|
||||
ssh_channel channel = session->channels;
|
||||
ssh_string str = NULL;
|
||||
|
||||
str = buffer_get_ssh_string(session->in_buffer);
|
||||
if (str == NULL) {
|
||||
@@ -218,7 +222,7 @@ static int channel_rcv_data1(SSH_SESSION *session, int is_stderr) {
|
||||
"Adding %zu bytes data in %d",
|
||||
string_len(str), is_stderr);
|
||||
|
||||
if (channel_default_bufferize(channel, str->string, string_len(str),
|
||||
if (channel_default_bufferize(channel, string_data(str), string_len(str),
|
||||
is_stderr) < 0) {
|
||||
string_free(str);
|
||||
return -1;
|
||||
@@ -228,9 +232,9 @@ static int channel_rcv_data1(SSH_SESSION *session, int is_stderr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int channel_rcv_close1(SSH_SESSION *session) {
|
||||
CHANNEL *channel = session->channels;
|
||||
u32 status;
|
||||
static int channel_rcv_close1(ssh_session session) {
|
||||
ssh_channel channel = session->channels;
|
||||
uint32_t status;
|
||||
|
||||
buffer_get_u32(session->in_buffer, &status);
|
||||
/*
|
||||
@@ -253,7 +257,7 @@ static int channel_rcv_close1(SSH_SESSION *session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int channel_handle1(SSH_SESSION *session, int type) {
|
||||
int channel_handle1(ssh_session session, int type) {
|
||||
ssh_log(session, SSH_LOG_RARE, "Channel_handle1(%d)", type);
|
||||
switch (type) {
|
||||
case SSH_SMSG_STDOUT_DATA:
|
||||
@@ -261,6 +265,11 @@ int channel_handle1(SSH_SESSION *session, int type) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case SSH_SMSG_STDERR_DATA:
|
||||
if (channel_rcv_data1(session,1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case SSH_SMSG_EXITSTATUS:
|
||||
if (channel_rcv_close1(session) < 0) {
|
||||
return -1;
|
||||
@@ -273,11 +282,11 @@ int channel_handle1(SSH_SESSION *session, int type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int channel_write1(CHANNEL *channel, const void *data, int len) {
|
||||
SSH_SESSION *session = channel->session;
|
||||
int channel_write1(ssh_channel channel, const void *data, int len) {
|
||||
ssh_session session = channel->session;
|
||||
int origlen = len;
|
||||
int effectivelen;
|
||||
|
||||
const unsigned char *ptr=data;
|
||||
while (len > 0) {
|
||||
if (buffer_add_u8(session->out_buffer, SSH_CMSG_STDIN_DATA) < 0) {
|
||||
return -1;
|
||||
@@ -286,11 +295,11 @@ int channel_write1(CHANNEL *channel, const void *data, int len) {
|
||||
effectivelen = len > 32000 ? 32000 : len;
|
||||
|
||||
if (buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 ||
|
||||
buffer_add_data(session->out_buffer, data, effectivelen) < 0) {
|
||||
buffer_add_data(session->out_buffer, ptr, effectivelen) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data += effectivelen;
|
||||
ptr += effectivelen;
|
||||
len -= effectivelen;
|
||||
|
||||
if (packet_send(session) != SSH_OK) {
|
||||
@@ -301,5 +310,5 @@ int channel_write1(CHANNEL *channel, const void *data, int len) {
|
||||
return origlen;
|
||||
}
|
||||
|
||||
#endif /* HAVE_SSH1 */
|
||||
#endif /* WITH_SSH1 */
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
|
||||
137
libssh/client.c
137
libssh/client.c
@@ -31,10 +31,15 @@
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/dh.h"
|
||||
|
||||
#define set_status(opt,status) do {\
|
||||
if (opt->connect_status_function) \
|
||||
opt->connect_status_function(opt->connect_status_arg, status); \
|
||||
#define set_status(session, status) do {\
|
||||
if (session->callbacks && session->callbacks->connect_status_function) \
|
||||
session->callbacks->connect_status_function(session->callbacks->userdata, status); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
@@ -48,7 +53,7 @@
|
||||
*
|
||||
* @return A newly allocated string with the banner or NULL on error.
|
||||
*/
|
||||
char *ssh_get_banner(SSH_SESSION *session) {
|
||||
char *ssh_get_banner(ssh_session session) {
|
||||
char buffer[128] = {0};
|
||||
char *str = NULL;
|
||||
int i;
|
||||
@@ -61,7 +66,11 @@ char *ssh_get_banner(SSH_SESSION *session) {
|
||||
leave_function();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef WITH_PCAP
|
||||
if(session->pcap_ctx && buffer[i] == '\n'){
|
||||
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_IN,buffer,i+1,i+1);
|
||||
}
|
||||
#endif
|
||||
if (buffer[i] == '\r') {
|
||||
buffer[i] = '\0';
|
||||
}
|
||||
@@ -97,8 +106,11 @@ char *ssh_get_banner(SSH_SESSION *session) {
|
||||
*
|
||||
* @see ssh_get_banner()
|
||||
*/
|
||||
static int ssh_analyze_banner(SSH_SESSION *session, int *ssh1, int *ssh2) {
|
||||
char *banner = session->serverbanner;
|
||||
static int ssh_analyze_banner(ssh_session session, int *ssh1, int *ssh2) {
|
||||
const char *banner = session->serverbanner;
|
||||
const char *openssh;
|
||||
|
||||
ssh_log(session, SSH_LOG_RARE, "Analyzing banner: %s", banner);
|
||||
|
||||
if (strncmp(banner, "SSH-", 4) != 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Protocol mismatch: %s", banner);
|
||||
@@ -129,6 +141,17 @@ static int ssh_analyze_banner(SSH_SESSION *session, int *ssh1, int *ssh2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
openssh = strstr(banner, "OpenSSH");
|
||||
if (openssh != NULL) {
|
||||
int major, minor;
|
||||
major = strtol(openssh + 8, (char **) NULL, 10);
|
||||
minor = strtol(openssh + 10, (char **) NULL, 10);
|
||||
session->openssh = SSH_VERSION_INT(major, minor, 0);
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
"We are talking to an OpenSSH server version: %d.%d (%x)",
|
||||
major, minor, session->openssh);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -141,7 +164,7 @@ static int ssh_analyze_banner(SSH_SESSION *session, int *ssh1, int *ssh2) {
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
int ssh_send_banner(SSH_SESSION *session, int server) {
|
||||
int ssh_send_banner(ssh_session session, int server) {
|
||||
const char *banner = NULL;
|
||||
char buffer[128] = {0};
|
||||
|
||||
@@ -149,8 +172,8 @@ int ssh_send_banner(SSH_SESSION *session, int server) {
|
||||
|
||||
banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2;
|
||||
|
||||
if (session->options->banner) {
|
||||
banner = session->options->banner;
|
||||
if (session->xbanner) {
|
||||
banner = session->xbanner;
|
||||
}
|
||||
|
||||
if (server) {
|
||||
@@ -178,7 +201,10 @@ int ssh_send_banner(SSH_SESSION *session, int server) {
|
||||
leave_function();
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef WITH_PCAP
|
||||
if(session->pcap_ctx)
|
||||
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,buffer,strlen(buffer),strlen(buffer));
|
||||
#endif
|
||||
leave_function();
|
||||
return 0;
|
||||
}
|
||||
@@ -189,11 +215,11 @@ int ssh_send_banner(SSH_SESSION *session, int server) {
|
||||
#define DH_STATE_NEWKEYS_TO_SEND 3
|
||||
#define DH_STATE_NEWKEYS_SENT 4
|
||||
#define DH_STATE_FINISHED 5
|
||||
static int dh_handshake(SSH_SESSION *session) {
|
||||
STRING *e = NULL;
|
||||
STRING *f = NULL;
|
||||
STRING *pubkey = NULL;
|
||||
STRING *signature = NULL;
|
||||
static int dh_handshake(ssh_session session) {
|
||||
ssh_string e = NULL;
|
||||
ssh_string f = NULL;
|
||||
ssh_string pubkey = NULL;
|
||||
ssh_string signature = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
enter_function();
|
||||
@@ -399,8 +425,8 @@ error:
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
int ssh_service_request(SSH_SESSION *session, const char *service) {
|
||||
STRING *service_s = NULL;
|
||||
int ssh_service_request(ssh_session session, const char *service) {
|
||||
ssh_string service_s = NULL;
|
||||
|
||||
enter_function();
|
||||
|
||||
@@ -455,8 +481,7 @@ int ssh_service_request(SSH_SESSION *session, const char *service) {
|
||||
* \see ssh_new()
|
||||
* \see ssh_disconnect()
|
||||
*/
|
||||
int ssh_connect(SSH_SESSION *session) {
|
||||
SSH_OPTIONS *options = session->options;
|
||||
int ssh_connect(ssh_session session) {
|
||||
int ssh1 = 0;
|
||||
int ssh2 = 0;
|
||||
int fd = -1;
|
||||
@@ -466,42 +491,31 @@ int ssh_connect(SSH_SESSION *session) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session->options == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No options set");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
options = session->options;
|
||||
|
||||
enter_function();
|
||||
|
||||
session->alive = 0;
|
||||
session->client = 1;
|
||||
|
||||
if (ssh_crypto_init() < 0) {
|
||||
if (ssh_init() < 0) {
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (ssh_socket_init() < 0) {
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (options->fd == -1 && options->host == NULL) {
|
||||
if (session->fd == -1 && session->host == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Hostname required");
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (options->fd != -1) {
|
||||
fd = options->fd;
|
||||
if (session->fd != -1) {
|
||||
fd = session->fd;
|
||||
} else {
|
||||
fd = ssh_connect_host(session, options->host, options->bindaddr,
|
||||
options->port, options->timeout, options->timeout_usec);
|
||||
fd = ssh_connect_host(session, session->host, session->bindaddr,
|
||||
session->port, session->timeout, session->timeout_usec);
|
||||
}
|
||||
if (fd < 0) {
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
set_status(options, 0.2);
|
||||
set_status(session, 0.2);
|
||||
|
||||
ssh_socket_set_fd(session->socket, fd);
|
||||
|
||||
@@ -513,7 +527,7 @@ int ssh_connect(SSH_SESSION *session) {
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
set_status(options, 0.4);
|
||||
set_status(session, 0.4);
|
||||
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
"SSH server banner: %s", session->serverbanner);
|
||||
@@ -527,9 +541,9 @@ int ssh_connect(SSH_SESSION *session) {
|
||||
}
|
||||
|
||||
/* Here we decide which version of the protocol to use. */
|
||||
if (ssh2 && options->ssh2allowed) {
|
||||
if (ssh2 && session->ssh2) {
|
||||
session->version = 2;
|
||||
} else if(ssh1 && options->ssh1allowed) {
|
||||
} else if(ssh1 && session->ssh1) {
|
||||
session->version = 1;
|
||||
} else {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
@@ -548,7 +562,7 @@ int ssh_connect(SSH_SESSION *session) {
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
set_status(options, 0.5);
|
||||
set_status(session, 0.5);
|
||||
|
||||
switch (session->version) {
|
||||
case 2:
|
||||
@@ -558,7 +572,7 @@ int ssh_connect(SSH_SESSION *session) {
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
set_status(options,0.6);
|
||||
set_status(session,0.6);
|
||||
|
||||
ssh_list_kex(session, &session->server_kex);
|
||||
if (set_kex(session) < 0) {
|
||||
@@ -573,7 +587,7 @@ int ssh_connect(SSH_SESSION *session) {
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
set_status(options,0.8);
|
||||
set_status(session,0.8);
|
||||
|
||||
if (dh_handshake(session) < 0) {
|
||||
ssh_socket_close(session->socket);
|
||||
@@ -581,7 +595,7 @@ int ssh_connect(SSH_SESSION *session) {
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
set_status(options,1.0);
|
||||
set_status(session,1.0);
|
||||
|
||||
session->connected = 1;
|
||||
break;
|
||||
@@ -592,7 +606,7 @@ int ssh_connect(SSH_SESSION *session) {
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
set_status(options,0.6);
|
||||
set_status(session,0.6);
|
||||
|
||||
session->connected = 1;
|
||||
break;
|
||||
@@ -612,7 +626,7 @@ int ssh_connect(SSH_SESSION *session) {
|
||||
*
|
||||
* @return A newly allocated string with the banner, NULL on error.
|
||||
*/
|
||||
char *ssh_get_issue_banner(SSH_SESSION *session) {
|
||||
char *ssh_get_issue_banner(ssh_session session) {
|
||||
if (session == NULL || session->banner == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -620,21 +634,39 @@ char *ssh_get_issue_banner(SSH_SESSION *session) {
|
||||
return string_to_char(session->banner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the version of the OpenSSH server, if it is not an OpenSSH server
|
||||
* then 0 will be returned.
|
||||
*
|
||||
* You can use the SSH_VERSION_INT macro to compare version numbers.
|
||||
*
|
||||
* @param session The SSH session to use.
|
||||
*
|
||||
* @return The version number if available, 0 otherwise.
|
||||
*/
|
||||
int ssh_get_openssh_version(ssh_session session) {
|
||||
if (session == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return session->openssh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disconnect from a session (client or server).
|
||||
* The session can then be reused to open a new session.
|
||||
*
|
||||
* @param session The SSH session to disconnect.
|
||||
*/
|
||||
void ssh_disconnect(SSH_SESSION *session) {
|
||||
STRING *str = NULL;
|
||||
|
||||
enter_function();
|
||||
void ssh_disconnect(ssh_session session) {
|
||||
ssh_string str = NULL;
|
||||
|
||||
if (session == NULL) {
|
||||
leave_function();
|
||||
return;
|
||||
}
|
||||
|
||||
enter_function();
|
||||
|
||||
if (ssh_socket_is_open(session->socket)) {
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_DISCONNECT) < 0) {
|
||||
goto error;
|
||||
@@ -662,7 +694,6 @@ void ssh_disconnect(SSH_SESSION *session) {
|
||||
|
||||
error:
|
||||
leave_function();
|
||||
ssh_cleanup(session);
|
||||
}
|
||||
|
||||
const char *ssh_copyright(void) {
|
||||
|
||||
315
libssh/config.c
Normal file
315
libssh/config.c
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* config.c - parse the ssh config file
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
enum ssh_config_opcode_e {
|
||||
SOC_UNSUPPORTED = -1,
|
||||
SOC_HOST,
|
||||
SOC_HOSTNAME,
|
||||
SOC_PORT,
|
||||
SOC_USERNAME,
|
||||
SOC_IDENTITY,
|
||||
SOC_CIPHER,
|
||||
SOC_CIPHERS,
|
||||
SOC_COMPRESSION,
|
||||
SOC_TIMEOUT,
|
||||
SOC_PROTOCOL
|
||||
};
|
||||
|
||||
struct ssh_config_keyword_table_s {
|
||||
const char *name;
|
||||
enum ssh_config_opcode_e opcode;
|
||||
};
|
||||
|
||||
static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
||||
{ "host", SOC_HOST },
|
||||
{ "hostname", SOC_HOSTNAME },
|
||||
{ "port", SOC_PORT },
|
||||
{ "user", SOC_USERNAME },
|
||||
{ "identityfile", SOC_IDENTITY },
|
||||
{ "cipher", SOC_CIPHER },
|
||||
{ "ciphers", SOC_CIPHERS },
|
||||
{ "compression", SOC_COMPRESSION },
|
||||
{ "connecttimeout", SOC_TIMEOUT },
|
||||
{ "protocol", SOC_PROTOCOL },
|
||||
{ NULL, SOC_UNSUPPORTED }
|
||||
};
|
||||
|
||||
static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
|
||||
int i;
|
||||
|
||||
for (i = 0; ssh_config_keyword_table[i].name != NULL; i++) {
|
||||
if (strcasecmp(keyword, ssh_config_keyword_table[i].name) == 0) {
|
||||
return ssh_config_keyword_table[i].opcode;
|
||||
}
|
||||
}
|
||||
|
||||
return SOC_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static char *ssh_config_get_token(char **str) {
|
||||
register char *c;
|
||||
char *r;
|
||||
|
||||
/* Ignore leading spaces */
|
||||
for (c = *str; *c; c++) {
|
||||
if (! isblank(*c)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*c == '\"') {
|
||||
for (r = ++c; *c; c++) {
|
||||
if (*c == '\"') {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (r = c; *c; c++) {
|
||||
if (isblank(*c)) {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
*str = c + 1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ssh_config_get_int(char **str, int notfound) {
|
||||
char *p, *endp;
|
||||
int i;
|
||||
|
||||
p = ssh_config_get_token(str);
|
||||
if (p && *p) {
|
||||
i = strtol(p, &endp, 10);
|
||||
if (p == endp) {
|
||||
return notfound;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
return notfound;
|
||||
}
|
||||
|
||||
static const char *ssh_config_get_str(char **str, const char *def) {
|
||||
char *p;
|
||||
|
||||
p = ssh_config_get_token(str);
|
||||
if (p && *p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
static int ssh_config_get_yesno(char **str, int notfound) {
|
||||
const char *p;
|
||||
|
||||
p = ssh_config_get_str(str, NULL);
|
||||
if (p == NULL) {
|
||||
return notfound;
|
||||
}
|
||||
|
||||
if (strncasecmp(p, "yes", 3) == 0) {
|
||||
return 1;
|
||||
} else if (strncasecmp(p, "no", 2) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return notfound;
|
||||
}
|
||||
|
||||
static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
unsigned int count, int *parsing) {
|
||||
enum ssh_config_opcode_e opcode;
|
||||
const char *p;
|
||||
char *s, *x;
|
||||
char *keyword;
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
x = s = strdup(line);
|
||||
if (s == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Remove trailing spaces */
|
||||
for (len = strlen(s) - 1; len > 0; len--) {
|
||||
if (! isspace(s[len])) {
|
||||
break;
|
||||
}
|
||||
s[len] = '\0';
|
||||
}
|
||||
|
||||
keyword = ssh_config_get_token(&s);
|
||||
if (keyword == NULL || *keyword == '#' ||
|
||||
*keyword == '\0' || *keyword == '\n') {
|
||||
SAFE_FREE(x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
opcode = ssh_config_get_opcode(keyword);
|
||||
|
||||
switch (opcode) {
|
||||
case SOC_HOST:
|
||||
*parsing = 0;
|
||||
for (p = ssh_config_get_str(&s, NULL); p && *p;
|
||||
p = ssh_config_get_str(&s, NULL)) {
|
||||
if (match_hostname(session->host, p, strlen(p))) {
|
||||
*parsing = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SOC_HOSTNAME:
|
||||
p = ssh_config_get_str(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, p);
|
||||
}
|
||||
break;
|
||||
case SOC_PORT:
|
||||
p = ssh_config_get_str(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
|
||||
}
|
||||
break;
|
||||
case SOC_USERNAME:
|
||||
p = ssh_config_get_str(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_USER, p);
|
||||
}
|
||||
break;
|
||||
case SOC_IDENTITY:
|
||||
p = ssh_config_get_str(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_IDENTITY, p);
|
||||
}
|
||||
break;
|
||||
case SOC_CIPHERS:
|
||||
p = ssh_config_get_str(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, p);
|
||||
ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, p);
|
||||
}
|
||||
break;
|
||||
case SOC_COMPRESSION:
|
||||
i = ssh_config_get_yesno(&s, -1);
|
||||
if (i >= 0 && *parsing) {
|
||||
if (i) {
|
||||
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "zlib,none");
|
||||
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_S_C, "zlib,none");
|
||||
} else {
|
||||
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "none");
|
||||
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_S_C, "none");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SOC_PROTOCOL:
|
||||
p = ssh_config_get_str(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
char *a, *b;
|
||||
b = strdup(p);
|
||||
if (b == NULL) {
|
||||
SAFE_FREE(x);
|
||||
ssh_set_error_oom(session);
|
||||
return -1;
|
||||
}
|
||||
i = 0;
|
||||
ssh_options_set(session, SSH_OPTIONS_SSH1, &i);
|
||||
ssh_options_set(session, SSH_OPTIONS_SSH2, &i);
|
||||
|
||||
for (a = strtok(b, ","); a; a = strtok(NULL, ",")) {
|
||||
switch (atoi(a)) {
|
||||
case 1:
|
||||
i = 1;
|
||||
ssh_options_set(session, SSH_OPTIONS_SSH1, &i);
|
||||
break;
|
||||
case 2:
|
||||
i = 1;
|
||||
ssh_options_set(session, SSH_OPTIONS_SSH2, &i);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
SAFE_FREE(b);
|
||||
}
|
||||
break;
|
||||
case SOC_TIMEOUT:
|
||||
i = ssh_config_get_int(&s, -1);
|
||||
if (i >= 0 && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &i);
|
||||
}
|
||||
break;
|
||||
case SOC_UNSUPPORTED:
|
||||
fprintf(stderr, "Unsupported option: %s, line: %d\n", keyword, count);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "ERROR - unimplemented opcode: %d\n", opcode);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
SAFE_FREE(x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ssh_config_parse_file */
|
||||
int ssh_config_parse_file(ssh_session session, const char *filename) {
|
||||
char line[1024] = {0};
|
||||
unsigned int count = 0;
|
||||
FILE *f;
|
||||
int parsing;
|
||||
|
||||
if ((f = fopen(filename, "r")) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (session->log_verbosity) {
|
||||
fprintf(stderr, "Reading configuration data from %s\n", filename);
|
||||
}
|
||||
|
||||
parsing = 1;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
count++;
|
||||
if (ssh_config_parse_line(session, line, count, &parsing) < 0) {
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
130
libssh/connect.c
130
libssh/connect.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
@@ -26,16 +26,33 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
/* getaddrinfo, freeaddrinfo, getnameinfo */
|
||||
#define _WIN32_WINNT 0x0501
|
||||
/*
|
||||
* Only use Windows API functions available on Windows 2000 SP4 or later.
|
||||
* The available constants are in <sdkddkver.h>.
|
||||
* http://msdn.microsoft.com/en-us/library/aa383745.aspx
|
||||
* http://blogs.msdn.com/oldnewthing/archive/2007/04/11/2079137.aspx
|
||||
*/
|
||||
#undef _WIN32_WINNT
|
||||
#ifdef HAVE_WSPIAPI_H
|
||||
#define _WIN32_WINNT 0x0500 /* _WIN32_WINNT_WIN2K */
|
||||
#undef NTDDI_VERSION
|
||||
#define NTDDI_VERSION 0x05000400 /* NTDDI_WIN2KSP4 */
|
||||
#else
|
||||
#define _WIN32_WINNT 0x0501 /* _WIN32_WINNT_WINXP */
|
||||
#undef NTDDI_VERSION
|
||||
#define NTDDI_VERSION 0x05010000 /* NTDDI_WINXP */
|
||||
#endif
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include "wspiapi.h" /* Workaround for w2k systems */
|
||||
/* <wspiapi.h> is necessary for getaddrinfo before Windows XP, but it isn't
|
||||
* available on some platforms like MinGW. */
|
||||
#ifdef HAVE_WSPIAPI_H
|
||||
#include <wspiapi.h>
|
||||
#endif
|
||||
|
||||
#else /* _WIN32 */
|
||||
|
||||
@@ -47,6 +64,9 @@
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/channels.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
#ifndef HAVE_SELECT
|
||||
#error "Your system must have select()"
|
||||
@@ -56,6 +76,14 @@
|
||||
#error "Your system must have getaddrinfo()"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_REGCOMP
|
||||
/* don't declare gnu extended regexp's */
|
||||
#ifndef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE
|
||||
#endif
|
||||
#include <regex.h>
|
||||
#endif /* HAVE_REGCOMP */
|
||||
|
||||
#ifdef _WIN32
|
||||
static void sock_set_nonblocking(socket_t sock) {
|
||||
u_long nonblocking = 1;
|
||||
@@ -85,9 +113,64 @@ static void sock_set_nonblocking(socket_t sock) {
|
||||
static void sock_set_blocking(socket_t sock) {
|
||||
fcntl(sock, F_SETFL, 0);
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
static int getai(const char *host, int port, struct addrinfo **ai) {
|
||||
#ifdef HAVE_REGCOMP
|
||||
static regex_t *ip_regex = NULL;
|
||||
|
||||
/** @internal
|
||||
* @brief initializes and compile the regexp to be used for IP matching
|
||||
* @returns -1 on error (and error message is set)
|
||||
* @returns 0 on success
|
||||
*/
|
||||
int ssh_regex_init(){
|
||||
if(ip_regex==NULL){
|
||||
int err;
|
||||
regex_t *regex=malloc(sizeof (regex_t));
|
||||
ZERO_STRUCTP(regex);
|
||||
err=regcomp(regex,"^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$",REG_EXTENDED | REG_NOSUB);
|
||||
if(err != 0){
|
||||
char buffer[128];
|
||||
regerror(err,regex,buffer,sizeof(buffer));
|
||||
fprintf(stderr,"Error while compiling regular expression : %s\n",buffer);
|
||||
SAFE_FREE(regex);
|
||||
return -1;
|
||||
}
|
||||
ip_regex=regex;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief clean up the IP regexp
|
||||
*/
|
||||
void ssh_regex_finalize(){
|
||||
if(ip_regex){
|
||||
regfree(ip_regex);
|
||||
SAFE_FREE(ip_regex);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* HAVE_REGCOMP */
|
||||
int ssh_regex_init(){
|
||||
return 0;
|
||||
}
|
||||
void ssh_regex_finalize(){
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int ssh_connect_socket_close(socket_t s){
|
||||
#ifdef _WIN32
|
||||
return closesocket(s);
|
||||
#else
|
||||
return close(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int getai(ssh_session session, const char *host, int port, struct addrinfo **ai) {
|
||||
const char *service = NULL;
|
||||
struct addrinfo hints;
|
||||
char s_port[10];
|
||||
@@ -103,12 +186,21 @@ static int getai(const char *host, int port, struct addrinfo **ai) {
|
||||
} else {
|
||||
snprintf(s_port, sizeof(s_port), "%hu", port);
|
||||
service = s_port;
|
||||
#ifdef AI_NUMERICSERV
|
||||
hints.ai_flags=AI_NUMERICSERV;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_REGCOMP
|
||||
if(regexec(ip_regex,host,0,NULL,0) == 0){
|
||||
/* this is an IP address */
|
||||
ssh_log(session,SSH_LOG_PACKET,"host %s matches an IP address",host);
|
||||
hints.ai_flags |= AI_NUMERICHOST;
|
||||
}
|
||||
#endif
|
||||
return getaddrinfo(host, service, &hints, ai);
|
||||
}
|
||||
|
||||
static int ssh_connect_ai_timeout(SSH_SESSION *session, const char *host,
|
||||
static int ssh_connect_ai_timeout(ssh_session session, const char *host,
|
||||
int port, struct addrinfo *ai, long timeout, long usec, socket_t s) {
|
||||
struct timeval to;
|
||||
fd_set set;
|
||||
@@ -122,6 +214,9 @@ static int ssh_connect_ai_timeout(SSH_SESSION *session, const char *host,
|
||||
|
||||
sock_set_nonblocking(s);
|
||||
|
||||
ssh_log(session, SSH_LOG_RARE, "Trying to connect to host: %s:%d with "
|
||||
"timeout %ld.%ld", host, port, timeout, usec);
|
||||
|
||||
/* The return value is checked later */
|
||||
connect(s, ai->ai_addr, ai->ai_addrlen);
|
||||
freeaddrinfo(ai);
|
||||
@@ -134,7 +229,7 @@ static int ssh_connect_ai_timeout(SSH_SESSION *session, const char *host,
|
||||
/* timeout */
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Timeout while connecting to %s:%d", host, port);
|
||||
close(s);
|
||||
ssh_connect_socket_close(s);
|
||||
leave_function();
|
||||
return -1;
|
||||
}
|
||||
@@ -142,7 +237,7 @@ static int ssh_connect_ai_timeout(SSH_SESSION *session, const char *host,
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Select error: %s", strerror(errno));
|
||||
close(s);
|
||||
ssh_connect_socket_close(s);
|
||||
leave_function();
|
||||
return -1;
|
||||
}
|
||||
@@ -153,7 +248,7 @@ static int ssh_connect_ai_timeout(SSH_SESSION *session, const char *host,
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Connect to %s:%d failed: %s", host, port, strerror(rc));
|
||||
close(s);
|
||||
ssh_connect_socket_close(s);
|
||||
leave_function();
|
||||
return -1;
|
||||
}
|
||||
@@ -174,7 +269,7 @@ static int ssh_connect_ai_timeout(SSH_SESSION *session, const char *host,
|
||||
*
|
||||
* @returns A file descriptor, < 0 on error.
|
||||
*/
|
||||
socket_t ssh_connect_host(SSH_SESSION *session, const char *host,
|
||||
socket_t ssh_connect_host(ssh_session session, const char *host,
|
||||
const char *bind_addr, int port, long timeout, long usec) {
|
||||
socket_t s = -1;
|
||||
int rc;
|
||||
@@ -183,7 +278,7 @@ socket_t ssh_connect_host(SSH_SESSION *session, const char *host,
|
||||
|
||||
enter_function();
|
||||
|
||||
rc = getai(host, port, &ai);
|
||||
rc = getai(session,host, port, &ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
|
||||
@@ -206,7 +301,7 @@ socket_t ssh_connect_host(SSH_SESSION *session, const char *host,
|
||||
|
||||
ssh_log(session, SSH_LOG_PACKET, "Resolving %s\n", bind_addr);
|
||||
|
||||
rc = getai(host, 0, &bind_ai);
|
||||
rc = getai(session,bind_addr, 0, &bind_ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve bind address %s (%s)",
|
||||
@@ -229,7 +324,7 @@ socket_t ssh_connect_host(SSH_SESSION *session, const char *host,
|
||||
|
||||
/* Cannot bind to any local addresses */
|
||||
if (bind_itr == NULL) {
|
||||
close(s);
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
@@ -244,9 +339,8 @@ socket_t ssh_connect_host(SSH_SESSION *session, const char *host,
|
||||
|
||||
if (connect(s, itr->ai_addr, itr->ai_addrlen) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Connect failed: %s", strerror(errno));
|
||||
close(s);
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
leave_function();
|
||||
continue;
|
||||
} else {
|
||||
/* We are connected */
|
||||
@@ -292,7 +386,7 @@ socket_t ssh_connect_host(SSH_SESSION *session, const char *host,
|
||||
*
|
||||
* @see select(2)
|
||||
*/
|
||||
int ssh_select(CHANNEL **channels, CHANNEL **outchannels, socket_t maxfd,
|
||||
int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
||||
fd_set *readfds, struct timeval *timeout) {
|
||||
struct timeval zerotime;
|
||||
fd_set localset, localset2;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include "libssh/priv.h"
|
||||
|
||||
static u32 crc_table[] = {
|
||||
static uint32_t crc_table[] = {
|
||||
0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
|
||||
0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
|
||||
0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
|
||||
@@ -78,8 +78,8 @@ static u32 crc_table[] = {
|
||||
0x2d02ef8dUL
|
||||
};
|
||||
|
||||
u32 ssh_crc32(const char *buf, u32 len) {
|
||||
u32 ret = 0;
|
||||
uint32_t ssh_crc32(const char *buf, uint32_t len) {
|
||||
uint32_t ret = 0;
|
||||
while(len > 0) {
|
||||
ret = crc_table[(ret ^ *buf) & 0xff] ^ (ret >> 8);
|
||||
--len;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -37,10 +37,11 @@
|
||||
#endif
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/wrapper.h"
|
||||
#include "libssh/crypto.h"
|
||||
|
||||
u32 packet_decrypt_len(SSH_SESSION *session, char *crypted){
|
||||
u32 decrypted;
|
||||
uint32_t packet_decrypt_len(ssh_session session, char *crypted){
|
||||
uint32_t decrypted;
|
||||
|
||||
if (session->current_crypto) {
|
||||
if (packet_decrypt(session, crypted,
|
||||
@@ -57,10 +58,13 @@ u32 packet_decrypt_len(SSH_SESSION *session, char *crypted){
|
||||
return ntohl(decrypted);
|
||||
}
|
||||
|
||||
int packet_decrypt(SSH_SESSION *session, void *data,u32 len) {
|
||||
int packet_decrypt(ssh_session session, void *data,uint32_t len) {
|
||||
struct crypto_struct *crypto = session->current_crypto->in_cipher;
|
||||
char *out = NULL;
|
||||
|
||||
if(len % session->current_crypto->in_cipher->blocksize != 0){
|
||||
ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
out = malloc(len);
|
||||
if (out == NULL) {
|
||||
return -1;
|
||||
@@ -90,17 +94,20 @@ int packet_decrypt(SSH_SESSION *session, void *data,u32 len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char *packet_encrypt(SSH_SESSION *session, void *data, u32 len) {
|
||||
unsigned char *packet_encrypt(ssh_session session, void *data, uint32_t len) {
|
||||
struct crypto_struct *crypto = NULL;
|
||||
HMACCTX ctx = NULL;
|
||||
char *out = NULL;
|
||||
unsigned int finallen;
|
||||
u32 seq;
|
||||
uint32_t seq;
|
||||
|
||||
if (!session->current_crypto) {
|
||||
return NULL; /* nothing to do here */
|
||||
}
|
||||
|
||||
if(len % session->current_crypto->in_cipher->blocksize != 0){
|
||||
ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len);
|
||||
return NULL;
|
||||
}
|
||||
out = malloc(len);
|
||||
if (out == NULL) {
|
||||
return NULL;
|
||||
@@ -132,7 +139,7 @@ unsigned char *packet_encrypt(SSH_SESSION *session, void *data, u32 len) {
|
||||
SAFE_FREE(out);
|
||||
return NULL;
|
||||
}
|
||||
hmac_update(ctx,(unsigned char *)&seq,sizeof(u32));
|
||||
hmac_update(ctx,(unsigned char *)&seq,sizeof(uint32_t));
|
||||
hmac_update(ctx,data,len);
|
||||
hmac_final(ctx,session->current_crypto->hmacbuf,&finallen);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
@@ -174,12 +181,12 @@ unsigned char *packet_encrypt(SSH_SESSION *session, void *data, u32 len) {
|
||||
* @return 0 if hmac and mac are equal, < 0 if not or an error
|
||||
* occured.
|
||||
*/
|
||||
int packet_hmac_verify(SSH_SESSION *session, BUFFER *buffer,
|
||||
int packet_hmac_verify(ssh_session session, ssh_buffer buffer,
|
||||
unsigned char *mac) {
|
||||
unsigned char hmacbuf[EVP_MAX_MD_SIZE] = {0};
|
||||
HMACCTX ctx;
|
||||
unsigned int len;
|
||||
u32 seq;
|
||||
uint32_t seq;
|
||||
|
||||
ctx = hmac_init(session->current_crypto->decryptMAC, 20, HMAC_SHA1);
|
||||
if (ctx == NULL) {
|
||||
@@ -188,14 +195,14 @@ int packet_hmac_verify(SSH_SESSION *session, BUFFER *buffer,
|
||||
|
||||
seq = htonl(session->recv_seq);
|
||||
|
||||
hmac_update(ctx, (unsigned char *) &seq, sizeof(u32));
|
||||
hmac_update(ctx, (unsigned char *) &seq, sizeof(uint32_t));
|
||||
hmac_update(ctx, buffer_get(buffer), buffer_get_len(buffer));
|
||||
hmac_final(ctx, hmacbuf, &len);
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("received mac",mac,len);
|
||||
ssh_print_hexa("Computed mac",hmacbuf,len);
|
||||
ssh_print_hexa("seq",(unsigned char *)&seq,sizeof(u32));
|
||||
ssh_print_hexa("seq",(unsigned char *)&seq,sizeof(uint32_t));
|
||||
#endif
|
||||
if (memcmp(mac, hmacbuf, len) == 0) {
|
||||
return 0;
|
||||
|
||||
117
libssh/dh.c
117
libssh/dh.c
@@ -40,6 +40,7 @@
|
||||
* if everything went correctly, k and k' are equal
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -50,7 +51,13 @@
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/keys.h"
|
||||
#include "libssh/dh.h"
|
||||
|
||||
/* todo: remove it */
|
||||
#include "libssh/string.h"
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/evp.h>
|
||||
@@ -149,6 +156,7 @@ void ssh_crypto_finalize(void) {
|
||||
g = NULL;
|
||||
bignum_free(p);
|
||||
p = NULL;
|
||||
ssh_crypto_initialized=0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +224,7 @@ void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) {
|
||||
printf("%s: %s\n", descr, hexa);
|
||||
}
|
||||
|
||||
int dh_generate_x(SSH_SESSION *session) {
|
||||
int dh_generate_x(ssh_session session) {
|
||||
session->next_crypto->x = bignum_new();
|
||||
if (session->next_crypto->x == NULL) {
|
||||
return -1;
|
||||
@@ -237,7 +245,7 @@ int dh_generate_x(SSH_SESSION *session) {
|
||||
}
|
||||
|
||||
/* used by server */
|
||||
int dh_generate_y(SSH_SESSION *session) {
|
||||
int dh_generate_y(ssh_session session) {
|
||||
session->next_crypto->y = bignum_new();
|
||||
if (session->next_crypto->y == NULL) {
|
||||
return -1;
|
||||
@@ -258,7 +266,7 @@ int dh_generate_y(SSH_SESSION *session) {
|
||||
}
|
||||
|
||||
/* used by server */
|
||||
int dh_generate_e(SSH_SESSION *session) {
|
||||
int dh_generate_e(ssh_session session) {
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
if (ctx == NULL) {
|
||||
@@ -291,7 +299,7 @@ int dh_generate_e(SSH_SESSION *session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dh_generate_f(SSH_SESSION *session) {
|
||||
int dh_generate_f(ssh_session session) {
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
if (ctx == NULL) {
|
||||
@@ -324,8 +332,8 @@ int dh_generate_f(SSH_SESSION *session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
STRING *make_bignum_string(bignum num) {
|
||||
STRING *ptr = NULL;
|
||||
ssh_string make_bignum_string(bignum num) {
|
||||
ssh_string ptr = NULL;
|
||||
int pad = 0;
|
||||
unsigned int len = bignum_num_bytes(num);
|
||||
unsigned int bits = bignum_num_bits(num);
|
||||
@@ -339,7 +347,7 @@ STRING *make_bignum_string(bignum num) {
|
||||
#ifdef DEBUG_CRYPTO
|
||||
fprintf(stderr, "%d bits, %d bytes, %d padding\n", bits, len, pad);
|
||||
#endif /* DEBUG_CRYPTO */
|
||||
|
||||
/* TODO: fix that crap !! */
|
||||
ptr = malloc(4 + len + pad);
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
@@ -358,7 +366,7 @@ STRING *make_bignum_string(bignum num) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bignum make_string_bn(STRING *string){
|
||||
bignum make_string_bn(ssh_string string){
|
||||
bignum bn = NULL;
|
||||
unsigned int len = string_len(string);
|
||||
|
||||
@@ -376,20 +384,20 @@ bignum make_string_bn(STRING *string){
|
||||
return bn;
|
||||
}
|
||||
|
||||
STRING *dh_get_e(SSH_SESSION *session) {
|
||||
ssh_string dh_get_e(ssh_session session) {
|
||||
return make_bignum_string(session->next_crypto->e);
|
||||
}
|
||||
|
||||
/* used by server */
|
||||
STRING *dh_get_f(SSH_SESSION *session) {
|
||||
ssh_string dh_get_f(ssh_session session) {
|
||||
return make_bignum_string(session->next_crypto->f);
|
||||
}
|
||||
|
||||
void dh_import_pubkey(SSH_SESSION *session, STRING *pubkey_string) {
|
||||
void dh_import_pubkey(ssh_session session, ssh_string pubkey_string) {
|
||||
session->next_crypto->server_pubkey = pubkey_string;
|
||||
}
|
||||
|
||||
int dh_import_f(SSH_SESSION *session, STRING *f_string) {
|
||||
int dh_import_f(ssh_session session, ssh_string f_string) {
|
||||
session->next_crypto->f = make_string_bn(f_string);
|
||||
if (session->next_crypto->f == NULL) {
|
||||
return -1;
|
||||
@@ -403,7 +411,7 @@ int dh_import_f(SSH_SESSION *session, STRING *f_string) {
|
||||
}
|
||||
|
||||
/* used by the server implementation */
|
||||
int dh_import_e(SSH_SESSION *session, STRING *e_string) {
|
||||
int dh_import_e(ssh_session session, ssh_string e_string) {
|
||||
session->next_crypto->e = make_string_bn(e_string);
|
||||
if (session->next_crypto->e == NULL) {
|
||||
return -1;
|
||||
@@ -416,7 +424,7 @@ int dh_import_e(SSH_SESSION *session, STRING *e_string) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dh_build_k(SSH_SESSION *session) {
|
||||
int dh_build_k(ssh_session session) {
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
if (ctx == NULL) {
|
||||
@@ -465,7 +473,7 @@ int dh_build_k(SSH_SESSION *session) {
|
||||
}
|
||||
|
||||
/*
|
||||
static void sha_add(STRING *str,SHACTX ctx){
|
||||
static void sha_add(ssh_string str,SHACTX ctx){
|
||||
sha1_update(ctx,str,string_len(str)+4);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("partial hashed sessionid",str,string_len(str)+4);
|
||||
@@ -473,14 +481,14 @@ static void sha_add(STRING *str,SHACTX ctx){
|
||||
}
|
||||
*/
|
||||
|
||||
int make_sessionid(SSH_SESSION *session) {
|
||||
int make_sessionid(ssh_session session) {
|
||||
SHACTX ctx;
|
||||
STRING *num = NULL;
|
||||
STRING *str = NULL;
|
||||
BUFFER *server_hash = NULL;
|
||||
BUFFER *client_hash = NULL;
|
||||
BUFFER *buf = NULL;
|
||||
u32 len;
|
||||
ssh_string num = NULL;
|
||||
ssh_string str = NULL;
|
||||
ssh_buffer server_hash = NULL;
|
||||
ssh_buffer client_hash = NULL;
|
||||
ssh_buffer buf = NULL;
|
||||
uint32_t len;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
enter_function();
|
||||
@@ -619,27 +627,27 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int hashbufout_add_cookie(SSH_SESSION *session) {
|
||||
int hashbufout_add_cookie(ssh_session session) {
|
||||
session->out_hashbuf = buffer_new();
|
||||
if (session->out_hashbuf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffer_add_u8(session->out_hashbuf, 20) < 0) {
|
||||
buffer_free(session->out_hashbuf);
|
||||
buffer_reinit(session->out_hashbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (session->server) {
|
||||
if (buffer_add_data(session->out_hashbuf,
|
||||
session->server_kex.cookie, 16) < 0) {
|
||||
buffer_free(session->out_hashbuf);
|
||||
buffer_reinit(session->out_hashbuf);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (buffer_add_data(session->out_hashbuf,
|
||||
session->client_kex.cookie, 16) < 0) {
|
||||
buffer_free(session->out_hashbuf);
|
||||
buffer_reinit(session->out_hashbuf);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -647,25 +655,25 @@ int hashbufout_add_cookie(SSH_SESSION *session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hashbufin_add_cookie(SSH_SESSION *session, unsigned char *cookie) {
|
||||
int hashbufin_add_cookie(ssh_session session, unsigned char *cookie) {
|
||||
session->in_hashbuf = buffer_new();
|
||||
if (session->in_hashbuf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffer_add_u8(session->in_hashbuf, 20) < 0) {
|
||||
buffer_free(session->in_hashbuf);
|
||||
buffer_reinit(session->in_hashbuf);
|
||||
return -1;
|
||||
}
|
||||
if (buffer_add_data(session->in_hashbuf,cookie, 16) < 0) {
|
||||
buffer_free(session->in_hashbuf);
|
||||
buffer_reinit(session->in_hashbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int generate_one_key(STRING *k,
|
||||
static int generate_one_key(ssh_string k,
|
||||
unsigned char session_id[SHA_DIGEST_LEN],
|
||||
unsigned char output[SHA_DIGEST_LEN],
|
||||
char letter) {
|
||||
@@ -685,8 +693,8 @@ static int generate_one_key(STRING *k,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int generate_session_keys(SSH_SESSION *session) {
|
||||
STRING *k_string = NULL;
|
||||
int generate_session_keys(ssh_session session) {
|
||||
ssh_string k_string = NULL;
|
||||
SHACTX ctx = NULL;
|
||||
int rc = -1;
|
||||
|
||||
@@ -815,8 +823,8 @@ error:
|
||||
* @see ssh_get_hexa()
|
||||
* @see ssh_print_hexa()
|
||||
*/
|
||||
int ssh_get_pubkey_hash(SSH_SESSION *session, unsigned char **hash) {
|
||||
STRING *pubkey;
|
||||
int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) {
|
||||
ssh_string pubkey;
|
||||
MD5CTX ctx;
|
||||
unsigned char *h;
|
||||
|
||||
@@ -847,7 +855,21 @@ int ssh_get_pubkey_hash(SSH_SESSION *session, unsigned char **hash) {
|
||||
return MD5_DIGEST_LEN;
|
||||
}
|
||||
|
||||
STRING *ssh_get_pubkey(SSH_SESSION *session){
|
||||
/**
|
||||
* @brief Deallocate the hash obtained by ssh_get_pubkey_hash.
|
||||
* This is required under Microsoft platform as this library might use a
|
||||
* different C library than your software, hence a different heap.
|
||||
*
|
||||
* @param hash The buffer to deallocate.
|
||||
*
|
||||
* @see ssh_get_pubkey_hash()
|
||||
*/
|
||||
void ssh_clean_pubkey_hash(unsigned char **hash) {
|
||||
SAFE_FREE(*hash);
|
||||
*hash = NULL;
|
||||
}
|
||||
|
||||
ssh_string ssh_get_pubkey(ssh_session session){
|
||||
return string_copy(session->current_crypto->server_pubkey);
|
||||
}
|
||||
|
||||
@@ -875,8 +897,8 @@ static int match(const char *group, const char *object){
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sig_verify(SSH_SESSION *session, PUBLIC_KEY *pubkey,
|
||||
SIGNATURE *signature, unsigned char *digest) {
|
||||
int sig_verify(ssh_session session, ssh_public_key pubkey,
|
||||
SIGNATURE *signature, unsigned char *digest, int size) {
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_error_t valid = 0;
|
||||
gcry_sexp_t gcryhash;
|
||||
@@ -885,7 +907,7 @@ static int sig_verify(SSH_SESSION *session, PUBLIC_KEY *pubkey,
|
||||
#endif
|
||||
unsigned char hash[SHA_DIGEST_LEN + 1] = {0};
|
||||
|
||||
sha1(digest,SHA_DIGEST_LEN, hash + 1);
|
||||
sha1(digest, size, hash + 1);
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Hash to be verified with dsa", hash + 1, SHA_DIGEST_LEN);
|
||||
@@ -970,30 +992,24 @@ static int sig_verify(SSH_SESSION *session, PUBLIC_KEY *pubkey,
|
||||
return -1;
|
||||
}
|
||||
|
||||
int signature_verify(SSH_SESSION *session, STRING *signature) {
|
||||
PUBLIC_KEY *pubkey = NULL;
|
||||
int signature_verify(ssh_session session, ssh_string signature) {
|
||||
ssh_public_key pubkey = NULL;
|
||||
SIGNATURE *sign = NULL;
|
||||
int err;
|
||||
|
||||
enter_function();
|
||||
|
||||
if (session->options->dont_verify_hostkey) {
|
||||
ssh_log(session, SSH_LOG_FUNCTIONS, "Host key wasn't verified");
|
||||
leave_function();
|
||||
return 0;
|
||||
}
|
||||
|
||||
pubkey = publickey_from_string(session,session->next_crypto->server_pubkey);
|
||||
if(pubkey == NULL) {
|
||||
leave_function();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (session->options->wanted_methods[SSH_HOSTKEYS]) {
|
||||
if(!match(session->options->wanted_methods[SSH_HOSTKEYS],pubkey->type_c)) {
|
||||
if (session->wanted_methods[SSH_HOSTKEYS]) {
|
||||
if(!match(session->wanted_methods[SSH_HOSTKEYS],pubkey->type_c)) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Public key from server (%s) doesn't match user preference (%s)",
|
||||
pubkey->type_c, session->options->wanted_methods[SSH_HOSTKEYS]);
|
||||
pubkey->type_c, session->wanted_methods[SSH_HOSTKEYS]);
|
||||
publickey_free(pubkey);
|
||||
leave_function();
|
||||
return -1;
|
||||
@@ -1011,7 +1027,8 @@ int signature_verify(SSH_SESSION *session, STRING *signature) {
|
||||
ssh_log(session, SSH_LOG_FUNCTIONS,
|
||||
"Going to verify a %s type signature", pubkey->type_c);
|
||||
|
||||
err = sig_verify(session,pubkey,sign,session->next_crypto->session_id);
|
||||
err = sig_verify(session,pubkey,sign,
|
||||
session->next_crypto->session_id,SHA_DIGEST_LEN);
|
||||
signature_free(sign);
|
||||
session->next_crypto->server_pubkey_type = pubkey->type_c;
|
||||
publickey_free(pubkey);
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
*
|
||||
* @brief Registers an error with a description.
|
||||
*
|
||||
* @param error The class of error.
|
||||
* @param error The place to store the error.
|
||||
*
|
||||
* @param code The class of error.
|
||||
*
|
||||
@@ -58,6 +58,35 @@ void ssh_set_error(void *error, int code, const char *descr, ...) {
|
||||
err->error_code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Registers an out of memory error
|
||||
*
|
||||
* @param error The place to store the error.
|
||||
*
|
||||
*/
|
||||
void ssh_set_error_oom(void *error) {
|
||||
struct error_struct *err = error;
|
||||
|
||||
strcpy(err->error_buffer, "Out of memory");
|
||||
err->error_code = SSH_FATAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Registers an invalid argument error
|
||||
*
|
||||
* @param error The place to store the error.
|
||||
*
|
||||
* @param function The function the error happened in.
|
||||
*
|
||||
*/
|
||||
void ssh_set_error_invalid(void *error, const char *function) {
|
||||
ssh_set_error(error, SSH_FATAL, "Invalid argument in %s", function);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieve the error text message from the last error.
|
||||
*
|
||||
@@ -76,13 +105,13 @@ const char *ssh_get_error(void *error) {
|
||||
*
|
||||
* @param error The SSH session pointer.
|
||||
*
|
||||
* \return SSH_NO_ERROR No error occured\n
|
||||
* \return SSH_NO_ERROR No error occurred\n
|
||||
* SSH_REQUEST_DENIED The last request was denied but situation is
|
||||
* recoverable\n
|
||||
* SSH_FATAL A fatal error occured. This could be an unexpected
|
||||
* SSH_FATAL A fatal error occurred. This could be an unexpected
|
||||
* disconnection\n
|
||||
*
|
||||
* \nOther error codes are internal but can be considered same than
|
||||
* Other error codes are internal but can be considered same than
|
||||
* SSH_FATAL.
|
||||
*/
|
||||
int ssh_get_error_code(void *error) {
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
|
||||
|
||||
@@ -33,7 +35,7 @@
|
||||
|
||||
#define BLOCKSIZE 4092
|
||||
|
||||
static z_stream *initcompress(SSH_SESSION *session, int level) {
|
||||
static z_stream *initcompress(ssh_session session, int level) {
|
||||
z_stream *stream = NULL;
|
||||
int status;
|
||||
|
||||
@@ -54,11 +56,11 @@ static z_stream *initcompress(SSH_SESSION *session, int level) {
|
||||
return stream;
|
||||
}
|
||||
|
||||
static BUFFER *gzip_compress(SSH_SESSION *session,BUFFER *source,int level){
|
||||
static ssh_buffer gzip_compress(ssh_session session,ssh_buffer source,int level){
|
||||
z_stream *zout = session->current_crypto->compress_out_ctx;
|
||||
void *in_ptr = buffer_get(source);
|
||||
unsigned long in_size = buffer_get_len(source);
|
||||
BUFFER *dest = NULL;
|
||||
ssh_buffer dest = NULL;
|
||||
static unsigned char out_buf[BLOCKSIZE] = {0};
|
||||
unsigned long len;
|
||||
int status;
|
||||
@@ -98,8 +100,8 @@ static BUFFER *gzip_compress(SSH_SESSION *session,BUFFER *source,int level){
|
||||
return dest;
|
||||
}
|
||||
|
||||
int compress_buffer(SSH_SESSION *session, BUFFER *buf) {
|
||||
BUFFER *dest = NULL;
|
||||
int compress_buffer(ssh_session session, ssh_buffer buf) {
|
||||
ssh_buffer dest = NULL;
|
||||
|
||||
dest = gzip_compress(session, buf, 9);
|
||||
if (dest == NULL) {
|
||||
@@ -122,7 +124,7 @@ int compress_buffer(SSH_SESSION *session, BUFFER *buf) {
|
||||
|
||||
/* decompression */
|
||||
|
||||
static z_stream *initdecompress(SSH_SESSION *session) {
|
||||
static z_stream *initdecompress(ssh_session session) {
|
||||
z_stream *stream = NULL;
|
||||
int status;
|
||||
|
||||
@@ -143,12 +145,12 @@ static z_stream *initdecompress(SSH_SESSION *session) {
|
||||
return stream;
|
||||
}
|
||||
|
||||
static BUFFER *gzip_decompress(SSH_SESSION *session, BUFFER *source) {
|
||||
static ssh_buffer gzip_decompress(ssh_session session, ssh_buffer source, size_t maxlen) {
|
||||
z_stream *zin = session->current_crypto->compress_in_ctx;
|
||||
void *in_ptr = buffer_get_rest(source);
|
||||
unsigned long in_size = buffer_get_rest_len(source);
|
||||
static unsigned char out_buf[BLOCKSIZE] = {0};
|
||||
BUFFER *dest = NULL;
|
||||
ssh_buffer dest = NULL;
|
||||
unsigned long len;
|
||||
int status;
|
||||
|
||||
@@ -183,17 +185,21 @@ static BUFFER *gzip_decompress(SSH_SESSION *session, BUFFER *source) {
|
||||
buffer_free(dest);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (buffer_get_len(dest) > maxlen){
|
||||
/* Size of packet exceded, avoid a denial of service attack */
|
||||
buffer_free(dest);
|
||||
return NULL;
|
||||
}
|
||||
zin->next_out = out_buf;
|
||||
} while (zin->avail_out == 0);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
int decompress_buffer(SSH_SESSION *session,BUFFER *buf){
|
||||
BUFFER *dest = NULL;
|
||||
int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen){
|
||||
ssh_buffer dest = NULL;
|
||||
|
||||
dest = gzip_decompress(session,buf);
|
||||
dest = gzip_decompress(session,buf, maxlen);
|
||||
if (dest == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2006 by Aris Adamantiadis
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
@@ -21,7 +21,11 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/dh.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
@@ -31,14 +35,35 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief initialize global cryptographic data structures.
|
||||
*
|
||||
* This function should only be called once, at the beginning of the program, in
|
||||
* the main thread. It may be omitted if your program is not multithreaded.
|
||||
*
|
||||
* @returns 0
|
||||
*/
|
||||
int ssh_init(void) {
|
||||
if(ssh_crypto_init())
|
||||
return -1;
|
||||
if(ssh_socket_init())
|
||||
return -1;
|
||||
if(ssh_regex_init())
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Finalize and cleanup all libssh and cryptographic data structures.
|
||||
*
|
||||
* This function should only be called once, at the end of the program!
|
||||
*
|
||||
* @returns 0
|
||||
* @returns -1 in case of error
|
||||
@returns 0 otherwise
|
||||
*/
|
||||
int ssh_finalize(void) {
|
||||
ssh_regex_finalize();
|
||||
ssh_crypto_finalize();
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_control(GCRYCTL_TERM_SECMEM);
|
||||
|
||||
130
libssh/kex.c
130
libssh/kex.c
@@ -21,6 +21,8 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -29,14 +31,19 @@
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/ssh1.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/wrapper.h"
|
||||
#include "libssh/keys.h"
|
||||
#include "libssh/dh.h"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#define BLOWFISH "blowfish-cbc,"
|
||||
#define AES "aes256-cbc,aes192-cbc,aes128-cbc,"
|
||||
#define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
|
||||
#define DES "3des-cbc"
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
#ifdef HAVE_OPENSSL_BLOWFISH_H
|
||||
@@ -45,7 +52,7 @@
|
||||
#define BLOWFISH ""
|
||||
#endif
|
||||
#ifdef HAVE_OPENSSL_AES_H
|
||||
#define AES "aes256-cbc,aes192-cbc,aes128-cbc,"
|
||||
#define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
|
||||
#else
|
||||
#define AES ""
|
||||
#endif
|
||||
@@ -60,7 +67,7 @@
|
||||
|
||||
const char *default_methods[] = {
|
||||
"diffie-hellman-group1-sha1",
|
||||
"ssh-dss,ssh-rsa",
|
||||
"ssh-rsa,ssh-dss",
|
||||
AES BLOWFISH DES,
|
||||
AES BLOWFISH DES,
|
||||
"hmac-sha1",
|
||||
@@ -74,7 +81,7 @@ const char *default_methods[] = {
|
||||
|
||||
const char *supported_methods[] = {
|
||||
"diffie-hellman-group1-sha1",
|
||||
"ssh-dss,ssh-rsa",
|
||||
"ssh-rsa,ssh-dss",
|
||||
AES BLOWFISH DES,
|
||||
AES BLOWFISH DES,
|
||||
"hmac-sha1",
|
||||
@@ -211,19 +218,19 @@ char *ssh_find_matching(const char *in_d, const char *what_d){
|
||||
SAFE_FREE(tok_in);
|
||||
}
|
||||
|
||||
for(i_in=0; tok_in[i_in]; ++i_in){
|
||||
for(i_what=0; tok_what[i_what] ; ++i_what){
|
||||
if(!strcmp(tok_in[i_in],tok_what[i_what])){
|
||||
/* match */
|
||||
ret=strdup(tok_in[i_in]);
|
||||
/* free the tokens */
|
||||
free(tok_in[0]);
|
||||
free(tok_what[0]);
|
||||
free(tok_in);
|
||||
free(tok_what);
|
||||
return ret;
|
||||
}
|
||||
for(i_what=0; tok_what[i_what] ; ++i_what){
|
||||
for(i_in=0; tok_in[i_in]; ++i_in){
|
||||
if(!strcmp(tok_in[i_in],tok_what[i_what])){
|
||||
/* match */
|
||||
ret=strdup(tok_in[i_in]);
|
||||
/* free the tokens */
|
||||
free(tok_in[0]);
|
||||
free(tok_what[0]);
|
||||
free(tok_in);
|
||||
free(tok_what);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(tok_in[0]);
|
||||
free(tok_what[0]);
|
||||
@@ -232,8 +239,8 @@ char *ssh_find_matching(const char *in_d, const char *what_d){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ssh_get_kex(SSH_SESSION *session, int server_kex) {
|
||||
STRING *str = NULL;
|
||||
int ssh_get_kex(ssh_session session, int server_kex) {
|
||||
ssh_string str = NULL;
|
||||
char *strings[10];
|
||||
int i;
|
||||
|
||||
@@ -311,7 +318,7 @@ error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ssh_list_kex(struct ssh_session *session, KEX *kex) {
|
||||
void ssh_list_kex(ssh_session session, KEX *kex) {
|
||||
int i = 0;
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
@@ -328,18 +335,13 @@ void ssh_list_kex(struct ssh_session *session, KEX *kex) {
|
||||
/* it must be aware of the server kex message */
|
||||
/* it can fail if option is null, not any user specified kex method matches the server one, if not any default kex matches */
|
||||
|
||||
int set_kex(SSH_SESSION *session){
|
||||
int set_kex(ssh_session session){
|
||||
KEX *server = &session->server_kex;
|
||||
KEX *client=&session->client_kex;
|
||||
SSH_OPTIONS *options=session->options;
|
||||
int i;
|
||||
const char *wanted;
|
||||
enter_function();
|
||||
/* the client might ask for a specific cookie to be sent. useful for server debugging */
|
||||
if(options->wanted_cookie)
|
||||
memcpy(client->cookie,options->wanted_cookie,16);
|
||||
else
|
||||
ssh_get_random(client->cookie,16,0);
|
||||
ssh_get_random(client->cookie,16,0);
|
||||
client->methods=malloc(10 * sizeof(char **));
|
||||
if (client->methods == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No space left");
|
||||
@@ -348,7 +350,7 @@ int set_kex(SSH_SESSION *session){
|
||||
}
|
||||
memset(client->methods,0,10*sizeof(char **));
|
||||
for (i=0;i<10;i++){
|
||||
if(!(wanted=options->wanted_methods[i]))
|
||||
if(!(wanted=session->wanted_methods[i]))
|
||||
wanted=default_methods[i];
|
||||
client->methods[i]=ssh_find_matching(server->methods[i],wanted);
|
||||
if(!client->methods[i] && i < SSH_LANG_C_S){
|
||||
@@ -371,9 +373,9 @@ int set_kex(SSH_SESSION *session){
|
||||
}
|
||||
|
||||
/* this function only sends the predefined set of kex methods */
|
||||
int ssh_send_kex(SSH_SESSION *session, int server_kex) {
|
||||
int ssh_send_kex(ssh_session session, int server_kex) {
|
||||
KEX *kex = (server_kex ? &session->server_kex : &session->client_kex);
|
||||
STRING *str = NULL;
|
||||
ssh_string str = NULL;
|
||||
int i;
|
||||
|
||||
enter_function();
|
||||
@@ -421,8 +423,8 @@ int ssh_send_kex(SSH_SESSION *session, int server_kex) {
|
||||
leave_function();
|
||||
return 0;
|
||||
error:
|
||||
buffer_free(session->out_buffer);
|
||||
buffer_free(session->out_hashbuf);
|
||||
buffer_reinit(session->out_buffer);
|
||||
buffer_reinit(session->out_hashbuf);
|
||||
string_free(str);
|
||||
|
||||
leave_function();
|
||||
@@ -444,10 +446,10 @@ int verify_existing_algo(int algo, const char *name){
|
||||
|
||||
/* makes a STRING contating 3 strings : ssh-rsa1,e and n */
|
||||
/* this is a public key in openssh's format */
|
||||
static STRING *make_rsa1_string(STRING *e, STRING *n){
|
||||
BUFFER *buffer = NULL;
|
||||
STRING *rsa = NULL;
|
||||
STRING *ret = NULL;
|
||||
static ssh_string make_rsa1_string(ssh_string e, ssh_string n){
|
||||
ssh_buffer buffer = NULL;
|
||||
ssh_string rsa = NULL;
|
||||
ssh_string ret = NULL;
|
||||
|
||||
buffer = buffer_new();
|
||||
rsa = string_from_char("ssh-rsa1");
|
||||
@@ -475,8 +477,8 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int build_session_id1(SSH_SESSION *session, STRING *servern,
|
||||
STRING *hostn) {
|
||||
static int build_session_id1(ssh_session session, ssh_string servern,
|
||||
ssh_string hostn) {
|
||||
MD5CTX md5 = NULL;
|
||||
|
||||
md5 = md5_init();
|
||||
@@ -488,8 +490,8 @@ static int build_session_id1(SSH_SESSION *session, STRING *servern,
|
||||
ssh_print_hexa("host modulus",hostn->string,string_len(hostn));
|
||||
ssh_print_hexa("server modulus",servern->string,string_len(servern));
|
||||
#endif
|
||||
md5_update(md5,hostn->string,string_len(hostn));
|
||||
md5_update(md5,servern->string,string_len(servern));
|
||||
md5_update(md5,string_data(hostn),string_len(hostn));
|
||||
md5_update(md5,string_data(servern),string_len(servern));
|
||||
md5_update(md5,session->server_kex.cookie,8);
|
||||
md5_final(session->next_crypto->session_id,md5);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
@@ -500,7 +502,7 @@ static int build_session_id1(SSH_SESSION *session, STRING *servern,
|
||||
}
|
||||
|
||||
/* returns 1 if the modulus of k1 is < than the one of k2 */
|
||||
static int modulus_smaller(PUBLIC_KEY *k1, PUBLIC_KEY *k2){
|
||||
static int modulus_smaller(ssh_public_key k1, ssh_public_key k2){
|
||||
bignum n1;
|
||||
bignum n2;
|
||||
int res;
|
||||
@@ -529,12 +531,12 @@ static int modulus_smaller(PUBLIC_KEY *k1, PUBLIC_KEY *k2){
|
||||
}
|
||||
|
||||
#define ABS(A) ( (A)<0 ? -(A):(A) )
|
||||
static STRING *encrypt_session_key(SSH_SESSION *session, PUBLIC_KEY *srvkey,
|
||||
PUBLIC_KEY *hostkey, int slen, int hlen) {
|
||||
static ssh_string encrypt_session_key(ssh_session session, ssh_public_key srvkey,
|
||||
ssh_public_key hostkey, int slen, int hlen) {
|
||||
unsigned char buffer[32] = {0};
|
||||
int i;
|
||||
STRING *data1 = NULL;
|
||||
STRING *data2 = NULL;
|
||||
ssh_string data1 = NULL;
|
||||
ssh_string data2 = NULL;
|
||||
|
||||
/* first, generate a session key */
|
||||
ssh_get_random(session->next_crypto->encryptkey, 32, 1);
|
||||
@@ -606,22 +608,22 @@ static STRING *encrypt_session_key(SSH_SESSION *session, PUBLIC_KEY *srvkey,
|
||||
* 32-bit int supported_authentications_mask
|
||||
*/
|
||||
|
||||
int ssh_get_kex1(SSH_SESSION *session) {
|
||||
STRING *server_exp = NULL;
|
||||
STRING *server_mod = NULL;
|
||||
STRING *host_exp = NULL;
|
||||
STRING *host_mod = NULL;
|
||||
STRING *serverkey = NULL;
|
||||
STRING *hostkey = NULL;
|
||||
STRING *enc_session = NULL;
|
||||
PUBLIC_KEY *srv = NULL;
|
||||
PUBLIC_KEY *host = NULL;
|
||||
u32 server_bits;
|
||||
u32 host_bits;
|
||||
u32 protocol_flags;
|
||||
u32 supported_ciphers_mask;
|
||||
u32 supported_authentications_mask;
|
||||
u16 bits;
|
||||
int ssh_get_kex1(ssh_session session) {
|
||||
ssh_string server_exp = NULL;
|
||||
ssh_string server_mod = NULL;
|
||||
ssh_string host_exp = NULL;
|
||||
ssh_string host_mod = NULL;
|
||||
ssh_string serverkey = NULL;
|
||||
ssh_string hostkey = NULL;
|
||||
ssh_string enc_session = NULL;
|
||||
ssh_public_key srv = NULL;
|
||||
ssh_public_key host = NULL;
|
||||
uint32_t server_bits;
|
||||
uint32_t host_bits;
|
||||
uint32_t protocol_flags;
|
||||
uint32_t supported_ciphers_mask;
|
||||
uint32_t supported_authentications_mask;
|
||||
uint16_t bits;
|
||||
int rc = -1;
|
||||
int ko;
|
||||
|
||||
@@ -661,7 +663,7 @@ int ssh_get_kex1(SSH_SESSION *session) {
|
||||
buffer_get_u32(session->in_buffer, &supported_ciphers_mask);
|
||||
ko = buffer_get_u32(session->in_buffer, &supported_authentications_mask);
|
||||
|
||||
if ((ko != sizeof(u32)) || !host_mod || !host_exp
|
||||
if ((ko != sizeof(uint32_t)) || !host_mod || !host_exp
|
||||
|| !server_mod || !server_exp) {
|
||||
ssh_log(session, SSH_LOG_RARE, "Invalid SSH_SMSG_PUBLIC_KEY packet");
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid SSH_SMSG_PUBLIC_KEY packet");
|
||||
@@ -738,10 +740,10 @@ int ssh_get_kex1(SSH_SESSION *session) {
|
||||
bits, string_len(enc_session));
|
||||
bits = htons(bits);
|
||||
/* the encrypted mpint */
|
||||
if (buffer_add_data(session->out_buffer, &bits, sizeof(u16)) < 0) {
|
||||
if (buffer_add_data(session->out_buffer, &bits, sizeof(uint16_t)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (buffer_add_data(session->out_buffer, enc_session->string,
|
||||
if (buffer_add_data(session->out_buffer, string_data(enc_session),
|
||||
string_len(enc_session)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -22,19 +22,32 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/keyfiles.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/wrapper.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/keys.h"
|
||||
|
||||
/*todo: remove this include */
|
||||
#include "libssh/string.h"
|
||||
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#include <gcrypt.h>
|
||||
@@ -46,15 +59,15 @@
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
#define MAXLINESIZE 80
|
||||
#define RSA_HEADER_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
|
||||
#define RSA_HEADER_END "-----END RSA PRIVATE KEY-----"
|
||||
#define DSA_HEADER_BEGIN "-----BEGIN DSA PRIVATE KEY-----"
|
||||
#define DSA_HEADER_END "-----END DSA PRIVATE KEY-----"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
|
||||
#define MAX_KEY_SIZE 32
|
||||
#define MAX_PASSPHRASE_SIZE 1024
|
||||
#define RSA_HEADER_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
|
||||
#define RSA_HEADER_END "-----END RSA PRIVATE KEY-----"
|
||||
#define DSA_HEADER_BEGIN "-----BEGIN DSA PRIVATE KEY-----"
|
||||
#define DSA_HEADER_END "-----END DSA PRIVATE KEY-----"
|
||||
#define ASN1_INTEGER 2
|
||||
#define ASN1_SEQUENCE 48
|
||||
#define PKCS5_SALT_LEN 8
|
||||
@@ -87,17 +100,17 @@ static int load_iv(char *header, unsigned char *iv, int iv_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 char_to_u32(unsigned char *data, u32 size) {
|
||||
u32 ret;
|
||||
u32 i;
|
||||
static uint32_t char_to_u32(unsigned char *data, uint32_t size) {
|
||||
uint32_t ret;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0, ret = 0; i < size; ret = ret << 8, ret += data[i++])
|
||||
;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 asn1_get_len(BUFFER *buffer) {
|
||||
u32 len;
|
||||
static uint32_t asn1_get_len(ssh_buffer buffer) {
|
||||
uint32_t len;
|
||||
unsigned char tmp[4];
|
||||
|
||||
if (buffer_get_data(buffer,tmp,1) == 0) {
|
||||
@@ -120,10 +133,10 @@ static u32 asn1_get_len(BUFFER *buffer) {
|
||||
return len;
|
||||
}
|
||||
|
||||
static STRING *asn1_get_int(BUFFER *buffer) {
|
||||
STRING *str;
|
||||
static ssh_string asn1_get_int(ssh_buffer buffer) {
|
||||
ssh_string str;
|
||||
unsigned char type;
|
||||
u32 size;
|
||||
uint32_t size;
|
||||
|
||||
if (buffer_get_data(buffer, &type, 1) == 0 || type != ASN1_INTEGER) {
|
||||
return NULL;
|
||||
@@ -146,12 +159,12 @@ static STRING *asn1_get_int(BUFFER *buffer) {
|
||||
return str;
|
||||
}
|
||||
|
||||
static int asn1_check_sequence(BUFFER *buffer) {
|
||||
static int asn1_check_sequence(ssh_buffer buffer) {
|
||||
unsigned char *j = NULL;
|
||||
unsigned char tmp;
|
||||
int i;
|
||||
u32 size;
|
||||
u32 padding;
|
||||
uint32_t size;
|
||||
uint32_t padding;
|
||||
|
||||
if (buffer_get_data(buffer, &tmp, 1) == 0 || tmp != ASN1_SEQUENCE) {
|
||||
return 0;
|
||||
@@ -160,7 +173,7 @@ static int asn1_check_sequence(BUFFER *buffer) {
|
||||
size = asn1_get_len(buffer);
|
||||
if ((padding = buffer_get_len(buffer) - buffer->pos - size) > 0) {
|
||||
for (i = buffer_get_len(buffer) - buffer->pos - size,
|
||||
j = buffer_get(buffer) + size + buffer->pos;
|
||||
j = (unsigned char*)buffer_get(buffer) + size + buffer->pos;
|
||||
i;
|
||||
i--, j++)
|
||||
{
|
||||
@@ -228,7 +241,7 @@ static int passphrase_to_key(char *data, unsigned int datalen,
|
||||
|
||||
static int privatekey_decrypt(int algo, int mode, unsigned int key_len,
|
||||
unsigned char *iv, unsigned int iv_len,
|
||||
BUFFER *data, ssh_auth_callback cb,
|
||||
ssh_buffer data, ssh_auth_callback cb,
|
||||
void *userdata,
|
||||
const char *desc)
|
||||
{
|
||||
@@ -329,10 +342,10 @@ static int privatekey_dek_header(char *header, unsigned int header_len,
|
||||
return load_iv(header + iv_pos, *iv, *iv_len);
|
||||
}
|
||||
|
||||
static BUFFER *privatekey_file_to_buffer(FILE *fp, int type,
|
||||
static ssh_buffer privatekey_file_to_buffer(FILE *fp, int type,
|
||||
ssh_auth_callback cb, void *userdata, const char *desc) {
|
||||
BUFFER *buffer = NULL;
|
||||
BUFFER *out = NULL;
|
||||
ssh_buffer buffer = NULL;
|
||||
ssh_buffer out = NULL;
|
||||
char buf[MAXLINESIZE] = {0};
|
||||
unsigned char *iv = NULL;
|
||||
const char *header_begin;
|
||||
@@ -443,16 +456,16 @@ static BUFFER *privatekey_file_to_buffer(FILE *fp, int type,
|
||||
|
||||
static int read_rsa_privatekey(FILE *fp, gcry_sexp_t *r,
|
||||
ssh_auth_callback cb, void *userdata, const char *desc) {
|
||||
STRING *n = NULL;
|
||||
STRING *e = NULL;
|
||||
STRING *d = NULL;
|
||||
STRING *p = NULL;
|
||||
STRING *q = NULL;
|
||||
STRING *unused1 = NULL;
|
||||
STRING *unused2 = NULL;
|
||||
STRING *u = NULL;
|
||||
STRING *v = NULL;
|
||||
BUFFER *buffer = NULL;
|
||||
ssh_string n = NULL;
|
||||
ssh_string e = NULL;
|
||||
ssh_string d = NULL;
|
||||
ssh_string p = NULL;
|
||||
ssh_string q = NULL;
|
||||
ssh_string unused1 = NULL;
|
||||
ssh_string unused2 = NULL;
|
||||
ssh_string u = NULL;
|
||||
ssh_string v = NULL;
|
||||
ssh_buffer buffer = NULL;
|
||||
int rc = 1;
|
||||
|
||||
buffer = privatekey_file_to_buffer(fp, TYPE_RSA, cb, userdata, desc);
|
||||
@@ -515,13 +528,13 @@ error:
|
||||
|
||||
static int read_dsa_privatekey(FILE *fp, gcry_sexp_t *r, ssh_auth_callback cb,
|
||||
void *userdata, const char *desc) {
|
||||
BUFFER *buffer = NULL;
|
||||
STRING *p = NULL;
|
||||
STRING *q = NULL;
|
||||
STRING *g = NULL;
|
||||
STRING *y = NULL;
|
||||
STRING *x = NULL;
|
||||
STRING *v = NULL;
|
||||
ssh_buffer buffer = NULL;
|
||||
ssh_string p = NULL;
|
||||
ssh_string q = NULL;
|
||||
ssh_string g = NULL;
|
||||
ssh_string y = NULL;
|
||||
ssh_string x = NULL;
|
||||
ssh_string v = NULL;
|
||||
int rc = 1;
|
||||
|
||||
buffer = privatekey_file_to_buffer(fp, TYPE_DSS, cb, userdata, desc);
|
||||
@@ -576,16 +589,18 @@ error:
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
static int pem_get_password(char *buf, int size, int rwflag, void *userdata) {
|
||||
SSH_SESSION *session = userdata;
|
||||
ssh_session session = userdata;
|
||||
|
||||
/* unused flag */
|
||||
(void) rwflag;
|
||||
|
||||
ZERO_STRUCTP(buf);
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
"Trying to call external authentication function");
|
||||
|
||||
if (session && session->options->auth_function) {
|
||||
if ((*session->options->auth_function)("Passphrase for private key:", buf, size, 0, 0,
|
||||
session->options->auth_userdata ? session->options->auth_userdata : NULL) < 0) {
|
||||
if (session && session->callbacks->auth_function) {
|
||||
if (session->callbacks->auth_function("Passphrase for private key:", buf, size, 0, 0,
|
||||
session->callbacks->userdata) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -596,6 +611,22 @@ static int pem_get_password(char *buf, int size, int rwflag, void *userdata) {
|
||||
}
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
static int privatekey_type_from_file(FILE *fp) {
|
||||
char buffer[MAXLINESIZE] = {0};
|
||||
|
||||
if (!fgets(buffer, MAXLINESIZE, fp)) {
|
||||
return 0;
|
||||
}
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
if (strncmp(buffer, DSA_HEADER_BEGIN, strlen(DSA_HEADER_BEGIN)) == 0) {
|
||||
return TYPE_DSS;
|
||||
}
|
||||
if (strncmp(buffer, RSA_HEADER_BEGIN, strlen(RSA_HEADER_BEGIN)) == 0) {
|
||||
return TYPE_RSA;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \addtogroup ssh_auth
|
||||
* @{
|
||||
*/
|
||||
@@ -603,16 +634,16 @@ static int pem_get_password(char *buf, int size, int rwflag, void *userdata) {
|
||||
/** \brief Reads a SSH private key from a file
|
||||
* \param session SSH Session
|
||||
* \param filename Filename containing the private key
|
||||
* \param type Type of the private key. One of TYPE_DSS or TYPE_RSA.
|
||||
* \param type Type of the private key. One of TYPE_DSS or TYPE_RSA. Pass 0 to automatically detect the type.
|
||||
* \param passphrase Passphrase to decrypt the private key. Set to null if none is needed or it is unknown.
|
||||
* \returns a PRIVATE_KEY object containing the private key, or NULL if it failed.
|
||||
* \see privatekey_free()
|
||||
* \see publickey_from_privatekey()
|
||||
*/
|
||||
PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session, const char *filename,
|
||||
ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
|
||||
int type, const char *passphrase) {
|
||||
ssh_auth_callback auth_cb = NULL;
|
||||
PRIVATE_KEY *privkey = NULL;
|
||||
ssh_private_key privkey = NULL;
|
||||
void *auth_ud = NULL;
|
||||
FILE *file = NULL;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
@@ -623,6 +654,7 @@ PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session, const char *filename,
|
||||
DSA *dsa = NULL;
|
||||
RSA *rsa = NULL;
|
||||
#endif
|
||||
ssh_log(session, SSH_LOG_RARE, "Trying to open %s", filename);
|
||||
file = fopen(filename,"r");
|
||||
if (file == NULL) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
@@ -630,14 +662,25 @@ PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session, const char *filename,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssh_log(session, SSH_LOG_RARE, "Trying to read %s, passphase=%s, authcb=%s",
|
||||
filename, passphrase ? "true" : "false",
|
||||
session->callbacks && session->callbacks->auth_function ? "true" : "false");
|
||||
|
||||
if (type == 0) {
|
||||
type = privatekey_type_from_file(file);
|
||||
if (type == 0) {
|
||||
fclose(file);
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid private key file.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
switch (type) {
|
||||
case TYPE_DSS:
|
||||
if (passphrase == NULL) {
|
||||
if (session->options->auth_function) {
|
||||
auth_cb = session->options->auth_function;
|
||||
if (session->options->auth_userdata) {
|
||||
auth_ud = session->options->auth_userdata;
|
||||
}
|
||||
if (session->callbacks->auth_function) {
|
||||
auth_cb = session->callbacks->auth_function;
|
||||
auth_ud = session->callbacks->userdata;
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
valid = read_dsa_privatekey(file, &dsa, auth_cb, auth_ud,
|
||||
"Passphrase for private key:");
|
||||
@@ -674,11 +717,9 @@ PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session, const char *filename,
|
||||
break;
|
||||
case TYPE_RSA:
|
||||
if (passphrase == NULL) {
|
||||
if (session->options->auth_function) {
|
||||
auth_cb = session->options->auth_function;
|
||||
if (session->options->auth_userdata) {
|
||||
auth_ud = session->options->auth_userdata;
|
||||
}
|
||||
if (session->callbacks && session->callbacks->auth_function) {
|
||||
auth_cb = session->callbacks->auth_function;
|
||||
auth_ud = session->callbacks->userdata;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
valid = read_rsa_privatekey(file, &rsa, auth_cb, auth_ud,
|
||||
"Passphrase for private key:");
|
||||
@@ -715,11 +756,12 @@ PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session, const char *filename,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fclose(file);
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", type);
|
||||
return NULL;
|
||||
} /* switch */
|
||||
|
||||
privkey = malloc(sizeof(PRIVATE_KEY));
|
||||
privkey = malloc(sizeof(struct ssh_private_key_struct));
|
||||
if (privkey == NULL) {
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_release(dsa);
|
||||
@@ -739,9 +781,9 @@ PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session, const char *filename,
|
||||
}
|
||||
|
||||
/* same that privatekey_from_file() but without any passphrase things. */
|
||||
PRIVATE_KEY *_privatekey_from_file(void *session, const char *filename,
|
||||
ssh_private_key _privatekey_from_file(void *session, const char *filename,
|
||||
int type) {
|
||||
PRIVATE_KEY *privkey = NULL;
|
||||
ssh_private_key privkey = NULL;
|
||||
FILE *file = NULL;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_t dsa = NULL;
|
||||
@@ -807,7 +849,7 @@ PRIVATE_KEY *_privatekey_from_file(void *session, const char *filename,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
privkey = malloc(sizeof(PRIVATE_KEY));
|
||||
privkey = malloc(sizeof(struct ssh_private_key_struct));
|
||||
if (privkey == NULL) {
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_release(dsa);
|
||||
@@ -829,7 +871,7 @@ PRIVATE_KEY *_privatekey_from_file(void *session, const char *filename,
|
||||
/** \brief deallocate a private key
|
||||
* \param prv a PRIVATE_KEY object
|
||||
*/
|
||||
void privatekey_free(PRIVATE_KEY *prv) {
|
||||
void privatekey_free(ssh_private_key prv) {
|
||||
if (prv == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -841,23 +883,23 @@ void privatekey_free(PRIVATE_KEY *prv) {
|
||||
DSA_free(prv->dsa_priv);
|
||||
RSA_free(prv->rsa_priv);
|
||||
#endif
|
||||
memset(prv, 0, sizeof(PRIVATE_KEY));
|
||||
memset(prv, 0, sizeof(struct ssh_private_key_struct));
|
||||
SAFE_FREE(prv);
|
||||
}
|
||||
|
||||
/** \brief Retrieve a public key from a file
|
||||
* \param session the SSH session
|
||||
* \param filename Filename of the key
|
||||
* \param _type Pointer to a integer. If it is not null, it contains the type of the key after execution.
|
||||
* \param type Pointer to a integer. If it is not null, it contains the type of the key after execution.
|
||||
* \return a SSH String containing the public key, or NULL if it failed.
|
||||
* \see string_free()
|
||||
* \see publickey_from_privatekey()
|
||||
*/
|
||||
STRING *publickey_from_file(SSH_SESSION *session, const char *filename,
|
||||
ssh_string publickey_from_file(ssh_session session, const char *filename,
|
||||
int *type) {
|
||||
BUFFER *buffer = NULL;
|
||||
ssh_buffer buffer = NULL;
|
||||
char buf[4096] = {0};
|
||||
STRING *str = NULL;
|
||||
ssh_string str = NULL;
|
||||
char *ptr = NULL;
|
||||
int key_type;
|
||||
int fd = -1;
|
||||
@@ -922,24 +964,14 @@ STRING *publickey_from_file(SSH_SESSION *session, const char *filename,
|
||||
return str;
|
||||
}
|
||||
|
||||
STRING *try_publickey_from_file(SSH_SESSION *session, struct keys_struct keytab,
|
||||
ssh_string try_publickey_from_file(ssh_session session, struct ssh_keys_struct keytab,
|
||||
char **privkeyfile, int *type) {
|
||||
static char *home = NULL;
|
||||
|
||||
char public[256] = {0};
|
||||
char private[256] = {0};
|
||||
char *public;
|
||||
char *private;
|
||||
const char *priv;
|
||||
const char *pub;
|
||||
char *new;
|
||||
STRING *pubkey;
|
||||
|
||||
if (home == NULL) {
|
||||
home = ssh_get_user_home_dir();
|
||||
if (home == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL,"User home dir impossible to guess");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
ssh_string pubkey=NULL;
|
||||
|
||||
pub = keytab.publickey;
|
||||
if (pub == NULL) {
|
||||
@@ -950,22 +982,31 @@ STRING *try_publickey_from_file(SSH_SESSION *session, struct keys_struct keytab,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (session->sshdir == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* are them readable ? */
|
||||
snprintf(public, sizeof(public), pub, home);
|
||||
ssh_log(session, SSH_LOG_PACKET, "Trying to open public key %s", public);
|
||||
public=dir_expand_dup(session,pub,1);
|
||||
private=dir_expand_dup(session,priv,1);
|
||||
//snprintf(public, sizeof(public), "%s/%s", session->sshdir, pub);
|
||||
//snprintf(private, sizeof(private), "%s/%s", session->sshdir, priv);
|
||||
|
||||
ssh_log(session, SSH_LOG_PACKET, "Trying to open publickey %s", public);
|
||||
if (!ssh_file_readaccess_ok(public)) {
|
||||
ssh_log(session, SSH_LOG_PACKET, "Failed");
|
||||
return NULL;
|
||||
ssh_log(session, SSH_LOG_PACKET, "Failed to open publickey %s", public);
|
||||
goto error;
|
||||
}
|
||||
|
||||
snprintf(private, sizeof(private), priv, home);
|
||||
ssh_log(session, SSH_LOG_PACKET, "Trying to open private key %s", private);
|
||||
ssh_log(session, SSH_LOG_PACKET, "Trying to open privatekey %s", private);
|
||||
if (!ssh_file_readaccess_ok(private)) {
|
||||
ssh_log(session, SSH_LOG_PACKET, "Failed");
|
||||
return NULL;
|
||||
ssh_log(session, SSH_LOG_PACKET, "Failed to open privatekey %s", private);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_log(session, SSH_LOG_PACKET, "Success reading public and private key");
|
||||
ssh_log(session, SSH_LOG_PACKET, "Success opening public and private key");
|
||||
|
||||
/*
|
||||
* We are sure both the private and public key file is readable. We return
|
||||
@@ -977,18 +1018,20 @@ STRING *try_publickey_from_file(SSH_SESSION *session, struct keys_struct keytab,
|
||||
"Wasn't able to open public key file %s: %s",
|
||||
public,
|
||||
ssh_get_error(session));
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
new = realloc(*privkeyfile, strlen(private) + 1);
|
||||
if (new == NULL) {
|
||||
string_free(pubkey);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
strcpy(new, private);
|
||||
*privkeyfile = new;
|
||||
|
||||
error:
|
||||
SAFE_FREE(public);
|
||||
SAFE_FREE(private);
|
||||
return pubkey;
|
||||
}
|
||||
|
||||
@@ -1017,10 +1060,14 @@ static int alldigits(const char *s) {
|
||||
* \internal
|
||||
*/
|
||||
static char *lowercase(const char* str) {
|
||||
char *p = 0;
|
||||
char *new = strdup(str);
|
||||
char *new, *p;
|
||||
|
||||
if((str == NULL) || (new == NULL)) {
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new = strdup(str);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1055,7 +1102,7 @@ static void tokens_free(char **tokens) {
|
||||
* \returns NULL if no match was found or the file was not found
|
||||
* \returns found_type type of key (ie "dsa","ssh-rsa1"). Don't free that value.
|
||||
*/
|
||||
static char **ssh_get_knownhost_line(SSH_SESSION *session, FILE **file,
|
||||
static char **ssh_get_knownhost_line(ssh_session session, FILE **file,
|
||||
const char *filename, const char **found_type) {
|
||||
char buffer[4096] = {0};
|
||||
char *ptr;
|
||||
@@ -1074,6 +1121,7 @@ static char **ssh_get_knownhost_line(SSH_SESSION *session, FILE **file,
|
||||
while (fgets(buffer, sizeof(buffer), *file)) {
|
||||
ptr = strchr(buffer, '\n');
|
||||
if (ptr) {
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
ptr = strchr(buffer,'\r');
|
||||
@@ -1136,16 +1184,16 @@ static char **ssh_get_knownhost_line(SSH_SESSION *session, FILE **file,
|
||||
* \return 0 if the key doesn't match
|
||||
* \return -1 on error
|
||||
*/
|
||||
static int check_public_key(SSH_SESSION *session, char **tokens) {
|
||||
STRING *pubkey = session->current_crypto->server_pubkey;
|
||||
BUFFER *pubkey_buffer;
|
||||
static int check_public_key(ssh_session session, char **tokens) {
|
||||
ssh_string pubkey = session->current_crypto->server_pubkey;
|
||||
ssh_buffer pubkey_buffer;
|
||||
char *pubkey_64;
|
||||
|
||||
/* ok we found some public key in known hosts file. now un-base64it */
|
||||
if (alldigits(tokens[1])) {
|
||||
/* openssh rsa1 format */
|
||||
bignum tmpbn;
|
||||
STRING *tmpstring;
|
||||
ssh_string tmpstring;
|
||||
unsigned int len;
|
||||
int i;
|
||||
|
||||
@@ -1185,6 +1233,7 @@ static int check_public_key(SSH_SESSION *session, char **tokens) {
|
||||
bignum_free(tmpbn);
|
||||
return -1;
|
||||
}
|
||||
/* TODO: fix the hardcoding */
|
||||
tmpstring->size = htonl(len);
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
bignum_bn2bin(tmpbn, len, tmpstring->string);
|
||||
@@ -1235,7 +1284,7 @@ static int check_public_key(SSH_SESSION *session, char **tokens) {
|
||||
* \returns 1 if it matches
|
||||
* \returns 0 otherwise
|
||||
*/
|
||||
static int match_hashed_host(SSH_SESSION *session, const char *host,
|
||||
static int match_hashed_host(ssh_session session, const char *host,
|
||||
const char *sourcehash) {
|
||||
/* Openssh hash structure :
|
||||
* |1|base64 encoded salt|base64 encoded hash
|
||||
@@ -1243,8 +1292,8 @@ static int match_hashed_host(SSH_SESSION *session, const char *host,
|
||||
* hash := HMAC_SHA1(key=salt,data=host)
|
||||
*/
|
||||
unsigned char buffer[256] = {0};
|
||||
BUFFER *salt;
|
||||
BUFFER *hash;
|
||||
ssh_buffer salt;
|
||||
ssh_buffer hash;
|
||||
HMACCTX mac;
|
||||
char *source;
|
||||
char *b64hash;
|
||||
@@ -1347,13 +1396,13 @@ static int match_hashed_host(SSH_SESSION *session, const char *host,
|
||||
* if host key is accepted\n
|
||||
* SSH_SERVER_ERROR: Some error happened
|
||||
*
|
||||
* \see ssh_options_set_wanted_algo()
|
||||
* \see ssh_options_set()
|
||||
* \see ssh_get_pubkey_hash()
|
||||
*
|
||||
* \bug There is no current way to remove or modify an entry into the known
|
||||
* host table.
|
||||
*/
|
||||
int ssh_is_server_known(SSH_SESSION *session) {
|
||||
int ssh_is_server_known(ssh_session session) {
|
||||
FILE *file = NULL;
|
||||
char **tokens;
|
||||
char *host;
|
||||
@@ -1363,21 +1412,23 @@ int ssh_is_server_known(SSH_SESSION *session) {
|
||||
|
||||
enter_function();
|
||||
|
||||
if (ssh_options_default_known_hosts_file(session->options) < 0) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Can't find a known_hosts file");
|
||||
leave_function();
|
||||
return SSH_SERVER_FILE_NOT_FOUND;
|
||||
if (session->knownhosts == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, NULL) < 0) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Can't find a known_hosts file");
|
||||
leave_function();
|
||||
return SSH_SERVER_FILE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
if (session->options->host == NULL) {
|
||||
if (session->host == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Can't verify host in known hosts if the hostname isn't known");
|
||||
leave_function();
|
||||
return SSH_SERVER_ERROR;
|
||||
}
|
||||
|
||||
host = lowercase(session->options->host);
|
||||
host = lowercase(session->host);
|
||||
if (host == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Not enough space!");
|
||||
leave_function();
|
||||
@@ -1386,7 +1437,7 @@ int ssh_is_server_known(SSH_SESSION *session) {
|
||||
|
||||
do {
|
||||
tokens = ssh_get_knownhost_line(session, &file,
|
||||
session->options->known_hosts_file, &type);
|
||||
session->knownhosts, &type);
|
||||
|
||||
/* End of file, return the current state */
|
||||
if (tokens == NULL) {
|
||||
@@ -1441,36 +1492,55 @@ int ssh_is_server_known(SSH_SESSION *session) {
|
||||
* \param session ssh session
|
||||
* \return 0 on success, -1 on error
|
||||
*/
|
||||
int ssh_write_knownhost(SSH_SESSION *session) {
|
||||
STRING *pubkey = session->current_crypto->server_pubkey;
|
||||
int ssh_write_knownhost(ssh_session session) {
|
||||
ssh_string pubkey = session->current_crypto->server_pubkey;
|
||||
unsigned char *pubkey_64;
|
||||
char buffer[4096] = {0};
|
||||
FILE *file;
|
||||
char *dir;
|
||||
size_t len = 0;
|
||||
|
||||
if (ssh_options_default_known_hosts_file(session->options) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot find known_hosts file.");
|
||||
return -1;
|
||||
if (session->knownhosts == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, NULL) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Can't find a known_hosts file");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (session->options->host == NULL) {
|
||||
if (session->host == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Cannot write host in known hosts if the hostname is unknown");
|
||||
return -1;
|
||||
}
|
||||
|
||||
file = fopen(session->options->known_hosts_file, "a");
|
||||
/* Check if ~/.ssh exists and create it if not */
|
||||
dir = ssh_dirname(session->knownhosts);
|
||||
if (dir == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (! ssh_file_readaccess_ok(dir)) {
|
||||
if (ssh_mkdir(dir, 0700) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Cannot create %s directory.", dir);
|
||||
SAFE_FREE(dir);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
SAFE_FREE(dir);
|
||||
|
||||
file = fopen(session->knownhosts, "a");
|
||||
if (file == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Couldn't open known_hosts file %s for appending: %s",
|
||||
session->options->known_hosts_file, strerror(errno));
|
||||
session->knownhosts, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(session->current_crypto->server_pubkey_type, "ssh-rsa1") == 0) {
|
||||
/* openssh uses a different format for ssh-rsa1 keys.
|
||||
Be compatible --kv */
|
||||
PUBLIC_KEY *key;
|
||||
ssh_public_key key;
|
||||
char *e_string = NULL;
|
||||
char *n_string = NULL;
|
||||
bignum e = NULL;
|
||||
@@ -1543,7 +1613,7 @@ int ssh_write_knownhost(SSH_SESSION *session) {
|
||||
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"%s %d %s %s\n",
|
||||
session->options->host,
|
||||
session->host,
|
||||
rsa_size << 3,
|
||||
e_string,
|
||||
n_string);
|
||||
@@ -1568,7 +1638,7 @@ int ssh_write_knownhost(SSH_SESSION *session) {
|
||||
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"%s %s %s\n",
|
||||
session->options->host,
|
||||
session->host,
|
||||
session->current_crypto->server_pubkey_type,
|
||||
pubkey_64);
|
||||
|
||||
@@ -1576,7 +1646,7 @@ int ssh_write_knownhost(SSH_SESSION *session) {
|
||||
}
|
||||
|
||||
len = strlen(buffer);
|
||||
if (fwrite(buffer, len, 1, file) != len || ferror(file)) {
|
||||
if (fwrite(buffer, len, 1, file) != 1 || ferror(file)) {
|
||||
fclose(file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
259
libssh/keys.c
259
libssh/keys.c
@@ -28,6 +28,14 @@
|
||||
#include <openssl/rsa.h>
|
||||
#endif
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/server.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/agent.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/keys.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/messages.h"
|
||||
|
||||
/** \addtogroup ssh_auth
|
||||
* @{
|
||||
@@ -65,14 +73,14 @@ int ssh_type_from_name(const char *name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC_KEY *publickey_make_dss(SSH_SESSION *session, BUFFER *buffer) {
|
||||
STRING *p = NULL;
|
||||
STRING *q = NULL;
|
||||
STRING *g = NULL;
|
||||
STRING *pubkey = NULL;
|
||||
PUBLIC_KEY *key = NULL;
|
||||
ssh_public_key publickey_make_dss(ssh_session session, ssh_buffer buffer) {
|
||||
ssh_string p = NULL;
|
||||
ssh_string q = NULL;
|
||||
ssh_string g = NULL;
|
||||
ssh_string pubkey = NULL;
|
||||
ssh_public_key key = NULL;
|
||||
|
||||
key = malloc(sizeof(PUBLIC_KEY));
|
||||
key = malloc(sizeof(struct ssh_public_key_struct));
|
||||
if (key == NULL) {
|
||||
buffer_free(buffer);
|
||||
return NULL;
|
||||
@@ -96,10 +104,10 @@ PUBLIC_KEY *publickey_make_dss(SSH_SESSION *session, BUFFER *buffer) {
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_build(&key->dsa_pub, NULL,
|
||||
"(public-key(dsa(p %b)(q %b)(g %b)(y %b)))",
|
||||
string_len(p), p->string,
|
||||
string_len(q), q->string,
|
||||
string_len(g), g->string,
|
||||
string_len(pubkey), pubkey->string);
|
||||
string_len(p), string_data(p),
|
||||
string_len(q), string_data(q),
|
||||
string_len(g), string_data(g),
|
||||
string_len(pubkey), string_data(pubkey));
|
||||
if (key->dsa_pub == NULL) {
|
||||
goto error;
|
||||
}
|
||||
@@ -151,13 +159,13 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PUBLIC_KEY *publickey_make_rsa(SSH_SESSION *session, BUFFER *buffer,
|
||||
ssh_public_key publickey_make_rsa(ssh_session session, ssh_buffer buffer,
|
||||
int type) {
|
||||
STRING *e = NULL;
|
||||
STRING *n = NULL;
|
||||
PUBLIC_KEY *key = NULL;
|
||||
ssh_string e = NULL;
|
||||
ssh_string n = NULL;
|
||||
ssh_public_key key = NULL;
|
||||
|
||||
key = malloc(sizeof(PUBLIC_KEY));
|
||||
key = malloc(sizeof(struct ssh_public_key_struct));
|
||||
if (key == NULL) {
|
||||
buffer_free(buffer);
|
||||
return NULL;
|
||||
@@ -178,8 +186,8 @@ PUBLIC_KEY *publickey_make_rsa(SSH_SESSION *session, BUFFER *buffer,
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_build(&key->rsa_pub, NULL,
|
||||
"(public-key(rsa(n %b)(e %b)))",
|
||||
string_len(n), n->string,
|
||||
string_len(e),e->string);
|
||||
string_len(n), string_data(n),
|
||||
string_len(e),string_data(e));
|
||||
if (key->rsa_pub == NULL) {
|
||||
goto error;
|
||||
}
|
||||
@@ -218,7 +226,7 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void publickey_free(PUBLIC_KEY *key) {
|
||||
void publickey_free(ssh_public_key key) {
|
||||
if (key == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -245,9 +253,9 @@ void publickey_free(PUBLIC_KEY *key) {
|
||||
SAFE_FREE(key);
|
||||
}
|
||||
|
||||
PUBLIC_KEY *publickey_from_string(SSH_SESSION *session, STRING *pubkey_s) {
|
||||
BUFFER *tmpbuf = NULL;
|
||||
STRING *type_s = NULL;
|
||||
ssh_public_key publickey_from_string(ssh_session session, ssh_string pubkey_s) {
|
||||
ssh_buffer tmpbuf = NULL;
|
||||
ssh_string type_s = NULL;
|
||||
char *type_c = NULL;
|
||||
int type;
|
||||
|
||||
@@ -256,7 +264,7 @@ PUBLIC_KEY *publickey_from_string(SSH_SESSION *session, STRING *pubkey_s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (buffer_add_data(tmpbuf, pubkey_s->string, string_len(pubkey_s)) < 0) {
|
||||
if (buffer_add_data(tmpbuf, string_data(pubkey_s), string_len(pubkey_s)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -296,21 +304,21 @@ error:
|
||||
* \returns the public key
|
||||
* \see publickey_to_string()
|
||||
*/
|
||||
PUBLIC_KEY *publickey_from_privatekey(PRIVATE_KEY *prv) {
|
||||
PUBLIC_KEY *key = NULL;
|
||||
ssh_public_key publickey_from_privatekey(ssh_private_key prv) {
|
||||
ssh_public_key key = NULL;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_t sexp;
|
||||
const char *tmp = NULL;
|
||||
size_t size;
|
||||
STRING *p = NULL;
|
||||
STRING *q = NULL;
|
||||
STRING *g = NULL;
|
||||
STRING *y = NULL;
|
||||
STRING *e = NULL;
|
||||
STRING *n = NULL;
|
||||
ssh_string p = NULL;
|
||||
ssh_string q = NULL;
|
||||
ssh_string g = NULL;
|
||||
ssh_string y = NULL;
|
||||
ssh_string e = NULL;
|
||||
ssh_string n = NULL;
|
||||
#endif /* HAVE_LIBGCRYPT */
|
||||
|
||||
key = malloc(sizeof(PUBLIC_KEY));
|
||||
key = malloc(sizeof(struct ssh_public_key_struct));
|
||||
if (key == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -369,10 +377,10 @@ PUBLIC_KEY *publickey_from_privatekey(PRIVATE_KEY *prv) {
|
||||
|
||||
gcry_sexp_build(&key->dsa_pub, NULL,
|
||||
"(public-key(dsa(p %b)(q %b)(g %b)(y %b)))",
|
||||
string_len(p), p->string,
|
||||
string_len(q), q->string,
|
||||
string_len(g), g->string,
|
||||
string_len(y), y->string);
|
||||
string_len(p), string_data(p),
|
||||
string_len(q), string_data(q),
|
||||
string_len(g), string_data(g),
|
||||
string_len(y), string_data(y));
|
||||
|
||||
string_burn(p);
|
||||
string_free(p);
|
||||
@@ -428,8 +436,8 @@ PUBLIC_KEY *publickey_from_privatekey(PRIVATE_KEY *prv) {
|
||||
|
||||
gcry_sexp_build(&key->rsa_pub, NULL,
|
||||
"(public-key(rsa(n %b)(e %b)))",
|
||||
string_len(n), n->string,
|
||||
string_len(e), e->string);
|
||||
string_len(n), string_data(n),
|
||||
string_len(e), string_data(e));
|
||||
if (key->rsa_pub == NULL) {
|
||||
goto error;
|
||||
}
|
||||
@@ -478,14 +486,14 @@ error:
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
static int dsa_public_to_string(gcry_sexp_t key, BUFFER *buffer) {
|
||||
static int dsa_public_to_string(gcry_sexp_t key, ssh_buffer buffer) {
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
static int dsa_public_to_string(DSA *key, BUFFER *buffer) {
|
||||
static int dsa_public_to_string(DSA *key, ssh_buffer buffer) {
|
||||
#endif
|
||||
STRING *p = NULL;
|
||||
STRING *q = NULL;
|
||||
STRING *g = NULL;
|
||||
STRING *n = NULL;
|
||||
ssh_string p = NULL;
|
||||
ssh_string q = NULL;
|
||||
ssh_string g = NULL;
|
||||
ssh_string n = NULL;
|
||||
|
||||
int rc = -1;
|
||||
|
||||
@@ -540,7 +548,6 @@ static int dsa_public_to_string(DSA *key, BUFFER *buffer) {
|
||||
goto error;
|
||||
}
|
||||
string_fill(n, (char *) tmp, size);
|
||||
gcry_sexp_release(sexp);
|
||||
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
p = make_bignum_string(key->p);
|
||||
@@ -583,13 +590,13 @@ error:
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
static int rsa_public_to_string(gcry_sexp_t key, BUFFER *buffer) {
|
||||
static int rsa_public_to_string(gcry_sexp_t key, ssh_buffer buffer) {
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
static int rsa_public_to_string(RSA *key, BUFFER *buffer) {
|
||||
static int rsa_public_to_string(RSA *key, ssh_buffer buffer) {
|
||||
#endif
|
||||
|
||||
STRING *e = NULL;
|
||||
STRING *n = NULL;
|
||||
ssh_string e = NULL;
|
||||
ssh_string n = NULL;
|
||||
|
||||
int rc = -1;
|
||||
|
||||
@@ -655,10 +662,10 @@ error:
|
||||
* \returns a SSH String containing the public key
|
||||
* \see string_free()
|
||||
*/
|
||||
STRING *publickey_to_string(PUBLIC_KEY *key) {
|
||||
STRING *type = NULL;
|
||||
STRING *ret = NULL;
|
||||
BUFFER *buf = NULL;
|
||||
ssh_string publickey_to_string(ssh_public_key key) {
|
||||
ssh_string type = NULL;
|
||||
ssh_string ret = NULL;
|
||||
ssh_buffer buf = NULL;
|
||||
|
||||
buf = buffer_new();
|
||||
if (buf == NULL) {
|
||||
@@ -702,12 +709,12 @@ error:
|
||||
}
|
||||
|
||||
/* Signature decoding functions */
|
||||
static STRING *signature_to_string(SIGNATURE *sign) {
|
||||
static ssh_string signature_to_string(SIGNATURE *sign) {
|
||||
unsigned char buffer[40] = {0};
|
||||
BUFFER *tmpbuf = NULL;
|
||||
STRING *str = NULL;
|
||||
STRING *tmp = NULL;
|
||||
STRING *rs = NULL;
|
||||
ssh_buffer tmpbuf = NULL;
|
||||
ssh_string str = NULL;
|
||||
ssh_string tmp = NULL;
|
||||
ssh_string rs = NULL;
|
||||
int rc = -1;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
const char *r = NULL;
|
||||
@@ -715,8 +722,8 @@ static STRING *signature_to_string(SIGNATURE *sign) {
|
||||
gcry_sexp_t sexp;
|
||||
size_t size = 0;
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
STRING *r = NULL;
|
||||
STRING *s = NULL;
|
||||
ssh_string r = NULL;
|
||||
ssh_string s = NULL;
|
||||
#endif
|
||||
|
||||
tmpbuf = buffer_new();
|
||||
@@ -777,8 +784,8 @@ static STRING *signature_to_string(SIGNATURE *sign) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(buffer, r->string + string_len(r) - 20, 20);
|
||||
memcpy(buffer + 20, s->string + string_len(s) - 20, 20);
|
||||
memcpy(buffer, (char *)string_data(r) + string_len(r) - 20, 20);
|
||||
memcpy(buffer + 20, (char *)string_data(s) + string_len(s) - 20, 20);
|
||||
|
||||
string_free(r);
|
||||
string_free(s);
|
||||
@@ -846,13 +853,13 @@ static STRING *signature_to_string(SIGNATURE *sign) {
|
||||
}
|
||||
|
||||
/* TODO : split this function in two so it becomes smaller */
|
||||
SIGNATURE *signature_from_string(SSH_SESSION *session, STRING *signature,
|
||||
PUBLIC_KEY *pubkey, int needed_type) {
|
||||
SIGNATURE *signature_from_string(ssh_session session, ssh_string signature,
|
||||
ssh_public_key pubkey, int needed_type) {
|
||||
SIGNATURE *sign = NULL;
|
||||
BUFFER *tmpbuf = NULL;
|
||||
STRING *rs = NULL;
|
||||
STRING *type_s = NULL;
|
||||
STRING *e = NULL;
|
||||
ssh_buffer tmpbuf = NULL;
|
||||
ssh_string rs = NULL;
|
||||
ssh_string type_s = NULL;
|
||||
ssh_string e = NULL;
|
||||
char *type_c = NULL;
|
||||
int type;
|
||||
int len;
|
||||
@@ -861,8 +868,8 @@ SIGNATURE *signature_from_string(SSH_SESSION *session, STRING *signature,
|
||||
gcry_sexp_t sig;
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
DSA_SIG *sig = NULL;
|
||||
STRING *r = NULL;
|
||||
STRING *s = NULL;
|
||||
ssh_string r = NULL;
|
||||
ssh_string s = NULL;
|
||||
#endif
|
||||
|
||||
sign = malloc(sizeof(SIGNATURE));
|
||||
@@ -878,7 +885,7 @@ SIGNATURE *signature_from_string(SSH_SESSION *session, STRING *signature,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (buffer_add_data(tmpbuf, signature->string, string_len(signature)) < 0) {
|
||||
if (buffer_add_data(tmpbuf, string_data(signature), string_len(signature)) < 0) {
|
||||
signature_free(sign);
|
||||
buffer_free(tmpbuf);
|
||||
return NULL;
|
||||
@@ -926,7 +933,7 @@ SIGNATURE *signature_from_string(SSH_SESSION *session, STRING *signature,
|
||||
* them to bignums (ou pas ;) */
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
if (gcry_sexp_build(&sig, NULL, "(sig-val(dsa(r %b)(s %b)))",
|
||||
20 ,rs->string, 20, rs->string + 20)) {
|
||||
20 ,string_data(rs), 20,(unsigned char *)string_data(rs) + 20)) {
|
||||
string_free(rs);
|
||||
signature_free(sign);
|
||||
return NULL;
|
||||
@@ -942,8 +949,8 @@ SIGNATURE *signature_from_string(SSH_SESSION *session, STRING *signature,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
string_fill(r, rs->string, 20);
|
||||
string_fill(s, rs->string + 20, 20);
|
||||
string_fill(r, string_data(rs), 20);
|
||||
string_fill(s, (char *)string_data(rs) + 20, 20);
|
||||
|
||||
sig = DSA_SIG_new();
|
||||
if (sig == NULL) {
|
||||
@@ -1004,7 +1011,7 @@ SIGNATURE *signature_from_string(SSH_SESSION *session, STRING *signature,
|
||||
sign->type = TYPE_RSA;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
if (gcry_sexp_build(&sig, NULL, "(sig-val(rsa(s %b)))",
|
||||
string_len(e), e->string)) {
|
||||
string_len(e), string_data(e))) {
|
||||
signature_free(sign);
|
||||
string_free(e);
|
||||
return NULL;
|
||||
@@ -1070,8 +1077,8 @@ void signature_free(SIGNATURE *sign) {
|
||||
* I think now, maybe it's a bad idea to name it has it should have be
|
||||
* named in libcrypto
|
||||
*/
|
||||
static STRING *RSA_do_sign(const unsigned char *payload, int len, RSA *privkey) {
|
||||
STRING *sign = NULL;
|
||||
static ssh_string RSA_do_sign(const unsigned char *payload, int len, RSA *privkey) {
|
||||
ssh_string sign = NULL;
|
||||
unsigned char *buffer = NULL;
|
||||
unsigned int size;
|
||||
|
||||
@@ -1099,11 +1106,11 @@ static STRING *RSA_do_sign(const unsigned char *payload, int len, RSA *privkey)
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
STRING *ssh_do_sign_with_agent(struct ssh_session *session,
|
||||
struct buffer_struct *buf, struct public_key_struct *publickey) {
|
||||
struct buffer_struct *sigbuf = NULL;
|
||||
struct string_struct *signature = NULL;
|
||||
struct string_struct *session_id = NULL;
|
||||
ssh_string ssh_do_sign_with_agent(ssh_session session,
|
||||
struct ssh_buffer_struct *buf, struct ssh_public_key_struct *publickey) {
|
||||
struct ssh_buffer_struct *sigbuf = NULL;
|
||||
struct ssh_string_struct *signature = NULL;
|
||||
struct ssh_string_struct *session_id = NULL;
|
||||
struct ssh_crypto_struct *crypto = NULL;
|
||||
|
||||
if (session->current_crypto) {
|
||||
@@ -1147,16 +1154,80 @@ STRING *ssh_do_sign_with_agent(struct ssh_session *session,
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/*
|
||||
* This function concats in a buffer the values needed to do a signature
|
||||
* verification. */
|
||||
ssh_buffer ssh_userauth_build_digest(ssh_session session, ssh_message msg, char *service) {
|
||||
/*
|
||||
The value of 'signature' is a signature by the corresponding private
|
||||
key over the following data, in the following order:
|
||||
|
||||
string session identifier
|
||||
byte SSH_MSG_USERAUTH_REQUEST
|
||||
string user name
|
||||
string service name
|
||||
string "publickey"
|
||||
boolean TRUE
|
||||
string public key algorithm name
|
||||
string public key to be used for authentication
|
||||
*/
|
||||
struct ssh_crypto_struct *crypto = session->current_crypto ? session->current_crypto :
|
||||
session->next_crypto;
|
||||
ssh_buffer buffer = NULL;
|
||||
ssh_string session_id = NULL;
|
||||
uint8_t type = SSH2_MSG_USERAUTH_REQUEST;
|
||||
ssh_string username = string_from_char(msg->auth_request.username);
|
||||
ssh_string servicename = string_from_char(service);
|
||||
ssh_string method = string_from_char("publickey");
|
||||
uint8_t has_sign = 1;
|
||||
ssh_string algo = string_from_char(msg->auth_request.public_key->type_c);
|
||||
ssh_string publickey = publickey_to_string(msg->auth_request.public_key);
|
||||
|
||||
buffer = buffer_new();
|
||||
if (buffer == NULL) {
|
||||
goto error;
|
||||
}
|
||||
session_id = string_new(SHA_DIGEST_LEN);
|
||||
if (session_id == NULL) {
|
||||
buffer_free(buffer);
|
||||
buffer = NULL;
|
||||
goto error;
|
||||
}
|
||||
string_fill(session_id, crypto->session_id, SHA_DIGEST_LEN);
|
||||
|
||||
if(buffer_add_ssh_string(buffer, session_id) < 0 ||
|
||||
buffer_add_u8(buffer, type) < 0 ||
|
||||
buffer_add_ssh_string(buffer, username) < 0 ||
|
||||
buffer_add_ssh_string(buffer, servicename) < 0 ||
|
||||
buffer_add_ssh_string(buffer, method) < 0 ||
|
||||
buffer_add_u8(buffer, has_sign) < 0 ||
|
||||
buffer_add_ssh_string(buffer, algo) < 0 ||
|
||||
buffer_add_ssh_string(buffer, publickey) < 0) {
|
||||
buffer_free(buffer);
|
||||
buffer = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
if(session_id) string_free(session_id);
|
||||
if(username) string_free(username);
|
||||
if(servicename) string_free(servicename);
|
||||
if(method) string_free(method);
|
||||
if(algo) string_free(algo);
|
||||
if(publickey) string_free(publickey);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function signs the session id (known as H) as a string then
|
||||
* the content of sigbuf */
|
||||
STRING *ssh_do_sign(SSH_SESSION *session, BUFFER *sigbuf,
|
||||
PRIVATE_KEY *privatekey) {
|
||||
CRYPTO *crypto = session->current_crypto ? session->current_crypto :
|
||||
ssh_string ssh_do_sign(ssh_session session, ssh_buffer sigbuf,
|
||||
ssh_private_key privatekey) {
|
||||
struct ssh_crypto_struct *crypto = session->current_crypto ? session->current_crypto :
|
||||
session->next_crypto;
|
||||
unsigned char hash[SHA_DIGEST_LEN + 1] = {0};
|
||||
STRING *session_str = NULL;
|
||||
STRING *signature = NULL;
|
||||
ssh_string session_str = NULL;
|
||||
ssh_string signature = NULL;
|
||||
SIGNATURE *sign = NULL;
|
||||
SHACTX ctx = NULL;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
@@ -1249,8 +1320,8 @@ STRING *ssh_do_sign(SSH_SESSION *session, BUFFER *sigbuf,
|
||||
return signature;
|
||||
}
|
||||
|
||||
STRING *ssh_encrypt_rsa1(SSH_SESSION *session, STRING *data, PUBLIC_KEY *key) {
|
||||
STRING *str = NULL;
|
||||
ssh_string ssh_encrypt_rsa1(ssh_session session, ssh_string data, ssh_public_key key) {
|
||||
ssh_string str = NULL;
|
||||
size_t len = string_len(data);
|
||||
size_t size = 0;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
@@ -1259,7 +1330,7 @@ STRING *ssh_encrypt_rsa1(SSH_SESSION *session, STRING *data, PUBLIC_KEY *key) {
|
||||
gcry_sexp_t data_sexp;
|
||||
|
||||
if (gcry_sexp_build(&data_sexp, NULL, "(data(flags pkcs1)(value %b))",
|
||||
len, data->string)) {
|
||||
len, string_data(data))) {
|
||||
ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error");
|
||||
return NULL;
|
||||
}
|
||||
@@ -1303,7 +1374,7 @@ STRING *ssh_encrypt_rsa1(SSH_SESSION *session, STRING *data, PUBLIC_KEY *key) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (RSA_public_encrypt(len, data->string, str->string, key->rsa_pub,
|
||||
if (RSA_public_encrypt(len, string_data(data), string_data(str), key->rsa_pub,
|
||||
RSA_PKCS1_PADDING) < 0) {
|
||||
string_free(str);
|
||||
return NULL;
|
||||
@@ -1315,11 +1386,11 @@ STRING *ssh_encrypt_rsa1(SSH_SESSION *session, STRING *data, PUBLIC_KEY *key) {
|
||||
|
||||
|
||||
/* this function signs the session id */
|
||||
STRING *ssh_sign_session_id(SSH_SESSION *session, PRIVATE_KEY *privatekey) {
|
||||
CRYPTO *crypto=session->current_crypto ? session->current_crypto :
|
||||
ssh_string ssh_sign_session_id(ssh_session session, ssh_private_key privatekey) {
|
||||
struct ssh_crypto_struct *crypto=session->current_crypto ? session->current_crypto :
|
||||
session->next_crypto;
|
||||
unsigned char hash[SHA_DIGEST_LEN + 1] = {0};
|
||||
STRING *signature = NULL;
|
||||
ssh_string signature = NULL;
|
||||
SIGNATURE *sign = NULL;
|
||||
SHACTX ctx = NULL;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
SSH_0.3 {
|
||||
global:
|
||||
ssh_get_error; ssh_get_error_code;
|
||||
ssh_new; ssh_set_options; ssh_get_fd; ssh_silent_disconnect;
|
||||
ssh_connect; ssh_disconnect; ssh_service_request; ssh_get_issue_banner;
|
||||
ssh_copyright; ssh_get_version; ssh_finalize;
|
||||
ssh_set_fd_toread; ssh_set_fd_towrite; ssh_set_fd_except;
|
||||
string_from_char; string_len; string_new; string_fill; string_to_char;
|
||||
string_copy; string_burn; string_data;
|
||||
ssh_crypto_init;
|
||||
ssh_get_hexa; ssh_print_hexa; ssh_get_random;
|
||||
ssh_get_pubkey_hash; ssh_get_pubkey;
|
||||
ssh_fd_poll; ssh_select; publickey_free;
|
||||
privatekey_from_file; publickey_to_string; publickey_from_privatekey;
|
||||
private_key_free; publickey_from_file; try_publickey_from_file;
|
||||
ssh_is_server_known; ssh_write_knownhost;
|
||||
channel_new; channel_open_forward; channel_open_session; channel_free;
|
||||
channel_request_pty; channel_request_pty_size; channel_change_pty_size;
|
||||
channel_request_shell; channel_request_subsystem; channel_request_env;
|
||||
channel_request_exec; channel_request_sftp; channel_write;
|
||||
channel_send_eof; channel_read_buffer; channel_read; channel_read_nonblocking;
|
||||
channel_poll; channel_close; channel_is_open;
|
||||
channel_is_closed; channel_is_eof; channel_select;
|
||||
ssh_options_new; ssh_options_copy; ssh_options_free; ssh_options_set_wanted_algos;
|
||||
ssh_options_set_username; ssh_options_set_port; ssh_options_getopt;
|
||||
ssh_options_set_host; ssh_options_set_fd; ssh_options_set_bind;
|
||||
ssh_options_set_identity; ssh_options_set_status_callback;
|
||||
ssh_options_set_timeout; ssh_options_set_ssh_dir;
|
||||
ssh_options_set_known_hosts_file; ssh_options_allow_ssh1;
|
||||
ssh_options_allow_ssh2; ssh_options_set_dsa_server_key;
|
||||
ssh_options_set_rsa_server_key;
|
||||
buffer_new; buffer_free; buffer_get; buffer_get_len;
|
||||
ssh_userauth_none; ssh_userauth_password; ssh_userauth_offer_pubkey;
|
||||
ssh_userauth_pubkey; ssh_userauth_autopubkey; ssh_userauth_kbdint;
|
||||
ssh_userauth_kbdint_getnprompts; ssh_userauth_kbdint_getname;
|
||||
ssh_userauth_kbdint_getinstruction; ssh_userauth_kbdint_getprompt;
|
||||
ssh_userauth_kbdint_setanswer;
|
||||
sftp_new; sftp_free; sftp_init; sftp_opendir; sftp_readdir; sftp_dir_eof;
|
||||
sftp_stat; sftp_lstat; sftp_fstat; sftp_attributes_free; sftp_dir_close;
|
||||
sftp_file_close; sftp_open; sftp_read; sftp_write; sftp_seek; sftp_tell;
|
||||
sftp_rewind; sftp_rm; sftp_rmdir; sftp_mkdir; sftp_rename; sftp_setstat;
|
||||
sftp_canonicalize_path; sftp_server_new; sftp_server_init;
|
||||
sftp_get_client_message; sftp_client_message_free; sftp_reply_name;
|
||||
sftp_reply_handle; sftp_handle_alloc; sftp_reply_attr; sftp_handle;
|
||||
sftp_reply_status; sftp_reply_names_add; sftp_reply_names;
|
||||
sftp_reply_data; sftp_handle_remove;
|
||||
ssh_bind_new; ssh_bind_set_options; ssh_bind_listen; ssh_bind_set_blocking;
|
||||
ssh_bind_get_fd; ssh_bind_set_toaccept; ssh_bind_accept; ssh_bind_free;
|
||||
ssh_accept;
|
||||
ssh_message_get; ssh_message_type; ssh_message_subtype;
|
||||
ssh_message_reply_default; ssh_message_free; ssh_message_auth_user;
|
||||
ssh_message_auth_password; ssh_message_auth_reply_success;
|
||||
ssh_message_auth_set_methods;
|
||||
ssh_message_channel_request_open_reply_accept;
|
||||
ssh_message_channel_request_channel; ssh_message_channel_request_pty_term;
|
||||
ssh_message_channel_request_subsystem;
|
||||
ssh_message_channel_request_reply_success;
|
||||
set_encrypt_key; set_decrypt_key; cbc_encrypt; cbc_decrypt;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
/**
|
||||
* @defgroup ssh_log SSH Logging
|
||||
@@ -44,7 +45,7 @@
|
||||
*
|
||||
* @param format The format string of the log entry.
|
||||
*/
|
||||
void ssh_log(SSH_SESSION *session, int verbosity, const char *format, ...) {
|
||||
void ssh_log(ssh_session session, int verbosity, const char *format, ...) {
|
||||
char buffer[1024];
|
||||
char indent[256];
|
||||
int min;
|
||||
@@ -55,8 +56,9 @@ void ssh_log(SSH_SESSION *session, int verbosity, const char *format, ...) {
|
||||
vsnprintf(buffer, sizeof(buffer), format, va);
|
||||
va_end(va);
|
||||
|
||||
if (session->options->log_function) {
|
||||
session->options->log_function(buffer, session, verbosity);
|
||||
if (session->callbacks && session->callbacks->log_function) {
|
||||
session->callbacks->log_function(session, verbosity, buffer,
|
||||
session->callbacks->userdata);
|
||||
} else if (verbosity == SSH_LOG_FUNCTIONS) {
|
||||
if (session->log_indent > 255) {
|
||||
min = 255;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2005 by Aris Adamantiadis
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
@@ -41,68 +41,59 @@
|
||||
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/server.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/channels.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/keys.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/messages.h"
|
||||
|
||||
|
||||
static SSH_MESSAGE *message_new(SSH_SESSION *session){
|
||||
SSH_MESSAGE *msg = session->ssh_message;
|
||||
|
||||
static ssh_message message_new(ssh_session session){
|
||||
ssh_message msg = malloc(sizeof(struct ssh_message_struct));
|
||||
if (msg == NULL) {
|
||||
msg = malloc(sizeof(SSH_MESSAGE));
|
||||
if (msg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
session->ssh_message = msg;
|
||||
return NULL;
|
||||
}
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
ZERO_STRUCTP(msg);
|
||||
msg->session = session;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
static int handle_service_request(SSH_SESSION *session) {
|
||||
STRING *service = NULL;
|
||||
static ssh_message handle_service_request(ssh_session session) {
|
||||
ssh_string service = NULL;
|
||||
char *service_c = NULL;
|
||||
int rc = -1;
|
||||
ssh_message msg=NULL;
|
||||
|
||||
enter_function();
|
||||
|
||||
service = buffer_get_ssh_string(session->in_buffer);
|
||||
if (service == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid SSH_MSG_SERVICE_REQUEST packet");
|
||||
leave_function();
|
||||
return -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
service_c = string_to_char(service);
|
||||
if (service_c == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"Sending a SERVICE_ACCEPT for service %s", service_c);
|
||||
SAFE_FREE(service_c);
|
||||
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_SERVICE_ACCEPT) < 0) {
|
||||
"Received a SERVICE_REQUEST for service %s", service_c);
|
||||
msg=message_new(session);
|
||||
if(!msg){
|
||||
SAFE_FREE(service_c);
|
||||
goto error;
|
||||
}
|
||||
if (buffer_add_ssh_string(session->out_buffer, service) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (packet_send(session) != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
error:
|
||||
msg->type=SSH_REQUEST_SERVICE;
|
||||
msg->service_request.service=service_c;
|
||||
error:
|
||||
string_free(service);
|
||||
leave_function();
|
||||
|
||||
return rc;
|
||||
return msg;
|
||||
}
|
||||
|
||||
static int handle_unimplemented(SSH_SESSION *session) {
|
||||
static int handle_unimplemented(ssh_session session) {
|
||||
if (buffer_add_u32(session->out_buffer, htonl(session->recv_seq - 1)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -114,13 +105,14 @@ static int handle_unimplemented(SSH_SESSION *session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SSH_MESSAGE *handle_userauth_request(SSH_SESSION *session){
|
||||
STRING *user = NULL;
|
||||
STRING *service = NULL;
|
||||
STRING *method = NULL;
|
||||
SSH_MESSAGE *msg = NULL;
|
||||
static ssh_message handle_userauth_request(ssh_session session){
|
||||
ssh_string user = NULL;
|
||||
ssh_string service = NULL;
|
||||
ssh_string method = NULL;
|
||||
ssh_message msg = NULL;
|
||||
char *service_c = NULL;
|
||||
char *method_c = NULL;
|
||||
uint32_t method_size = 0;
|
||||
|
||||
enter_function();
|
||||
|
||||
@@ -142,12 +134,13 @@ static SSH_MESSAGE *handle_userauth_request(SSH_SESSION *session){
|
||||
goto error;
|
||||
}
|
||||
|
||||
msg->type = SSH_AUTH_REQUEST;
|
||||
msg->type = SSH_REQUEST_AUTH;
|
||||
msg->auth_request.username = string_to_char(user);
|
||||
if (msg->auth_request.username == NULL) {
|
||||
goto error;
|
||||
}
|
||||
string_free(user);
|
||||
user = NULL;
|
||||
|
||||
service_c = string_to_char(service);
|
||||
if (service_c == NULL) {
|
||||
@@ -157,29 +150,33 @@ static SSH_MESSAGE *handle_userauth_request(SSH_SESSION *session){
|
||||
if (method_c == NULL) {
|
||||
goto error;
|
||||
}
|
||||
method_size = string_len(method);
|
||||
|
||||
string_free(service);
|
||||
service = NULL;
|
||||
string_free(method);
|
||||
method = NULL;
|
||||
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"Auth request for service %s, method %s for user '%s'",
|
||||
service_c, method_c,
|
||||
msg->auth_request.username);
|
||||
|
||||
SAFE_FREE(service_c);
|
||||
|
||||
if (strcmp(method_c, "none") == 0) {
|
||||
msg->auth_request.method = SSH_AUTH_NONE;
|
||||
if (strncmp(method_c, "none", method_size) == 0) {
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_NONE;
|
||||
SAFE_FREE(service_c);
|
||||
SAFE_FREE(method_c);
|
||||
leave_function();
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (strcmp(method_c, "password") == 0) {
|
||||
STRING *pass = NULL;
|
||||
u8 tmp;
|
||||
if (strncmp(method_c, "password", method_size) == 0) {
|
||||
ssh_string pass = NULL;
|
||||
uint8_t tmp;
|
||||
|
||||
msg->auth_request.method = SSH_AUTH_PASSWORD;
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_PASSWORD;
|
||||
SAFE_FREE(service_c);
|
||||
SAFE_FREE(method_c);
|
||||
buffer_get_u8(session->in_buffer, &tmp);
|
||||
pass = buffer_get_ssh_string(session->in_buffer);
|
||||
@@ -187,7 +184,9 @@ static SSH_MESSAGE *handle_userauth_request(SSH_SESSION *session){
|
||||
goto error;
|
||||
}
|
||||
msg->auth_request.password = string_to_char(pass);
|
||||
string_burn(pass);
|
||||
string_free(pass);
|
||||
pass = NULL;
|
||||
if (msg->auth_request.password == NULL) {
|
||||
goto error;
|
||||
}
|
||||
@@ -195,7 +194,83 @@ static SSH_MESSAGE *handle_userauth_request(SSH_SESSION *session){
|
||||
return msg;
|
||||
}
|
||||
|
||||
msg->auth_request.method = SSH_AUTH_UNKNOWN;
|
||||
if (strncmp(method_c, "publickey", method_size) == 0) {
|
||||
ssh_string algo = NULL;
|
||||
ssh_string publickey = NULL;
|
||||
uint8_t has_sign;
|
||||
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_PUBLICKEY;
|
||||
SAFE_FREE(method_c);
|
||||
buffer_get_u8(session->in_buffer, &has_sign);
|
||||
algo = buffer_get_ssh_string(session->in_buffer);
|
||||
if (algo == NULL) {
|
||||
goto error;
|
||||
}
|
||||
publickey = buffer_get_ssh_string(session->in_buffer);
|
||||
if (publickey == NULL) {
|
||||
string_free(algo);
|
||||
algo = NULL;
|
||||
goto error;
|
||||
}
|
||||
msg->auth_request.public_key = publickey_from_string(session, publickey);
|
||||
string_free(algo);
|
||||
algo = NULL;
|
||||
string_free(publickey);
|
||||
publickey = NULL;
|
||||
if (msg->auth_request.public_key == NULL) {
|
||||
goto error;
|
||||
}
|
||||
msg->auth_request.signature_state = 0;
|
||||
// has a valid signature ?
|
||||
if(has_sign) {
|
||||
SIGNATURE *signature = NULL;
|
||||
ssh_public_key public_key = msg->auth_request.public_key;
|
||||
ssh_string sign = NULL;
|
||||
ssh_buffer digest = NULL;
|
||||
|
||||
sign = buffer_get_ssh_string(session->in_buffer);
|
||||
if(sign == NULL) {
|
||||
ssh_log(session, SSH_LOG_PACKET, "Invalid signature packet from peer");
|
||||
msg->auth_request.signature_state = -2;
|
||||
goto error;
|
||||
}
|
||||
signature = signature_from_string(session, sign, public_key,
|
||||
public_key->type);
|
||||
digest = ssh_userauth_build_digest(session, msg, service_c);
|
||||
if ((digest == NULL || signature == NULL) ||
|
||||
(digest != NULL && signature != NULL &&
|
||||
sig_verify(session, public_key, signature,
|
||||
buffer_get(digest), buffer_get_len(digest)) < 0)) {
|
||||
ssh_log(session, SSH_LOG_PACKET, "Invalid signature from peer");
|
||||
|
||||
string_free(sign);
|
||||
sign = NULL;
|
||||
buffer_free(digest);
|
||||
digest = NULL;
|
||||
signature_free(signature);
|
||||
signature = NULL;
|
||||
|
||||
msg->auth_request.signature_state = -1;
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
ssh_log(session, SSH_LOG_PACKET, "Valid signature received");
|
||||
|
||||
buffer_free(digest);
|
||||
digest = NULL;
|
||||
string_free(sign);
|
||||
sign = NULL;
|
||||
signature_free(signature);
|
||||
signature = NULL;
|
||||
|
||||
msg->auth_request.signature_state = 1;
|
||||
}
|
||||
SAFE_FREE(service_c);
|
||||
leave_function();
|
||||
return msg;
|
||||
}
|
||||
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_UNKNOWN;
|
||||
SAFE_FREE(method_c);
|
||||
|
||||
leave_function();
|
||||
@@ -214,137 +289,36 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *ssh_message_auth_user(SSH_MESSAGE *msg) {
|
||||
if (msg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return msg->auth_request.username;
|
||||
}
|
||||
|
||||
char *ssh_message_auth_password(SSH_MESSAGE *msg){
|
||||
if (msg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return msg->auth_request.password;
|
||||
}
|
||||
|
||||
int ssh_message_auth_set_methods(SSH_MESSAGE *msg, int methods) {
|
||||
if (msg == NULL || msg->session == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg->session->auth_methods = methods;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ssh_message_auth_reply_default(SSH_MESSAGE *msg,int partial) {
|
||||
SSH_SESSION *session = msg->session;
|
||||
char methods_c[128] = {0};
|
||||
STRING *methods = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
enter_function();
|
||||
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_FAILURE) < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (session->auth_methods == 0) {
|
||||
session->auth_methods = SSH_AUTH_PUBLICKEY | SSH_AUTH_PASSWORD;
|
||||
}
|
||||
if (session->auth_methods & SSH_AUTH_PUBLICKEY) {
|
||||
strcat(methods_c, "publickey,");
|
||||
}
|
||||
if (session->auth_methods & SSH_AUTH_KEYBINT) {
|
||||
strcat(methods_c, "keyboard-interactive,");
|
||||
}
|
||||
if (session->auth_methods & SSH_AUTH_PASSWORD) {
|
||||
strcat(methods_c, "password,");
|
||||
}
|
||||
if (session->auth_methods & SSH_AUTH_HOSTBASED) {
|
||||
strcat(methods_c, "hostbased,");
|
||||
}
|
||||
|
||||
/* Strip the comma. */
|
||||
methods_c[strlen(methods_c) - 1] = '\0'; // strip the comma. We are sure there is at
|
||||
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"Sending a auth failure. methods that can continue: %s", methods_c);
|
||||
|
||||
methods = string_from_char(methods_c);
|
||||
if (methods == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (buffer_add_ssh_string(msg->session->out_buffer, methods) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (partial) {
|
||||
if (buffer_add_u8(session->out_buffer, 1) < 0) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (buffer_add_u8(session->out_buffer, 0) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
rc = packet_send(msg->session);
|
||||
error:
|
||||
string_free(methods);
|
||||
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ssh_message_auth_reply_success(SSH_MESSAGE *msg, int partial) {
|
||||
if (msg == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (partial) {
|
||||
return ssh_message_auth_reply_default(msg, partial);
|
||||
}
|
||||
|
||||
if (buffer_add_u8(msg->session->out_buffer,SSH2_MSG_USERAUTH_SUCCESS) < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return packet_send(msg->session);
|
||||
}
|
||||
|
||||
static SSH_MESSAGE *handle_channel_request_open(SSH_SESSION *session) {
|
||||
SSH_MESSAGE *msg = NULL;
|
||||
STRING *type = NULL;
|
||||
static ssh_message handle_channel_request_open(ssh_session session) {
|
||||
ssh_message msg = NULL;
|
||||
ssh_string type = NULL, originator = NULL, destination = NULL;
|
||||
char *type_c = NULL;
|
||||
u32 sender, window, packet;
|
||||
uint32_t sender, window, packet, originator_port, destination_port;
|
||||
|
||||
enter_function();
|
||||
|
||||
msg = message_new(session);
|
||||
if (msg == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
leave_function();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
msg->type = SSH_CHANNEL_REQUEST_OPEN;
|
||||
msg->type = SSH_REQUEST_CHANNEL_OPEN;
|
||||
|
||||
type = buffer_get_ssh_string(session->in_buffer);
|
||||
if (type == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
type_c = string_to_char(type);
|
||||
if (type_c == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"Clients wants to open a %s channel", type_c);
|
||||
string_free(type);
|
||||
|
||||
buffer_get_u32(session->in_buffer, &sender);
|
||||
buffer_get_u32(session->in_buffer, &window);
|
||||
@@ -356,12 +330,118 @@ static SSH_MESSAGE *handle_channel_request_open(SSH_SESSION *session) {
|
||||
|
||||
if (strcmp(type_c,"session") == 0) {
|
||||
msg->channel_request_open.type = SSH_CHANNEL_SESSION;
|
||||
string_free(type);
|
||||
SAFE_FREE(type_c);
|
||||
leave_function();
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (strcmp(type_c,"direct-tcpip") == 0) {
|
||||
destination = buffer_get_ssh_string(session->in_buffer);
|
||||
if (destination == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
msg->channel_request_open.destination = string_to_char(type);
|
||||
if (msg->channel_request_open.destination == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
string_free(destination);
|
||||
goto error;
|
||||
}
|
||||
string_free(destination);
|
||||
|
||||
buffer_get_u32(session->in_buffer, &destination_port);
|
||||
msg->channel_request_open.destination_port = ntohl(destination_port);
|
||||
|
||||
originator = buffer_get_ssh_string(session->in_buffer);
|
||||
if (originator == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
msg->channel_request_open.originator = string_to_char(type);
|
||||
if (msg->channel_request_open.originator == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
string_free(originator);
|
||||
goto error;
|
||||
}
|
||||
string_free(originator);
|
||||
|
||||
buffer_get_u32(session->in_buffer, &originator_port);
|
||||
msg->channel_request_open.originator_port = ntohl(originator_port);
|
||||
|
||||
msg->channel_request_open.type = SSH_CHANNEL_DIRECT_TCPIP;
|
||||
string_free(type);
|
||||
SAFE_FREE(type_c);
|
||||
leave_function();
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (strcmp(type_c,"forwarded-tcpip") == 0) {
|
||||
destination = buffer_get_ssh_string(session->in_buffer);
|
||||
if (destination == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
msg->channel_request_open.destination = string_to_char(type);
|
||||
if (msg->channel_request_open.destination == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
string_free(destination);
|
||||
goto error;
|
||||
}
|
||||
string_free(destination);
|
||||
|
||||
buffer_get_u32(session->in_buffer, &destination_port);
|
||||
msg->channel_request_open.destination_port = ntohl(destination_port);
|
||||
|
||||
originator = buffer_get_ssh_string(session->in_buffer);
|
||||
if (originator == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
msg->channel_request_open.originator = string_to_char(type);
|
||||
if (msg->channel_request_open.originator == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
string_free(originator);
|
||||
goto error;
|
||||
}
|
||||
string_free(originator);
|
||||
|
||||
buffer_get_u32(session->in_buffer, &originator_port);
|
||||
msg->channel_request_open.originator_port = ntohl(originator_port);
|
||||
|
||||
msg->channel_request_open.type = SSH_CHANNEL_FORWARDED_TCPIP;
|
||||
string_free(type);
|
||||
SAFE_FREE(type_c);
|
||||
leave_function();
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (strcmp(type_c,"x11") == 0) {
|
||||
originator = buffer_get_ssh_string(session->in_buffer);
|
||||
if (originator == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
msg->channel_request_open.originator = string_to_char(type);
|
||||
if (msg->channel_request_open.originator == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
string_free(originator);
|
||||
goto error;
|
||||
}
|
||||
string_free(originator);
|
||||
|
||||
buffer_get_u32(session->in_buffer, &originator_port);
|
||||
msg->channel_request_open.originator_port = ntohl(originator_port);
|
||||
|
||||
msg->channel_request_open.type = SSH_CHANNEL_X11;
|
||||
string_free(type);
|
||||
SAFE_FREE(type_c);
|
||||
leave_function();
|
||||
return msg;
|
||||
}
|
||||
|
||||
msg->channel_request_open.type = SSH_CHANNEL_UNKNOWN;
|
||||
string_free(type);
|
||||
SAFE_FREE(type_c);
|
||||
|
||||
leave_function();
|
||||
@@ -375,9 +455,9 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CHANNEL *ssh_message_channel_request_open_reply_accept(SSH_MESSAGE *msg) {
|
||||
SSH_SESSION *session = msg->session;
|
||||
CHANNEL *chan = NULL;
|
||||
ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg) {
|
||||
ssh_session session = msg->session;
|
||||
ssh_channel chan = NULL;
|
||||
|
||||
enter_function();
|
||||
|
||||
@@ -432,46 +512,18 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ssh_message_channel_request_open_reply_default(SSH_MESSAGE *msg) {
|
||||
ssh_log(msg->session, SSH_LOG_FUNCTIONS, "Refusing a channel");
|
||||
|
||||
if (buffer_add_u8(msg->session->out_buffer
|
||||
, SSH2_MSG_CHANNEL_OPEN_FAILURE) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (buffer_add_u32(msg->session->out_buffer,
|
||||
htonl(msg->channel_request_open.sender)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (buffer_add_u32(msg->session->out_buffer,
|
||||
htonl(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
/* reason is an empty string */
|
||||
if (buffer_add_u32(msg->session->out_buffer, 0) < 0) {
|
||||
goto error;
|
||||
}
|
||||
/* language too */
|
||||
if (buffer_add_u32(msg->session->out_buffer, 0) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return packet_send(msg->session);
|
||||
error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
static SSH_MESSAGE *handle_channel_request(SSH_SESSION *session) {
|
||||
SSH_MESSAGE *msg = NULL;
|
||||
STRING *type = NULL;
|
||||
static ssh_message handle_channel_request(ssh_session session) {
|
||||
ssh_message msg = NULL;
|
||||
ssh_string type = NULL;
|
||||
char *type_c = NULL;
|
||||
u32 channel;
|
||||
u8 want_reply;
|
||||
uint32_t channel;
|
||||
uint8_t want_reply;
|
||||
|
||||
enter_function();
|
||||
|
||||
msg = message_new(session);
|
||||
if (msg == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -480,10 +532,12 @@ static SSH_MESSAGE *handle_channel_request(SSH_SESSION *session) {
|
||||
|
||||
type = buffer_get_ssh_string(session->in_buffer);
|
||||
if (type == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
type_c = string_to_char(type);
|
||||
if (type_c == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
string_free(type);
|
||||
@@ -494,21 +548,28 @@ static SSH_MESSAGE *handle_channel_request(SSH_SESSION *session) {
|
||||
"Received a %s channel_request for channel %d (want_reply=%hhd)",
|
||||
type_c, channel, want_reply);
|
||||
|
||||
msg->type = SSH_CHANNEL_REQUEST;
|
||||
msg->type = SSH_REQUEST_CHANNEL;
|
||||
msg->channel_request.channel = ssh_channel_from_local(session, channel);
|
||||
if (msg->channel_request.channel == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "There are no channels with the id %u.",
|
||||
channel);
|
||||
goto error;
|
||||
}
|
||||
msg->channel_request.want_reply = want_reply;
|
||||
|
||||
if (strcmp(type_c, "pty-req") == 0) {
|
||||
STRING *term = NULL;
|
||||
ssh_string term = NULL;
|
||||
char *term_c = NULL;
|
||||
SAFE_FREE(type_c);
|
||||
|
||||
term = buffer_get_ssh_string(session->in_buffer);
|
||||
if (term == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
term_c = string_to_char(term);
|
||||
if (term_c == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
string_free(term);
|
||||
goto error;
|
||||
}
|
||||
@@ -536,18 +597,39 @@ static SSH_MESSAGE *handle_channel_request(SSH_SESSION *session) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (strcmp(type_c, "window-change") == 0) {
|
||||
SAFE_FREE(type_c);
|
||||
|
||||
msg->channel_request.type = SSH_CHANNEL_REQUEST_WINDOW_CHANGE;
|
||||
|
||||
buffer_get_u32(session->in_buffer, &msg->channel_request.width);
|
||||
buffer_get_u32(session->in_buffer, &msg->channel_request.height);
|
||||
buffer_get_u32(session->in_buffer, &msg->channel_request.pxwidth);
|
||||
buffer_get_u32(session->in_buffer, &msg->channel_request.pxheight);
|
||||
|
||||
msg->channel_request.width = ntohl(msg->channel_request.width);
|
||||
msg->channel_request.height = ntohl(msg->channel_request.height);
|
||||
msg->channel_request.pxwidth = ntohl(msg->channel_request.pxwidth);
|
||||
msg->channel_request.pxheight = ntohl(msg->channel_request.pxheight);
|
||||
|
||||
leave_function();
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (strcmp(type_c, "subsystem") == 0) {
|
||||
STRING *subsys = NULL;
|
||||
ssh_string subsys = NULL;
|
||||
char *subsys_c = NULL;
|
||||
|
||||
SAFE_FREE(type_c);
|
||||
|
||||
subsys = buffer_get_ssh_string(session->in_buffer);
|
||||
if (subsys == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
subsys_c = string_to_char(subsys);
|
||||
if (subsys_c == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
string_free(subsys);
|
||||
goto error;
|
||||
}
|
||||
@@ -567,13 +649,15 @@ static SSH_MESSAGE *handle_channel_request(SSH_SESSION *session) {
|
||||
leave_function();
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (strcmp(type_c, "exec") == 0) {
|
||||
STRING *cmd = NULL;
|
||||
ssh_string cmd = NULL;
|
||||
|
||||
SAFE_FREE(type_c);
|
||||
|
||||
cmd = buffer_get_ssh_string(session->in_buffer);
|
||||
if (cmd == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -589,6 +673,40 @@ static SSH_MESSAGE *handle_channel_request(SSH_SESSION *session) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (strcmp(type_c, "env") == 0) {
|
||||
ssh_string name = NULL;
|
||||
ssh_string value = NULL;
|
||||
|
||||
SAFE_FREE(type_c);
|
||||
|
||||
name = buffer_get_ssh_string(session->in_buffer);
|
||||
if (name == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
value = buffer_get_ssh_string(session->in_buffer);
|
||||
if (value == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
string_free(name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
msg->channel_request.type = SSH_CHANNEL_REQUEST_ENV;
|
||||
msg->channel_request.var_name = string_to_char(name);
|
||||
msg->channel_request.var_value = string_to_char(value);
|
||||
if (msg->channel_request.var_name == NULL ||
|
||||
msg->channel_request.var_value == NULL) {
|
||||
string_free(name);
|
||||
string_free(value);
|
||||
goto error;
|
||||
}
|
||||
string_free(name);
|
||||
string_free(value);
|
||||
|
||||
leave_function();
|
||||
return msg;
|
||||
}
|
||||
|
||||
msg->channel_request.type = SSH_CHANNEL_UNKNOWN;
|
||||
SAFE_FREE(type_c);
|
||||
|
||||
@@ -603,12 +721,8 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *ssh_message_channel_request_subsystem(SSH_MESSAGE *msg){
|
||||
return msg->channel_request.subsystem;
|
||||
}
|
||||
|
||||
int ssh_message_channel_request_reply_success(SSH_MESSAGE *msg) {
|
||||
u32 channel;
|
||||
int ssh_message_channel_request_reply_success(ssh_message msg) {
|
||||
uint32_t channel;
|
||||
|
||||
if (msg == NULL) {
|
||||
return SSH_ERROR;
|
||||
@@ -636,80 +750,51 @@ int ssh_message_channel_request_reply_success(SSH_MESSAGE *msg) {
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static int ssh_message_channel_request_reply_default(SSH_MESSAGE *msg) {
|
||||
u32 channel;
|
||||
|
||||
if (msg->channel_request.want_reply) {
|
||||
channel = msg->channel_request.channel->remote_channel;
|
||||
|
||||
ssh_log(msg->session, SSH_LOG_PACKET,
|
||||
"Sending a default channel_request denied to channel %d", channel);
|
||||
|
||||
if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_CHANNEL_FAILURE) < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (buffer_add_u32(msg->session->out_buffer, htonl(channel)) < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return packet_send(msg->session);
|
||||
ssh_message ssh_message_retrieve(ssh_session session, uint32_t packettype){
|
||||
ssh_message msg=NULL;
|
||||
enter_function();
|
||||
switch(packettype) {
|
||||
case SSH2_MSG_SERVICE_REQUEST:
|
||||
msg=handle_service_request(session);
|
||||
break;
|
||||
case SSH2_MSG_USERAUTH_REQUEST:
|
||||
msg = handle_userauth_request(session);
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_OPEN:
|
||||
msg = handle_channel_request_open(session);
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_REQUEST:
|
||||
msg = handle_channel_request(session);
|
||||
break;
|
||||
default:
|
||||
if (handle_unimplemented(session) == 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Unhandled message %d\n", session->in_packet.type);
|
||||
}
|
||||
}
|
||||
|
||||
ssh_log(msg->session, SSH_LOG_PACKET,
|
||||
"The client doesn't want to know the request failed!");
|
||||
|
||||
return SSH_OK;
|
||||
leave_function();
|
||||
return msg;
|
||||
}
|
||||
|
||||
SSH_MESSAGE *ssh_message_get(SSH_SESSION *session) {
|
||||
SSH_MESSAGE *msg = NULL;
|
||||
|
||||
/* \brief blocking message retrieval
|
||||
* \bug does anything that is not a message, like a channel read/write
|
||||
*/
|
||||
ssh_message ssh_message_get(ssh_session session) {
|
||||
ssh_message msg = NULL;
|
||||
enter_function();
|
||||
|
||||
do {
|
||||
if ((packet_read(session) != SSH_OK) ||
|
||||
(packet_translate(session) != SSH_OK)) {
|
||||
goto error;
|
||||
leave_function();
|
||||
return NULL;
|
||||
}
|
||||
switch(session->in_packet.type) {
|
||||
case SSH2_MSG_SERVICE_REQUEST:
|
||||
if (handle_service_request(session) < 0) {
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case SSH2_MSG_IGNORE:
|
||||
case SSH2_MSG_DEBUG:
|
||||
break;
|
||||
case SSH2_MSG_USERAUTH_REQUEST:
|
||||
msg = handle_userauth_request(session);
|
||||
|
||||
leave_function();
|
||||
return msg;
|
||||
case SSH2_MSG_CHANNEL_OPEN:
|
||||
msg = handle_channel_request_open(session);
|
||||
|
||||
leave_function();
|
||||
return msg;
|
||||
case SSH2_MSG_CHANNEL_REQUEST:
|
||||
msg = handle_channel_request(session);
|
||||
leave_function();
|
||||
|
||||
return msg;
|
||||
default:
|
||||
if (handle_unimplemented(session) == 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Unhandled message %d\n", session->in_packet.type);
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
} while(1);
|
||||
|
||||
error:
|
||||
} while(session->in_packet.type==SSH2_MSG_IGNORE || session->in_packet.type==SSH2_MSG_DEBUG);
|
||||
msg=ssh_message_retrieve(session,session->in_packet.type);
|
||||
leave_function();
|
||||
return NULL;
|
||||
return msg;
|
||||
}
|
||||
|
||||
int ssh_message_type(SSH_MESSAGE *msg) {
|
||||
int ssh_message_type(ssh_message msg) {
|
||||
if (msg == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -717,64 +802,43 @@ int ssh_message_type(SSH_MESSAGE *msg) {
|
||||
return msg->type;
|
||||
}
|
||||
|
||||
int ssh_message_subtype(SSH_MESSAGE *msg) {
|
||||
int ssh_message_subtype(ssh_message msg) {
|
||||
if (msg == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(msg->type) {
|
||||
case SSH_AUTH_REQUEST:
|
||||
case SSH_REQUEST_AUTH:
|
||||
return msg->auth_request.method;
|
||||
case SSH_CHANNEL_REQUEST_OPEN:
|
||||
case SSH_REQUEST_CHANNEL_OPEN:
|
||||
return msg->channel_request_open.type;
|
||||
case SSH_CHANNEL_REQUEST:
|
||||
case SSH_REQUEST_CHANNEL:
|
||||
return msg->channel_request.type;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ssh_message_reply_default(SSH_MESSAGE *msg) {
|
||||
if (msg == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(msg->type) {
|
||||
case SSH_AUTH_REQUEST:
|
||||
return ssh_message_auth_reply_default(msg, 0);
|
||||
case SSH_CHANNEL_REQUEST_OPEN:
|
||||
return ssh_message_channel_request_open_reply_default(msg);
|
||||
case SSH_CHANNEL_REQUEST:
|
||||
return ssh_message_channel_request_reply_default(msg);
|
||||
default:
|
||||
ssh_log(msg->session, SSH_LOG_PACKET,
|
||||
"Don't know what to default reply to %d type",
|
||||
msg->type);
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ssh_message_free(SSH_MESSAGE *msg){
|
||||
void ssh_message_free(ssh_message msg){
|
||||
if (msg == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(msg->type) {
|
||||
case SSH_AUTH_REQUEST:
|
||||
case SSH_REQUEST_AUTH:
|
||||
SAFE_FREE(msg->auth_request.username);
|
||||
if (msg->auth_request.password) {
|
||||
memset(msg->auth_request.password, 0,
|
||||
strlen(msg->auth_request.password));
|
||||
SAFE_FREE(msg->auth_request.password);
|
||||
}
|
||||
publickey_free(msg->auth_request.public_key);
|
||||
break;
|
||||
case SSH_CHANNEL_REQUEST_OPEN:
|
||||
case SSH_REQUEST_CHANNEL_OPEN:
|
||||
SAFE_FREE(msg->channel_request_open.originator);
|
||||
SAFE_FREE(msg->channel_request_open.destination);
|
||||
break;
|
||||
case SSH_CHANNEL_REQUEST:
|
||||
case SSH_REQUEST_CHANNEL:
|
||||
SAFE_FREE(msg->channel_request.TERM);
|
||||
SAFE_FREE(msg->channel_request.modes);
|
||||
SAFE_FREE(msg->channel_request.var_name);
|
||||
@@ -782,12 +846,31 @@ void ssh_message_free(SSH_MESSAGE *msg){
|
||||
SAFE_FREE(msg->channel_request.command);
|
||||
SAFE_FREE(msg->channel_request.subsystem);
|
||||
break;
|
||||
case SSH_REQUEST_SERVICE:
|
||||
SAFE_FREE(msg->service_request.service);
|
||||
break;
|
||||
}
|
||||
|
||||
ZERO_STRUCTP(msg);
|
||||
SAFE_FREE(msg);
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* \brief handle various SSH request messages and stack them for callback
|
||||
* \param session SSH session
|
||||
* \param type packet type
|
||||
* \returns nothing
|
||||
*/
|
||||
void message_handle(ssh_session session, uint32_t type){
|
||||
ssh_message msg=ssh_message_retrieve(session,type);
|
||||
ssh_log(session,SSH_LOG_PROTOCOL,"Stacking message from packet type %d",type);
|
||||
if(msg){
|
||||
if(!session->ssh_message_list){
|
||||
session->ssh_message_list=ssh_list_new();
|
||||
}
|
||||
ssh_list_add(session->ssh_message_list,msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
305
libssh/misc.c
305
libssh/misc.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003 by Aris Adamantiadis
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
* Copyright (c) 2008-2009 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
@@ -22,25 +22,30 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _WIN32_IE 0x0400 //SHGetSpecialFolderPath
|
||||
#define _WIN32_IE 0x0501 //SHGetSpecialFolderPath
|
||||
#include <winsock2.h> // Must be the first to include
|
||||
#include <shlobj.h>
|
||||
#include <winsock2.h>
|
||||
#include <direct.h>
|
||||
#else
|
||||
/* This is needed for a standard getpwuid_r on opensolaris */
|
||||
#define _POSIX_PTHREAD_SEMANTICS
|
||||
#include <pwd.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/misc.h"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#define GCRYPT_STRING "/gnutls"
|
||||
@@ -67,34 +72,69 @@
|
||||
* @{ */
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
char *ssh_get_user_home_dir(void) {
|
||||
static char szPath[MAX_PATH] = {0};
|
||||
char tmp[MAX_PATH] = {0};
|
||||
char *szPath = NULL;
|
||||
|
||||
if (SHGetSpecialFolderPathA(NULL, szPath, CSIDL_PROFILE, TRUE)) {
|
||||
if (SHGetSpecialFolderPathA(NULL, tmp, CSIDL_PROFILE, TRUE)) {
|
||||
szPath = malloc(strlen(tmp) + 1);
|
||||
if (szPath == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(szPath, tmp);
|
||||
return szPath;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* we have read access on file */
|
||||
int ssh_file_readaccess_ok(const char *file) {
|
||||
if (_access(file, 4) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define SSH_USEC_IN_SEC 1000000LL
|
||||
#define SSH_SECONDS_SINCE_1601 11644473600LL
|
||||
|
||||
int gettimeofday(struct timeval *__p, void *__t) {
|
||||
union {
|
||||
unsigned long long ns100; /* time since 1 Jan 1601 in 100ns units */
|
||||
FILETIME ft;
|
||||
} now;
|
||||
|
||||
GetSystemTimeAsFileTime (&now.ft);
|
||||
__p->tv_usec = (long) ((now.ns100 / 10LL) % SSH_USEC_IN_SEC);
|
||||
__p->tv_sec = (long)(((now.ns100 / 10LL ) / SSH_USEC_IN_SEC) - SSH_SECONDS_SINCE_1601);
|
||||
|
||||
return (0);
|
||||
}
|
||||
#else /* _WIN32 */
|
||||
#ifndef NSS_BUFLEN_PASSWD
|
||||
#define NSS_BUFLEN_PASSWD 4096
|
||||
#endif
|
||||
|
||||
char *ssh_get_user_home_dir(void) {
|
||||
static char szPath[PATH_MAX] = {0};
|
||||
struct passwd *pwd = NULL;
|
||||
char *szPath = NULL;
|
||||
struct passwd pwd;
|
||||
struct passwd *pwdbuf;
|
||||
char buf[NSS_BUFLEN_PASSWD];
|
||||
int rc;
|
||||
|
||||
pwd = getpwuid(getuid());
|
||||
if (pwd == NULL) {
|
||||
rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
|
||||
if (rc != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf(szPath, PATH_MAX - 1, "%s", pwd->pw_dir);
|
||||
szPath = strdup(pwd.pw_dir);
|
||||
|
||||
return szPath;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* we have read access on file */
|
||||
int ssh_file_readaccess_ok(const char *file) {
|
||||
if (access(file, R_OK) < 0) {
|
||||
@@ -103,17 +143,18 @@ int ssh_file_readaccess_ok(const char *file) {
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
u64 ntohll(u64 a) {
|
||||
uint64_t ntohll(uint64_t a) {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
return a;
|
||||
#else
|
||||
u32 low = a & 0xffffffff;
|
||||
u32 high = a >> 32 ;
|
||||
uint32_t low = (uint32_t)(a & 0xffffffff);
|
||||
uint32_t high = (uint32_t)(a >> 32);
|
||||
low = ntohl(low);
|
||||
high = ntohl(high);
|
||||
|
||||
return ((((u64) low) << 32) | ( high));
|
||||
return ((((uint64_t) low) << 32) | ( high));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -149,5 +190,221 @@ const char *ssh_version(int req_version) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ssh_list *ssh_list_new(){
|
||||
struct ssh_list *ret=malloc(sizeof(struct ssh_list));
|
||||
if(!ret)
|
||||
return NULL;
|
||||
ret->root=ret->end=NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ssh_list_free(struct ssh_list *list){
|
||||
struct ssh_iterator *ptr,*next;
|
||||
ptr=list->root;
|
||||
while(ptr){
|
||||
next=ptr->next;
|
||||
SAFE_FREE(ptr);
|
||||
ptr=next;
|
||||
}
|
||||
SAFE_FREE(list);
|
||||
}
|
||||
|
||||
struct ssh_iterator *ssh_list_get_iterator(const struct ssh_list *list){
|
||||
return list->root;
|
||||
}
|
||||
|
||||
static struct ssh_iterator *ssh_iterator_new(const void *data){
|
||||
struct ssh_iterator *iterator=malloc(sizeof(struct ssh_iterator));
|
||||
if(!iterator)
|
||||
return NULL;
|
||||
iterator->next=NULL;
|
||||
iterator->data=data;
|
||||
return iterator;
|
||||
}
|
||||
|
||||
int ssh_list_add(struct ssh_list *list,const void *data){
|
||||
struct ssh_iterator *iterator=ssh_iterator_new(data);
|
||||
if(!iterator)
|
||||
return SSH_ERROR;
|
||||
if(!list->end){
|
||||
/* list is empty */
|
||||
list->root=list->end=iterator;
|
||||
} else {
|
||||
/* put it on end of list */
|
||||
list->end->next=iterator;
|
||||
list->end=iterator;
|
||||
}
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator){
|
||||
struct ssh_iterator *ptr,*prev;
|
||||
prev=NULL;
|
||||
ptr=list->root;
|
||||
while(ptr && ptr != iterator){
|
||||
prev=ptr;
|
||||
ptr=ptr->next;
|
||||
}
|
||||
if(!ptr){
|
||||
/* we did not find the element */
|
||||
return;
|
||||
}
|
||||
/* unlink it */
|
||||
if(prev)
|
||||
prev->next=ptr->next;
|
||||
/* if iterator was the head */
|
||||
if(list->root == iterator)
|
||||
list->root=iterator->next;
|
||||
/* if iterator was the tail */
|
||||
if(list->end == iterator)
|
||||
list->end = prev;
|
||||
SAFE_FREE(iterator);
|
||||
}
|
||||
|
||||
const void *_ssh_list_get_head(struct ssh_list *list){
|
||||
struct ssh_iterator *iterator=list->root;
|
||||
const void *data;
|
||||
if(!list->root)
|
||||
return NULL;
|
||||
data=iterator->data;
|
||||
list->root=iterator->next;
|
||||
if(list->end==iterator)
|
||||
list->end=NULL;
|
||||
SAFE_FREE(iterator);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse directory component.
|
||||
*
|
||||
* dirname breaks a null-terminated pathname string into a directory component.
|
||||
* In the usual case, ssh_dirname() returns the string up to, but not including,
|
||||
* the final '/'. Trailing '/' characters are not counted as part of the
|
||||
* pathname. The caller must free the memory.
|
||||
*
|
||||
* @param path The path to parse.
|
||||
*
|
||||
* @return The dirname of path or NULL if we can't allocate memory. If path
|
||||
* does not contain a slash, c_dirname() returns the string ".". If
|
||||
* path is the string "/", it returns the string "/". If path is
|
||||
* NULL or an empty string, "." is returned.
|
||||
*/
|
||||
char *ssh_dirname (const char *path) {
|
||||
char *new = NULL;
|
||||
unsigned int len;
|
||||
|
||||
if (path == NULL || *path == '\0') {
|
||||
return strdup(".");
|
||||
}
|
||||
|
||||
len = strlen(path);
|
||||
|
||||
/* Remove trailing slashes */
|
||||
while(len > 0 && path[len - 1] == '/') --len;
|
||||
|
||||
/* We have only slashes */
|
||||
if (len == 0) {
|
||||
return strdup("/");
|
||||
}
|
||||
|
||||
/* goto next slash */
|
||||
while(len > 0 && path[len - 1] != '/') --len;
|
||||
|
||||
if (len == 0) {
|
||||
return strdup(".");
|
||||
} else if (len == 1) {
|
||||
return strdup("/");
|
||||
}
|
||||
|
||||
/* Remove slashes again */
|
||||
while(len > 0 && path[len - 1] == '/') --len;
|
||||
|
||||
new = malloc(len + 1);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strncpy(new, path, len);
|
||||
new[len] = '\0';
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief basename - parse filename component.
|
||||
*
|
||||
* basename breaks a null-terminated pathname string into a filename component.
|
||||
* ssh_basename() returns the component following the final '/'. Trailing '/'
|
||||
* characters are not counted as part of the pathname.
|
||||
*
|
||||
* @param path The path to parse.
|
||||
*
|
||||
* @return The filename of path or NULL if we can't allocate memory. If path
|
||||
* is a the string "/", basename returns the string "/". If path is
|
||||
* NULL or an empty string, "." is returned.
|
||||
*/
|
||||
char *ssh_basename (const char *path) {
|
||||
char *new = NULL;
|
||||
const char *s;
|
||||
unsigned int len;
|
||||
|
||||
if (path == NULL || *path == '\0') {
|
||||
return strdup(".");
|
||||
}
|
||||
|
||||
len = strlen(path);
|
||||
/* Remove trailing slashes */
|
||||
while(len > 0 && path[len - 1] == '/') --len;
|
||||
|
||||
/* We have only slashes */
|
||||
if (len == 0) {
|
||||
return strdup("/");
|
||||
}
|
||||
|
||||
while(len > 0 && path[len - 1] != '/') --len;
|
||||
|
||||
if (len > 0) {
|
||||
s = path + len;
|
||||
len = strlen(s);
|
||||
|
||||
while(len > 0 && s[len - 1] == '/') --len;
|
||||
} else {
|
||||
return strdup(path);
|
||||
}
|
||||
|
||||
new = malloc(len + 1);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strncpy(new, s, len);
|
||||
new[len] = '\0';
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Attempts to create a directory with the given pathname.
|
||||
*
|
||||
* This is the portable version of mkdir, mode is ignored on Windows systems.
|
||||
*
|
||||
* @param pathname The path name to create the directory.
|
||||
*
|
||||
* @param mode The permissions to use.
|
||||
*
|
||||
* @return 0 on success, < 0 on error with errno set.
|
||||
*/
|
||||
int ssh_mkdir(const char *pathname, mode_t mode) {
|
||||
int r;
|
||||
|
||||
#ifdef _WIN32
|
||||
r = _mkdir(pathname);
|
||||
#else
|
||||
r = mkdir(pathname, mode);
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
|
||||
1567
libssh/options.c
1567
libssh/options.c
File diff suppressed because it is too large
Load Diff
184
libssh/packet.c
184
libssh/packet.c
@@ -21,9 +21,10 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
@@ -31,11 +32,17 @@
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/ssh1.h"
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/channels.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/messages.h"
|
||||
#include "libssh/pcap.h"
|
||||
|
||||
/* XXX include selected mac size */
|
||||
static int macsize=SHA_DIGEST_LEN;
|
||||
@@ -48,7 +55,7 @@ static int macsize=SHA_DIGEST_LEN;
|
||||
#define PACKET_STATE_INIT 0
|
||||
#define PACKET_STATE_SIZEREAD 1
|
||||
|
||||
static int packet_read2(SSH_SESSION *session) {
|
||||
static int packet_read2(ssh_session session) {
|
||||
unsigned int blocksize = (session->current_crypto ?
|
||||
session->current_crypto->in_cipher->blocksize : 8);
|
||||
int current_macsize = session->current_crypto ? macsize : 0;
|
||||
@@ -58,8 +65,8 @@ static int packet_read2(SSH_SESSION *session) {
|
||||
int to_be_read;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
u32 len;
|
||||
u8 padding;
|
||||
uint32_t len;
|
||||
uint8_t padding;
|
||||
|
||||
enter_function();
|
||||
|
||||
@@ -103,7 +110,7 @@ static int packet_read2(SSH_SESSION *session) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
to_be_read = len - blocksize + sizeof(u32);
|
||||
to_be_read = len - blocksize + sizeof(uint32_t);
|
||||
if (to_be_read < 0) {
|
||||
/* remote sshd sends invalid sizes? */
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
@@ -116,7 +123,7 @@ static int packet_read2(SSH_SESSION *session) {
|
||||
session->packet_state = PACKET_STATE_SIZEREAD;
|
||||
case PACKET_STATE_SIZEREAD:
|
||||
len = session->in_packet.len;
|
||||
to_be_read = len - blocksize + sizeof(u32) + current_macsize;
|
||||
to_be_read = len - blocksize + sizeof(uint32_t) + current_macsize;
|
||||
/* if to_be_read is zero, the whole packet was blocksize bytes. */
|
||||
if (to_be_read != 0) {
|
||||
rc = ssh_socket_wait_for_data(session->socket,session,to_be_read);
|
||||
@@ -148,11 +155,19 @@ static int packet_read2(SSH_SESSION *session) {
|
||||
* have been decrypted)
|
||||
*/
|
||||
if (packet_decrypt(session,
|
||||
buffer_get(session->in_buffer) + blocksize,
|
||||
((uint8_t*)buffer_get(session->in_buffer) + blocksize),
|
||||
buffer_get_len(session->in_buffer) - blocksize) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Decrypt error");
|
||||
goto error;
|
||||
}
|
||||
#ifdef WITH_PCAP
|
||||
if(session->pcap_ctx){
|
||||
ssh_pcap_context_write(session->pcap_ctx,
|
||||
SSH_PCAP_DIR_IN, buffer_get(session->in_buffer),
|
||||
buffer_get_len(session->in_buffer),
|
||||
buffer_get_len(session->in_buffer));
|
||||
}
|
||||
#endif
|
||||
ssh_socket_read(session->socket, mac, macsize);
|
||||
|
||||
if (packet_hmac_verify(session, session->in_buffer, mac) < 0) {
|
||||
@@ -160,8 +175,19 @@ static int packet_read2(SSH_SESSION *session) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
#ifdef WITH_PCAP
|
||||
else {
|
||||
/* No crypto */
|
||||
if(session->pcap_ctx){
|
||||
ssh_pcap_context_write(session->pcap_ctx,
|
||||
SSH_PCAP_DIR_IN, buffer_get(session->in_buffer),
|
||||
buffer_get_len(session->in_buffer),
|
||||
buffer_get_len(session->in_buffer));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
buffer_pass_bytes(session->in_buffer, sizeof(u32));
|
||||
buffer_pass_bytes(session->in_buffer, sizeof(uint32_t));
|
||||
|
||||
/* pass the size which has been processed before */
|
||||
if (buffer_get_u8(session->in_buffer, &padding) == 0) {
|
||||
@@ -169,7 +195,7 @@ static int packet_read2(SSH_SESSION *session) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"%hhd bytes padding, %d bytes left in buffer",
|
||||
padding, buffer_get_rest_len(session->in_buffer));
|
||||
|
||||
@@ -187,13 +213,13 @@ static int packet_read2(SSH_SESSION *session) {
|
||||
}
|
||||
buffer_pass_bytes_end(session->in_buffer, padding);
|
||||
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"After padding, %d bytes left in buffer",
|
||||
buffer_get_rest_len(session->in_buffer));
|
||||
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
|
||||
if (session->current_crypto && session->current_crypto->do_compress_in) {
|
||||
ssh_log(session, SSH_LOG_RARE, "Decompressing in_buffer ...");
|
||||
if (decompress_buffer(session, session->in_buffer) < 0) {
|
||||
ssh_log(session, SSH_LOG_PACKET, "Decompressing in_buffer ...");
|
||||
if (decompress_buffer(session, session->in_buffer, MAX_PACKET_LEN) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
@@ -214,15 +240,15 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSH1
|
||||
#ifdef WITH_SSH1
|
||||
/* a slighty modified packet_read2() for SSH-1 protocol */
|
||||
static int packet_read1(SSH_SESSION *session) {
|
||||
static int packet_read1(ssh_session session) {
|
||||
void *packet = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
int to_be_read;
|
||||
u32 padding;
|
||||
u32 crc;
|
||||
u32 len;
|
||||
uint32_t padding;
|
||||
uint32_t crc;
|
||||
uint32_t len;
|
||||
|
||||
enter_function();
|
||||
|
||||
@@ -245,7 +271,7 @@ static int packet_read1(SSH_SESSION *session) {
|
||||
}
|
||||
}
|
||||
|
||||
rc = ssh_socket_read(session->socket, &len, sizeof(u32));
|
||||
rc = ssh_socket_read(session->socket, &len, sizeof(uint32_t));
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
@@ -312,29 +338,29 @@ static int packet_read1(SSH_SESSION *session) {
|
||||
#endif
|
||||
ssh_log(session, SSH_LOG_PACKET, "%d bytes padding", padding);
|
||||
if(((len + padding) != buffer_get_rest_len(session->in_buffer)) ||
|
||||
((len + padding) < sizeof(u32))) {
|
||||
((len + padding) < sizeof(uint32_t))) {
|
||||
ssh_log(session, SSH_LOG_RARE, "no crc32 in packet");
|
||||
ssh_set_error(session, SSH_FATAL, "no crc32 in packet");
|
||||
goto error;
|
||||
}
|
||||
|
||||
memcpy(&crc,
|
||||
buffer_get_rest(session->in_buffer) + (len+padding) - sizeof(u32),
|
||||
sizeof(u32));
|
||||
buffer_pass_bytes_end(session->in_buffer, sizeof(u32));
|
||||
(unsigned char *)buffer_get_rest(session->in_buffer) + (len+padding) - sizeof(uint32_t),
|
||||
sizeof(uint32_t));
|
||||
buffer_pass_bytes_end(session->in_buffer, sizeof(uint32_t));
|
||||
crc = ntohl(crc);
|
||||
if (ssh_crc32(buffer_get_rest(session->in_buffer),
|
||||
(len + padding) - sizeof(u32)) != crc) {
|
||||
(len + padding) - sizeof(uint32_t)) != crc) {
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("crc32 on",buffer_get_rest(session->in_buffer),
|
||||
len + padding - sizeof(u32));
|
||||
len + padding - sizeof(uint32_t));
|
||||
#endif
|
||||
ssh_log(session, SSH_LOG_RARE, "Invalid crc32");
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Invalid crc32: expected %.8x, got %.8x",
|
||||
crc,
|
||||
ssh_crc32(buffer_get_rest(session->in_buffer),
|
||||
len + padding - sizeof(u32)));
|
||||
len + padding - sizeof(uint32_t)));
|
||||
goto error;
|
||||
}
|
||||
/* pass the padding */
|
||||
@@ -363,11 +389,11 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* HAVE_SSH1 */
|
||||
#endif /* WITH_SSH1 */
|
||||
|
||||
/* that's where i'd like C to be object ... */
|
||||
int packet_read(SSH_SESSION *session) {
|
||||
#ifdef HAVE_SSH1
|
||||
int packet_read(ssh_session session) {
|
||||
#ifdef WITH_SSH1
|
||||
if (session->version == 1) {
|
||||
return packet_read1(session);
|
||||
}
|
||||
@@ -375,7 +401,7 @@ int packet_read(SSH_SESSION *session) {
|
||||
return packet_read2(session);
|
||||
}
|
||||
|
||||
int packet_translate(SSH_SESSION *session) {
|
||||
int packet_translate(ssh_session session) {
|
||||
enter_function();
|
||||
|
||||
memset(&session->in_packet, 0, sizeof(PACKET));
|
||||
@@ -384,7 +410,7 @@ int packet_translate(SSH_SESSION *session) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
ssh_log(session, SSH_LOG_RARE, "Final size %d",
|
||||
ssh_log(session, SSH_LOG_PACKET, "Final size %d",
|
||||
buffer_get_rest_len(session->in_buffer));
|
||||
|
||||
if(buffer_get_u8(session->in_buffer, &session->in_packet.type) == 0) {
|
||||
@@ -393,7 +419,7 @@ int packet_translate(SSH_SESSION *session) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
ssh_log(session, SSH_LOG_RARE, "Type %hhd", session->in_packet.type);
|
||||
ssh_log(session, SSH_LOG_PACKET, "Type %hhd", session->in_packet.type);
|
||||
session->in_packet.valid = 1;
|
||||
|
||||
leave_function();
|
||||
@@ -406,7 +432,7 @@ int packet_translate(SSH_SESSION *session) {
|
||||
* Return SSH_OK if everything has been sent, SSH_AGAIN if there are still
|
||||
* things to send on buffer, SSH_ERROR if there is an error.
|
||||
*/
|
||||
int packet_flush(SSH_SESSION *session, int enforce_blocking) {
|
||||
int packet_flush(ssh_session session, int enforce_blocking) {
|
||||
if (enforce_blocking || session->blocking) {
|
||||
return ssh_socket_blocking_flush(session->socket);
|
||||
}
|
||||
@@ -418,7 +444,7 @@ int packet_flush(SSH_SESSION *session, int enforce_blocking) {
|
||||
* This function places the outgoing packet buffer into an outgoing
|
||||
* socket buffer
|
||||
*/
|
||||
static int packet_write(SSH_SESSION *session) {
|
||||
static int packet_write(ssh_session session) {
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
enter_function();
|
||||
@@ -433,24 +459,24 @@ static int packet_write(SSH_SESSION *session) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int packet_send2(SSH_SESSION *session) {
|
||||
static int packet_send2(ssh_session session) {
|
||||
unsigned int blocksize = (session->current_crypto ?
|
||||
session->current_crypto->out_cipher->blocksize : 8);
|
||||
u32 currentlen = buffer_get_len(session->out_buffer);
|
||||
uint32_t currentlen = buffer_get_len(session->out_buffer);
|
||||
unsigned char *hmac = NULL;
|
||||
char padstring[32] = {0};
|
||||
int rc = SSH_ERROR;
|
||||
u32 finallen;
|
||||
u8 padding;
|
||||
uint32_t finallen;
|
||||
uint8_t padding;
|
||||
|
||||
enter_function();
|
||||
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"Writing on the wire a packet having %u bytes before", currentlen);
|
||||
|
||||
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
|
||||
if (session->current_crypto && session->current_crypto->do_compress_out) {
|
||||
ssh_log(session, SSH_LOG_RARE, "Compressing in_buffer ...");
|
||||
ssh_log(session, SSH_LOG_PACKET, "Compressing in_buffer ...");
|
||||
if (compress_buffer(session,session->out_buffer) < 0) {
|
||||
goto error;
|
||||
}
|
||||
@@ -469,20 +495,26 @@ static int packet_send2(SSH_SESSION *session) {
|
||||
}
|
||||
|
||||
finallen = htonl(currentlen + padding + 1);
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"%d bytes after comp + %d padding bytes = %lu bytes packet",
|
||||
currentlen, padding, (long unsigned int) ntohl(finallen));
|
||||
|
||||
if (buffer_prepend_data(session->out_buffer, &padding, sizeof(u8)) < 0) {
|
||||
if (buffer_prepend_data(session->out_buffer, &padding, sizeof(uint8_t)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(u32)) < 0) {
|
||||
if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (buffer_add_data(session->out_buffer, padstring, padding) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifdef WITH_PCAP
|
||||
if(session->pcap_ctx){
|
||||
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,
|
||||
buffer_get(session->out_buffer),buffer_get_len(session->out_buffer)
|
||||
,buffer_get_len(session->out_buffer));
|
||||
}
|
||||
#endif
|
||||
hmac = packet_encrypt(session, buffer_get(session->out_buffer),
|
||||
buffer_get_len(session->out_buffer));
|
||||
if (hmac) {
|
||||
@@ -502,16 +534,16 @@ error:
|
||||
return rc; /* SSH_OK, AGAIN or ERROR */
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSH1
|
||||
static int packet_send1(SSH_SESSION *session) {
|
||||
#ifdef WITH_SSH1
|
||||
static int packet_send1(ssh_session session) {
|
||||
unsigned int blocksize = (session->current_crypto ?
|
||||
session->current_crypto->out_cipher->blocksize : 8);
|
||||
u32 currentlen = buffer_get_len(session->out_buffer) + sizeof(u32);
|
||||
uint32_t currentlen = buffer_get_len(session->out_buffer) + sizeof(uint32_t);
|
||||
char padstring[32] = {0};
|
||||
int rc = SSH_ERROR;
|
||||
u32 finallen;
|
||||
u32 crc;
|
||||
u8 padding;
|
||||
uint32_t finallen;
|
||||
uint32_t crc;
|
||||
uint8_t padding;
|
||||
|
||||
enter_function();
|
||||
ssh_log(session,SSH_LOG_PACKET,"Sending a %d bytes long packet",currentlen);
|
||||
@@ -541,12 +573,12 @@ static int packet_send1(SSH_SESSION *session) {
|
||||
if (buffer_prepend_data(session->out_buffer, &padstring, padding) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(u32)) < 0) {
|
||||
if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
crc = ssh_crc32(buffer_get(session->out_buffer) + sizeof(u32),
|
||||
buffer_get_len(session->out_buffer) - sizeof(u32));
|
||||
crc = ssh_crc32((char *)buffer_get(session->out_buffer) + sizeof(uint32_t),
|
||||
buffer_get_len(session->out_buffer) - sizeof(uint32_t));
|
||||
|
||||
if (buffer_add_u32(session->out_buffer, ntohl(crc)) < 0) {
|
||||
goto error;
|
||||
@@ -557,8 +589,8 @@ static int packet_send1(SSH_SESSION *session) {
|
||||
buffer_get_len(session->out_buffer));
|
||||
#endif
|
||||
|
||||
packet_encrypt(session, buffer_get(session->out_buffer) + sizeof(u32),
|
||||
buffer_get_len(session->out_buffer) - sizeof(u32));
|
||||
packet_encrypt(session, (unsigned char *)buffer_get(session->out_buffer) + sizeof(uint32_t),
|
||||
buffer_get_len(session->out_buffer) - sizeof(uint32_t));
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("encrypted packet",buffer_get(session->out_buffer),
|
||||
@@ -580,10 +612,10 @@ error:
|
||||
return rc; /* SSH_OK, AGAIN or ERROR */
|
||||
}
|
||||
|
||||
#endif /* HAVE_SSH1 */
|
||||
#endif /* WITH_SSH1 */
|
||||
|
||||
int packet_send(SSH_SESSION *session) {
|
||||
#ifdef HAVE_SSH1
|
||||
int packet_send(ssh_session session) {
|
||||
#ifdef WITH_SSH1
|
||||
if (session->version == 1) {
|
||||
return packet_send1(session);
|
||||
}
|
||||
@@ -591,13 +623,13 @@ int packet_send(SSH_SESSION *session) {
|
||||
return packet_send2(session);
|
||||
}
|
||||
|
||||
void packet_parse(SSH_SESSION *session) {
|
||||
STRING *error_s = NULL;
|
||||
void packet_parse(ssh_session session) {
|
||||
ssh_string error_s = NULL;
|
||||
char *error = NULL;
|
||||
int type = session->in_packet.type;
|
||||
u32 tmp;
|
||||
uint32_t type = session->in_packet.type;
|
||||
uint32_t tmp;
|
||||
|
||||
#ifdef HAVE_SSH1
|
||||
#ifdef WITH_SSH1
|
||||
if (session->version == 1) {
|
||||
/* SSH-1 */
|
||||
switch(type) {
|
||||
@@ -622,7 +654,7 @@ void packet_parse(SSH_SESSION *session) {
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
#endif /* HAVE_SSH1 */
|
||||
#endif /* WITH_SSH1 */
|
||||
switch(type) {
|
||||
case SSH2_MSG_DISCONNECT:
|
||||
buffer_get_u32(session->in_buffer, &tmp);
|
||||
@@ -652,19 +684,25 @@ void packet_parse(SSH_SESSION *session) {
|
||||
case SSH2_MSG_CHANNEL_EOF:
|
||||
case SSH2_MSG_CHANNEL_CLOSE:
|
||||
channel_handle(session,type);
|
||||
return;
|
||||
case SSH2_MSG_IGNORE:
|
||||
case SSH2_MSG_DEBUG:
|
||||
return;
|
||||
case SSH2_MSG_SERVICE_REQUEST:
|
||||
case SSH2_MSG_USERAUTH_REQUEST:
|
||||
case SSH2_MSG_CHANNEL_OPEN:
|
||||
message_handle(session,type);
|
||||
return;
|
||||
default:
|
||||
ssh_log(session, SSH_LOG_RARE, "Received unhandled packet %d", type);
|
||||
}
|
||||
#ifdef HAVE_SSH1
|
||||
#ifdef WITH_SSH1
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSH1
|
||||
static int packet_wait1(SSH_SESSION *session, int type, int blocking) {
|
||||
#ifdef WITH_SSH1
|
||||
static int packet_wait1(ssh_session session, int type, int blocking) {
|
||||
|
||||
enter_function();
|
||||
|
||||
@@ -719,9 +757,9 @@ static int packet_wait1(SSH_SESSION *session, int type, int blocking) {
|
||||
leave_function();
|
||||
return SSH_OK;
|
||||
}
|
||||
#endif /* HAVE_SSH1 */
|
||||
#endif /* WITH_SSH1 */
|
||||
|
||||
static int packet_wait2(SSH_SESSION *session, int type, int blocking) {
|
||||
static int packet_wait2(ssh_session session, int type, int blocking) {
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
enter_function();
|
||||
@@ -747,9 +785,13 @@ static int packet_wait2(SSH_SESSION *session, int type, int blocking) {
|
||||
case SSH2_MSG_CHANNEL_REQUEST:
|
||||
case SSH2_MSG_CHANNEL_EOF:
|
||||
case SSH2_MSG_CHANNEL_CLOSE:
|
||||
case SSH2_MSG_SERVICE_REQUEST:
|
||||
case SSH2_MSG_USERAUTH_REQUEST:
|
||||
case SSH2_MSG_CHANNEL_OPEN:
|
||||
packet_parse(session);
|
||||
break;
|
||||
case SSH2_MSG_IGNORE:
|
||||
case SSH2_MSG_DEBUG:
|
||||
break;
|
||||
default:
|
||||
if (type && (type != session->in_packet.type)) {
|
||||
@@ -772,8 +814,8 @@ static int packet_wait2(SSH_SESSION *session, int type, int blocking) {
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int packet_wait(SSH_SESSION *session, int type, int block) {
|
||||
#ifdef HAVE_SSH1
|
||||
int packet_wait(ssh_session session, int type, int block) {
|
||||
#ifdef WITH_SSH1
|
||||
if (session->version == 1) {
|
||||
return packet_wait1(session, type, block);
|
||||
}
|
||||
|
||||
386
libssh/pcap.c
Normal file
386
libssh/pcap.c
Normal file
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* pcap.c */
|
||||
/** \defgroup ssh_pcap SSH-pcap
|
||||
* \brief libssh pcap file generation
|
||||
*
|
||||
* \addtogroup ssh_pcap
|
||||
* @{ */
|
||||
|
||||
#include "config.h"
|
||||
#ifdef WITH_PCAP
|
||||
|
||||
#include <stdio.h>
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/pcap.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/socket.h"
|
||||
|
||||
/* The header of a pcap file is the following. We are not going to make it
|
||||
* very complicated.
|
||||
* Just for information.
|
||||
*/
|
||||
struct pcap_hdr_s {
|
||||
uint32_t magic_number; /* magic number */
|
||||
uint16_t version_major; /* major version number */
|
||||
uint16_t version_minor; /* minor version number */
|
||||
int32_t thiszone; /* GMT to local correction */
|
||||
uint32_t sigfigs; /* accuracy of timestamps */
|
||||
uint32_t snaplen; /* max length of captured packets, in octets */
|
||||
uint32_t network; /* data link type */
|
||||
};
|
||||
|
||||
#define PCAP_MAGIC 0xa1b2c3d4
|
||||
#define PCAP_VERSION_MAJOR 2
|
||||
#define PCAP_VERSION_MINOR 4
|
||||
|
||||
#define DLT_RAW 12 /* raw IP */
|
||||
|
||||
/* TCP flags */
|
||||
#define TH_FIN 0x01
|
||||
#define TH_SYN 0x02
|
||||
#define TH_RST 0x04
|
||||
#define TH_PUSH 0x08
|
||||
#define TH_ACK 0x10
|
||||
#define TH_URG 0x20
|
||||
|
||||
/* The header of a pcap packet.
|
||||
* Just for information.
|
||||
*/
|
||||
struct pcaprec_hdr_s {
|
||||
uint32_t ts_sec; /* timestamp seconds */
|
||||
uint32_t ts_usec; /* timestamp microseconds */
|
||||
uint32_t incl_len; /* number of octets of packet saved in file */
|
||||
uint32_t orig_len; /* actual length of packet */
|
||||
};
|
||||
|
||||
/** @private
|
||||
* @brief a pcap context expresses the state of a pcap dump
|
||||
* in a SSH session only. Multiple pcap contexts may be used into
|
||||
* a single pcap file.
|
||||
*/
|
||||
|
||||
struct ssh_pcap_context_struct {
|
||||
ssh_session session;
|
||||
ssh_pcap_file file;
|
||||
int connected;
|
||||
/* All of these informations are useful to generate
|
||||
* the dummy IP and TCP packets
|
||||
*/
|
||||
uint32_t ipsource;
|
||||
uint32_t ipdest;
|
||||
uint16_t portsource;
|
||||
uint16_t portdest;
|
||||
uint32_t outsequence;
|
||||
uint32_t insequence;
|
||||
};
|
||||
|
||||
/** @private
|
||||
* @brief a pcap file expresses the state of a pcap file which may
|
||||
* contain several streams.
|
||||
*/
|
||||
struct ssh_pcap_file_struct {
|
||||
FILE *output;
|
||||
uint16_t ipsequence;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief create a new ssh_pcap_file object
|
||||
*/
|
||||
ssh_pcap_file ssh_pcap_file_new(){
|
||||
return malloc(sizeof(struct ssh_pcap_file_struct));
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief writes a packet on file
|
||||
*/
|
||||
static int ssh_pcap_file_write(ssh_pcap_file pcap, ssh_buffer packet){
|
||||
int err;
|
||||
uint32_t len;
|
||||
if(pcap == NULL || pcap->output==NULL)
|
||||
return SSH_ERROR;
|
||||
len=buffer_get_len(packet);
|
||||
err=fwrite(buffer_get(packet),len,1,pcap->output);
|
||||
if(err<0)
|
||||
return SSH_ERROR;
|
||||
else
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief prepends a packet with the pcap header and writes packet
|
||||
* on file
|
||||
*/
|
||||
int ssh_pcap_file_write_packet(ssh_pcap_file pcap, ssh_buffer packet, uint32_t original_len){
|
||||
ssh_buffer header=buffer_new();
|
||||
struct timeval now;
|
||||
int err;
|
||||
if(header == NULL)
|
||||
return SSH_ERROR;
|
||||
gettimeofday(&now,NULL);
|
||||
buffer_add_u32(header,htonl(now.tv_sec));
|
||||
buffer_add_u32(header,htonl(now.tv_usec));
|
||||
buffer_add_u32(header,htonl(buffer_get_len(packet)));
|
||||
buffer_add_u32(header,htonl(original_len));
|
||||
buffer_add_buffer(header,packet);
|
||||
err=ssh_pcap_file_write(pcap,header);
|
||||
buffer_free(header);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief opens a new pcap file and create header
|
||||
*/
|
||||
int ssh_pcap_file_open(ssh_pcap_file pcap, const char *filename){
|
||||
ssh_buffer header;
|
||||
int err;
|
||||
if(pcap == NULL)
|
||||
return SSH_ERROR;
|
||||
if(pcap->output){
|
||||
fclose(pcap->output);
|
||||
pcap->output=NULL;
|
||||
}
|
||||
pcap->output=fopen(filename,"wb");
|
||||
if(pcap->output==NULL)
|
||||
return SSH_ERROR;
|
||||
header=buffer_new();
|
||||
if(header==NULL)
|
||||
return SSH_ERROR;
|
||||
buffer_add_u32(header,htonl(PCAP_MAGIC));
|
||||
buffer_add_u16(header,htons(PCAP_VERSION_MAJOR));
|
||||
buffer_add_u16(header,htons(PCAP_VERSION_MINOR));
|
||||
/* currently hardcode GMT to 0 */
|
||||
buffer_add_u32(header,htonl(0));
|
||||
/* accuracy */
|
||||
buffer_add_u32(header,htonl(0));
|
||||
/* size of the biggest packet */
|
||||
buffer_add_u32(header,htonl(MAX_PACKET_LEN));
|
||||
/* we will write sort-of IP */
|
||||
buffer_add_u32(header,htonl(DLT_RAW));
|
||||
err=ssh_pcap_file_write(pcap,header);
|
||||
buffer_free(header);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ssh_pcap_file_close(ssh_pcap_file pcap){
|
||||
int err;
|
||||
if(pcap ==NULL || pcap->output==NULL)
|
||||
return SSH_ERROR;
|
||||
err=fclose(pcap->output);
|
||||
pcap->output=NULL;
|
||||
if(err != 0)
|
||||
return SSH_ERROR;
|
||||
else
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
void ssh_pcap_file_free(ssh_pcap_file pcap){
|
||||
ssh_pcap_file_close(pcap);
|
||||
SAFE_FREE(pcap);
|
||||
}
|
||||
|
||||
|
||||
/** @internal
|
||||
* @brief allocates a new ssh_pcap_context object
|
||||
*/
|
||||
|
||||
ssh_pcap_context ssh_pcap_context_new(ssh_session session){
|
||||
ssh_pcap_context ctx=malloc(sizeof(struct ssh_pcap_context_struct));
|
||||
if(ctx==NULL){
|
||||
ssh_set_error_oom(session);
|
||||
return NULL;
|
||||
}
|
||||
ZERO_STRUCTP(ctx);
|
||||
ctx->session=session;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void ssh_pcap_context_free(ssh_pcap_context ctx){
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
|
||||
void ssh_pcap_context_set_file(ssh_pcap_context ctx, ssh_pcap_file pcap){
|
||||
ctx->file=pcap;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief sets the IP and port parameters in the connection
|
||||
*/
|
||||
static int ssh_pcap_context_connect(ssh_pcap_context ctx){
|
||||
ssh_session session=ctx->session;
|
||||
struct sockaddr_in local, remote;
|
||||
socket_t fd;
|
||||
socklen_t len;
|
||||
if(session==NULL)
|
||||
return SSH_ERROR;
|
||||
if(session->socket==NULL)
|
||||
return SSH_ERROR;
|
||||
fd=ssh_socket_get_fd(session->socket);
|
||||
/* TODO: adapt for windows */
|
||||
if(fd<0)
|
||||
return SSH_ERROR;
|
||||
len=sizeof(local);
|
||||
if(getsockname(fd,(struct sockaddr *)&local,&len)<0){
|
||||
ssh_set_error(session,SSH_REQUEST_DENIED,"Getting local IP address: %s",strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
len=sizeof(remote);
|
||||
if(getpeername(fd,(struct sockaddr *)&remote,&len)<0){
|
||||
ssh_set_error(session,SSH_REQUEST_DENIED,"Getting remote IP address: %s",strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(local.sin_family != AF_INET){
|
||||
ssh_set_error(session,SSH_REQUEST_DENIED,"Only IPv4 supported for pcap logging");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
memcpy(&ctx->ipsource,&local.sin_addr,sizeof(ctx->ipsource));
|
||||
memcpy(&ctx->ipdest,&remote.sin_addr,sizeof(ctx->ipdest));
|
||||
memcpy(&ctx->portsource,&local.sin_port,sizeof(ctx->portsource));
|
||||
memcpy(&ctx->portdest,&remote.sin_port,sizeof(ctx->portdest));
|
||||
|
||||
ctx->connected=1;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
#define IPHDR_LEN 20
|
||||
#define TCPHDR_LEN 20
|
||||
#define TCPIPHDR_LEN (IPHDR_LEN + TCPHDR_LEN)
|
||||
/** @internal
|
||||
* @brief write a SSH packet as a TCP over IP in a pcap file
|
||||
* @param ctx open pcap context
|
||||
* @param direction SSH_PCAP_DIRECTION_IN if the packet has been received
|
||||
* @param direction SSH_PCAP_DIRECTION_OUT if the packet has been emitted
|
||||
* @param data pointer to the data to write
|
||||
* @param len data to write in the pcap file. May be smaller than origlen.
|
||||
* @param origlen number of bytes of complete data.
|
||||
* @returns SSH_OK write is successful
|
||||
* @returns SSH_ERROR an error happened.
|
||||
*/
|
||||
int ssh_pcap_context_write(ssh_pcap_context ctx,enum ssh_pcap_direction direction
|
||||
, void *data, uint32_t len, uint32_t origlen){
|
||||
ssh_buffer ip;
|
||||
int err;
|
||||
if(ctx==NULL || ctx->file ==NULL)
|
||||
return SSH_ERROR;
|
||||
if(ctx->connected==0)
|
||||
if(ssh_pcap_context_connect(ctx)==SSH_ERROR)
|
||||
return SSH_ERROR;
|
||||
ip=buffer_new();
|
||||
if(ip==NULL){
|
||||
ssh_set_error_oom(ctx->session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
/* build an IP packet */
|
||||
/* V4, 20 bytes */
|
||||
buffer_add_u8(ip,4 << 4 | 5);
|
||||
/* tos */
|
||||
buffer_add_u8(ip,0);
|
||||
/* total len */
|
||||
buffer_add_u16(ip,htons(origlen + TCPIPHDR_LEN));
|
||||
/* IP id number */
|
||||
buffer_add_u16(ip,htons(ctx->file->ipsequence));
|
||||
ctx->file->ipsequence++;
|
||||
/* fragment offset */
|
||||
buffer_add_u16(ip,htons(0));
|
||||
/* TTL */
|
||||
buffer_add_u8(ip,64);
|
||||
/* protocol TCP=6 */
|
||||
buffer_add_u8(ip,6);
|
||||
/* checksum */
|
||||
buffer_add_u16(ip,0);
|
||||
if(direction==SSH_PCAP_DIR_OUT){
|
||||
buffer_add_u32(ip,ctx->ipsource);
|
||||
buffer_add_u32(ip,ctx->ipdest);
|
||||
} else {
|
||||
buffer_add_u32(ip,ctx->ipdest);
|
||||
buffer_add_u32(ip,ctx->ipsource);
|
||||
}
|
||||
/* TCP */
|
||||
if(direction==SSH_PCAP_DIR_OUT){
|
||||
buffer_add_u16(ip,ctx->portsource);
|
||||
buffer_add_u16(ip,ctx->portdest);
|
||||
} else {
|
||||
buffer_add_u16(ip,ctx->portdest);
|
||||
buffer_add_u16(ip,ctx->portsource);
|
||||
}
|
||||
/* sequence number */
|
||||
if(direction==SSH_PCAP_DIR_OUT){
|
||||
buffer_add_u32(ip,ntohl(ctx->outsequence));
|
||||
ctx->outsequence+=origlen;
|
||||
} else {
|
||||
buffer_add_u32(ip,ntohl(ctx->insequence));
|
||||
ctx->insequence+=origlen;
|
||||
}
|
||||
/* ack number */
|
||||
if(direction==SSH_PCAP_DIR_OUT){
|
||||
buffer_add_u32(ip,ntohl(ctx->insequence));
|
||||
} else {
|
||||
buffer_add_u32(ip,ntohl(ctx->outsequence));
|
||||
}
|
||||
/* header len = 20 = 5 * 32 bits, at offset 4*/
|
||||
buffer_add_u8(ip,5 << 4);
|
||||
/* flags */
|
||||
buffer_add_u8(ip,TH_PUSH | TH_ACK);
|
||||
/* window */
|
||||
buffer_add_u16(ip,htons(65535));
|
||||
/* checksum */
|
||||
buffer_add_u16(ip,htons(0));
|
||||
/* urgent data ptr */
|
||||
buffer_add_u16(ip,0);
|
||||
/* actual data */
|
||||
buffer_add_data(ip,data,len);
|
||||
err=ssh_pcap_file_write_packet(ctx->file,ip,origlen + TCPIPHDR_LEN);
|
||||
buffer_free(ip);
|
||||
return err;
|
||||
}
|
||||
|
||||
/** @brief sets the pcap file used to trace the session
|
||||
* @param current session
|
||||
* @param pcap an handler to a pcap file. A pcap file may be used in several
|
||||
* sessions.
|
||||
* @returns SSH_ERROR in case of error, SSH_OK otherwise.
|
||||
*/
|
||||
int ssh_set_pcap_file(ssh_session session, ssh_pcap_file pcap){
|
||||
ssh_pcap_context ctx=ssh_pcap_context_new(session);
|
||||
if(ctx==NULL){
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
ctx->file=pcap;
|
||||
if(session->pcap_ctx)
|
||||
ssh_pcap_context_free(session->pcap_ctx);
|
||||
session->pcap_ctx=ctx;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
|
||||
#endif /* WITH_PCAP */
|
||||
/** @} */
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
362
libssh/poll.c
362
libssh/poll.c
@@ -3,7 +3,8 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
* Copyright (c) 2009 Aleksandar Kanchev
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
@@ -25,26 +26,53 @@
|
||||
|
||||
/* This code is based on glib's gpoll */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/poll.h"
|
||||
|
||||
#ifndef SSH_POLL_CTX_CHUNK
|
||||
#define SSH_POLL_CTX_CHUNK 5
|
||||
#endif
|
||||
|
||||
struct ssh_poll_handle_struct {
|
||||
ssh_poll_ctx ctx;
|
||||
union {
|
||||
socket_t fd;
|
||||
size_t idx;
|
||||
} x;
|
||||
short events;
|
||||
ssh_poll_callback cb;
|
||||
void *cb_data;
|
||||
};
|
||||
|
||||
struct ssh_poll_ctx_struct {
|
||||
ssh_poll_handle *pollptrs;
|
||||
ssh_pollfd_t *pollfds;
|
||||
size_t polls_allocated;
|
||||
size_t polls_used;
|
||||
size_t chunk_size;
|
||||
};
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
#include <poll.h>
|
||||
|
||||
int ssh_poll(pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||
return poll((struct pollfd *) fds, nfds, timeout);
|
||||
}
|
||||
|
||||
#else /* HAVE_POLL */
|
||||
#ifdef _WIN32
|
||||
|
||||
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
|
||||
#if 0
|
||||
/* defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) */
|
||||
|
||||
#include <winsock2.h>
|
||||
|
||||
int ssh_poll(pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||
return WSAPoll(fds, nfds, timeout);
|
||||
}
|
||||
|
||||
@@ -56,11 +84,12 @@ int ssh_poll(pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <errno.h>
|
||||
|
||||
static int poll_rest (HANDLE *handles, int nhandles,
|
||||
pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||
ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||
DWORD ready;
|
||||
pollfd_t *f;
|
||||
ssh_pollfd_t *f;
|
||||
int recursed_result;
|
||||
|
||||
if (nhandles == 0) {
|
||||
@@ -117,9 +146,9 @@ static int poll_rest (HANDLE *handles, int nhandles,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ssh_poll(pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
|
||||
pollfd_t *f;
|
||||
ssh_pollfd_t *f;
|
||||
int nhandles = 0;
|
||||
int rc = -1;
|
||||
|
||||
@@ -204,3 +233,318 @@ int ssh_poll(pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||
|
||||
#endif /* HAVE_POLL */
|
||||
|
||||
/**
|
||||
* @brief Allocate a new poll object, which could be used within a poll context.
|
||||
*
|
||||
* @param fd Socket that will be polled.
|
||||
* @param events Poll events that will be monitored for the socket. i.e.
|
||||
* POLLIN, POLLPRI, POLLOUT, POLLERR, POLLHUP, POLLNVAL
|
||||
* @param cb Function to be called if any of the events are set.
|
||||
* @param userdata Userdata to be passed to the callback function. NULL if
|
||||
* not needed.
|
||||
*
|
||||
* @return A new poll object, NULL on error
|
||||
*/
|
||||
|
||||
ssh_poll_handle ssh_poll_new(socket_t fd, short events, ssh_poll_callback cb,
|
||||
void *userdata) {
|
||||
ssh_poll_handle p;
|
||||
|
||||
p = malloc(sizeof(struct ssh_poll_handle_struct));
|
||||
if (p != NULL) {
|
||||
p->ctx = NULL;
|
||||
p->x.fd = fd;
|
||||
p->events = events;
|
||||
p->cb = cb;
|
||||
p->cb_data = userdata;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Free a poll object.
|
||||
*
|
||||
* @param p Pointer to an already allocated poll object.
|
||||
*/
|
||||
|
||||
void ssh_poll_free(ssh_poll_handle p) {
|
||||
SAFE_FREE(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the poll context of a poll object.
|
||||
*
|
||||
* @param p Pointer to an already allocated poll object.
|
||||
*
|
||||
* @return Poll context or NULL if the poll object isn't attached.
|
||||
*/
|
||||
ssh_poll_ctx ssh_poll_get_ctx(ssh_poll_handle p) {
|
||||
return p->ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the events of a poll object.
|
||||
*
|
||||
* @param p Pointer to an already allocated poll object.
|
||||
*
|
||||
* @return Poll events.
|
||||
*/
|
||||
short ssh_poll_get_events(ssh_poll_handle p) {
|
||||
return p->events;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the events of a poll object. The events will also be propagated
|
||||
* to an associated poll context.
|
||||
*
|
||||
* @param p Pointer to an already allocated poll object.
|
||||
* @param events Poll events.
|
||||
*/
|
||||
void ssh_poll_set_events(ssh_poll_handle p, short events) {
|
||||
p->events = events;
|
||||
if (p->ctx != NULL) {
|
||||
p->ctx->pollfds[p->x.idx].events = events;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add extra events to a poll object. Duplicates are ignored.
|
||||
* The events will also be propagated to an associated poll context.
|
||||
*
|
||||
* @param p Pointer to an already allocated poll object.
|
||||
* @param events Poll events.
|
||||
*/
|
||||
void ssh_poll_add_events(ssh_poll_handle p, short events) {
|
||||
ssh_poll_set_events(p, ssh_poll_get_events(p) | events);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove events from a poll object. Non-existent are ignored.
|
||||
* The events will also be propagated to an associated poll context.
|
||||
*
|
||||
* @param p Pointer to an already allocated poll object.
|
||||
* @param events Poll events.
|
||||
*/
|
||||
void ssh_poll_remove_events(ssh_poll_handle p, short events) {
|
||||
ssh_poll_set_events(p, ssh_poll_get_events(p) & ~events);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the raw socket of a poll object.
|
||||
*
|
||||
* @param p Pointer to an already allocated poll object.
|
||||
*
|
||||
* @return Raw socket.
|
||||
*/
|
||||
|
||||
socket_t ssh_poll_get_fd(ssh_poll_handle p) {
|
||||
if (p->ctx != NULL) {
|
||||
return p->ctx->pollfds[p->x.idx].fd;
|
||||
}
|
||||
|
||||
return p->x.fd;
|
||||
}
|
||||
/**
|
||||
* @brief Set the callback of a poll object.
|
||||
*
|
||||
* @param p Pointer to an already allocated poll object.
|
||||
* @param cb Function to be called if any of the events are set.
|
||||
* @param userdata Userdata to be passed to the callback function. NULL if
|
||||
* not needed.
|
||||
*/
|
||||
void ssh_poll_set_callback(ssh_poll_handle p, ssh_poll_callback cb, void *userdata) {
|
||||
if (cb != NULL) {
|
||||
p->cb = cb;
|
||||
p->cb_data = userdata;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a new poll context. It could be associated with many poll object
|
||||
* which are going to be polled at the same time as the poll context. You
|
||||
* would need a single poll context per thread.
|
||||
*
|
||||
* @param chunk_size The size of the memory chunk that will be allocated, when
|
||||
* more memory is needed. This is for efficiency reasons,
|
||||
* i.e. don't allocate memory for each new poll object, but
|
||||
* for the next 5. Set it to 0 if you want to use the
|
||||
* library's default value.
|
||||
*/
|
||||
ssh_poll_ctx ssh_poll_ctx_new(size_t chunk_size) {
|
||||
ssh_poll_ctx ctx;
|
||||
|
||||
ctx = malloc(sizeof(struct ssh_poll_ctx_struct));
|
||||
if (ctx != NULL) {
|
||||
if (!chunk_size) {
|
||||
chunk_size = SSH_POLL_CTX_CHUNK;
|
||||
}
|
||||
|
||||
ctx->chunk_size = chunk_size;
|
||||
ctx->pollptrs = NULL;
|
||||
ctx->pollfds = NULL;
|
||||
ctx->polls_allocated = 0;
|
||||
ctx->polls_used = 0;
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free a poll context.
|
||||
*
|
||||
* @param ctx Pointer to an already allocated poll context.
|
||||
*/
|
||||
void ssh_poll_ctx_free(ssh_poll_ctx ctx) {
|
||||
if (ctx->polls_allocated > 0) {
|
||||
register size_t i, used;
|
||||
|
||||
used = ctx->polls_used;
|
||||
for (i = 0; i < used; ) {
|
||||
ssh_poll_handle p = ctx->pollptrs[i];
|
||||
int fd = ctx->pollfds[i].fd;
|
||||
|
||||
/* force poll object removal */
|
||||
if (p->cb(p, fd, POLLERR, p->cb_data) < 0) {
|
||||
used = ctx->polls_used;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
SAFE_FREE(ctx->pollptrs);
|
||||
SAFE_FREE(ctx->pollfds);
|
||||
}
|
||||
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
|
||||
static int ssh_poll_ctx_resize(ssh_poll_ctx ctx, size_t new_size) {
|
||||
ssh_poll_handle *pollptrs;
|
||||
ssh_pollfd_t *pollfds;
|
||||
|
||||
pollptrs = realloc(ctx->pollptrs, sizeof(ssh_poll_handle *) * new_size);
|
||||
if (pollptrs == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pollfds = realloc(ctx->pollfds, sizeof(ssh_pollfd_t) * new_size);
|
||||
if (pollfds == NULL) {
|
||||
ctx->pollptrs = realloc(pollptrs, sizeof(ssh_poll_handle *) * ctx->polls_allocated);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->pollptrs = pollptrs;
|
||||
ctx->pollfds = pollfds;
|
||||
ctx->polls_allocated = new_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add a poll object to a poll context.
|
||||
*
|
||||
* @param ctx Pointer to an already allocated poll context.
|
||||
* @param p Pointer to an already allocated poll object.
|
||||
*
|
||||
* @return 0 on success, < 0 on error
|
||||
*/
|
||||
int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p) {
|
||||
int fd;
|
||||
|
||||
if (p->ctx != NULL) {
|
||||
/* already attached to a context */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->polls_used == ctx->polls_allocated &&
|
||||
ssh_poll_ctx_resize(ctx, ctx->polls_allocated + ctx->chunk_size) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = p->x.fd;
|
||||
p->x.idx = ctx->polls_used++;
|
||||
ctx->pollptrs[p->x.idx] = p;
|
||||
ctx->pollfds[p->x.idx].fd = fd;
|
||||
ctx->pollfds[p->x.idx].events = p->events;
|
||||
ctx->pollfds[p->x.idx].revents = 0;
|
||||
p->ctx = ctx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove a poll object from a poll context.
|
||||
*
|
||||
* @param ctx Pointer to an already allocated poll context.
|
||||
* @param p Pointer to an already allocated poll object.
|
||||
*/
|
||||
void ssh_poll_ctx_remove(ssh_poll_ctx ctx, ssh_poll_handle p) {
|
||||
size_t i;
|
||||
|
||||
i = p->x.idx;
|
||||
p->x.fd = ctx->pollfds[i].fd;
|
||||
p->ctx = NULL;
|
||||
|
||||
ctx->polls_used--;
|
||||
|
||||
/* fill the empty poll slot with the last one */
|
||||
if (ctx->polls_used > 0 && ctx->polls_used != i) {
|
||||
ctx->pollfds[i] = ctx->pollfds[ctx->polls_used];
|
||||
ctx->pollptrs[i] = ctx->pollptrs[ctx->polls_used];
|
||||
}
|
||||
|
||||
/* this will always leave at least chunk_size polls allocated */
|
||||
if (ctx->polls_allocated - ctx->polls_used > ctx->chunk_size) {
|
||||
ssh_poll_ctx_resize(ctx, ctx->polls_allocated - ctx->chunk_size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Poll all the sockets associated through a poll object with a
|
||||
* poll context. If any of the events are set after the poll, the
|
||||
* call back function of the socket will be called.
|
||||
* This function should be called once within the programs main loop.
|
||||
*
|
||||
* @param ctx Pointer to an already allocated poll context.
|
||||
* @param timeout An upper limit on the time for which ssh_poll_ctx() will
|
||||
* block, in milliseconds. Specifying a negative value
|
||||
* means an infinite timeout. This parameter is passed to
|
||||
* the poll() function.
|
||||
*/
|
||||
|
||||
int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) {
|
||||
int rc;
|
||||
|
||||
if (!ctx->polls_used)
|
||||
return 0;
|
||||
|
||||
rc = ssh_poll(ctx->pollfds, ctx->polls_used, timeout);
|
||||
if (rc > 0) {
|
||||
register size_t i, used;
|
||||
|
||||
used = ctx->polls_used;
|
||||
for (i = 0; i < used && rc > 0; ) {
|
||||
if (!ctx->pollfds[i].revents) {
|
||||
i++;
|
||||
} else {
|
||||
ssh_poll_handle p = ctx->pollptrs[i];
|
||||
int fd = ctx->pollfds[i].fd;
|
||||
int revents = ctx->pollfds[i].revents;
|
||||
|
||||
if (p->cb(p, fd, revents, p->cb_data) < 0) {
|
||||
/* the poll was removed, reload the used counter and stall the loop */
|
||||
used = ctx->polls_used;
|
||||
} else {
|
||||
ctx->pollfds[i].revents = 0;
|
||||
i++;
|
||||
}
|
||||
|
||||
rc--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
603
libssh/scp.c
Normal file
603
libssh/scp.c
Normal file
@@ -0,0 +1,603 @@
|
||||
/*
|
||||
* scp - SSH scp wrapper functions
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis <aris@0xbadc0de.be>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/scp.h"
|
||||
|
||||
/** @brief Creates a new scp session
|
||||
* @param session the SSH session to use
|
||||
* @param mode one of SSH_SCP_WRITE or SSH_SCP_READ, depending if you need to drop files remotely or read them.
|
||||
* It is not possible to combine read and write.
|
||||
* @returns NULL if the creation was impossible.
|
||||
* @returns a ssh_scp handle if it worked.
|
||||
*/
|
||||
ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location){
|
||||
ssh_scp scp=malloc(sizeof(struct ssh_scp_struct));
|
||||
if(scp == NULL){
|
||||
ssh_set_error(session,SSH_FATAL,"Error allocating memory for ssh_scp");
|
||||
return NULL;
|
||||
}
|
||||
ZERO_STRUCTP(scp);
|
||||
if((mode&~SSH_SCP_RECURSIVE) != SSH_SCP_WRITE && (mode &~SSH_SCP_RECURSIVE) != SSH_SCP_READ){
|
||||
ssh_set_error(session,SSH_FATAL,"Invalid mode %d for ssh_scp_new()",mode);
|
||||
ssh_scp_free(scp);
|
||||
return NULL;
|
||||
}
|
||||
scp->location=strdup(location);
|
||||
if (scp->location == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL,"Error allocating memory for ssh_scp");
|
||||
ssh_scp_free(scp);
|
||||
return NULL;
|
||||
}
|
||||
scp->session=session;
|
||||
scp->mode=mode & ~SSH_SCP_RECURSIVE;
|
||||
scp->recursive = (mode & SSH_SCP_RECURSIVE) != 0;
|
||||
scp->channel=NULL;
|
||||
scp->state=SSH_SCP_NEW;
|
||||
return scp;
|
||||
}
|
||||
|
||||
int ssh_scp_init(ssh_scp scp){
|
||||
int r;
|
||||
char execbuffer[1024];
|
||||
uint8_t code;
|
||||
if(scp->state != SSH_SCP_NEW){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_init called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
ssh_log(scp->session,SSH_LOG_PROTOCOL,"Initializing scp session %s %son location '%s'",
|
||||
scp->mode==SSH_SCP_WRITE?"write":"read",
|
||||
scp->recursive?"recursive ":"",
|
||||
scp->location);
|
||||
scp->channel=channel_new(scp->session);
|
||||
if(scp->channel == NULL){
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
r= channel_open_session(scp->channel);
|
||||
if(r==SSH_ERROR){
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(scp->mode == SSH_SCP_WRITE)
|
||||
snprintf(execbuffer,sizeof(execbuffer),"scp -t %s %s",
|
||||
scp->recursive ? "-r":"", scp->location);
|
||||
else
|
||||
snprintf(execbuffer,sizeof(execbuffer),"scp -f %s %s",
|
||||
scp->recursive ? "-r":"", scp->location);
|
||||
if(channel_request_exec(scp->channel,execbuffer) == SSH_ERROR){
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(scp->mode == SSH_SCP_WRITE){
|
||||
r=channel_read(scp->channel,&code,1,0);
|
||||
if(code != 0){
|
||||
ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
} else {
|
||||
channel_write(scp->channel,"",1);
|
||||
}
|
||||
if(scp->mode == SSH_SCP_WRITE)
|
||||
scp->state=SSH_SCP_WRITE_INITED;
|
||||
else
|
||||
scp->state=SSH_SCP_READ_INITED;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_scp_close(ssh_scp scp){
|
||||
if(scp->channel != NULL){
|
||||
if(channel_send_eof(scp->channel) == SSH_ERROR){
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(channel_close(scp->channel) == SSH_ERROR){
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
channel_free(scp->channel);
|
||||
scp->channel=NULL;
|
||||
}
|
||||
scp->state=SSH_SCP_NEW;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
void ssh_scp_free(ssh_scp scp){
|
||||
if(scp->state != SSH_SCP_NEW)
|
||||
ssh_scp_close(scp);
|
||||
if(scp->channel)
|
||||
channel_free(scp->channel);
|
||||
SAFE_FREE(scp->location);
|
||||
SAFE_FREE(scp->request_name);
|
||||
SAFE_FREE(scp->warning);
|
||||
SAFE_FREE(scp);
|
||||
}
|
||||
|
||||
/** @brief creates a directory in a scp in sink mode
|
||||
* @param dirname Name of the directory being created.
|
||||
* @param mode Unix permissions for the new directory, e.g. 0755.
|
||||
* @returns SSH_OK if the directory was created.
|
||||
* @returns SSH_ERROR if an error happened.
|
||||
* @see ssh_scp_leave_directory
|
||||
*/
|
||||
int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode){
|
||||
char buffer[1024];
|
||||
int r;
|
||||
uint8_t code;
|
||||
char *dir;
|
||||
char *perms;
|
||||
if(scp->state != SSH_SCP_WRITE_INITED){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_push_directory called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
dir=ssh_basename(dirname);
|
||||
perms=ssh_scp_string_mode(mode);
|
||||
snprintf(buffer, sizeof(buffer), "D%s 0 %s\n", perms, dir);
|
||||
SAFE_FREE(dir);
|
||||
SAFE_FREE(perms);
|
||||
r=channel_write(scp->channel,buffer,strlen(buffer));
|
||||
if(r==SSH_ERROR){
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
r=channel_read(scp->channel,&code,1,0);
|
||||
if(code != 0){
|
||||
ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Leaves a directory
|
||||
* @returns SSH_OK if the directory was created.
|
||||
* @returns SSH_ERROR if an error happened.
|
||||
* @see ssh_scp_push_directory
|
||||
*/
|
||||
int ssh_scp_leave_directory(ssh_scp scp){
|
||||
char buffer[]="E\n";
|
||||
int r;
|
||||
uint8_t code;
|
||||
if(scp->state != SSH_SCP_WRITE_INITED){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_leave_directory called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
r=channel_write(scp->channel,buffer,strlen(buffer));
|
||||
if(r==SSH_ERROR){
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
r=channel_read(scp->channel,&code,1,0);
|
||||
if(code != 0){
|
||||
ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
|
||||
/** @brief initializes the sending of a file to a scp in sink mode
|
||||
* @param filename Name of the file being sent. It should not contain any path indicator
|
||||
* @param size Exact size in bytes of the file being sent.
|
||||
* @param mode Unix permissions for the new file, e.g. 0644
|
||||
* @returns SSH_OK if the file is ready to be sent.
|
||||
* @returns SSH_ERROR if an error happened.
|
||||
*/
|
||||
int ssh_scp_push_file(ssh_scp scp, const char *filename, size_t size, int mode){
|
||||
char buffer[1024];
|
||||
int r;
|
||||
uint8_t code;
|
||||
char *file;
|
||||
char *perms;
|
||||
if(scp->state != SSH_SCP_WRITE_INITED){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_push_file called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
file=ssh_basename(filename);
|
||||
perms=ssh_scp_string_mode(mode);
|
||||
ssh_log(scp->session,SSH_LOG_PROTOCOL,"SCP pushing file %s, size %" PRIdS " with permissions '%s'",file,size,perms);
|
||||
snprintf(buffer, sizeof(buffer), "C%s %" PRIdS " %s\n", perms, size, file);
|
||||
SAFE_FREE(file);
|
||||
SAFE_FREE(perms);
|
||||
r=channel_write(scp->channel,buffer,strlen(buffer));
|
||||
if(r==SSH_ERROR){
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
r=channel_read(scp->channel,&code,1,0);
|
||||
if(code != 0){
|
||||
ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
scp->filelen = size;
|
||||
scp->processed = 0;
|
||||
scp->state=SSH_SCP_WRITE_WRITING;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @brief waits for a response of the scp server
|
||||
* @internal
|
||||
* @param response pointer where the response message must be
|
||||
* copied if any. This pointer must then be free'd.
|
||||
* @returns the return code.
|
||||
* @returns SSH_ERROR a error occured
|
||||
*/
|
||||
int ssh_scp_response(ssh_scp scp, char **response){
|
||||
unsigned char code;
|
||||
int r;
|
||||
char msg[128];
|
||||
r=channel_read(scp->channel,&code,1,0);
|
||||
if(r == SSH_ERROR)
|
||||
return SSH_ERROR;
|
||||
if(code == 0)
|
||||
return 0;
|
||||
if(code > 2){
|
||||
ssh_set_error(scp->session,SSH_FATAL, "SCP: invalid status code %ud received", code);
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
r=ssh_scp_read_string(scp,msg,sizeof(msg));
|
||||
if(r==SSH_ERROR)
|
||||
return r;
|
||||
/* Warning */
|
||||
if(code == 1){
|
||||
ssh_set_error(scp->session,SSH_REQUEST_DENIED, "SCP: Warning: status code 1 received: %s", msg);
|
||||
ssh_log(scp->session,SSH_LOG_RARE,"SCP: Warning: status code 1 received: %s", msg);
|
||||
if(response)
|
||||
*response=strdup(msg);
|
||||
return 1;
|
||||
}
|
||||
if(code == 2){
|
||||
ssh_set_error(scp->session,SSH_FATAL, "SCP: Error: status code 2 received: %s", msg);
|
||||
if(response)
|
||||
*response=strdup(msg);
|
||||
return 2;
|
||||
}
|
||||
/* Not reached */
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/** @brief Write into a remote scp file
|
||||
* @param buffer the buffer to write
|
||||
* @param len the number of bytes to write
|
||||
* @returns SSH_OK the write was successful
|
||||
* @returns SSH_ERROR an error happened while writing
|
||||
*/
|
||||
int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){
|
||||
int w;
|
||||
//int r;
|
||||
//uint8_t code;
|
||||
if(scp->state != SSH_SCP_WRITE_WRITING){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_write called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(scp->processed + len > scp->filelen)
|
||||
len = scp->filelen - scp->processed;
|
||||
/* hack to avoid waiting for window change */
|
||||
channel_poll(scp->channel,0);
|
||||
w=channel_write(scp->channel,buffer,len);
|
||||
if(w != SSH_ERROR)
|
||||
scp->processed += w;
|
||||
else {
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
//return=channel_get_exit_status(scp->channel);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
/* Check if we arrived at end of file */
|
||||
if(scp->processed == scp->filelen) {
|
||||
/* r=channel_read(scp->channel,&code,1,0);
|
||||
if(r==SSH_ERROR){
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(code != 0){
|
||||
ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
*/
|
||||
scp->processed=scp->filelen=0;
|
||||
scp->state=SSH_SCP_WRITE_INITED;
|
||||
}
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief reads a string on a channel, terminated by '\n'
|
||||
* @param buffer pointer to a buffer to place the string
|
||||
* @param len size of the buffer in bytes. If the string is bigger
|
||||
* than len-1, only len-1 bytes are read and the string
|
||||
* is null-terminated.
|
||||
* @returns SSH_OK The string was read
|
||||
* @returns SSH_ERROR Error happened while reading
|
||||
*/
|
||||
int ssh_scp_read_string(ssh_scp scp, char *buffer, size_t len){
|
||||
size_t r=0;
|
||||
int err=SSH_OK;
|
||||
while(r<len-1){
|
||||
err=channel_read(scp->channel,&buffer[r],1,0);
|
||||
if(err==SSH_ERROR){
|
||||
break;
|
||||
}
|
||||
if(err==0){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"End of file while reading string");
|
||||
err=SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
r++;
|
||||
if(buffer[r-1] == '\n')
|
||||
break;
|
||||
}
|
||||
buffer[r]=0;
|
||||
return err;
|
||||
}
|
||||
|
||||
/** @brief waits for a scp request (file, directory)
|
||||
* @returns SSH_ERROR Some error happened
|
||||
* @returns SSH_SCP_REQUEST_NEWFILE The other side is sending a file
|
||||
* @returns SSH_SCP_REQUEST_NEWDIRECTORY The other side is sending a directory
|
||||
* @returns SSH_SCP_REQUEST_END_DIRECTORY The other side has finished with the current directory
|
||||
* @see ssh_scp_read
|
||||
* @see ssh_scp_deny_request
|
||||
* @see ssh_scp_accept_request
|
||||
*/
|
||||
int ssh_scp_pull_request(ssh_scp scp){
|
||||
char buffer[4096];
|
||||
char *mode=NULL;
|
||||
char *p,*tmp;
|
||||
size_t size;
|
||||
char *name=NULL;
|
||||
int err;
|
||||
if(scp->state != SSH_SCP_READ_INITED){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_pull_request called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
err=ssh_scp_read_string(scp,buffer,sizeof(buffer));
|
||||
if(err==SSH_ERROR){
|
||||
if(channel_is_eof(scp->channel)){
|
||||
scp->state=SSH_SCP_TERMINATED;
|
||||
return SSH_SCP_REQUEST_EOF;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
p=strchr(buffer,'\n');
|
||||
if(p!=NULL)
|
||||
*p='\0';
|
||||
ssh_log(scp->session,SSH_LOG_PROTOCOL,"Received SCP request: '%s'",buffer);
|
||||
switch(buffer[0]){
|
||||
case 'C':
|
||||
/* File */
|
||||
case 'D':
|
||||
/* Directory */
|
||||
p=strchr(buffer,' ');
|
||||
if(p==NULL)
|
||||
goto error;
|
||||
*p='\0';
|
||||
p++;
|
||||
//mode=strdup(&buffer[1]);
|
||||
scp->request_mode=ssh_scp_integer_mode(&buffer[1]);
|
||||
tmp=p;
|
||||
p=strchr(p,' ');
|
||||
if(p==NULL)
|
||||
goto error;
|
||||
*p=0;
|
||||
size=strtoull(tmp,NULL,10);
|
||||
p++;
|
||||
name=strdup(p);
|
||||
SAFE_FREE(scp->request_name);
|
||||
scp->request_name=name;
|
||||
if(buffer[0]=='C'){
|
||||
scp->filelen=size;
|
||||
scp->request_type=SSH_SCP_REQUEST_NEWFILE;
|
||||
} else {
|
||||
scp->filelen='0';
|
||||
scp->request_type=SSH_SCP_REQUEST_NEWDIR;
|
||||
}
|
||||
scp->state=SSH_SCP_READ_REQUESTED;
|
||||
scp->processed = 0;
|
||||
return scp->request_type;
|
||||
break;
|
||||
case 'E':
|
||||
scp->request_type=SSH_SCP_REQUEST_ENDDIR;
|
||||
channel_write(scp->channel,"",1);
|
||||
return scp->request_type;
|
||||
case 0x1:
|
||||
ssh_set_error(scp->session,SSH_REQUEST_DENIED,"SCP: Warning: %s",&buffer[1]);
|
||||
scp->request_type=SSH_SCP_REQUEST_WARNING;
|
||||
SAFE_FREE(scp->warning);
|
||||
scp->warning=strdup(&buffer[1]);
|
||||
return scp->request_type;
|
||||
case 0x2:
|
||||
ssh_set_error(scp->session,SSH_FATAL,"SCP: Error: %s",&buffer[1]);
|
||||
return SSH_ERROR;
|
||||
case 'T':
|
||||
/* Timestamp */
|
||||
default:
|
||||
ssh_set_error(scp->session,SSH_FATAL,"Unhandled message: (%d)%s",buffer[0],buffer);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* a parsing error occured */
|
||||
error:
|
||||
SAFE_FREE(name);
|
||||
SAFE_FREE(mode);
|
||||
ssh_set_error(scp->session,SSH_FATAL,"Parsing error while parsing message: %s",buffer);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief denies the transfer of a file or creation of a directory
|
||||
* coming from the remote party
|
||||
* @param reason nul-terminated string with a human-readable explanation
|
||||
* of the deny
|
||||
* @returns SSH_OK the message was sent
|
||||
* @returns SSH_ERROR Error sending the message, or sending it in a bad state
|
||||
*/
|
||||
int ssh_scp_deny_request(ssh_scp scp, const char *reason){
|
||||
char buffer[4096];
|
||||
int err;
|
||||
if(scp->state != SSH_SCP_READ_REQUESTED){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_deny_request called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
snprintf(buffer,sizeof(buffer),"%c%s\n",2,reason);
|
||||
err=channel_write(scp->channel,buffer,strlen(buffer));
|
||||
if(err==SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
else {
|
||||
scp->state=SSH_SCP_READ_INITED;
|
||||
return SSH_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief accepts transfer of a file or creation of a directory
|
||||
* coming from the remote party
|
||||
* @returns SSH_OK the message was sent
|
||||
* @returns SSH_ERROR Error sending the message, or sending it in a bad state
|
||||
*/
|
||||
int ssh_scp_accept_request(ssh_scp scp){
|
||||
char buffer[]={0x00};
|
||||
int err;
|
||||
if(scp->state != SSH_SCP_READ_REQUESTED){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_deny_request called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
err=channel_write(scp->channel,buffer,1);
|
||||
if(err==SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(scp->request_type==SSH_SCP_REQUEST_NEWFILE)
|
||||
scp->state=SSH_SCP_READ_READING;
|
||||
else
|
||||
scp->state=SSH_SCP_READ_INITED;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @brief Read from a remote scp file
|
||||
* @param buffer Destination buffer
|
||||
* @param size Size of the buffer
|
||||
* @returns Number of bytes read
|
||||
* @returns SSH_ERROR An error happened while reading
|
||||
*/
|
||||
int ssh_scp_read(ssh_scp scp, void *buffer, size_t size){
|
||||
int r;
|
||||
int code;
|
||||
if(scp->state == SSH_SCP_READ_REQUESTED && scp->request_type == SSH_SCP_REQUEST_NEWFILE){
|
||||
r=ssh_scp_accept_request(scp);
|
||||
if(r==SSH_ERROR)
|
||||
return r;
|
||||
}
|
||||
if(scp->state != SSH_SCP_READ_READING){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_read called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(scp->processed + size > scp->filelen)
|
||||
size = scp->filelen - scp->processed;
|
||||
if(size > 65536)
|
||||
size=65536; /* avoid too large reads */
|
||||
r=channel_read(scp->channel,buffer,size,0);
|
||||
if(r != SSH_ERROR)
|
||||
scp->processed += r;
|
||||
else {
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
/* Check if we arrived at end of file */
|
||||
if(scp->processed == scp->filelen) {
|
||||
scp->processed=scp->filelen=0;
|
||||
channel_write(scp->channel,"",1);
|
||||
code=ssh_scp_response(scp,NULL);
|
||||
if(code == 0){
|
||||
scp->state=SSH_SCP_READ_INITED;
|
||||
return r;
|
||||
}
|
||||
if(code==1){
|
||||
scp->state=SSH_SCP_READ_INITED;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
scp->state=SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/** @brief Gets the name of the directory or file being
|
||||
* pushed from the other party
|
||||
* @returns file name. Should not be freed.
|
||||
*/
|
||||
const char *ssh_scp_request_get_filename(ssh_scp scp){
|
||||
return scp->request_name;
|
||||
}
|
||||
|
||||
/**@brief Gets the permissions of the directory or file being
|
||||
* pushed from the other party
|
||||
* @returns Unix permission, e.g 0644.
|
||||
*/
|
||||
int ssh_scp_request_get_permissions(ssh_scp scp){
|
||||
return scp->request_mode;
|
||||
}
|
||||
|
||||
/** @brief Gets the size of the file being pushed
|
||||
* from the other party
|
||||
* @returns Numeric size of the file being read.
|
||||
*/
|
||||
size_t ssh_scp_request_get_size(ssh_scp scp){
|
||||
return scp->filelen;
|
||||
}
|
||||
|
||||
/** @brief Converts a scp text mode to an integer one
|
||||
* @param mode mode to convert, e.g. "0644"
|
||||
* @returns integer value, e.g. 420 for "0644"
|
||||
*/
|
||||
int ssh_scp_integer_mode(const char *mode){
|
||||
int value=strtoul(mode,NULL,8) & 0xffff;
|
||||
return value;
|
||||
}
|
||||
|
||||
/** @brief Converts a unix mode into a scp string one.
|
||||
* @param mode mode to convert, e.g. 420 or 0644
|
||||
* @retuns pointer to a malloc'ed string containing the scp mode,
|
||||
* e.g. "0644".
|
||||
*/
|
||||
char *ssh_scp_string_mode(int mode){
|
||||
char buffer[16];
|
||||
snprintf(buffer,sizeof(buffer),"%.4o",mode);
|
||||
return strdup(buffer);
|
||||
}
|
||||
|
||||
/** @brief Gets the warning string
|
||||
* @returns Warning string. Should not be freed.
|
||||
*/
|
||||
|
||||
const char *ssh_scp_request_get_warning(ssh_scp scp){
|
||||
return scp->warning;
|
||||
}
|
||||
590
libssh/server.c
590
libssh/server.c
@@ -27,17 +27,28 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/server.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/keyfiles.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/channels.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/keys.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/messages.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
@@ -45,7 +56,7 @@
|
||||
#define SOCKOPT_TYPE_ARG4 char
|
||||
|
||||
/* We need to provide hstrerror. Not we can't call the parameter h_errno because it's #defined */
|
||||
inline char *hstrerror(int h_errno_val) {
|
||||
static char *hstrerror(int h_errno_val) {
|
||||
static char text[50] = {0};
|
||||
|
||||
snprintf(text, sizeof(text), "gethostbyname error %d\n", h_errno_val);
|
||||
@@ -62,7 +73,7 @@ inline char *hstrerror(int h_errno_val) {
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/* TODO FIXME: must use getaddrinfo */
|
||||
static socket_t bind_socket(SSH_BIND *ssh_bind, const char *hostname,
|
||||
static socket_t bind_socket(ssh_bind sshbind, const char *hostname,
|
||||
int port) {
|
||||
struct sockaddr_in myaddr;
|
||||
struct hostent *hp=NULL;
|
||||
@@ -71,7 +82,7 @@ static socket_t bind_socket(SSH_BIND *ssh_bind, const char *hostname,
|
||||
|
||||
s = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (s < 0) {
|
||||
ssh_set_error(ssh_bind, SSH_FATAL, "%s", strerror(errno));
|
||||
ssh_set_error(sshbind, SSH_FATAL, "%s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -80,7 +91,7 @@ static socket_t bind_socket(SSH_BIND *ssh_bind, const char *hostname,
|
||||
#endif
|
||||
|
||||
if (hp == NULL) {
|
||||
ssh_set_error(ssh_bind, SSH_FATAL,
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"Resolving %s: %s", hostname, hstrerror(h_errno));
|
||||
close(s);
|
||||
return -1;
|
||||
@@ -92,14 +103,14 @@ static socket_t bind_socket(SSH_BIND *ssh_bind, const char *hostname,
|
||||
myaddr.sin_port = htons(port);
|
||||
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0) {
|
||||
ssh_set_error(ssh_bind, SSH_FATAL,
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"Setting socket options failed: %s", hstrerror(h_errno));
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *) &myaddr, sizeof(myaddr)) < 0) {
|
||||
ssh_set_error(ssh_bind, SSH_FATAL, "Binding to %s:%d: %s",
|
||||
ssh_set_error(sshbind, SSH_FATAL, "Binding to %s:%d: %s",
|
||||
hostname,
|
||||
port,
|
||||
strerror(errno));
|
||||
@@ -110,48 +121,42 @@ static socket_t bind_socket(SSH_BIND *ssh_bind, const char *hostname,
|
||||
return s;
|
||||
}
|
||||
|
||||
SSH_BIND *ssh_bind_new(void) {
|
||||
SSH_BIND *ptr;
|
||||
ssh_bind ssh_bind_new(void) {
|
||||
ssh_bind ptr;
|
||||
|
||||
ptr = malloc(sizeof(SSH_BIND));
|
||||
ptr = malloc(sizeof(struct ssh_bind_struct));
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ZERO_STRUCTP(ptr);
|
||||
ptr->bindfd = -1;
|
||||
ptr->bindport= 22;
|
||||
ptr->log_verbosity = 0;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void ssh_bind_set_options(SSH_BIND *ssh_bind, SSH_OPTIONS *options) {
|
||||
ssh_bind->options = options;
|
||||
}
|
||||
|
||||
int ssh_bind_listen(SSH_BIND *ssh_bind) {
|
||||
int ssh_bind_listen(ssh_bind sshbind) {
|
||||
const char *host;
|
||||
int fd;
|
||||
|
||||
if (ssh_bind->options == NULL) {
|
||||
if (ssh_init() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ssh_socket_init() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
host = ssh_bind->options->bindaddr;
|
||||
host = sshbind->bindaddr;
|
||||
if (host == NULL) {
|
||||
host = "0.0.0.0";
|
||||
}
|
||||
|
||||
fd = bind_socket(ssh_bind, host, ssh_bind->options->bindport);
|
||||
fd = bind_socket(sshbind, host, sshbind->bindport);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
ssh_bind->bindfd = fd;
|
||||
sshbind->bindfd = fd;
|
||||
|
||||
if (listen(fd, 10) < 0) {
|
||||
ssh_set_error(ssh_bind, SSH_FATAL,
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"Listening to socket %d: %s",
|
||||
fd, strerror(errno));
|
||||
close(fd);
|
||||
@@ -161,143 +166,169 @@ int ssh_bind_listen(SSH_BIND *ssh_bind) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ssh_bind_set_blocking(SSH_BIND *ssh_bind, int blocking) {
|
||||
ssh_bind->blocking = blocking ? 1 : 0;
|
||||
void ssh_bind_set_blocking(ssh_bind sshbind, int blocking) {
|
||||
sshbind->blocking = blocking ? 1 : 0;
|
||||
}
|
||||
|
||||
socket_t ssh_bind_get_fd(SSH_BIND *ssh_bind) {
|
||||
return ssh_bind->bindfd;
|
||||
socket_t ssh_bind_get_fd(ssh_bind sshbind) {
|
||||
return sshbind->bindfd;
|
||||
}
|
||||
|
||||
void ssh_bind_set_fd(SSH_BIND *ssh_bind, socket_t fd) {
|
||||
ssh_bind->bindfd = fd;
|
||||
void ssh_bind_set_fd(ssh_bind sshbind, socket_t fd) {
|
||||
sshbind->bindfd = fd;
|
||||
}
|
||||
|
||||
void ssh_bind_fd_toaccept(SSH_BIND *ssh_bind) {
|
||||
ssh_bind->toaccept = 1;
|
||||
void ssh_bind_fd_toaccept(ssh_bind sshbind) {
|
||||
sshbind->toaccept = 1;
|
||||
}
|
||||
|
||||
SSH_SESSION *ssh_bind_accept(SSH_BIND *ssh_bind) {
|
||||
SSH_SESSION *session;
|
||||
PRIVATE_KEY *dsa = NULL;
|
||||
PRIVATE_KEY *rsa = NULL;
|
||||
int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
|
||||
ssh_private_key dsa = NULL;
|
||||
ssh_private_key rsa = NULL;
|
||||
int fd = -1;
|
||||
int i;
|
||||
|
||||
if (ssh_bind->bindfd < 0) {
|
||||
ssh_set_error(ssh_bind, SSH_FATAL,
|
||||
if (sshbind->bindfd < 0) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"Can't accept new clients on a not bound socket.");
|
||||
return NULL;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (ssh_bind->options->dsakey == NULL || ssh_bind->options->rsakey == NULL) {
|
||||
ssh_set_error(ssh_bind, SSH_FATAL,
|
||||
if(session == NULL){
|
||||
ssh_set_error(sshbind, SSH_FATAL,"session is null");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (sshbind->dsakey == NULL && sshbind->rsakey == NULL) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"DSA or RSA host key file must be set before accept()");
|
||||
return NULL;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (ssh_bind->options->dsakey) {
|
||||
dsa = _privatekey_from_file(ssh_bind, ssh_bind->options->dsakey, TYPE_DSS);
|
||||
if (sshbind->dsakey) {
|
||||
dsa = _privatekey_from_file(sshbind, sshbind->dsakey, TYPE_DSS);
|
||||
if (dsa == NULL) {
|
||||
return NULL;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (ssh_bind->options->rsakey) {
|
||||
rsa = _privatekey_from_file(ssh_bind, ssh_bind->options->rsakey, TYPE_RSA);
|
||||
if (sshbind->rsakey) {
|
||||
rsa = _privatekey_from_file(sshbind, sshbind->rsakey, TYPE_RSA);
|
||||
if (rsa == NULL) {
|
||||
privatekey_free(dsa);
|
||||
return NULL;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
fd = accept(ssh_bind->bindfd, NULL, NULL);
|
||||
fd = accept(sshbind->bindfd, NULL, NULL);
|
||||
if (fd < 0) {
|
||||
ssh_set_error(ssh_bind, SSH_FATAL,
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"Accepting a new connection: %s",
|
||||
strerror(errno));
|
||||
privatekey_free(dsa);
|
||||
privatekey_free(rsa);
|
||||
return NULL;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
session = ssh_new();
|
||||
if (session == NULL) {
|
||||
ssh_set_error(ssh_bind, SSH_FATAL, "Not enough space");
|
||||
privatekey_free(dsa);
|
||||
privatekey_free(rsa);
|
||||
return NULL;
|
||||
}
|
||||
session->server = 1;
|
||||
session->version = 2;
|
||||
session->options = ssh_options_copy(ssh_bind->options);
|
||||
if (session->options == NULL) {
|
||||
ssh_set_error(ssh_bind, SSH_FATAL, "No space left");
|
||||
privatekey_free(dsa);
|
||||
privatekey_free(rsa);
|
||||
ssh_cleanup(session);
|
||||
return NULL;
|
||||
|
||||
/* copy options */
|
||||
for (i = 0; i < 10; ++i) {
|
||||
if (sshbind->wanted_methods[i]) {
|
||||
session->wanted_methods[i] = strdup(sshbind->wanted_methods[i]);
|
||||
if (session->wanted_methods[i] == NULL) {
|
||||
privatekey_free(dsa);
|
||||
privatekey_free(rsa);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sshbind->bindaddr == NULL)
|
||||
session->bindaddr = NULL;
|
||||
else {
|
||||
session->bindaddr = strdup(sshbind->bindaddr);
|
||||
if (session->bindaddr == NULL) {
|
||||
privatekey_free(dsa);
|
||||
privatekey_free(rsa);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
session->log_verbosity = sshbind->log_verbosity;
|
||||
|
||||
ssh_socket_free(session->socket);
|
||||
session->socket = ssh_socket_new(session);
|
||||
if (session->socket == NULL) {
|
||||
privatekey_free(dsa);
|
||||
privatekey_free(rsa);
|
||||
ssh_cleanup(session);
|
||||
return NULL;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
ssh_socket_set_fd(session->socket,fd);
|
||||
ssh_socket_set_fd(session->socket, fd);
|
||||
session->dsa_key = dsa;
|
||||
session->rsa_key = rsa;
|
||||
|
||||
return session;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
void ssh_bind_free(SSH_BIND *ssh_bind){
|
||||
if (ssh_bind == NULL) {
|
||||
void ssh_bind_free(ssh_bind sshbind){
|
||||
int i;
|
||||
|
||||
if (sshbind == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ssh_bind->bindfd >= 0) {
|
||||
close(ssh_bind->bindfd);
|
||||
if (sshbind->bindfd >= 0) {
|
||||
#ifdef _WIN32
|
||||
closesocket(sshbind->bindfd);
|
||||
#else
|
||||
close(sshbind->bindfd);
|
||||
#endif
|
||||
}
|
||||
ssh_bind->bindfd = -1;
|
||||
if (ssh_bind->options) {
|
||||
ssh_options_free(ssh_bind->options);
|
||||
sshbind->bindfd = -1;
|
||||
|
||||
/* options */
|
||||
SAFE_FREE(sshbind->banner);
|
||||
SAFE_FREE(sshbind->dsakey);
|
||||
SAFE_FREE(sshbind->rsakey);
|
||||
SAFE_FREE(sshbind->bindaddr);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (sshbind->wanted_methods[i]) {
|
||||
SAFE_FREE(sshbind->wanted_methods[i]);
|
||||
}
|
||||
}
|
||||
SAFE_FREE(ssh_bind);
|
||||
|
||||
SAFE_FREE(sshbind);
|
||||
}
|
||||
|
||||
extern char *supported_methods[];
|
||||
/** @internal
|
||||
* This functions sets the Key Exchange protocols to be accepted
|
||||
* by the server. They depend on
|
||||
* -What the user asked (via options)
|
||||
* -What is available (keys)
|
||||
* It should then accept the intersection of what the user asked
|
||||
* and what is available, and return an error if nothing matches
|
||||
*/
|
||||
|
||||
static int server_set_kex(SSH_SESSION * session) {
|
||||
static int server_set_kex(ssh_session session) {
|
||||
KEX *server = &session->server_kex;
|
||||
SSH_OPTIONS *options = session->options;
|
||||
int i, j;
|
||||
char *wanted;
|
||||
|
||||
ZERO_STRUCTP(server);
|
||||
/*
|
||||
* The program might ask for a specific cookie to be sent. Useful for server
|
||||
* debugging
|
||||
*/
|
||||
if (options->wanted_cookie) {
|
||||
memcpy(server->cookie, options->wanted_cookie, 16);
|
||||
} else {
|
||||
ssh_get_random(server->cookie, 16, 0);
|
||||
}
|
||||
|
||||
ssh_get_random(server->cookie, 16, 0);
|
||||
if (session->dsa_key != NULL && session->rsa_key != NULL) {
|
||||
if (ssh_options_set_wanted_algos(options, SSH_HOSTKEYS,
|
||||
if (ssh_options_set_algo(session, SSH_HOSTKEYS,
|
||||
"ssh-dss,ssh-rsa") < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if (session->dsa_key != NULL) {
|
||||
if (ssh_options_set_wanted_algos(options, SSH_HOSTKEYS, "ssh-dss") < 0) {
|
||||
if (ssh_options_set_algo(session, SSH_HOSTKEYS, "ssh-dss") < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (ssh_options_set_wanted_algos(options, SSH_HOSTKEYS, "ssh-rsa") < 0) {
|
||||
if (ssh_options_set_algo(session, SSH_HOSTKEYS, "ssh-rsa") < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -308,7 +339,7 @@ static int server_set_kex(SSH_SESSION * session) {
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if ((wanted = options->wanted_methods[i]) == NULL) {
|
||||
if ((wanted = session->wanted_methods[i]) == NULL) {
|
||||
wanted = supported_methods[i];
|
||||
}
|
||||
server->methods[i] = strdup(wanted);
|
||||
@@ -324,13 +355,13 @@ static int server_set_kex(SSH_SESSION * session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dh_handshake_server(SSH_SESSION *session) {
|
||||
STRING *e;
|
||||
STRING *f;
|
||||
STRING *pubkey;
|
||||
STRING *sign;
|
||||
PUBLIC_KEY *pub;
|
||||
PRIVATE_KEY *prv;
|
||||
static int dh_handshake_server(ssh_session session) {
|
||||
ssh_string e;
|
||||
ssh_string f;
|
||||
ssh_string pubkey;
|
||||
ssh_string sign;
|
||||
ssh_public_key pub;
|
||||
ssh_private_key prv;
|
||||
|
||||
if (packet_wait(session, SSH2_MSG_KEXDH_INIT, 1) != SSH_OK) {
|
||||
return -1;
|
||||
@@ -424,7 +455,7 @@ static int dh_handshake_server(SSH_SESSION *session) {
|
||||
buffer_add_ssh_string(session->out_buffer, f) < 0 ||
|
||||
buffer_add_ssh_string(session->out_buffer, sign) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Not enough space");
|
||||
buffer_free(session->out_buffer);
|
||||
buffer_reinit(session->out_buffer);
|
||||
string_free(f);
|
||||
string_free(sign);
|
||||
return -1;
|
||||
@@ -437,7 +468,7 @@ static int dh_handshake_server(SSH_SESSION *session) {
|
||||
}
|
||||
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||
buffer_free(session->out_buffer);
|
||||
buffer_reinit(session->out_buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -474,15 +505,11 @@ static int dh_handshake_server(SSH_SESSION *session) {
|
||||
}
|
||||
|
||||
/* Do the banner and key exchange */
|
||||
int ssh_accept(SSH_SESSION *session) {
|
||||
int ssh_accept(ssh_session session) {
|
||||
if (ssh_send_banner(session, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ssh_crypto_init() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
session->alive = 1;
|
||||
|
||||
session->clientbanner = ssh_get_banner(session);
|
||||
@@ -514,6 +541,353 @@ int ssh_accept(SSH_SESSION *session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Blocking write on channel for stderr.
|
||||
*
|
||||
* @param channel The channel to write to.
|
||||
*
|
||||
* @param data A pointer to the data to write.
|
||||
*
|
||||
* @param len The length of the buffer to write to.
|
||||
*
|
||||
* @return The number of bytes written, SSH_ERROR on error.
|
||||
*
|
||||
* @see channel_read()
|
||||
*/
|
||||
int channel_write_stderr(ssh_channel channel, const void *data, uint32_t len) {
|
||||
return channel_write_common(channel, data, len, 1);
|
||||
}
|
||||
|
||||
/* messages */
|
||||
|
||||
static int ssh_message_auth_reply_default(ssh_message msg,int partial) {
|
||||
ssh_session session = msg->session;
|
||||
char methods_c[128] = {0};
|
||||
ssh_string methods = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
enter_function();
|
||||
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_FAILURE) < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (session->auth_methods == 0) {
|
||||
session->auth_methods = SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_PASSWORD;
|
||||
}
|
||||
if (session->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
|
||||
strcat(methods_c, "publickey,");
|
||||
}
|
||||
if (session->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
|
||||
strcat(methods_c, "keyboard-interactive,");
|
||||
}
|
||||
if (session->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
|
||||
strcat(methods_c, "password,");
|
||||
}
|
||||
if (session->auth_methods & SSH_AUTH_METHOD_HOSTBASED) {
|
||||
strcat(methods_c, "hostbased,");
|
||||
}
|
||||
|
||||
/* Strip the comma. */
|
||||
methods_c[strlen(methods_c) - 1] = '\0'; // strip the comma. We are sure there is at
|
||||
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"Sending a auth failure. methods that can continue: %s", methods_c);
|
||||
|
||||
methods = string_from_char(methods_c);
|
||||
if (methods == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (buffer_add_ssh_string(msg->session->out_buffer, methods) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (partial) {
|
||||
if (buffer_add_u8(session->out_buffer, 1) < 0) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (buffer_add_u8(session->out_buffer, 0) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
rc = packet_send(msg->session);
|
||||
error:
|
||||
string_free(methods);
|
||||
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ssh_message_channel_request_open_reply_default(ssh_message msg) {
|
||||
ssh_log(msg->session, SSH_LOG_FUNCTIONS, "Refusing a channel");
|
||||
|
||||
if (buffer_add_u8(msg->session->out_buffer
|
||||
, SSH2_MSG_CHANNEL_OPEN_FAILURE) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (buffer_add_u32(msg->session->out_buffer,
|
||||
htonl(msg->channel_request_open.sender)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (buffer_add_u32(msg->session->out_buffer,
|
||||
htonl(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
/* reason is an empty string */
|
||||
if (buffer_add_u32(msg->session->out_buffer, 0) < 0) {
|
||||
goto error;
|
||||
}
|
||||
/* language too */
|
||||
if (buffer_add_u32(msg->session->out_buffer, 0) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return packet_send(msg->session);
|
||||
error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
static int ssh_message_channel_request_reply_default(ssh_message msg) {
|
||||
uint32_t channel;
|
||||
|
||||
if (msg->channel_request.want_reply) {
|
||||
channel = msg->channel_request.channel->remote_channel;
|
||||
|
||||
ssh_log(msg->session, SSH_LOG_PACKET,
|
||||
"Sending a default channel_request denied to channel %d", channel);
|
||||
|
||||
if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_CHANNEL_FAILURE) < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (buffer_add_u32(msg->session->out_buffer, htonl(channel)) < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return packet_send(msg->session);
|
||||
}
|
||||
|
||||
ssh_log(msg->session, SSH_LOG_PACKET,
|
||||
"The client doesn't want to know the request failed!");
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static int ssh_message_service_request_reply_default(ssh_message msg) {
|
||||
/* The only return code accepted by specifications are success or disconnect */
|
||||
return ssh_message_service_reply_success(msg);
|
||||
}
|
||||
|
||||
int ssh_message_service_reply_success(ssh_message msg) {
|
||||
struct ssh_string_struct *service;
|
||||
ssh_session session=msg->session;
|
||||
if (msg == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"Sending a SERVICE_ACCEPT for service %s", msg->service_request.service);
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_SERVICE_ACCEPT) < 0) {
|
||||
return -1;
|
||||
}
|
||||
service=string_from_char(msg->service_request.service);
|
||||
if (buffer_add_ssh_string(session->out_buffer, service) < 0) {
|
||||
string_free(service);
|
||||
return -1;
|
||||
}
|
||||
string_free(service);
|
||||
return packet_send(msg->session);
|
||||
}
|
||||
|
||||
int ssh_message_reply_default(ssh_message msg) {
|
||||
if (msg == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(msg->type) {
|
||||
case SSH_REQUEST_AUTH:
|
||||
return ssh_message_auth_reply_default(msg, 0);
|
||||
case SSH_REQUEST_CHANNEL_OPEN:
|
||||
return ssh_message_channel_request_open_reply_default(msg);
|
||||
case SSH_REQUEST_CHANNEL:
|
||||
return ssh_message_channel_request_reply_default(msg);
|
||||
case SSH_REQUEST_SERVICE:
|
||||
return ssh_message_service_request_reply_default(msg);
|
||||
default:
|
||||
ssh_log(msg->session, SSH_LOG_PACKET,
|
||||
"Don't know what to default reply to %d type",
|
||||
msg->type);
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *ssh_message_service_service(ssh_message msg){
|
||||
if (msg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return msg->service_request.service;
|
||||
}
|
||||
|
||||
char *ssh_message_auth_user(ssh_message msg) {
|
||||
if (msg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return msg->auth_request.username;
|
||||
}
|
||||
|
||||
char *ssh_message_auth_password(ssh_message msg){
|
||||
if (msg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return msg->auth_request.password;
|
||||
}
|
||||
|
||||
/* Get the publickey of an auth request */
|
||||
ssh_public_key ssh_message_auth_publickey(ssh_message msg){
|
||||
if (msg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return msg->auth_request.public_key;
|
||||
}
|
||||
|
||||
int ssh_message_auth_set_methods(ssh_message msg, int methods) {
|
||||
if (msg == NULL || msg->session == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg->session->auth_methods = methods;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ssh_message_auth_reply_success(ssh_message msg, int partial) {
|
||||
if (msg == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (partial) {
|
||||
return ssh_message_auth_reply_default(msg, partial);
|
||||
}
|
||||
|
||||
if (buffer_add_u8(msg->session->out_buffer,SSH2_MSG_USERAUTH_SUCCESS) < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return packet_send(msg->session);
|
||||
}
|
||||
|
||||
/* Answer OK to a pubkey auth request */
|
||||
int ssh_message_auth_reply_pk_ok(ssh_message msg, ssh_string algo, ssh_string pubkey) {
|
||||
if (msg == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_USERAUTH_PK_OK) < 0 ||
|
||||
buffer_add_ssh_string(msg->session->out_buffer, algo) < 0 ||
|
||||
buffer_add_ssh_string(msg->session->out_buffer, pubkey) < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return packet_send(msg->session);
|
||||
}
|
||||
|
||||
char *ssh_message_channel_request_open_originator(ssh_message msg){
|
||||
return msg->channel_request_open.originator;
|
||||
}
|
||||
|
||||
int ssh_message_channel_request_open_originator_port(ssh_message msg){
|
||||
return msg->channel_request_open.originator_port;
|
||||
}
|
||||
|
||||
char *ssh_message_channel_request_open_destination(ssh_message msg){
|
||||
return msg->channel_request_open.destination;
|
||||
}
|
||||
|
||||
int ssh_message_channel_request_open_destination_port(ssh_message msg){
|
||||
return msg->channel_request_open.destination_port;
|
||||
}
|
||||
|
||||
ssh_channel ssh_message_channel_request_channel(ssh_message msg){
|
||||
return msg->channel_request.channel;
|
||||
}
|
||||
|
||||
char *ssh_message_channel_request_pty_term(ssh_message msg){
|
||||
return msg->channel_request.TERM;
|
||||
}
|
||||
|
||||
int ssh_message_channel_request_pty_width(ssh_message msg){
|
||||
return msg->channel_request.width;
|
||||
}
|
||||
|
||||
int ssh_message_channel_request_pty_height(ssh_message msg){
|
||||
return msg->channel_request.height;
|
||||
}
|
||||
|
||||
int ssh_message_channel_request_pty_pxwidth(ssh_message msg){
|
||||
return msg->channel_request.pxwidth;
|
||||
}
|
||||
|
||||
int ssh_message_channel_request_pty_pxheight(ssh_message msg){
|
||||
return msg->channel_request.pxheight;
|
||||
}
|
||||
|
||||
char *ssh_message_channel_request_env_name(ssh_message msg){
|
||||
return msg->channel_request.var_name;
|
||||
}
|
||||
|
||||
char *ssh_message_channel_request_env_value(ssh_message msg){
|
||||
return msg->channel_request.var_value;
|
||||
}
|
||||
|
||||
char *ssh_message_channel_request_command(ssh_message msg){
|
||||
return msg->channel_request.command;
|
||||
}
|
||||
|
||||
char *ssh_message_channel_request_subsystem(ssh_message msg){
|
||||
return msg->channel_request.subsystem;
|
||||
}
|
||||
|
||||
/** @brief defines the SSH_MESSAGE callback
|
||||
* @param session the current ssh session
|
||||
* @param ssh_message_callback a function pointer to a callback taking the
|
||||
* current ssh session and received message as parameters. the function returns
|
||||
* 0 if the message has been parsed and treated sucessfuly, 1 otherwise (libssh
|
||||
* must take care of the response).
|
||||
*/
|
||||
void ssh_set_message_callback(ssh_session session,
|
||||
int(*ssh_message_callback)(ssh_session session, ssh_message msg)){
|
||||
session->ssh_message_callback=ssh_message_callback;
|
||||
}
|
||||
|
||||
int ssh_execute_message_callbacks(ssh_session session){
|
||||
ssh_message msg=NULL;
|
||||
int ret;
|
||||
if(!session->ssh_message_list)
|
||||
return SSH_OK;
|
||||
if(session->ssh_message_callback){
|
||||
while((msg=ssh_list_get_head(ssh_message , session->ssh_message_list)) != NULL){
|
||||
ret=session->ssh_message_callback(session,msg);
|
||||
if(ret==1){
|
||||
ret = ssh_message_reply_default(msg);
|
||||
if(ret != SSH_OK)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while((msg=ssh_list_get_head(ssh_message , session->ssh_message_list)) != NULL){
|
||||
ret = ssh_message_reply_default(msg);
|
||||
if(ret != SSH_OK)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return SSH_OK;
|
||||
}
|
||||
/** @}
|
||||
*/
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
|
||||
121
libssh/session.c
121
libssh/session.c
@@ -21,11 +21,18 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/server.h"
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/agent.h"
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
|
||||
#define FIRST_CHANNEL 42 // why not ? it helps to find bugs.
|
||||
|
||||
/** \defgroup ssh_session SSH Session
|
||||
@@ -37,32 +44,25 @@
|
||||
/** \brief creates a new ssh session
|
||||
* \returns new ssh_session pointer
|
||||
*/
|
||||
SSH_SESSION *ssh_new(void) {
|
||||
SSH_SESSION *session;
|
||||
ssh_session ssh_new(void) {
|
||||
ssh_session session;
|
||||
|
||||
session = malloc(sizeof (SSH_SESSION));
|
||||
session = malloc(sizeof (struct ssh_session_struct));
|
||||
if (session == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(session, 0, sizeof(SSH_SESSION));
|
||||
ZERO_STRUCTP(session);
|
||||
|
||||
session->next_crypto = crypto_new();
|
||||
if (session->next_crypto == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
session->maxchannel = FIRST_CHANNEL;
|
||||
session->socket = ssh_socket_new(session);
|
||||
if (session->socket == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
session->alive = 0;
|
||||
session->auth_methods = 0;
|
||||
session->blocking = 1;
|
||||
session->log_indent = 0;
|
||||
|
||||
session->out_buffer = buffer_new();
|
||||
if (session->out_buffer == NULL) {
|
||||
goto err;
|
||||
@@ -73,6 +73,22 @@ SSH_SESSION *ssh_new(void) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
session->alive = 0;
|
||||
session->auth_methods = 0;
|
||||
session->blocking = 1;
|
||||
session->log_indent = 0;
|
||||
session->maxchannel = FIRST_CHANNEL;
|
||||
|
||||
/* options */
|
||||
session->port = 22;
|
||||
session->fd = -1;
|
||||
session->ssh2 = 1;
|
||||
#ifdef WITH_SSH1
|
||||
session->ssh1 = 1;
|
||||
#else
|
||||
session->ssh1 = 0;
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
session->agent = agent_new(session);
|
||||
if (session->agent == NULL) {
|
||||
@@ -82,11 +98,16 @@ SSH_SESSION *ssh_new(void) {
|
||||
return session;
|
||||
|
||||
err:
|
||||
ssh_cleanup(session);
|
||||
ssh_free(session);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ssh_cleanup(SSH_SESSION *session) {
|
||||
/**
|
||||
* @brief deallocate a session handle
|
||||
* @see ssh_disconnect()
|
||||
* @see ssh_new()
|
||||
*/
|
||||
void ssh_free(ssh_session session) {
|
||||
int i;
|
||||
enter_function();
|
||||
|
||||
@@ -97,8 +118,15 @@ void ssh_cleanup(SSH_SESSION *session) {
|
||||
SAFE_FREE(session->serverbanner);
|
||||
SAFE_FREE(session->clientbanner);
|
||||
SAFE_FREE(session->banner);
|
||||
#ifdef WITH_PCAP
|
||||
if(session->pcap_ctx){
|
||||
ssh_pcap_context_free(session->pcap_ctx);
|
||||
session->pcap_ctx=NULL;
|
||||
}
|
||||
#endif
|
||||
buffer_free(session->in_buffer);
|
||||
buffer_free(session->out_buffer);
|
||||
session->in_buffer=session->out_buffer=NULL;
|
||||
crypto_free(session->current_crypto);
|
||||
crypto_free(session->next_crypto);
|
||||
ssh_socket_free(session->socket);
|
||||
@@ -125,20 +153,38 @@ void ssh_cleanup(SSH_SESSION *session) {
|
||||
|
||||
privatekey_free(session->dsa_key);
|
||||
privatekey_free(session->rsa_key);
|
||||
ssh_message_free(session->ssh_message);
|
||||
ssh_options_free(session->options);
|
||||
if(session->ssh_message_list){
|
||||
ssh_message msg;
|
||||
while((msg=ssh_list_get_head(ssh_message ,session->ssh_message_list))
|
||||
!= NULL){
|
||||
ssh_message_free(msg);
|
||||
}
|
||||
ssh_list_free(session->ssh_message_list);
|
||||
}
|
||||
|
||||
/* options */
|
||||
SAFE_FREE(session->username);
|
||||
SAFE_FREE(session->host);
|
||||
SAFE_FREE(session->identity);
|
||||
SAFE_FREE(session->sshdir);
|
||||
SAFE_FREE(session->knownhosts);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (session->wanted_methods[i]) {
|
||||
SAFE_FREE(session->wanted_methods[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* burn connection, it could hang sensitive datas */
|
||||
memset(session,'X',sizeof(SSH_SESSION));
|
||||
|
||||
ZERO_STRUCTP(session);
|
||||
SAFE_FREE(session);
|
||||
/* FIXME: leave_function(); ??? */
|
||||
}
|
||||
|
||||
/** \brief disconnect impolitely from remote host
|
||||
/** \brief disconnect impolitely from remote host by closing the socket.
|
||||
* Suitable if you forked and want to destroy this session.
|
||||
* \param session current ssh session
|
||||
*/
|
||||
void ssh_silent_disconnect(SSH_SESSION *session) {
|
||||
void ssh_silent_disconnect(ssh_session session) {
|
||||
enter_function();
|
||||
|
||||
if (session == NULL) {
|
||||
@@ -148,22 +194,7 @@ void ssh_silent_disconnect(SSH_SESSION *session) {
|
||||
ssh_socket_close(session->socket);
|
||||
session->alive = 0;
|
||||
ssh_disconnect(session);
|
||||
/* FIXME: leave_function(); ??? */
|
||||
}
|
||||
|
||||
/** \brief set the options for the current session
|
||||
* \param session ssh session
|
||||
* \param options options structure
|
||||
* \see ssh_new()
|
||||
* \see ssh_options_new()
|
||||
*/
|
||||
void ssh_set_options(SSH_SESSION *session, SSH_OPTIONS *options) {
|
||||
if (session == NULL || options == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
session->options = options;
|
||||
session->log_verbosity = options->log_verbosity;
|
||||
leave_function();
|
||||
}
|
||||
|
||||
/** \brief set the session in blocking/nonblocking mode
|
||||
@@ -171,7 +202,7 @@ void ssh_set_options(SSH_SESSION *session, SSH_OPTIONS *options) {
|
||||
* \param blocking zero for nonblocking mode
|
||||
* \bug nonblocking code is in development and won't work as expected
|
||||
*/
|
||||
void ssh_set_blocking(SSH_SESSION *session, int blocking) {
|
||||
void ssh_set_blocking(ssh_session session, int blocking) {
|
||||
if (session == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -186,7 +217,7 @@ void ssh_set_blocking(SSH_SESSION *session, int blocking) {
|
||||
* \return file descriptor of the connection, or -1 if it is
|
||||
* not connected
|
||||
*/
|
||||
socket_t ssh_get_fd(SSH_SESSION *session) {
|
||||
socket_t ssh_get_fd(ssh_session session) {
|
||||
if (session == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -197,7 +228,7 @@ socket_t ssh_get_fd(SSH_SESSION *session) {
|
||||
/** \brief say to the session it has data to read on the file descriptor without blocking
|
||||
* \param session ssh session
|
||||
*/
|
||||
void ssh_set_fd_toread(SSH_SESSION *session) {
|
||||
void ssh_set_fd_toread(ssh_session session) {
|
||||
if (session == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -208,7 +239,7 @@ void ssh_set_fd_toread(SSH_SESSION *session) {
|
||||
/** \brief say the session it may write to the file descriptor without blocking
|
||||
* \param session ssh session
|
||||
*/
|
||||
void ssh_set_fd_towrite(SSH_SESSION *session) {
|
||||
void ssh_set_fd_towrite(ssh_session session) {
|
||||
if (session == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -219,7 +250,7 @@ void ssh_set_fd_towrite(SSH_SESSION *session) {
|
||||
/** \brief say the session it has an exception to catch on the file descriptor
|
||||
* \param session ssh session
|
||||
*/
|
||||
void ssh_set_fd_except(SSH_SESSION *session) {
|
||||
void ssh_set_fd_except(ssh_session session) {
|
||||
if (session == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -230,7 +261,7 @@ void ssh_set_fd_except(SSH_SESSION *session) {
|
||||
/** \warning I don't remember if this should be internal or not
|
||||
*/
|
||||
/* looks if there is data to read on the socket and parse it. */
|
||||
int ssh_handle_packets(SSH_SESSION *session) {
|
||||
int ssh_handle_packets(ssh_session session) {
|
||||
int w = 0;
|
||||
int e = 0;
|
||||
int rc = -1;
|
||||
@@ -268,7 +299,7 @@ int ssh_handle_packets(SSH_SESSION *session) {
|
||||
* which respectively means the session is closed, has data to read on
|
||||
* the connection socket and session was closed due to an error.
|
||||
*/
|
||||
int ssh_get_status(SSH_SESSION *session) {
|
||||
int ssh_get_status(ssh_session session) {
|
||||
int socketstate;
|
||||
int r = 0;
|
||||
|
||||
@@ -296,7 +327,7 @@ int ssh_get_status(SSH_SESSION *session) {
|
||||
* \return message sent by the server along with the disconnect, or NULL in which case the reason of the disconnect may be found with ssh_get_error.
|
||||
* \see ssh_get_error()
|
||||
*/
|
||||
const char *ssh_get_disconnect_message(SSH_SESSION *session) {
|
||||
const char *ssh_get_disconnect_message(ssh_session session) {
|
||||
if (session == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -324,7 +355,7 @@ const char *ssh_get_disconnect_message(SSH_SESSION *session) {
|
||||
*
|
||||
* @return 1 or 2, for ssh1 or ssh2, < 0 on error.
|
||||
*/
|
||||
int ssh_get_version(SSH_SESSION *session) {
|
||||
int ssh_get_version(ssh_session session) {
|
||||
if (session == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
1340
libssh/sftp.c
1340
libssh/sftp.c
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,6 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
@@ -34,14 +33,16 @@
|
||||
#include "libssh/sftp.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/misc.h"
|
||||
|
||||
SFTP_CLIENT_MESSAGE *sftp_get_client_message(SFTP_SESSION *sftp) {
|
||||
SFTP_PACKET *packet;
|
||||
SFTP_CLIENT_MESSAGE *msg;
|
||||
BUFFER *payload;
|
||||
STRING *tmp;
|
||||
sftp_client_message sftp_get_client_message(sftp_session sftp) {
|
||||
sftp_packet packet;
|
||||
sftp_client_message msg;
|
||||
ssh_buffer payload;
|
||||
ssh_string tmp;
|
||||
|
||||
msg = malloc(sizeof (SFTP_CLIENT_MESSAGE));
|
||||
msg = malloc(sizeof (struct sftp_client_message_struct));
|
||||
if (msg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -212,7 +213,7 @@ SFTP_CLIENT_MESSAGE *sftp_get_client_message(SFTP_SESSION *sftp) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
void sftp_client_message_free(SFTP_CLIENT_MESSAGE *msg) {
|
||||
void sftp_client_message_free(sftp_client_message msg) {
|
||||
if (msg == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -226,10 +227,10 @@ void sftp_client_message_free(SFTP_CLIENT_MESSAGE *msg) {
|
||||
SAFE_FREE(msg);
|
||||
}
|
||||
|
||||
int sftp_reply_name(SFTP_CLIENT_MESSAGE *msg, const char *name,
|
||||
SFTP_ATTRIBUTES *attr) {
|
||||
BUFFER *out;
|
||||
STRING *file;
|
||||
int sftp_reply_name(sftp_client_message msg, const char *name,
|
||||
sftp_attributes attr) {
|
||||
ssh_buffer out;
|
||||
ssh_string file;
|
||||
|
||||
out = buffer_new();
|
||||
if (out == NULL) {
|
||||
@@ -258,8 +259,8 @@ int sftp_reply_name(SFTP_CLIENT_MESSAGE *msg, const char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sftp_reply_handle(SFTP_CLIENT_MESSAGE *msg, STRING *handle){
|
||||
BUFFER *out;
|
||||
int sftp_reply_handle(sftp_client_message msg, ssh_string handle){
|
||||
ssh_buffer out;
|
||||
|
||||
out = buffer_new();
|
||||
if (out == NULL) {
|
||||
@@ -277,8 +278,8 @@ int sftp_reply_handle(SFTP_CLIENT_MESSAGE *msg, STRING *handle){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sftp_reply_attr(SFTP_CLIENT_MESSAGE *msg, SFTP_ATTRIBUTES *attr) {
|
||||
BUFFER *out;
|
||||
int sftp_reply_attr(sftp_client_message msg, sftp_attributes attr) {
|
||||
ssh_buffer out;
|
||||
|
||||
out = buffer_new();
|
||||
if (out == NULL) {
|
||||
@@ -296,9 +297,9 @@ int sftp_reply_attr(SFTP_CLIENT_MESSAGE *msg, SFTP_ATTRIBUTES *attr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sftp_reply_names_add(SFTP_CLIENT_MESSAGE *msg, const char *file,
|
||||
const char *longname, SFTP_ATTRIBUTES *attr) {
|
||||
STRING *name;
|
||||
int sftp_reply_names_add(sftp_client_message msg, const char *file,
|
||||
const char *longname, sftp_attributes attr) {
|
||||
ssh_string name;
|
||||
|
||||
name = string_from_char(file);
|
||||
if (name == NULL) {
|
||||
@@ -334,8 +335,8 @@ int sftp_reply_names_add(SFTP_CLIENT_MESSAGE *msg, const char *file,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sftp_reply_names(SFTP_CLIENT_MESSAGE *msg) {
|
||||
BUFFER *out;
|
||||
int sftp_reply_names(sftp_client_message msg) {
|
||||
ssh_buffer out;
|
||||
|
||||
out = buffer_new();
|
||||
if (out == NULL) {
|
||||
@@ -362,10 +363,10 @@ int sftp_reply_names(SFTP_CLIENT_MESSAGE *msg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sftp_reply_status(SFTP_CLIENT_MESSAGE *msg, u32 status,
|
||||
int sftp_reply_status(sftp_client_message msg, uint32_t status,
|
||||
const char *message) {
|
||||
BUFFER *out;
|
||||
STRING *s;
|
||||
ssh_buffer out;
|
||||
ssh_string s;
|
||||
|
||||
out = buffer_new();
|
||||
if (out == NULL) {
|
||||
@@ -394,8 +395,8 @@ int sftp_reply_status(SFTP_CLIENT_MESSAGE *msg, u32 status,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sftp_reply_data(SFTP_CLIENT_MESSAGE *msg, const void *data, int len) {
|
||||
BUFFER *out;
|
||||
int sftp_reply_data(sftp_client_message msg, const void *data, int len) {
|
||||
ssh_buffer out;
|
||||
|
||||
out = buffer_new();
|
||||
if (out == NULL) {
|
||||
@@ -420,9 +421,9 @@ int sftp_reply_data(SFTP_CLIENT_MESSAGE *msg, const void *data, int len) {
|
||||
* the handle. Care is given that a corrupted handle won't give a
|
||||
* valid info (or worse).
|
||||
*/
|
||||
STRING *sftp_handle_alloc(SFTP_SESSION *sftp, void *info) {
|
||||
STRING *ret;
|
||||
u32 val;
|
||||
ssh_string sftp_handle_alloc(sftp_session sftp, void *info) {
|
||||
ssh_string ret;
|
||||
uint32_t val;
|
||||
int i;
|
||||
|
||||
if (sftp->handles == NULL) {
|
||||
@@ -449,24 +450,24 @@ STRING *sftp_handle_alloc(SFTP_SESSION *sftp, void *info) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(ret->string, &val, sizeof(u32));
|
||||
memcpy(string_data(ret), &val, sizeof(uint32_t));
|
||||
sftp->handles[i] = info;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *sftp_handle(SFTP_SESSION *sftp, STRING *handle){
|
||||
u32 val;
|
||||
void *sftp_handle(sftp_session sftp, ssh_string handle){
|
||||
uint32_t val;
|
||||
|
||||
if (sftp->handles == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (string_len(handle) != sizeof(u32)) {
|
||||
if (string_len(handle) != sizeof(uint32_t)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(&val, handle->string, sizeof(u32));
|
||||
memcpy(&val, string_data(handle), sizeof(uint32_t));
|
||||
|
||||
if (val > SFTP_HANDLES) {
|
||||
return NULL;
|
||||
@@ -475,7 +476,7 @@ void *sftp_handle(SFTP_SESSION *sftp, STRING *handle){
|
||||
return sftp->handles[val];
|
||||
}
|
||||
|
||||
void sftp_handle_remove(SFTP_SESSION *sftp, void *handle) {
|
||||
void sftp_handle_remove(sftp_session sftp, void *handle) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SFTP_HANDLES; i++) {
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@@ -35,6 +34,10 @@
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/poll.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
/** \defgroup ssh_socket SSH Sockets
|
||||
* \addtogroup ssh_socket
|
||||
@@ -48,9 +51,9 @@ struct socket {
|
||||
not block */
|
||||
int data_to_write;
|
||||
int data_except;
|
||||
BUFFER *out_buffer;
|
||||
BUFFER *in_buffer;
|
||||
SSH_SESSION *session;
|
||||
ssh_buffer out_buffer;
|
||||
ssh_buffer in_buffer;
|
||||
ssh_session session;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -72,7 +75,7 @@ int ssh_socket_init(void) {
|
||||
* \internal
|
||||
* \brief creates a new Socket object
|
||||
*/
|
||||
struct socket *ssh_socket_new(SSH_SESSION *session) {
|
||||
struct socket *ssh_socket_new(ssh_session session) {
|
||||
struct socket *s;
|
||||
|
||||
s = malloc(sizeof(struct socket));
|
||||
@@ -182,7 +185,7 @@ int ssh_socket_is_open(struct socket *s) {
|
||||
/* \internal
|
||||
* \brief read len bytes from socket into buffer
|
||||
*/
|
||||
static int ssh_socket_unbuffered_read(struct socket *s, void *buffer, u32 len) {
|
||||
static int ssh_socket_unbuffered_read(struct socket *s, void *buffer, uint32_t len) {
|
||||
int rc = -1;
|
||||
|
||||
if (s->data_except) {
|
||||
@@ -208,7 +211,7 @@ static int ssh_socket_unbuffered_read(struct socket *s, void *buffer, u32 len) {
|
||||
* \brief writes len bytes from buffer to socket
|
||||
*/
|
||||
static int ssh_socket_unbuffered_write(struct socket *s, const void *buffer,
|
||||
u32 len) {
|
||||
uint32_t len) {
|
||||
int w = -1;
|
||||
|
||||
if (s->data_except) {
|
||||
@@ -256,15 +259,15 @@ void ssh_socket_fd_set(struct socket *s, fd_set *set, int *fd_max) {
|
||||
/** \internal
|
||||
* \brief reads blocking until len bytes have been read
|
||||
*/
|
||||
int ssh_socket_completeread(struct socket *s, void *buffer, u32 len) {
|
||||
int ssh_socket_completeread(struct socket *s, void *buffer, uint32_t len) {
|
||||
int r = -1;
|
||||
u32 total = 0;
|
||||
u32 toread = len;
|
||||
uint32_t total = 0;
|
||||
uint32_t toread = len;
|
||||
if(! ssh_socket_is_open(s)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
while((r = ssh_socket_unbuffered_read(s, buffer + total, toread))) {
|
||||
while((r = ssh_socket_unbuffered_read(s, ((uint8_t*)buffer + total), toread))) {
|
||||
if (r < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -285,8 +288,8 @@ int ssh_socket_completeread(struct socket *s, void *buffer, u32 len) {
|
||||
/** \internal
|
||||
* \brief Blocking write of len bytes
|
||||
*/
|
||||
int ssh_socket_completewrite(struct socket *s, const void *buffer, u32 len) {
|
||||
SSH_SESSION *session = s->session;
|
||||
int ssh_socket_completewrite(struct socket *s, const void *buffer, uint32_t len) {
|
||||
ssh_session session = s->session;
|
||||
int written = -1;
|
||||
|
||||
enter_function();
|
||||
@@ -303,7 +306,7 @@ int ssh_socket_completewrite(struct socket *s, const void *buffer, u32 len) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
len -= written;
|
||||
buffer += written;
|
||||
buffer = ((uint8_t*)buffer + written);
|
||||
}
|
||||
|
||||
leave_function();
|
||||
@@ -316,7 +319,7 @@ int ssh_socket_completewrite(struct socket *s, const void *buffer, u32 len) {
|
||||
* \returns SSH_AGAIN in nonblocking mode
|
||||
*/
|
||||
int ssh_socket_read(struct socket *s, void *buffer, int len){
|
||||
SSH_SESSION *session = s->session;
|
||||
ssh_session session = s->session;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
enter_function();
|
||||
@@ -341,7 +344,7 @@ int ssh_socket_read(struct socket *s, void *buffer, int len){
|
||||
* \warning has no effect on socket before a flush
|
||||
*/
|
||||
int ssh_socket_write(struct socket *s, const void *buffer, int len) {
|
||||
SSH_SESSION *session = s->session;
|
||||
ssh_session session = s->session;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
enter_function();
|
||||
@@ -370,7 +373,7 @@ int ssh_socket_write(struct socket *s, const void *buffer, int len) {
|
||||
* \returns SSH_AGAIN need to call later for data
|
||||
* \returns SSH_ERROR error happened
|
||||
*/
|
||||
int ssh_socket_wait_for_data(struct socket *s, SSH_SESSION *session, u32 len) {
|
||||
int ssh_socket_wait_for_data(struct socket *s, ssh_session session, uint32_t len) {
|
||||
char buffer[4096] = {0};
|
||||
char *buf = NULL;
|
||||
int except;
|
||||
@@ -446,7 +449,7 @@ int ssh_socket_wait_for_data(struct socket *s, SSH_SESSION *session, u32 len) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (buffer_add_data(s->in_buffer,buffer, (u32) r) < 0) {
|
||||
if (buffer_add_data(s->in_buffer,buffer, (uint32_t) r) < 0) {
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -458,8 +461,8 @@ int ssh_socket_wait_for_data(struct socket *s, SSH_SESSION *session, u32 len) {
|
||||
|
||||
/* ssh_socket_poll */
|
||||
int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
|
||||
SSH_SESSION *session = s->session;
|
||||
pollfd_t fd[1];
|
||||
ssh_session session = s->session;
|
||||
ssh_pollfd_t fd[1];
|
||||
int rc = -1;
|
||||
|
||||
enter_function();
|
||||
@@ -509,7 +512,7 @@ int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
|
||||
* \brief nonblocking flush of the output buffer
|
||||
*/
|
||||
int ssh_socket_nonblocking_flush(struct socket *s) {
|
||||
SSH_SESSION *session = s->session;
|
||||
ssh_session session = s->session;
|
||||
int except;
|
||||
int can_write;
|
||||
int w;
|
||||
@@ -578,7 +581,7 @@ int ssh_socket_nonblocking_flush(struct socket *s) {
|
||||
* \brief locking flush of the output packet buffer
|
||||
*/
|
||||
int ssh_socket_blocking_flush(struct socket *s) {
|
||||
SSH_SESSION *session = s->session;
|
||||
ssh_session session = s->session;
|
||||
|
||||
enter_function();
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -30,7 +29,7 @@
|
||||
#endif
|
||||
|
||||
#include "libssh/priv.h"
|
||||
|
||||
#include "libssh/string.h"
|
||||
/** \defgroup ssh_string SSH Strings
|
||||
* \brief string manipulations
|
||||
*/
|
||||
@@ -42,8 +41,8 @@
|
||||
* \param size size of the string
|
||||
* \return the newly allocated string
|
||||
*/
|
||||
struct string_struct *string_new(size_t size) {
|
||||
struct string_struct *str = NULL;
|
||||
struct ssh_string_struct *string_new(size_t size) {
|
||||
struct ssh_string_struct *str = NULL;
|
||||
|
||||
str = malloc(size + 4);
|
||||
if (str == NULL) {
|
||||
@@ -65,7 +64,7 @@ struct string_struct *string_new(size_t size) {
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
int string_fill(struct string_struct *s, const void *data, size_t len) {
|
||||
int string_fill(struct ssh_string_struct *s, const void *data, size_t len) {
|
||||
if ((s == NULL) || (data == NULL) ||
|
||||
(len == 0) || (len > s->size)) {
|
||||
return -1;
|
||||
@@ -81,8 +80,8 @@ int string_fill(struct string_struct *s, const void *data, size_t len) {
|
||||
* \return the newly allocated string.
|
||||
* \warning The nul byte is not copied nor counted in the ouput string.
|
||||
*/
|
||||
struct string_struct *string_from_char(const char *what) {
|
||||
struct string_struct *ptr = NULL;
|
||||
struct ssh_string_struct *string_from_char(const char *what) {
|
||||
struct ssh_string_struct *ptr = NULL;
|
||||
size_t len = strlen(what);
|
||||
|
||||
ptr = malloc(4 + len);
|
||||
@@ -97,10 +96,10 @@ struct string_struct *string_from_char(const char *what) {
|
||||
|
||||
/**
|
||||
* \brief returns the size of a SSH string
|
||||
* \param str the input SSH string
|
||||
* \param s the input SSH string
|
||||
* \return size of the content of str, 0 on error
|
||||
*/
|
||||
size_t string_len(struct string_struct *s) {
|
||||
size_t string_len(struct ssh_string_struct *s) {
|
||||
if (s == NULL) {
|
||||
return ntohl(0);
|
||||
}
|
||||
@@ -110,12 +109,12 @@ size_t string_len(struct string_struct *s) {
|
||||
|
||||
/**
|
||||
* \brief convert a SSH string to a C nul-terminated string
|
||||
* \param str the input SSH string
|
||||
* \param s the input SSH string
|
||||
* \return a malloc'ed string pointer.
|
||||
* \warning If the input SSH string contains zeroes, some parts of
|
||||
* the output string may not be readable with regular libc functions.
|
||||
*/
|
||||
char *string_to_char(struct string_struct *s) {
|
||||
char *string_to_char(struct ssh_string_struct *s) {
|
||||
size_t len = ntohl(s->size) + 1;
|
||||
char *new = malloc(len);
|
||||
|
||||
@@ -135,8 +134,8 @@ char *string_to_char(struct string_struct *s) {
|
||||
*
|
||||
* @return Newly allocated copy of the string, NULL on error.
|
||||
*/
|
||||
struct string_struct *string_copy(struct string_struct *s) {
|
||||
struct string_struct *new = malloc(ntohl(s->size) + 4);
|
||||
struct ssh_string_struct *string_copy(struct ssh_string_struct *s) {
|
||||
struct ssh_string_struct *new = malloc(ntohl(s->size) + 4);
|
||||
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
@@ -150,7 +149,7 @@ struct string_struct *string_copy(struct string_struct *s) {
|
||||
/** \brief destroy data in a string so it couldn't appear in a core dump
|
||||
* \param s string to burn
|
||||
*/
|
||||
void string_burn(struct string_struct *s) {
|
||||
void string_burn(struct ssh_string_struct *s) {
|
||||
if (s == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -164,7 +163,7 @@ void string_burn(struct string_struct *s) {
|
||||
*
|
||||
* @return Return the data of the string or NULL on error.
|
||||
*/
|
||||
void *string_data(struct string_struct *s) {
|
||||
void *string_data(struct ssh_string_struct *s) {
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -176,7 +175,7 @@ void *string_data(struct string_struct *s) {
|
||||
* \brief deallocate a STRING object
|
||||
* \param s String to delete
|
||||
*/
|
||||
void string_free(struct string_struct *s) {
|
||||
void string_free(struct ssh_string_struct *s) {
|
||||
SAFE_FREE(s);
|
||||
}
|
||||
|
||||
|
||||
329
libssh/wrapper.c
329
libssh/wrapper.c
@@ -31,16 +31,19 @@
|
||||
* are welcome.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/wrapper.h"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#include <gcrypt.h>
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
|
||||
static int alloc_key(struct crypto_struct *cipher) {
|
||||
cipher->key = malloc(cipher->keylen);
|
||||
@@ -154,29 +157,31 @@ static void blowfish_decrypt(struct crypto_struct *cipher, void *in,
|
||||
}
|
||||
|
||||
static int aes_set_key(struct crypto_struct *cipher, void *key, void *IV) {
|
||||
int mode=GCRY_CIPHER_MODE_CBC;
|
||||
if (cipher->key == NULL) {
|
||||
if (alloc_key(cipher) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(strstr(cipher->name,"-ctr"))
|
||||
mode=GCRY_CIPHER_MODE_CTR;
|
||||
switch (cipher->keysize) {
|
||||
case 128:
|
||||
if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES128,
|
||||
GCRY_CIPHER_MODE_CBC, 0)) {
|
||||
mode, 0)) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 192:
|
||||
if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES192,
|
||||
GCRY_CIPHER_MODE_CBC, 0)) {
|
||||
mode, 0)) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 256:
|
||||
if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES256,
|
||||
GCRY_CIPHER_MODE_CBC, 0)) {
|
||||
mode, 0)) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
@@ -186,9 +191,17 @@ static int aes_set_key(struct crypto_struct *cipher, void *key, void *IV) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
if (gcry_cipher_setiv(cipher->key[0], IV, 16)) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
if(mode == GCRY_CIPHER_MODE_CBC){
|
||||
if (gcry_cipher_setiv(cipher->key[0], IV, 16)) {
|
||||
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if(gcry_cipher_setctr(cipher->key[0],IV,16)){
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,11 +275,11 @@ static int des3_1_set_key(struct crypto_struct *cipher, void *key, void *IV) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
if (gcry_cipher_setkey(cipher->key[1], key + 8, 8)) {
|
||||
if (gcry_cipher_setkey(cipher->key[1], (unsigned char *)key + 8, 8)) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
if (gcry_cipher_setiv(cipher->key[1], IV + 8, 8)) {
|
||||
if (gcry_cipher_setiv(cipher->key[1], (unsigned char *)IV + 8, 8)) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
@@ -276,11 +289,11 @@ static int des3_1_set_key(struct crypto_struct *cipher, void *key, void *IV) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
if (gcry_cipher_setkey(cipher->key[2], key + 16, 8)) {
|
||||
if (gcry_cipher_setkey(cipher->key[2], (unsigned char *)key + 16, 8)) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
if (gcry_cipher_setiv(cipher->key[2], IV + 16, 8)) {
|
||||
if (gcry_cipher_setiv(cipher->key[2], (unsigned char *)IV + 16, 8)) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
@@ -316,6 +329,39 @@ static struct crypto_struct ssh_ciphertab[] = {
|
||||
.cbc_encrypt = blowfish_encrypt,
|
||||
.cbc_decrypt = blowfish_decrypt
|
||||
},
|
||||
{
|
||||
.name = "aes128-ctr",
|
||||
.blocksize = 16,
|
||||
.keylen = sizeof(gcry_cipher_hd_t),
|
||||
.key = NULL,
|
||||
.keysize = 128,
|
||||
.set_encrypt_key = aes_set_key,
|
||||
.set_decrypt_key = aes_set_key,
|
||||
.cbc_encrypt = aes_encrypt,
|
||||
.cbc_decrypt = aes_encrypt
|
||||
},
|
||||
{
|
||||
.name = "aes192-ctr",
|
||||
.blocksize = 16,
|
||||
.keylen = sizeof(gcry_cipher_hd_t),
|
||||
.key = NULL,
|
||||
.keysize = 192,
|
||||
.set_encrypt_key = aes_set_key,
|
||||
.set_decrypt_key = aes_set_key,
|
||||
.cbc_encrypt = aes_encrypt,
|
||||
.cbc_decrypt = aes_encrypt
|
||||
},
|
||||
{
|
||||
.name = "aes256-ctr",
|
||||
.blocksize = 16,
|
||||
.keylen = sizeof(gcry_cipher_hd_t),
|
||||
.key = NULL,
|
||||
.keysize = 256,
|
||||
.set_encrypt_key = aes_set_key,
|
||||
.set_decrypt_key = aes_set_key,
|
||||
.cbc_encrypt = aes_encrypt,
|
||||
.cbc_decrypt = aes_encrypt
|
||||
},
|
||||
{
|
||||
.name = "aes128-cbc",
|
||||
.blocksize = 16,
|
||||
@@ -405,7 +451,7 @@ static struct crypto_struct ssh_ciphertab[] = {
|
||||
#include <openssl/des.h>
|
||||
#endif
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER<0x009070000)
|
||||
#if (OPENSSL_VERSION_NUMBER<0x00907000L)
|
||||
#define OLD_CRYPTO
|
||||
#endif
|
||||
|
||||
@@ -567,6 +613,24 @@ static void aes_decrypt(struct crypto_struct *cipher, void *in, void *out,
|
||||
unsigned long len, void *IV) {
|
||||
AES_cbc_encrypt(in, out, len, cipher->key, IV, AES_DECRYPT);
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief encrypts/decrypts data with stream cipher AES_ctr128. 128 bits is actually
|
||||
* the size of the CTR counter and incidentally the blocksize, but not the keysize.
|
||||
* @param len[in] must be a multiple of AES128 block size.
|
||||
*/
|
||||
static void aes_ctr128_encrypt(struct crypto_struct *cipher, void *in, void *out,
|
||||
unsigned long len, void *IV) {
|
||||
unsigned char tmp_buffer[128/8];
|
||||
unsigned int num=0;
|
||||
/* Some things are special with ctr128 :
|
||||
* In this case, tmp_buffer is not being used, because it is used to store temporary data
|
||||
* when an encryption is made on lengths that are not multiple of blocksize.
|
||||
* Same for num, which is being used to store the current offset in blocksize in CTR
|
||||
* function.
|
||||
*/
|
||||
AES_ctr128_encrypt(in, out, len, cipher->key, IV, tmp_buffer, &num);
|
||||
}
|
||||
#endif /* HAS_AES */
|
||||
|
||||
#ifdef HAS_DES
|
||||
@@ -577,11 +641,11 @@ static int des3_set_key(struct crypto_struct *cipher, void *key) {
|
||||
}
|
||||
|
||||
DES_set_odd_parity(key);
|
||||
DES_set_odd_parity(key + 8);
|
||||
DES_set_odd_parity(key + 16);
|
||||
DES_set_odd_parity((void*)((uint8_t*)key + 8));
|
||||
DES_set_odd_parity((void*)((uint8_t*)key + 16));
|
||||
DES_set_key_unchecked(key, cipher->key);
|
||||
DES_set_key_unchecked(key + 8, cipher->key + sizeof(DES_key_schedule));
|
||||
DES_set_key_unchecked(key + 16, cipher->key + 2 * sizeof(DES_key_schedule));
|
||||
DES_set_key_unchecked((void*)((uint8_t*)key + 8), (void*)((uint8_t*)cipher->key + sizeof(DES_key_schedule)));
|
||||
DES_set_key_unchecked((void*)((uint8_t*)key + 16), (void*)((uint8_t*)cipher->key + 2 * sizeof(DES_key_schedule)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -590,16 +654,16 @@ static int des3_set_key(struct crypto_struct *cipher, void *key) {
|
||||
static void des3_encrypt(struct crypto_struct *cipher, void *in,
|
||||
void *out, unsigned long len, void *IV) {
|
||||
DES_ede3_cbc_encrypt(in, out, len, cipher->key,
|
||||
cipher->key + sizeof(DES_key_schedule),
|
||||
cipher->key + 2 * sizeof(DES_key_schedule),
|
||||
(void*)((uint8_t*)cipher->key + sizeof(DES_key_schedule)),
|
||||
(void*)((uint8_t*)cipher->key + 2 * sizeof(DES_key_schedule)),
|
||||
IV, 1);
|
||||
}
|
||||
|
||||
static void des3_decrypt(struct crypto_struct *cipher, void *in,
|
||||
void *out, unsigned long len, void *IV) {
|
||||
DES_ede3_cbc_encrypt(in, out, len, cipher->key,
|
||||
cipher->key + sizeof(DES_key_schedule),
|
||||
cipher->key + 2 * sizeof(DES_key_schedule),
|
||||
(void*)((uint8_t*)cipher->key + sizeof(DES_key_schedule)),
|
||||
(void*)((uint8_t*)cipher->key + 2 * sizeof(DES_key_schedule)),
|
||||
IV, 0);
|
||||
}
|
||||
|
||||
@@ -609,10 +673,10 @@ static void des3_1_encrypt(struct crypto_struct *cipher, void *in,
|
||||
ssh_print_hexa("Encrypt IV before", IV, 24);
|
||||
#endif
|
||||
DES_ncbc_encrypt(in, out, len, cipher->key, IV, 1);
|
||||
DES_ncbc_encrypt(out, in, len, cipher->key + sizeof(DES_key_schedule),
|
||||
IV + 8, 0);
|
||||
DES_ncbc_encrypt(in, out, len, cipher->key + 2 * sizeof(DES_key_schedule),
|
||||
IV + 16, 1);
|
||||
DES_ncbc_encrypt(out, in, len, (void*)((uint8_t*)cipher->key + sizeof(DES_key_schedule)),
|
||||
(void*)((uint8_t*)IV + 8), 0);
|
||||
DES_ncbc_encrypt(in, out, len, (void*)((uint8_t*)cipher->key + 2 * sizeof(DES_key_schedule)),
|
||||
(void*)((uint8_t*)IV + 16), 1);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Encrypt IV after", IV, 24);
|
||||
#endif
|
||||
@@ -624,11 +688,11 @@ static void des3_1_decrypt(struct crypto_struct *cipher, void *in,
|
||||
ssh_print_hexa("Decrypt IV before", IV, 24);
|
||||
#endif
|
||||
|
||||
DES_ncbc_encrypt(in, out, len, cipher->key + 2 * sizeof(DES_key_schedule),
|
||||
DES_ncbc_encrypt(in, out, len, (void*)((uint8_t*)cipher->key + 2 * sizeof(DES_key_schedule)),
|
||||
IV, 0);
|
||||
DES_ncbc_encrypt(out, in, len, cipher->key + sizeof(DES_key_schedule),
|
||||
IV + 8, 1);
|
||||
DES_ncbc_encrypt(in, out, len, cipher->key, IV + 16, 0);
|
||||
DES_ncbc_encrypt(out, in, len, (void*)((uint8_t*)cipher->key + sizeof(DES_key_schedule)),
|
||||
(void*)((uint8_t*)IV + 8), 1);
|
||||
DES_ncbc_encrypt(in, out, len, cipher->key, (void*)((uint8_t*)IV + 16), 0);
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Decrypt IV after", IV, 24);
|
||||
@@ -637,90 +701,128 @@ static void des3_1_decrypt(struct crypto_struct *cipher, void *in,
|
||||
|
||||
#endif /* HAS_DES */
|
||||
|
||||
/* the table of supported ciphers */
|
||||
/*
|
||||
* The table of supported ciphers
|
||||
*
|
||||
* WARNING: If you modify crypto_struct, you must make sure the order is
|
||||
* correct!
|
||||
*/
|
||||
static struct crypto_struct ssh_ciphertab[] = {
|
||||
#ifdef HAS_BLOWFISH
|
||||
{
|
||||
.name = "blowfish-cbc",
|
||||
.blocksize = 8,
|
||||
.keylen = sizeof (BF_KEY),
|
||||
.key = NULL,
|
||||
.keysize = 128,
|
||||
.set_encrypt_key = blowfish_set_key,
|
||||
.set_decrypt_key = blowfish_set_key,
|
||||
.cbc_encrypt = blowfish_encrypt,
|
||||
.cbc_decrypt = blowfish_decrypt
|
||||
"blowfish-cbc",
|
||||
8,
|
||||
sizeof (BF_KEY),
|
||||
NULL,
|
||||
128,
|
||||
blowfish_set_key,
|
||||
blowfish_set_key,
|
||||
blowfish_encrypt,
|
||||
blowfish_decrypt
|
||||
},
|
||||
#endif /* HAS_BLOWFISH */
|
||||
#ifdef HAS_AES
|
||||
{
|
||||
.name = "aes128-cbc",
|
||||
.blocksize = 16,
|
||||
.keylen = sizeof(AES_KEY),
|
||||
.key = NULL,
|
||||
.keysize = 128,
|
||||
.set_encrypt_key = aes_set_encrypt_key,
|
||||
.set_decrypt_key = aes_set_decrypt_key,
|
||||
.cbc_encrypt = aes_encrypt,
|
||||
.cbc_decrypt = aes_decrypt
|
||||
"aes128-ctr",
|
||||
16,
|
||||
sizeof(AES_KEY),
|
||||
NULL,
|
||||
128,
|
||||
aes_set_encrypt_key,
|
||||
aes_set_encrypt_key,
|
||||
aes_ctr128_encrypt,
|
||||
aes_ctr128_encrypt
|
||||
},
|
||||
{
|
||||
.name = "aes192-cbc",
|
||||
.blocksize = 16,
|
||||
.keylen = sizeof(AES_KEY),
|
||||
.key = NULL,
|
||||
.keysize = 192,
|
||||
.set_encrypt_key = aes_set_encrypt_key,
|
||||
.set_decrypt_key = aes_set_decrypt_key,
|
||||
.cbc_encrypt = aes_encrypt,
|
||||
.cbc_decrypt = aes_decrypt
|
||||
"aes192-ctr",
|
||||
16,
|
||||
sizeof(AES_KEY),
|
||||
NULL,
|
||||
192,
|
||||
aes_set_encrypt_key,
|
||||
aes_set_encrypt_key,
|
||||
aes_ctr128_encrypt,
|
||||
aes_ctr128_encrypt
|
||||
},
|
||||
{
|
||||
.name = "aes256-cbc",
|
||||
.blocksize = 16,
|
||||
.keylen = sizeof(AES_KEY),
|
||||
.key = NULL,
|
||||
.keysize = 256,
|
||||
.set_encrypt_key = aes_set_encrypt_key,
|
||||
.set_decrypt_key = aes_set_decrypt_key,
|
||||
.cbc_encrypt = aes_encrypt,
|
||||
.cbc_decrypt = aes_decrypt
|
||||
"aes256-ctr",
|
||||
16,
|
||||
sizeof(AES_KEY),
|
||||
NULL,
|
||||
256,
|
||||
aes_set_encrypt_key,
|
||||
aes_set_encrypt_key,
|
||||
aes_ctr128_encrypt,
|
||||
aes_ctr128_encrypt
|
||||
},
|
||||
{
|
||||
"aes128-cbc",
|
||||
16,
|
||||
sizeof(AES_KEY),
|
||||
NULL,
|
||||
128,
|
||||
aes_set_encrypt_key,
|
||||
aes_set_decrypt_key,
|
||||
aes_encrypt,
|
||||
aes_decrypt
|
||||
},
|
||||
{
|
||||
"aes192-cbc",
|
||||
16,
|
||||
sizeof(AES_KEY),
|
||||
NULL,
|
||||
192,
|
||||
aes_set_encrypt_key,
|
||||
aes_set_decrypt_key,
|
||||
aes_encrypt,
|
||||
aes_decrypt
|
||||
},
|
||||
{
|
||||
"aes256-cbc",
|
||||
16,
|
||||
sizeof(AES_KEY),
|
||||
NULL,
|
||||
256,
|
||||
aes_set_encrypt_key,
|
||||
aes_set_decrypt_key,
|
||||
aes_encrypt,
|
||||
aes_decrypt
|
||||
},
|
||||
#endif /* HAS_AES */
|
||||
#ifdef HAS_DES
|
||||
{
|
||||
.name = "3des-cbc",
|
||||
.blocksize = 8,
|
||||
.keylen = sizeof(DES_key_schedule) * 3,
|
||||
.key = NULL,
|
||||
.keysize = 192,
|
||||
.set_encrypt_key = des3_set_key,
|
||||
.set_decrypt_key = des3_set_key,
|
||||
.cbc_encrypt = des3_encrypt,
|
||||
.cbc_decrypt = des3_decrypt
|
||||
"3des-cbc",
|
||||
8,
|
||||
sizeof(DES_key_schedule) * 3,
|
||||
NULL,
|
||||
192,
|
||||
des3_set_key,
|
||||
des3_set_key,
|
||||
des3_encrypt,
|
||||
des3_decrypt
|
||||
},
|
||||
{
|
||||
.name = "3des-cbc-ssh1",
|
||||
.blocksize = 8,
|
||||
.keylen = sizeof(DES_key_schedule) * 3,
|
||||
.key = NULL,
|
||||
.keysize = 192,
|
||||
.set_encrypt_key = des3_set_key,
|
||||
.set_decrypt_key = des3_set_key,
|
||||
.cbc_encrypt = des3_1_encrypt,
|
||||
.cbc_decrypt = des3_1_decrypt
|
||||
"3des-cbc-ssh1",
|
||||
8,
|
||||
sizeof(DES_key_schedule) * 3,
|
||||
NULL,
|
||||
192,
|
||||
des3_set_key,
|
||||
des3_set_key,
|
||||
des3_1_encrypt,
|
||||
des3_1_decrypt
|
||||
},
|
||||
#endif /* HAS_DES */
|
||||
{
|
||||
.name = NULL,
|
||||
.blocksize = 0,
|
||||
.keylen = 0,
|
||||
.key = NULL,
|
||||
.keysize = 0,
|
||||
.set_encrypt_key = NULL,
|
||||
.set_decrypt_key = NULL,
|
||||
.cbc_encrypt = NULL,
|
||||
.cbc_decrypt = NULL
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
#endif /* OPENSSL_CRYPTO */
|
||||
@@ -763,20 +865,18 @@ static void cipher_free(struct crypto_struct *cipher) {
|
||||
SAFE_FREE(cipher);
|
||||
}
|
||||
|
||||
CRYPTO *crypto_new(void) {
|
||||
CRYPTO *crypto;
|
||||
struct ssh_crypto_struct *crypto_new(void) {
|
||||
struct ssh_crypto_struct *crypto;
|
||||
|
||||
crypto = malloc(sizeof(CRYPTO));
|
||||
crypto = malloc(sizeof(struct ssh_crypto_struct));
|
||||
if (crypto == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(crypto, 0, sizeof(CRYPTO));
|
||||
|
||||
ZERO_STRUCTP(crypto);
|
||||
return crypto;
|
||||
}
|
||||
|
||||
void crypto_free(CRYPTO *crypto){
|
||||
void crypto_free(struct ssh_crypto_struct *crypto){
|
||||
if (crypto == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -798,7 +898,7 @@ void crypto_free(CRYPTO *crypto){
|
||||
SAFE_FREE(crypto);
|
||||
}
|
||||
|
||||
static int crypt_set_algorithms2(SSH_SESSION *session){
|
||||
static int crypt_set_algorithms2(ssh_session session){
|
||||
const char *wanted;
|
||||
int i = 0;
|
||||
|
||||
@@ -855,7 +955,7 @@ static int crypt_set_algorithms2(SSH_SESSION *session){
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static int crypt_set_algorithms1(SSH_SESSION *session) {
|
||||
static int crypt_set_algorithms1(ssh_session session) {
|
||||
int i = 0;
|
||||
|
||||
/* right now, we force 3des-cbc to be taken */
|
||||
@@ -884,13 +984,13 @@ static int crypt_set_algorithms1(SSH_SESSION *session) {
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int crypt_set_algorithms(SSH_SESSION *session) {
|
||||
int crypt_set_algorithms(ssh_session session) {
|
||||
return (session->version == 1) ? crypt_set_algorithms1(session) :
|
||||
crypt_set_algorithms2(session);
|
||||
}
|
||||
|
||||
// TODO Obviously too much cut and paste here
|
||||
int crypt_set_algorithms_server(SSH_SESSION *session){
|
||||
int crypt_set_algorithms_server(ssh_session session){
|
||||
char *server = NULL;
|
||||
char *client = NULL;
|
||||
char *match = NULL;
|
||||
@@ -901,7 +1001,7 @@ int crypt_set_algorithms_server(SSH_SESSION *session){
|
||||
/* out */
|
||||
server = session->server_kex.methods[SSH_CRYPT_S_C];
|
||||
client = session->client_kex.methods[SSH_CRYPT_S_C];
|
||||
match = ssh_find_matching(client,server);
|
||||
match = ssh_find_matching(client, server);
|
||||
|
||||
if(!match){
|
||||
ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server : no matching algorithm function found for %s",server);
|
||||
@@ -963,8 +1063,8 @@ int crypt_set_algorithms_server(SSH_SESSION *session){
|
||||
ssh_log(session,SSH_LOG_PACKET,"enabling C->S compression");
|
||||
session->next_crypto->do_compress_in=1;
|
||||
}
|
||||
free(match);
|
||||
|
||||
SAFE_FREE(match);
|
||||
|
||||
client=session->client_kex.methods[SSH_CRYPT_S_C];
|
||||
server=session->server_kex.methods[SSH_CRYPT_S_C];
|
||||
match=ssh_find_matching(client,server);
|
||||
@@ -972,22 +1072,23 @@ int crypt_set_algorithms_server(SSH_SESSION *session){
|
||||
ssh_log(session,SSH_LOG_PACKET,"enabling S->C compression\n");
|
||||
session->next_crypto->do_compress_out=1;
|
||||
}
|
||||
free(match);
|
||||
|
||||
SAFE_FREE(match);
|
||||
|
||||
server=session->server_kex.methods[SSH_HOSTKEYS];
|
||||
client=session->client_kex.methods[SSH_HOSTKEYS];
|
||||
match=ssh_find_matching(client,server);
|
||||
if(!strcmp(match,"ssh-dss"))
|
||||
if(match && !strcmp(match,"ssh-dss"))
|
||||
session->hostkeys=TYPE_DSS;
|
||||
else if(!strcmp(match,"ssh-rsa"))
|
||||
else if(match && !strcmp(match,"ssh-rsa"))
|
||||
session->hostkeys=TYPE_RSA;
|
||||
else {
|
||||
ssh_set_error(session,SSH_FATAL,"cannot know what %s is into %s",match,server);
|
||||
free(match);
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot know what %s is into %s",
|
||||
match ? match : NULL, server);
|
||||
SAFE_FREE(match);
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
free(match);
|
||||
SAFE_FREE(match);
|
||||
leave_function();
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
567
sample.c
567
sample.c
@@ -1,567 +0,0 @@
|
||||
/* client.c */
|
||||
/*
|
||||
Copyright 2003 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef HAVE_PTY_H
|
||||
#include <pty.h>
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/sftp.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#define MAXCMD 10
|
||||
char *host;
|
||||
char *user;
|
||||
int sftp;
|
||||
char *cmds[MAXCMD];
|
||||
struct termios terminal;
|
||||
void do_sftp(SSH_SESSION *session);
|
||||
|
||||
static void add_cmd(char *cmd){
|
||||
int n;
|
||||
for(n=0;cmds[n] && (n<MAXCMD);n++);
|
||||
if(n==MAXCMD)
|
||||
return;
|
||||
cmds[n]=strdup(cmd);
|
||||
}
|
||||
|
||||
static void usage(){
|
||||
fprintf(stderr,"Usage : ssh [options] [login@]hostname\n"
|
||||
"sample client - libssh-%s\n"
|
||||
"Options :\n"
|
||||
" -l user : log in as user\n"
|
||||
" -p port : connect to port\n"
|
||||
" -d : use DSS to verify host public key\n"
|
||||
" -r : use RSA to verify host public key\n",
|
||||
ssh_version(0));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int opts(int argc, char **argv){
|
||||
int i;
|
||||
if(strstr(argv[0],"sftp"))
|
||||
sftp=1;
|
||||
// for(i=0;i<argc;i++)
|
||||
// printf("%d : %s\n",i,argv[i]);
|
||||
/* insert your own arguments here */
|
||||
while((i=getopt(argc,argv,""))!=-1){
|
||||
switch(i){
|
||||
default:
|
||||
fprintf(stderr,"unknown option %c\n",optopt);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
if(optind < argc)
|
||||
host=argv[optind++];
|
||||
while(optind < argc)
|
||||
add_cmd(argv[optind++]);
|
||||
if(host==NULL)
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_CFMAKERAW
|
||||
static void cfmakeraw(struct termios *termios_p){
|
||||
termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
|
||||
termios_p->c_oflag &= ~OPOST;
|
||||
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
||||
termios_p->c_cflag &= ~(CSIZE|PARENB);
|
||||
termios_p->c_cflag |= CS8;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void do_cleanup(int i) {
|
||||
/* unused variable */
|
||||
(void) i;
|
||||
|
||||
tcsetattr(0,TCSANOW,&terminal);
|
||||
}
|
||||
|
||||
static void do_exit(int i) {
|
||||
/* unused variable */
|
||||
(void) i;
|
||||
|
||||
do_cleanup(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
CHANNEL *chan;
|
||||
int signal_delayed=0;
|
||||
|
||||
static void sigwindowchanged(int i){
|
||||
(void) i;
|
||||
signal_delayed=1;
|
||||
}
|
||||
|
||||
static void setsignal(void){
|
||||
signal(SIGWINCH, sigwindowchanged);
|
||||
signal_delayed=0;
|
||||
}
|
||||
|
||||
static void sizechanged(void){
|
||||
struct winsize win = { 0, 0, 0, 0 };
|
||||
ioctl(1, TIOCGWINSZ, &win);
|
||||
channel_change_pty_size(chan,win.ws_col, win.ws_row);
|
||||
// printf("Changed pty size\n");
|
||||
setsignal();
|
||||
}
|
||||
static void select_loop(SSH_SESSION *session,CHANNEL *channel){
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
char buffer[10];
|
||||
BUFFER *readbuf=buffer_new();
|
||||
CHANNEL *channels[2];
|
||||
int lus;
|
||||
int eof=0;
|
||||
int maxfd;
|
||||
int ret;
|
||||
while(channel){
|
||||
/* when a signal is caught, ssh_select will return
|
||||
* with SSH_EINTR, which means it should be started
|
||||
* again. It lets you handle the signal the faster you
|
||||
* can, like in this window changed example. Of course, if
|
||||
* your signal handler doesn't call libssh at all, you're
|
||||
* free to handle signals directly in sighandler.
|
||||
*/
|
||||
do{
|
||||
FD_ZERO(&fds);
|
||||
if(!eof)
|
||||
FD_SET(0,&fds);
|
||||
timeout.tv_sec=30;
|
||||
timeout.tv_usec=0;
|
||||
FD_SET(ssh_get_fd(session),&fds);
|
||||
maxfd=ssh_get_fd(session)+1;
|
||||
ret=select(maxfd,&fds,NULL,NULL,&timeout);
|
||||
if(ret==EINTR)
|
||||
continue;
|
||||
if(FD_ISSET(0,&fds)){
|
||||
lus=read(0,buffer,10);
|
||||
if(lus)
|
||||
channel_write(channel,buffer,lus);
|
||||
else {
|
||||
eof=1;
|
||||
channel_send_eof(channel);
|
||||
}
|
||||
}
|
||||
if(FD_ISSET(ssh_get_fd(session),&fds)){
|
||||
ssh_set_fd_toread(session);
|
||||
}
|
||||
channels[0]=channel; // set the first channel we want to read from
|
||||
channels[1]=NULL;
|
||||
ret=channel_select(channels,NULL,NULL,NULL); // no specific timeout - just poll
|
||||
if(signal_delayed)
|
||||
sizechanged();
|
||||
} while (ret==EINTR || ret==SSH_EINTR);
|
||||
|
||||
// we already looked for input from stdin. Now, we are looking for input from the channel
|
||||
|
||||
if(channel && channel_is_closed(channel)){
|
||||
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
|
||||
|
||||
channel_free(channel);
|
||||
channel=NULL;
|
||||
channels[0]=NULL;
|
||||
}
|
||||
if(channels[0]){
|
||||
while(channel && channel_is_open(channel) && channel_poll(channel,0)){
|
||||
lus=channel_read_buffer(channel,readbuf,0,0);
|
||||
if(lus==-1){
|
||||
fprintf(stderr, "Error reading channel: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(lus==0){
|
||||
ssh_log(session,SSH_LOG_RARE,"EOF received\n");
|
||||
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
|
||||
|
||||
channel_free(channel);
|
||||
channel=channels[0]=NULL;
|
||||
} else
|
||||
write(1,buffer_get(readbuf),lus);
|
||||
}
|
||||
while(channel && channel_is_open(channel) && channel_poll(channel,1)){ /* stderr */
|
||||
lus=channel_read_buffer(channel,readbuf,0,1);
|
||||
if(lus==-1){
|
||||
fprintf(stderr, "Error reading channel: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(lus==0){
|
||||
ssh_log(session,SSH_LOG_RARE,"EOF received\n");
|
||||
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
|
||||
channel_free(channel);
|
||||
channel=channels[0]=NULL;
|
||||
} else
|
||||
write(2,buffer_get(readbuf),lus);
|
||||
}
|
||||
}
|
||||
if(channel && channel_is_closed(channel)){
|
||||
channel_free(channel);
|
||||
channel=NULL;
|
||||
}
|
||||
}
|
||||
buffer_free(readbuf);
|
||||
}
|
||||
|
||||
|
||||
static void shell(SSH_SESSION *session){
|
||||
CHANNEL *channel;
|
||||
struct termios terminal_local;
|
||||
int interactive=isatty(0);
|
||||
channel = channel_new(session);
|
||||
if(interactive){
|
||||
tcgetattr(0,&terminal_local);
|
||||
memcpy(&terminal,&terminal_local,sizeof(struct termios));
|
||||
}
|
||||
if(channel_open_session(channel)){
|
||||
printf("error opening channel : %s\n",ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
chan=channel;
|
||||
if(interactive){
|
||||
channel_request_pty(channel);
|
||||
sizechanged();
|
||||
}
|
||||
if(channel_request_shell(channel)){
|
||||
printf("Requesting shell : %s\n",ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(interactive){
|
||||
cfmakeraw(&terminal_local);
|
||||
tcsetattr(0,TCSANOW,&terminal_local);
|
||||
setsignal();
|
||||
}
|
||||
signal(SIGTERM,do_cleanup);
|
||||
select_loop(session,channel);
|
||||
}
|
||||
|
||||
static void batch_shell(SSH_SESSION *session){
|
||||
CHANNEL *channel;
|
||||
char buffer[1024];
|
||||
int i,s=0;
|
||||
for(i=0;i<MAXCMD && cmds[i];++i)
|
||||
s+=snprintf(buffer+s,sizeof(buffer)-s,"%s ",cmds[i]);
|
||||
channel=channel_new(session);
|
||||
channel_open_session(channel);
|
||||
if(channel_request_exec(channel,buffer)){
|
||||
printf("error executing \"%s\" : %s\n",buffer,ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
select_loop(session,channel);
|
||||
}
|
||||
|
||||
#ifdef WITH_SFTP
|
||||
/* it's just a proof of concept code for sftp, till i write a real documentation about it */
|
||||
void do_sftp(SSH_SESSION *session){
|
||||
SFTP_SESSION *sftp_session=sftp_new(session);
|
||||
SFTP_DIR *dir;
|
||||
SFTP_ATTRIBUTES *file;
|
||||
SFTP_FILE *fichier;
|
||||
SFTP_FILE *to;
|
||||
int len=1;
|
||||
int i;
|
||||
char data[8000];
|
||||
if(!sftp_session){
|
||||
fprintf(stderr, "sftp error initialising channel: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(sftp_init(sftp_session)){
|
||||
fprintf(stderr, "error initialising sftp: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
/* the connection is made */
|
||||
/* opening a directory */
|
||||
dir=sftp_opendir(sftp_session,"./");
|
||||
if(!dir) {
|
||||
fprintf(stderr, "Directory not opened(%s)\n", ssh_get_error(session));
|
||||
return ;
|
||||
}
|
||||
/* reading the whole directory, file by file */
|
||||
while((file=sftp_readdir(sftp_session,dir))){
|
||||
fprintf(stderr, "%30s(%.8o) : %.5d.%.5d : %.10llu bytes\n",
|
||||
file->name,
|
||||
file->permissions,
|
||||
file->uid,
|
||||
file->gid,
|
||||
(long long unsigned int) file->size);
|
||||
sftp_attributes_free(file);
|
||||
}
|
||||
/* when file=NULL, an error has occured OR the directory listing is end of file */
|
||||
if(!sftp_dir_eof(dir)){
|
||||
fprintf(stderr, "Error: %s\n", ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(sftp_closedir(dir)){
|
||||
fprintf(stderr, "Error: %s\n", ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
/* this will open a file and copy it into your /home directory */
|
||||
/* the small buffer size was intended to stress the library. of course, you can use a buffer till 20kbytes without problem */
|
||||
|
||||
fichier=sftp_open(sftp_session,"/usr/bin/ssh",O_RDONLY, 0);
|
||||
if(!fichier){
|
||||
fprintf(stderr, "Error opening /usr/bin/ssh: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
/* open a file for writing... */
|
||||
to=sftp_open(sftp_session,"ssh-copy",O_WRONLY | O_CREAT, 0);
|
||||
if(!to){
|
||||
fprintf(stderr, "Error opening ssh-copy for writing: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
while((len=sftp_read(fichier,data,4096)) > 0){
|
||||
if(sftp_write(to,data,len)!=len){
|
||||
fprintf(stderr, "Error writing %d bytes: %s\n",
|
||||
len, ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
}
|
||||
printf("finished\n");
|
||||
if(len<0)
|
||||
fprintf(stderr, "Error reading file: %s\n", ssh_get_error(session));
|
||||
sftp_close(fichier);
|
||||
sftp_close(to);
|
||||
printf("fichiers ferm\n");
|
||||
to=sftp_open(sftp_session,"/tmp/grosfichier",O_WRONLY|O_CREAT, 0644);
|
||||
for(i=0;i<1000;++i){
|
||||
len=sftp_write(to,data,8000);
|
||||
printf("wrote %d bytes\n",len);
|
||||
if(len != 8000){
|
||||
printf("chunk %d : %d (%s)\n",i,len,ssh_get_error(session));
|
||||
}
|
||||
}
|
||||
sftp_close(to);
|
||||
/* close the sftp session */
|
||||
sftp_free(sftp_session);
|
||||
printf("session sftp termin<69>\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static int auth_kbdint(SSH_SESSION *session){
|
||||
int err=ssh_userauth_kbdint(session,NULL,NULL);
|
||||
char *name,*instruction,*prompt,*ptr;
|
||||
char buffer[128];
|
||||
int i,n;
|
||||
char echo;
|
||||
while (err==SSH_AUTH_INFO){
|
||||
name=ssh_userauth_kbdint_getname(session);
|
||||
instruction=ssh_userauth_kbdint_getinstruction(session);
|
||||
n=ssh_userauth_kbdint_getnprompts(session);
|
||||
if(strlen(name)>0)
|
||||
printf("%s\n",name);
|
||||
if(strlen(instruction)>0)
|
||||
printf("%s\n",instruction);
|
||||
for(i=0;i<n;++i){
|
||||
prompt=ssh_userauth_kbdint_getprompt(session,i,&echo);
|
||||
if(echo){
|
||||
printf("%s",prompt);
|
||||
fgets(buffer,sizeof(buffer),stdin);
|
||||
buffer[sizeof(buffer)-1]=0;
|
||||
if((ptr=strchr(buffer,'\n')))
|
||||
*ptr=0;
|
||||
if (ssh_userauth_kbdint_setanswer(session,i,buffer) < 0) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
memset(buffer,0,strlen(buffer));
|
||||
} else {
|
||||
ptr=getpass(prompt);
|
||||
if (ssh_userauth_kbdint_setanswer(session,i,ptr) < 0) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
err=ssh_userauth_kbdint(session,NULL,NULL);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
SSH_SESSION *session;
|
||||
SSH_OPTIONS *options;
|
||||
int auth=0;
|
||||
char *password;
|
||||
char *banner;
|
||||
char *hexa;
|
||||
int state;
|
||||
char buf[10];
|
||||
unsigned char *hash = NULL;
|
||||
int hlen;
|
||||
|
||||
options=ssh_options_new();
|
||||
if(ssh_options_getopt(options,&argc, argv)){
|
||||
fprintf(stderr,"error parsing command line :%s\n",ssh_get_error(options));
|
||||
usage();
|
||||
}
|
||||
opts(argc,argv);
|
||||
signal(SIGTERM, do_exit);
|
||||
|
||||
if (user) {
|
||||
if (ssh_options_set_username(options,user) < 0) {
|
||||
ssh_options_free(options);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ssh_options_set_host(options,host) < 0) {
|
||||
ssh_options_free(options);
|
||||
return 1;
|
||||
}
|
||||
session=ssh_new();
|
||||
ssh_set_options(session,options);
|
||||
if(ssh_connect(session)){
|
||||
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
return 1;
|
||||
}
|
||||
state=ssh_is_server_known(session);
|
||||
|
||||
hlen = ssh_get_pubkey_hash(session, &hash);
|
||||
if (hlen < 0) {
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
return 1;
|
||||
}
|
||||
switch(state){
|
||||
case SSH_SERVER_KNOWN_OK:
|
||||
break; /* ok */
|
||||
case SSH_SERVER_KNOWN_CHANGED:
|
||||
fprintf(stderr,"Host key for server changed : server's one is now :\n");
|
||||
ssh_print_hexa("Public key hash",hash, hlen);
|
||||
free(hash);
|
||||
fprintf(stderr,"For security reason, connection will be stopped\n");
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
exit(-1);
|
||||
case SSH_SERVER_FOUND_OTHER:
|
||||
fprintf(stderr,"The host key for this server was not found but an other type of key exists.\n");
|
||||
fprintf(stderr,"An attacker might change the default server key to confuse your client"
|
||||
"into thinking the key does not exist\n"
|
||||
"We advise you to rerun the client with -d or -r for more safety.\n");
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
exit(-1);
|
||||
case SSH_SERVER_FILE_NOT_FOUND:
|
||||
fprintf(stderr,"Could not find known host file. If you accept the host key here,\n");
|
||||
fprintf(stderr,"the file will be automatically created.\n");
|
||||
/* fallback to SSH_SERVER_NOT_KNOWN behaviour */
|
||||
case SSH_SERVER_NOT_KNOWN:
|
||||
hexa = ssh_get_hexa(hash, hlen);
|
||||
free(hash);
|
||||
fprintf(stderr,"The server is unknown. Do you trust the host key ?\n");
|
||||
fprintf(stderr, "Public key hash: %s\n", hexa);
|
||||
free(hexa);
|
||||
fgets(buf,sizeof(buf),stdin);
|
||||
if(strncasecmp(buf,"yes",3)!=0){
|
||||
ssh_disconnect(session);
|
||||
exit(-1);
|
||||
}
|
||||
fprintf(stderr,"This new key will be written on disk for further usage. do you agree ?\n");
|
||||
fgets(buf,sizeof(buf),stdin);
|
||||
if(strncasecmp(buf,"yes",3)==0){
|
||||
if(ssh_write_knownhost(session))
|
||||
fprintf(stderr,"error %s\n",ssh_get_error(session));
|
||||
}
|
||||
|
||||
break;
|
||||
case SSH_SERVER_ERROR:
|
||||
free(hash);
|
||||
fprintf(stderr,"%s",ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
exit(-1);
|
||||
}
|
||||
free(hash);
|
||||
|
||||
ssh_userauth_none(session, NULL);
|
||||
|
||||
auth = ssh_auth_list(session);
|
||||
printf("auth: 0x%04x\n", auth);
|
||||
printf("supported auth methods: ");
|
||||
if (auth & SSH_AUTH_METHOD_PUBLICKEY) {
|
||||
printf("publickey");
|
||||
}
|
||||
if (auth & SSH_AUTH_METHOD_INTERACTIVE) {
|
||||
printf(", keyboard-interactive");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* no ? you should :) */
|
||||
auth=ssh_userauth_autopubkey(session, NULL);
|
||||
if(auth==SSH_AUTH_ERROR){
|
||||
fprintf(stderr,"Authenticating with pubkey: %s\n",ssh_get_error(session));
|
||||
ssh_finalize();
|
||||
return -1;
|
||||
}
|
||||
banner=ssh_get_issue_banner(session);
|
||||
if(banner){
|
||||
printf("%s\n",banner);
|
||||
free(banner);
|
||||
}
|
||||
if(auth!=SSH_AUTH_SUCCESS){
|
||||
auth=auth_kbdint(session);
|
||||
if(auth==SSH_AUTH_ERROR){
|
||||
fprintf(stderr,"authenticating with keyb-interactive: %s\n",
|
||||
ssh_get_error(session));
|
||||
ssh_finalize();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(auth!=SSH_AUTH_SUCCESS){
|
||||
password=getpass("Password: ");
|
||||
if(ssh_userauth_password(session,NULL,password) != SSH_AUTH_SUCCESS){
|
||||
fprintf(stderr,"Authentication failed: %s\n",ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
return -1;
|
||||
}
|
||||
memset(password,0,strlen(password));
|
||||
}
|
||||
ssh_log(session, SSH_LOG_FUNCTIONS, "Authentication success");
|
||||
if(strstr(argv[0],"sftp")){
|
||||
sftp=1;
|
||||
ssh_log(session, SSH_LOG_FUNCTIONS, "Doing sftp instead");
|
||||
}
|
||||
if(!sftp){
|
||||
if(!cmds[0])
|
||||
shell(session);
|
||||
else
|
||||
batch_shell(session);
|
||||
}
|
||||
else
|
||||
do_sftp(session);
|
||||
if(!sftp && !cmds[0])
|
||||
do_cleanup(0);
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
158
samplesshd.c
158
samplesshd.c
@@ -1,158 +0,0 @@
|
||||
/* sshd.c */
|
||||
/* yet another ssh daemon (Yawn!) */
|
||||
/*
|
||||
Copyright 2004 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
The SSH Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The SSH Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the SSH Library; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA. */
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/server.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#ifdef _WIN32
|
||||
#define KEYS_FOLDER
|
||||
#else
|
||||
#define KEYS_FOLDER "/etc/ssh/"
|
||||
#endif
|
||||
|
||||
static int auth_password(char *user, char *password){
|
||||
if(strcmp(user,"aris"))
|
||||
return 0;
|
||||
if(strcmp(password,"lala"))
|
||||
return 0;
|
||||
return 1; // authenticated
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
SSH_OPTIONS *options=ssh_options_new();
|
||||
SSH_SESSION *session;
|
||||
SSH_BIND *ssh_bind;
|
||||
SSH_MESSAGE *message;
|
||||
CHANNEL *chan=0;
|
||||
BUFFER *buf;
|
||||
int auth=0;
|
||||
int sftp=0;
|
||||
int i;
|
||||
ssh_options_getopt(options,&argc,argv);
|
||||
ssh_options_set_dsa_server_key(options, KEYS_FOLDER "ssh_host_dsa_key");
|
||||
ssh_options_set_rsa_server_key(options, KEYS_FOLDER "ssh_host_rsa_key");
|
||||
ssh_bind=ssh_bind_new();
|
||||
ssh_bind_set_options(ssh_bind,options);
|
||||
if(ssh_bind_listen(ssh_bind)<0){
|
||||
printf("Error listening to socket: %s\n",ssh_get_error(ssh_bind));
|
||||
return 1;
|
||||
}
|
||||
session=ssh_bind_accept(ssh_bind);
|
||||
if(!session){
|
||||
printf("error accepting a connection : %s\n",ssh_get_error(ssh_bind));
|
||||
return 1;
|
||||
}
|
||||
printf("Socket connected: fd = %d\n", ssh_get_fd(session));
|
||||
if(ssh_accept(session)){
|
||||
printf("ssh_accept: %s\n",ssh_get_error(session));
|
||||
return 1;
|
||||
}
|
||||
do {
|
||||
message=ssh_message_get(session);
|
||||
if(!message)
|
||||
break;
|
||||
switch(ssh_message_type(message)){
|
||||
case SSH_AUTH_REQUEST:
|
||||
switch(ssh_message_subtype(message)){
|
||||
case SSH_AUTH_PASSWORD:
|
||||
printf("User %s wants to auth with pass %s\n",
|
||||
ssh_message_auth_user(message),
|
||||
ssh_message_auth_password(message));
|
||||
if(auth_password(ssh_message_auth_user(message),
|
||||
ssh_message_auth_password(message))){
|
||||
auth=1;
|
||||
ssh_message_auth_reply_success(message,0);
|
||||
break;
|
||||
}
|
||||
// not authenticated, send default message
|
||||
case SSH_AUTH_NONE:
|
||||
default:
|
||||
ssh_message_auth_set_methods(message,SSH_AUTH_PASSWORD);
|
||||
ssh_message_reply_default(message);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ssh_message_reply_default(message);
|
||||
}
|
||||
ssh_message_free(message);
|
||||
} while (!auth);
|
||||
if(!auth){
|
||||
printf("auth error: %s\n",ssh_get_error(session));
|
||||
ssh_finalize();
|
||||
return 1;
|
||||
}
|
||||
do {
|
||||
message=ssh_message_get(session);
|
||||
if(message){
|
||||
switch(ssh_message_type(message)){
|
||||
case SSH_CHANNEL_REQUEST_OPEN:
|
||||
if(ssh_message_subtype(message)==SSH_CHANNEL_SESSION){
|
||||
chan=ssh_message_channel_request_open_reply_accept(message);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ssh_message_reply_default(message);
|
||||
}
|
||||
ssh_message_free(message);
|
||||
}
|
||||
} while(message && !chan);
|
||||
if(!chan){
|
||||
printf("error : %s\n",ssh_get_error(session));
|
||||
ssh_finalize();
|
||||
return 1;
|
||||
}
|
||||
do {
|
||||
message=ssh_message_get(session);
|
||||
if(message && ssh_message_type(message)==SSH_CHANNEL_REQUEST &&
|
||||
ssh_message_subtype(message)==SSH_CHANNEL_REQUEST_SHELL){
|
||||
// if(!strcmp(ssh_message_channel_request_subsystem(message),"sftp")){
|
||||
sftp=1;
|
||||
ssh_message_channel_request_reply_success(message);
|
||||
break;
|
||||
// }
|
||||
}
|
||||
if(!sftp){
|
||||
ssh_message_reply_default(message);
|
||||
}
|
||||
ssh_message_free(message);
|
||||
} while (message && !sftp);
|
||||
if(!sftp){
|
||||
printf("error : %s\n",ssh_get_error(session));
|
||||
return 1;
|
||||
}
|
||||
printf("it works !\n");
|
||||
buf=buffer_new();
|
||||
do{
|
||||
i=channel_read_buffer(chan,buf,0,0);
|
||||
if(i>0)
|
||||
write(1,buffer_get(buf),buffer_get_len(buf));
|
||||
} while (i>0);
|
||||
buffer_free(buf);
|
||||
ssh_disconnect(session);
|
||||
ssh_bind_free(ssh_bind);
|
||||
ssh_finalize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
all: test_tunnel test_exec
|
||||
all: test_tunnel test_exec test_pcap
|
||||
CFLAGS=-I../include/ -g -Wall
|
||||
LDFLAGS=-lssh -L../build/libssh/
|
||||
|
||||
@@ -8,5 +8,8 @@ test_tunnel: test_tunnel.o authentication.o connection.o
|
||||
test_exec: test_exec.o authentication.o connection.o
|
||||
gcc -o $@ $^ $(LDFLAGS)
|
||||
|
||||
test_pcap: test_pcap.o
|
||||
gcc -o $@ $^ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f *.o test_tunnel
|
||||
|
||||
13
tests/bench1.sh
Normal file
13
tests/bench1.sh
Normal file
@@ -0,0 +1,13 @@
|
||||
export CIPHER=aes128-cbc
|
||||
export DEST=localhost
|
||||
|
||||
echo "Upload raw SSH statistics"
|
||||
echo "local machine: `uname -a`"
|
||||
echo "Cipher : $CIPHER ; Destination : $DEST (`ssh $DEST uname -a`)"
|
||||
echo "Local ssh version: `ssh -V 2>&1`"
|
||||
echo "Ping latency to $DEST":
|
||||
ping -q -c 1 -n $DEST
|
||||
echo "Destination $DEST SSHD vesion : `echo | nc $DEST 22 | head -n1`"
|
||||
echo "ssh login latency :`(time -f user:%U ssh $DEST 'id > /dev/null') 2>&1`"
|
||||
./generate.py | dd bs=4096 count=100000 | time ssh -c $CIPHER $DEST "dd bs=4096 of=/dev/null" 2>&1
|
||||
|
||||
13
tests/bench2.sh
Executable file
13
tests/bench2.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
export CIPHER=aes128-cbc
|
||||
export DEST=localhost
|
||||
|
||||
echo "Upload raw SSH statistics"
|
||||
echo "local machine: `uname -a`"
|
||||
echo "Cipher : $CIPHER ; Destination : $DEST (`ssh $DEST uname -a`)"
|
||||
echo "Local ssh version: `samplessh -V 2>&1`"
|
||||
echo "Ping latency to $DEST":
|
||||
ping -q -c 1 -n $DEST
|
||||
echo "Destination $DEST SSHD vesion : `echo | nc $DEST 22 | head -n1`"
|
||||
echo "ssh login latency :`(time -f user:%U samplessh $DEST 'id > /dev/null') 2>&1`"
|
||||
./generate.py | dd bs=4096 count=100000 | strace samplessh -c $CIPHER $DEST "dd bs=4096 of=/dev/null" 2>&1
|
||||
|
||||
10
tests/generate.py
Executable file
10
tests/generate.py
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/python
|
||||
import os
|
||||
a=""
|
||||
for i in xrange(4096):
|
||||
a+=chr(i % 256);
|
||||
while True:
|
||||
try:
|
||||
os.write(1,a)
|
||||
except:
|
||||
exit(0)
|
||||
174
tests/sftp_stress/main.c
Normal file
174
tests/sftp_stress/main.c
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* main.c
|
||||
*
|
||||
* Created on: 22 juin 2009
|
||||
* Author: aris
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/sftp.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#define TEST_READ 1
|
||||
#define TEST_WRITE 2
|
||||
#define NTHREADS 3
|
||||
#define FILESIZE 100000
|
||||
unsigned char samplefile[FILESIZE];
|
||||
volatile int stop=0;
|
||||
|
||||
const char* hosts[]={"localhost","barebone"};
|
||||
void signal_stop(){
|
||||
stop=1;
|
||||
printf("Stopping...\n");
|
||||
}
|
||||
|
||||
SSH_SESSION *connect_host(const char *hostname);
|
||||
int sftp_test(SSH_SESSION *session, int test);
|
||||
|
||||
int docycle(const char *host, int test){
|
||||
SSH_SESSION *session=connect_host(host);
|
||||
int ret=SSH_ERROR;
|
||||
if(!session){
|
||||
printf("connect failed\n");
|
||||
} else {
|
||||
printf("Connected\n");
|
||||
ret=sftp_test(session,test);
|
||||
if(ret != SSH_OK){
|
||||
printf("Error in sftp\n");
|
||||
}
|
||||
ssh_disconnect(session);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int thread(){
|
||||
while(docycle(hosts[rand()%2],TEST_WRITE) == SSH_OK)
|
||||
if(stop)
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int i;
|
||||
pthread_t threads[NTHREADS];
|
||||
ssh_init();
|
||||
srand(time(NULL));
|
||||
for(i=0;i<FILESIZE;++i)
|
||||
samplefile[i]=rand() & 0xff;
|
||||
signal(SIGTERM,signal_stop);
|
||||
signal(SIGINT,signal_stop);
|
||||
|
||||
for(i=0;i<NTHREADS;++i){
|
||||
srand(i);
|
||||
pthread_create(&threads[i],NULL,(void *) thread, NULL);
|
||||
}
|
||||
for(i=0;i<NTHREADS;++i){
|
||||
pthread_join(threads[i],NULL);
|
||||
}
|
||||
ssh_finalize();
|
||||
printf("Ended\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SSH_SESSION *connect_host(const char *hostname){
|
||||
SSH_SESSION *session;
|
||||
SSH_OPTIONS *options;
|
||||
int auth=0;
|
||||
int state;
|
||||
|
||||
options=ssh_options_new();
|
||||
ssh_options_set_host(options,hostname);
|
||||
session=ssh_new();
|
||||
ssh_set_options(session,options);
|
||||
if(ssh_connect(session)){
|
||||
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
return NULL;
|
||||
}
|
||||
state=ssh_is_server_known(session);
|
||||
|
||||
switch(state){
|
||||
case SSH_SERVER_KNOWN_OK:
|
||||
break; /* ok */
|
||||
case SSH_SERVER_KNOWN_CHANGED:
|
||||
fprintf(stderr,"Host key for server changed : server's one is now :\n");
|
||||
fprintf(stderr,"For security reason, connection will be stopped\n");
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
return NULL;
|
||||
case SSH_SERVER_FOUND_OTHER:
|
||||
fprintf(stderr,"The host key for this server was not found but an other type of key exists.\n");
|
||||
fprintf(stderr,"An attacker might change the default server key to confuse your client"
|
||||
"into thinking the key does not exist\n"
|
||||
"We advise you to rerun the client with -d or -r for more safety.\n");
|
||||
ssh_disconnect(session);
|
||||
ssh_finalize();
|
||||
return NULL;
|
||||
case SSH_SERVER_NOT_KNOWN:
|
||||
fprintf(stderr,"The server is unknown. Leaving now");
|
||||
ssh_disconnect(session);
|
||||
return NULL;
|
||||
case SSH_SERVER_ERROR:
|
||||
fprintf(stderr,"%s",ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssh_userauth_none(session, NULL);
|
||||
|
||||
auth=ssh_userauth_autopubkey(session, NULL);
|
||||
if(auth==SSH_AUTH_ERROR){
|
||||
fprintf(stderr,"Authenticating with pubkey: %s\n",ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
return NULL;
|
||||
}
|
||||
if(auth!=SSH_AUTH_SUCCESS){
|
||||
fprintf(stderr,"Authentication failed: %s\n",ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
return NULL;
|
||||
}
|
||||
ssh_log(session, SSH_LOG_FUNCTIONS, "Authentication success");
|
||||
return session;
|
||||
}
|
||||
|
||||
int sftp_test(SSH_SESSION *session, int test){
|
||||
SFTP_SESSION *sftp=sftp_new(session);
|
||||
SFTP_FILE *file;
|
||||
int wrote=0;
|
||||
char name[128];
|
||||
if(sftp == NULL)
|
||||
return SSH_ERROR;
|
||||
if(sftp_init(sftp)<0){
|
||||
printf("problem initializing sftp : %s\n",ssh_get_error(session));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(test==TEST_WRITE){
|
||||
snprintf(name,sizeof(name),"/tmp/libsshstress%d",rand());
|
||||
file=sftp_open(sftp,name,O_RDWR|O_CREAT,0777);
|
||||
if(!file){
|
||||
printf("Failed to open file : %s\n",ssh_get_error(session));
|
||||
sftp_free(sftp);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
while(wrote<FILESIZE){
|
||||
int max=FILESIZE-wrote;
|
||||
int towrite=rand()%max + 1;
|
||||
int ret=sftp_write(file,&samplefile[wrote],towrite);
|
||||
if(ret<=0){
|
||||
printf("Problem while writing : %s\n",ssh_get_error(session));
|
||||
sftp_free(sftp);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(ret != towrite){
|
||||
printf("Asked to write %d, wrote %d\n",towrite,ret);
|
||||
}
|
||||
wrote += ret;
|
||||
}
|
||||
sftp_close(file);
|
||||
}
|
||||
sftp_free(sftp);
|
||||
return SSH_OK;
|
||||
}
|
||||
50
tests/test_pcap.c
Normal file
50
tests/test_pcap.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* Simple test for the pcap functions */
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/pcap.h>
|
||||
#include <libssh/buffer.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char **argv){
|
||||
ssh_pcap_file pcap;
|
||||
ssh_pcap_context ctx;
|
||||
ssh_buffer buffer=buffer_new();
|
||||
char *str="Hello, this is a test string to test the capabilities of the"
|
||||
"pcap file writer.";
|
||||
printf("Simple pcap tester\n");
|
||||
pcap=ssh_pcap_file_new();
|
||||
if(ssh_pcap_file_open(pcap,"test.cap") != SSH_OK){
|
||||
printf("error happened\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
buffer_add_data(buffer,str,strlen(str));
|
||||
ctx=ssh_pcap_context_new(NULL);
|
||||
ssh_pcap_context_set_file(ctx,pcap);
|
||||
ssh_pcap_context_write(ctx,SSH_PCAP_DIR_OUT,str,strlen(str),strlen(str));
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user