mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-05 21:00:33 +09:00
Compare commits
229 Commits
libssh-0.1
...
libssh-0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10e09e273f | ||
|
|
622421018b | ||
|
|
8977e246b6 | ||
|
|
8b66d037d5 | ||
|
|
63ff242131 | ||
|
|
610d7a09f9 | ||
|
|
89df759200 | ||
|
|
5846e57538 | ||
|
|
0870c8db28 | ||
|
|
4cef5e965a | ||
|
|
2c492ee179 | ||
|
|
cea841d71c | ||
|
|
62d3101c1f | ||
|
|
d7467498fd | ||
|
|
22492b69bb | ||
|
|
9bbb817c0c | ||
|
|
c618040967 | ||
|
|
8615c24647 | ||
|
|
a66b4a6eae | ||
|
|
c2c56bacab | ||
|
|
52ebecf81c | ||
|
|
4b935d0785 | ||
|
|
57b92b18d6 | ||
|
|
48f217176f | ||
|
|
e8474e1ba3 | ||
|
|
85ce922bc4 | ||
|
|
49ead8f08e | ||
|
|
0813b75799 | ||
|
|
29ad26db26 | ||
|
|
cd2bf21f9a | ||
|
|
ed8b7ea7a7 | ||
|
|
105835d542 | ||
|
|
479eca13aa | ||
|
|
994acfe2c5 | ||
|
|
968e09aae0 | ||
|
|
a006d34372 | ||
|
|
a669408201 | ||
|
|
c68a58575b | ||
|
|
e8dfbb85a2 | ||
|
|
dc1254d53e | ||
|
|
d08f1b2377 | ||
|
|
70565ac438 | ||
|
|
fc1a8bb455 | ||
|
|
b759ae557d | ||
|
|
6df2daea04 | ||
|
|
99760776d4 | ||
|
|
247a4a761c | ||
|
|
a30339d7b1 | ||
|
|
8dde4e1924 | ||
|
|
b1d9bff6ee | ||
|
|
a0f10b9860 | ||
|
|
7e40f13125 | ||
|
|
36273e708a | ||
|
|
41c63fa88d | ||
|
|
d726eca7d2 | ||
|
|
ad2797613e | ||
|
|
653e5ee117 | ||
|
|
d8b1b5e0cc | ||
|
|
7341615e2f | ||
|
|
f8ba2b0148 | ||
|
|
d26cc63dd5 | ||
|
|
e41dacbf10 | ||
|
|
e786bacb92 | ||
|
|
19e2521242 | ||
|
|
429d0422dc | ||
|
|
559ebc9ccb | ||
|
|
d7f18c468e | ||
|
|
f73dac8eed | ||
|
|
3c381565c9 | ||
|
|
833c3d3330 | ||
|
|
6d073f2746 | ||
|
|
fe83733a7c | ||
|
|
d3d7eeab75 | ||
|
|
8a037e9afe | ||
|
|
dd0aaec67e | ||
|
|
8b3b041096 | ||
|
|
e9e9190079 | ||
|
|
bc4afc1067 | ||
|
|
6a187990c1 | ||
|
|
ec5bd83e50 | ||
|
|
e818700734 | ||
|
|
9e20e180e6 | ||
|
|
e426664623 | ||
|
|
921efbeea1 | ||
|
|
03f8fcae84 | ||
|
|
ea639b0258 | ||
|
|
bb5bdac321 | ||
|
|
554fe06aeb | ||
|
|
298155da71 | ||
|
|
44ceeb4d53 | ||
|
|
0c725d7602 | ||
|
|
2461027f72 | ||
|
|
967082c207 | ||
|
|
1f7995ccea | ||
|
|
662fe00c15 | ||
|
|
0d86688da2 | ||
|
|
02f39b5e60 | ||
|
|
1bf87909e7 | ||
|
|
096416d306 | ||
|
|
019040f693 | ||
|
|
f1c5888553 | ||
|
|
8a5bdc3a21 | ||
|
|
3a77bb2992 | ||
|
|
b2ca8b07ec | ||
|
|
1bc9b20b1a | ||
|
|
b9a6fac062 | ||
|
|
2eee844025 | ||
|
|
be2084f9e2 | ||
|
|
cfa95d9ead | ||
|
|
1685c14024 | ||
|
|
7f12c572d3 | ||
|
|
2177c9e567 | ||
|
|
96bc6af2b3 | ||
|
|
ec33973319 | ||
|
|
512ac7620b | ||
|
|
d190053660 | ||
|
|
253658dce8 | ||
|
|
8ac8b19017 | ||
|
|
e8838f419b | ||
|
|
2b45e61f74 | ||
|
|
54bcce5aa2 | ||
|
|
1fb95070f2 | ||
|
|
438cc6df52 | ||
|
|
4aeb685b04 | ||
|
|
54a3da64ad | ||
|
|
e21ceae755 | ||
|
|
905049d1e1 | ||
|
|
2c03f3bd0b | ||
|
|
e218745d0e | ||
|
|
24c44e2c7a | ||
|
|
7fd953ef42 | ||
|
|
80c994ef72 | ||
|
|
5c5811bf7c | ||
|
|
27f3e955e8 | ||
|
|
54a0eb6846 | ||
|
|
8c17a79797 | ||
|
|
13363975d8 | ||
|
|
e8dccfe1dd | ||
|
|
bff436695b | ||
|
|
e3d0f60281 | ||
|
|
92eedd8f19 | ||
|
|
a29f98be26 | ||
|
|
53bc265987 | ||
|
|
d993088553 | ||
|
|
5d26b0967d | ||
|
|
0d52be0f5b | ||
|
|
fc66be08a1 | ||
|
|
13a2aa3a97 | ||
|
|
4a36e52bc4 | ||
|
|
01a92b5838 | ||
|
|
e5f72468b8 | ||
|
|
1761db6f97 | ||
|
|
73ea9a8922 | ||
|
|
78e79fbc35 | ||
|
|
990db53ee6 | ||
|
|
18b46a6e17 | ||
|
|
096996501b | ||
|
|
569164740d | ||
|
|
0da3fe245b | ||
|
|
b448c3ad98 | ||
|
|
02e0eaa104 | ||
|
|
82e76a15d1 | ||
|
|
bddbe2a76d | ||
|
|
e8322817a9 | ||
|
|
e0c2f2809b | ||
|
|
9bb91df20f | ||
|
|
783f2b97a8 | ||
|
|
8d05810255 | ||
|
|
1d29d4b627 | ||
|
|
787711a271 | ||
|
|
ddea657ba7 | ||
|
|
9ae46bc364 | ||
|
|
fd1563575f | ||
|
|
1f973320a8 | ||
|
|
4fc7ab4399 | ||
|
|
87bac425a0 | ||
|
|
0e637e3327 | ||
|
|
9b1f4e9bf6 | ||
|
|
630f335415 | ||
|
|
b7934ab370 | ||
|
|
0aaad9eb25 | ||
|
|
8fe4cabb26 | ||
|
|
1689b83d0f | ||
|
|
7c6105882b | ||
|
|
bb6d1b78dc | ||
|
|
5a884b8c5a | ||
|
|
90128929e7 | ||
|
|
a7d509ca50 | ||
|
|
d26f7253a9 | ||
|
|
3ad2a21d13 | ||
|
|
7f6b3fab4e | ||
|
|
cd7ccf93f0 | ||
|
|
5944124428 | ||
|
|
8c40b2491d | ||
|
|
3331b794bc | ||
|
|
02f1873b9e | ||
|
|
5da93db25a | ||
|
|
b18495b56b | ||
|
|
a96763b195 | ||
|
|
540257b421 | ||
|
|
b657eeb65e | ||
|
|
4a87515026 | ||
|
|
886ed379d8 | ||
|
|
9b9197d86b | ||
|
|
64e89affeb | ||
|
|
2c1ad3262a | ||
|
|
14ff31490f | ||
|
|
3db3511467 | ||
|
|
4c5da86f91 | ||
|
|
2564246024 | ||
|
|
146d1a620d | ||
|
|
19c43ff6b7 | ||
|
|
58a2943d42 | ||
|
|
54c5472b53 | ||
|
|
17e9cd70a5 | ||
|
|
cee5c9f404 | ||
|
|
43fb1d7c8d | ||
|
|
5c629f22f6 | ||
|
|
46e0703c6e | ||
|
|
cffa103378 | ||
|
|
ea6558b3a6 | ||
|
|
33e12317c3 | ||
|
|
d17c635617 | ||
|
|
dde5fd8d38 | ||
|
|
46e78aaa3a | ||
|
|
3107133d10 | ||
|
|
b9ccaf6e23 | ||
|
|
38b17e6e6e | ||
|
|
db0a1d6811 |
@@ -1,29 +0,0 @@
|
|||||||
---
|
|
||||||
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
|
||||||
BasedOnStyle: LLVM
|
|
||||||
IndentWidth: 4
|
|
||||||
UseTab: Never
|
|
||||||
AllowShortIfStatementsOnASingleLine: false
|
|
||||||
BreakBeforeBraces: Custom
|
|
||||||
BraceWrapping:
|
|
||||||
AfterEnum: false
|
|
||||||
AfterFunction: true
|
|
||||||
AfterStruct: false
|
|
||||||
AfterUnion: false
|
|
||||||
AfterExternBlock: false
|
|
||||||
BeforeElse: false
|
|
||||||
BeforeWhile: false
|
|
||||||
IndentCaseLabels: false
|
|
||||||
IndentCaseBlocks: false
|
|
||||||
ColumnLimit: 80
|
|
||||||
AlignAfterOpenBracket: Align
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: false
|
|
||||||
BinPackArguments: false
|
|
||||||
BinPackParameters: false
|
|
||||||
AllowAllArgumentsOnNextLine: false
|
|
||||||
AllowShortFunctionsOnASingleLine: Empty
|
|
||||||
# TODO with Clang 19, replace the below with
|
|
||||||
# BreakAfterReturnType: ExceptShortType
|
|
||||||
AlwaysBreakAfterReturnType: AllDefinitions
|
|
||||||
AlignEscapedNewlines: Left
|
|
||||||
ForEachMacros: ['ssh_callbacks_iterate']
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
*.a
|
*.a
|
||||||
*.o
|
*.o
|
||||||
|
.*
|
||||||
*.swp
|
*.swp
|
||||||
*~$
|
*~$
|
||||||
cscope.*
|
cscope.*
|
||||||
@@ -9,4 +10,3 @@ compile_commands.json
|
|||||||
tags
|
tags
|
||||||
/build
|
/build
|
||||||
/obj*
|
/obj*
|
||||||
doc/tags.xml
|
|
||||||
|
|||||||
170
.gitlab-ci.yml
170
.gitlab-ci.yml
@@ -1,6 +1,7 @@
|
|||||||
---
|
---
|
||||||
variables:
|
variables:
|
||||||
BUILD_IMAGES_PROJECT: libssh/build-images
|
BUILD_IMAGES_PROJECT: libssh/build-images
|
||||||
|
CENTOS7_BUILD: buildenv-centos7
|
||||||
CENTOS8_BUILD: buildenv-c8s
|
CENTOS8_BUILD: buildenv-c8s
|
||||||
CENTOS9_BUILD: buildenv-c9s
|
CENTOS9_BUILD: buildenv-c9s
|
||||||
FEDORA_BUILD: buildenv-fedora
|
FEDORA_BUILD: buildenv-fedora
|
||||||
@@ -15,23 +16,12 @@ stages:
|
|||||||
- test
|
- test
|
||||||
- analysis
|
- analysis
|
||||||
|
|
||||||
# This is some black magic to select between branch pipelines and
|
|
||||||
# merge request pipelines to avoid running same pipelines in twice
|
|
||||||
workflow:
|
|
||||||
rules:
|
|
||||||
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"'
|
|
||||||
when: never
|
|
||||||
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
||||||
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
|
|
||||||
when: never
|
|
||||||
- if: '$CI_COMMIT_BRANCH'
|
|
||||||
|
|
||||||
.build:
|
.build:
|
||||||
stage: build
|
stage: build
|
||||||
variables:
|
variables:
|
||||||
CMAKE_DEFAULT_OPTIONS: "-DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON"
|
CMAKE_DEFAULT_OPTIONS: "-DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON"
|
||||||
CMAKE_BUILD_OPTIONS: "-DWITH_BLOWFISH_CIPHER=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON"
|
CMAKE_BUILD_OPTIONS: "-DWITH_BLOWFISH_CIPHER=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON -DWITH_DSA=ON"
|
||||||
CMAKE_TEST_OPTIONS: "-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DGSSAPI_TESTING=ON -DWITH_BENCHMARKS=ON -DFUZZ_TESTING=ON"
|
CMAKE_TEST_OPTIONS: "-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DWITH_BENCHMARKS=ON"
|
||||||
CMAKE_OPTIONS: $CMAKE_DEFAULT_OPTIONS $CMAKE_BUILD_OPTIONS $CMAKE_TEST_OPTIONS
|
CMAKE_OPTIONS: $CMAKE_DEFAULT_OPTIONS $CMAKE_BUILD_OPTIONS $CMAKE_TEST_OPTIONS
|
||||||
before_script: &build
|
before_script: &build
|
||||||
- uname -a
|
- uname -a
|
||||||
@@ -47,11 +37,7 @@ workflow:
|
|||||||
make -j$(nproc) install
|
make -j$(nproc) install
|
||||||
# Do not use after_script as it does not make the targets fail
|
# Do not use after_script as it does not make the targets fail
|
||||||
tags:
|
tags:
|
||||||
- saas-linux-small-amd64
|
- shared
|
||||||
only:
|
|
||||||
- merge_requests
|
|
||||||
- branches
|
|
||||||
|
|
||||||
except:
|
except:
|
||||||
- tags
|
- tags
|
||||||
artifacts:
|
artifacts:
|
||||||
@@ -84,7 +70,8 @@ workflow:
|
|||||||
.fips:
|
.fips:
|
||||||
extends: .tests
|
extends: .tests
|
||||||
variables:
|
variables:
|
||||||
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON
|
# DSA is turned off in fips mode
|
||||||
|
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_DSA=OFF
|
||||||
before_script:
|
before_script:
|
||||||
- *build
|
- *build
|
||||||
- echo "# userspace fips" > /etc/system-fips
|
- echo "# userspace fips" > /etc/system-fips
|
||||||
@@ -97,31 +84,19 @@ workflow:
|
|||||||
- update-crypto-policies --set FIPS
|
- update-crypto-policies --set FIPS
|
||||||
- update-crypto-policies --show
|
- update-crypto-policies --show
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Review #
|
|
||||||
###############################################################################
|
|
||||||
review:
|
|
||||||
variables:
|
|
||||||
GIT_DEPTH: 100
|
|
||||||
stage: review
|
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
|
||||||
script:
|
|
||||||
- ERROR=0
|
|
||||||
codespell --ignore-words-list=keypair,sorce,ned,nd,ue || ERROR=1;
|
|
||||||
./.gitlab-ci/clang-format-check.sh || ERROR=1;
|
|
||||||
./.gitlab-ci/git-check-signoff-trailer.sh ${CI_MERGE_REQUEST_DIFF_BASE_SHA} || ERROR=1;
|
|
||||||
./.gitlab-ci/shellcheck.sh || ERROR=1;
|
|
||||||
exit $ERROR
|
|
||||||
# the format is not always matching our intentions
|
|
||||||
allow_failure: true
|
|
||||||
tags:
|
|
||||||
- saas-linux-small-amd64
|
|
||||||
only:
|
|
||||||
- merge_requests
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# CentOS builds #
|
# CentOS builds #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
# pkd tests fail on CentOS7 docker images, so we don't use -DSERVER_TESTING=ON
|
||||||
|
centos7/openssl_1.0.x/x86_64:
|
||||||
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS7_BUILD
|
||||||
|
extends: .tests
|
||||||
|
script:
|
||||||
|
- cmake3 $CMAKE_OPTIONS .. &&
|
||||||
|
make -j$(nproc) &&
|
||||||
|
ctest --output-on-failure
|
||||||
|
|
||||||
centos9s/openssl_3.0.x/x86_64:
|
centos9s/openssl_3.0.x/x86_64:
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
|
||||||
extends: .tests
|
extends: .tests
|
||||||
@@ -133,12 +108,6 @@ centos9s/openssl_3.0.x/x86_64:
|
|||||||
make -j$(nproc) &&
|
make -j$(nproc) &&
|
||||||
ctest --output-on-failure
|
ctest --output-on-failure
|
||||||
|
|
||||||
centos9s/mbedtls_2.x/x86_64:
|
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
|
|
||||||
extends: .tests
|
|
||||||
variables:
|
|
||||||
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF"
|
|
||||||
|
|
||||||
centos9s/openssl_3.0.x/x86_64/fips:
|
centos9s/openssl_3.0.x/x86_64/fips:
|
||||||
extends: .fips
|
extends: .fips
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
|
||||||
@@ -177,8 +146,7 @@ fedora/docs:
|
|||||||
extends: .build
|
extends: .build
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||||
script:
|
script:
|
||||||
- cmake .. && make docs_coverage && make docs
|
- cmake .. && make docs
|
||||||
coverage: '/^Documentation coverage is \d+.\d+%/'
|
|
||||||
|
|
||||||
fedora/ninja:
|
fedora/ninja:
|
||||||
extends: .fedora
|
extends: .fedora
|
||||||
@@ -186,73 +154,24 @@ fedora/ninja:
|
|||||||
script:
|
script:
|
||||||
- cmake -G Ninja $CMAKE_OPTIONS ../ && ninja && CTEST_OUTPUT_ON_FAILURE=1 ninja test
|
- cmake -G Ninja $CMAKE_OPTIONS ../ && ninja && CTEST_OUTPUT_ON_FAILURE=1 ninja test
|
||||||
|
|
||||||
fedora/coverage:
|
|
||||||
extends: .fedora
|
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
|
||||||
variables:
|
|
||||||
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_BUILD_TYPE=Debug -DWITH_COVERAGE=ON"
|
|
||||||
script:
|
|
||||||
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
|
||||||
make -j$(nproc) &&
|
|
||||||
make coverage_xml
|
|
||||||
coverage: /^\s*lines:\s*\d+.\d+\%/
|
|
||||||
artifacts:
|
|
||||||
name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
|
|
||||||
expire_in: 1 week
|
|
||||||
reports:
|
|
||||||
coverage_report:
|
|
||||||
coverage_format: cobertura
|
|
||||||
path: obj/coverage_xml.xml
|
|
||||||
|
|
||||||
fedora/openssl_3.0.x/x86_64:
|
fedora/openssl_3.0.x/x86_64:
|
||||||
extends: .fedora
|
extends: .fedora
|
||||||
|
|
||||||
fedora/openssl_3.0.x/x86_64/pkcs11-provider:
|
|
||||||
variables:
|
|
||||||
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
|
|
||||||
extends: .fedora
|
|
||||||
|
|
||||||
fedora/openssl_3.0.x/x86_64/minimal:
|
fedora/openssl_3.0.x/x86_64/minimal:
|
||||||
extends: .fedora
|
extends: .fedora
|
||||||
variables:
|
variables:
|
||||||
script:
|
script:
|
||||||
- cmake $CMAKE_DEFAULT_OPTIONS
|
- cmake $CMAKE_DEFAULT_OPTIONS
|
||||||
-DWITH_EXEC=OFF
|
|
||||||
-DWITH_SFTP=OFF
|
-DWITH_SFTP=OFF
|
||||||
-DWITH_SERVER=OFF
|
-DWITH_SERVER=OFF
|
||||||
-DWITH_ZLIB=OFF
|
-DWITH_ZLIB=OFF
|
||||||
-DWITH_PCAP=OFF
|
-DWITH_PCAP=OFF
|
||||||
|
-DWITH_DSA=OFF
|
||||||
-DUNIT_TESTING=ON
|
-DUNIT_TESTING=ON
|
||||||
-DCLIENT_TESTING=ON
|
-DCLIENT_TESTING=ON
|
||||||
-DWITH_GEX=OFF .. &&
|
-DWITH_GEX=OFF .. &&
|
||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
|
|
||||||
.valgrind:
|
|
||||||
extends: .fedora
|
|
||||||
stage: analysis
|
|
||||||
script:
|
|
||||||
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
|
||||||
make -j$(nproc) &&
|
|
||||||
make test_memcheck
|
|
||||||
- cat Testing/Temporary/MemoryChecker.*.log | wc -l | grep "^0$"
|
|
||||||
|
|
||||||
# The PKCS#11 support is turned off as it brings dozens of memory issues from
|
|
||||||
# engine_pkcs11 or openssl itself
|
|
||||||
fedora/valgrind/openssl:
|
|
||||||
variables:
|
|
||||||
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=OFF
|
|
||||||
extends: .valgrind
|
|
||||||
|
|
||||||
fedora/valgrind/mbedtls:
|
|
||||||
variables:
|
|
||||||
CMAKE_ADDITIONAL_OPTIONS: -DWITH_MBEDTLS=ON
|
|
||||||
extends: .valgrind
|
|
||||||
|
|
||||||
fedora/valgrind/libgcrypt:
|
|
||||||
variables:
|
|
||||||
CMAKE_ADDITIONAL_OPTIONS: -DWITH_GCRYPT=ON
|
|
||||||
extends: .valgrind
|
|
||||||
|
|
||||||
# Address sanitizer doesn't mix well with LD_PRELOAD used in the testsuite
|
# Address sanitizer doesn't mix well with LD_PRELOAD used in the testsuite
|
||||||
# so, this is only enabled for unit tests right now.
|
# so, this is only enabled for unit tests right now.
|
||||||
# TODO: add -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
# TODO: add -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
||||||
@@ -308,10 +227,10 @@ fedora/libgcrypt/x86_64:
|
|||||||
variables:
|
variables:
|
||||||
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_GCRYPT=ON -DWITH_DEBUG_CRYPTO=ON"
|
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_GCRYPT=ON -DWITH_DEBUG_CRYPTO=ON"
|
||||||
|
|
||||||
fedora/mbedtls_2.x/x86_64:
|
fedora/mbedtls/x86_64:
|
||||||
extends: .fedora
|
extends: .fedora
|
||||||
variables:
|
variables:
|
||||||
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON "
|
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_DSA=OFF"
|
||||||
|
|
||||||
# Unit testing only, no client and pkd testing, because cwrap is not available
|
# Unit testing only, no client and pkd testing, because cwrap is not available
|
||||||
# for MinGW
|
# for MinGW
|
||||||
@@ -358,11 +277,6 @@ fedora/mingw32:
|
|||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||||
before_script:
|
before_script:
|
||||||
- |
|
- |
|
||||||
# for merge requests
|
|
||||||
if [[ -n "$CI_MERGE_REQUEST_DIFF_BASE_SHA" ]]; then
|
|
||||||
export CI_COMMIT_BEFORE_SHA="$CI_MERGE_REQUEST_DIFF_BASE_SHA"
|
|
||||||
fi
|
|
||||||
# for branches run
|
|
||||||
if [[ -z "$CI_COMMIT_BEFORE_SHA" ]]; then
|
if [[ -z "$CI_COMMIT_BEFORE_SHA" ]]; then
|
||||||
export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
|
export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
|
||||||
fi
|
fi
|
||||||
@@ -373,11 +287,9 @@ fedora/mingw32:
|
|||||||
|
|
||||||
export CI_COMMIT_RANGE="$CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA"
|
export CI_COMMIT_RANGE="$CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA"
|
||||||
tags:
|
tags:
|
||||||
- saas-linux-small-amd64
|
- shared
|
||||||
except:
|
except:
|
||||||
- tags
|
- tags
|
||||||
only:
|
|
||||||
- merge_requests
|
|
||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 1 week
|
expire_in: 1 week
|
||||||
when: on_failure
|
when: on_failure
|
||||||
@@ -389,7 +301,7 @@ fedora/csbuild/openssl_3.0.x:
|
|||||||
script:
|
script:
|
||||||
- csbuild
|
- csbuild
|
||||||
--build-dir=obj-csbuild
|
--build-dir=obj-csbuild
|
||||||
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON @SRCDIR@ && make clean && make -j$(nproc)"
|
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON -DWITH_DSA=ON @SRCDIR@ && make clean && make -j$(nproc)"
|
||||||
--git-commit-range $CI_COMMIT_RANGE
|
--git-commit-range $CI_COMMIT_RANGE
|
||||||
--color
|
--color
|
||||||
--print-current --print-fixed
|
--print-current --print-fixed
|
||||||
@@ -399,7 +311,7 @@ fedora/csbuild/libgcrypt:
|
|||||||
script:
|
script:
|
||||||
- csbuild
|
- csbuild
|
||||||
--build-dir=obj-csbuild
|
--build-dir=obj-csbuild
|
||||||
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON -DWITH_GCRYPT=ON @SRCDIR@ && make clean && make -j$(nproc)"
|
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON -DWITH_GCRYPT=ON -DWITH_DSA=ON @SRCDIR@ && make clean && make -j$(nproc)"
|
||||||
--git-commit-range $CI_COMMIT_RANGE
|
--git-commit-range $CI_COMMIT_RANGE
|
||||||
--color
|
--color
|
||||||
--print-current --print-fixed
|
--print-current --print-fixed
|
||||||
@@ -445,6 +357,8 @@ alpine/openssl_3.0.x/musl:
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
tumbleweed/openssl_3.0.x/x86_64/gcc:
|
tumbleweed/openssl_3.0.x/x86_64/gcc:
|
||||||
extends: .tumbleweed
|
extends: .tumbleweed
|
||||||
|
variables:
|
||||||
|
CMAKE_ADDITIONAL_OPTIONS: "-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config"
|
||||||
|
|
||||||
tumbleweed/openssl_3.0.x/x86/gcc:
|
tumbleweed/openssl_3.0.x/x86/gcc:
|
||||||
extends: .tumbleweed
|
extends: .tumbleweed
|
||||||
@@ -456,13 +370,14 @@ tumbleweed/openssl_3.0.x/x86/gcc:
|
|||||||
-DWITH_SERVER=ON
|
-DWITH_SERVER=ON
|
||||||
-DWITH_ZLIB=ON
|
-DWITH_ZLIB=ON
|
||||||
-DWITH_PCAP=ON
|
-DWITH_PCAP=ON
|
||||||
|
-DWITH_DSA=ON
|
||||||
-DUNIT_TESTING=ON .. &&
|
-DUNIT_TESTING=ON .. &&
|
||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
|
|
||||||
tumbleweed/openssl_3.0.x/x86_64/gcc7:
|
tumbleweed/openssl_3.0.x/x86_64/gcc7:
|
||||||
extends: .tumbleweed
|
extends: .tumbleweed
|
||||||
variables:
|
variables:
|
||||||
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7"
|
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7 -DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config"
|
||||||
|
|
||||||
tumbleweed/openssl_3.0.x/x86/gcc7:
|
tumbleweed/openssl_3.0.x/x86/gcc7:
|
||||||
extends: .tumbleweed
|
extends: .tumbleweed
|
||||||
@@ -472,6 +387,7 @@ tumbleweed/openssl_3.0.x/x86/gcc7:
|
|||||||
-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7
|
-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7
|
||||||
$CMAKE_DEFAULT_OPTIONS
|
$CMAKE_DEFAULT_OPTIONS
|
||||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||||
|
-DWITH_DSA=ON
|
||||||
-DUNIT_TESTING=ON .. &&
|
-DUNIT_TESTING=ON .. &&
|
||||||
make -j$(nproc) &&
|
make -j$(nproc) &&
|
||||||
ctest --output-on-failure
|
ctest --output-on-failure
|
||||||
@@ -479,12 +395,7 @@ tumbleweed/openssl_3.0.x/x86/gcc7:
|
|||||||
tumbleweed/openssl_3.0.x/x86_64/clang:
|
tumbleweed/openssl_3.0.x/x86_64/clang:
|
||||||
extends: .tumbleweed
|
extends: .tumbleweed
|
||||||
variables:
|
variables:
|
||||||
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
|
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config"
|
||||||
|
|
||||||
tumbleweed/mbedtls-3.6.x/x86_64/gcc:
|
|
||||||
extends: .tumbleweed
|
|
||||||
variables:
|
|
||||||
CMAKE_ADDITIONAL_OPTIONS: "-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config -DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF "
|
|
||||||
|
|
||||||
tumbleweed/static-analysis:
|
tumbleweed/static-analysis:
|
||||||
extends: .tests
|
extends: .tests
|
||||||
@@ -544,12 +455,8 @@ freebsd/openssl_1.1.1/x86_64:
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# Visual Studio builds #
|
# Visual Studio builds #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# 2024-05-13: These jobs run out of the stages as they take extremely long and
|
|
||||||
# usually timeout with the update to Gitlab 17.0
|
|
||||||
.vs:
|
.vs:
|
||||||
stage: analysis
|
stage: test
|
||||||
needs: []
|
|
||||||
allow_failure: true
|
|
||||||
cache:
|
cache:
|
||||||
key: vcpkg.${CI_JOB_NAME}
|
key: vcpkg.${CI_JOB_NAME}
|
||||||
paths:
|
paths:
|
||||||
@@ -560,10 +467,8 @@ freebsd/openssl_1.1.1/x86_64:
|
|||||||
- cmake --build .
|
- cmake --build .
|
||||||
- ctest --output-on-failure
|
- ctest --output-on-failure
|
||||||
tags:
|
tags:
|
||||||
- saas-windows-medium-amd64
|
- windows
|
||||||
only:
|
- shared-windows
|
||||||
- merge_requests
|
|
||||||
- branches
|
|
||||||
except:
|
except:
|
||||||
- tags
|
- tags
|
||||||
artifacts:
|
artifacts:
|
||||||
@@ -627,7 +532,7 @@ coverity:
|
|||||||
--form description="CI build"
|
--form description="CI build"
|
||||||
https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
|
https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
|
||||||
tags:
|
tags:
|
||||||
- saas-linux-small-amd64
|
- shared
|
||||||
only:
|
only:
|
||||||
refs:
|
refs:
|
||||||
- master
|
- master
|
||||||
@@ -641,3 +546,14 @@ coverity:
|
|||||||
when: on_failure
|
when: on_failure
|
||||||
paths:
|
paths:
|
||||||
- obj/cov-int/*.txt
|
- obj/cov-int/*.txt
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Codespell #
|
||||||
|
###############################################################################
|
||||||
|
codespell:
|
||||||
|
stage: review
|
||||||
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||||
|
script:
|
||||||
|
- codespell --ignore-words-list=keypair,sorce,ned,nd,ue
|
||||||
|
tags:
|
||||||
|
- shared
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Based on Github Action
|
|
||||||
# https://github.com/yshui/git-clang-format-lint
|
|
||||||
|
|
||||||
diff=$(git-clang-format --diff --commit "$CI_MERGE_REQUEST_DIFF_BASE_SHA")
|
|
||||||
[ "$diff" = "no modified files to format" ] && exit 0
|
|
||||||
[ "$diff" = "clang-format did not modify any files" ] && exit 0
|
|
||||||
|
|
||||||
printf "You have introduced coding style breakages, suggested changes:\n\n"
|
|
||||||
|
|
||||||
echo "${diff}" | colordiff
|
|
||||||
exit 1
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [ $# != 1 ]; then
|
|
||||||
echo "Usage: $0 UPSTREAM_COMMIT_SHA"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
failed=0
|
|
||||||
|
|
||||||
if [ -z "$CI_COMMIT_SHA" ]; then
|
|
||||||
echo "CI_COMMIT_SHA is not set"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
CI_COMMIT_RANGE="$1..$CI_COMMIT_SHA"
|
|
||||||
|
|
||||||
red='\033[0;31m'
|
|
||||||
blue='\033[0;34m'
|
|
||||||
|
|
||||||
echo -e "${blue}Checking commit range: $CI_COMMIT_RANGE"
|
|
||||||
echo
|
|
||||||
echo
|
|
||||||
|
|
||||||
for commit in $(git rev-list "$CI_COMMIT_RANGE"); do
|
|
||||||
git show -s --format=%B "$commit" | grep "^Signed-off-by: " >/dev/null 2>&1
|
|
||||||
ret=$?
|
|
||||||
if [ $ret -eq 1 ]; then
|
|
||||||
echo -e "${red} >>> Missing Signed-off-by trailer in commit $commit"
|
|
||||||
failed=$(("$failed" + 1))
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo
|
|
||||||
|
|
||||||
exit $failed
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Simplified and de-github-ed version of
|
|
||||||
# https://github.com/ludeeus/action-shellcheck/blob/master/action.yaml
|
|
||||||
|
|
||||||
statuscode=0
|
|
||||||
|
|
||||||
declare -a filepaths
|
|
||||||
shebangregex="^#! */[^ ]*/(env *)?[abk]*sh"
|
|
||||||
set -f # temporarily disable globbing so that globs in inputs aren't expanded
|
|
||||||
|
|
||||||
while IFS= read -r -d '' file; do
|
|
||||||
filepaths+=("$file")
|
|
||||||
done < <(find . \
|
|
||||||
-type f \
|
|
||||||
'(' \
|
|
||||||
-name '*.bash' \
|
|
||||||
-o -name '.bashrc' \
|
|
||||||
-o -name 'bashrc' \
|
|
||||||
-o -name '.bash_aliases' \
|
|
||||||
-o -name '.bash_completion' \
|
|
||||||
-o -name '.bash_login' \
|
|
||||||
-o -name '.bash_logout' \
|
|
||||||
-o -name '.bash_profile' \
|
|
||||||
-o -name 'bash_profile' \
|
|
||||||
-o -name '*.ksh' \
|
|
||||||
-o -name 'suid_profile' \
|
|
||||||
-o -name '*.zsh' \
|
|
||||||
-o -name '.zlogin' \
|
|
||||||
-o -name 'zlogin' \
|
|
||||||
-o -name '.zlogout' \
|
|
||||||
-o -name 'zlogout' \
|
|
||||||
-o -name '.zprofile' \
|
|
||||||
-o -name 'zprofile' \
|
|
||||||
-o -name '.zsenv' \
|
|
||||||
-o -name 'zsenv' \
|
|
||||||
-o -name '.zshrc' \
|
|
||||||
-o -name 'zshrc' \
|
|
||||||
-o -name '*.sh' \
|
|
||||||
-o -path '*/.profile' \
|
|
||||||
-o -path '*/profile' \
|
|
||||||
-o -name '*.shlib' \
|
|
||||||
')' \
|
|
||||||
-print0)
|
|
||||||
|
|
||||||
while IFS= read -r -d '' file; do
|
|
||||||
head -n1 "$file" | grep -Eqs "$shebangregex" || continue
|
|
||||||
filepaths+=("$file")
|
|
||||||
done < <(find . \
|
|
||||||
-type f ! -name '*.*' -perm /111 \
|
|
||||||
-print0)
|
|
||||||
|
|
||||||
shellcheck "${filepaths[@]}" || statuscode=$?
|
|
||||||
|
|
||||||
set +f # re-enable globbing
|
|
||||||
|
|
||||||
exit "$statuscode"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#
|
|
||||||
# GitLeaks Repo Specific Configuration
|
|
||||||
#
|
|
||||||
# This allowlist is used to help Red Hat ignore false positives during its code
|
|
||||||
# scans.
|
|
||||||
|
|
||||||
[allowlist]
|
|
||||||
paths = [
|
|
||||||
'''tests/*''',
|
|
||||||
]
|
|
||||||
80
CHANGELOG
80
CHANGELOG
@@ -1,82 +1,5 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
version 0.11.1 (released 2024-08-30)
|
|
||||||
* Fixed default TTY modes that are set when stdin is not connected to tty (#270)
|
|
||||||
* Fixed zlib cleanup procedure, which could crash on i386
|
|
||||||
* Various test fixes improving their stability
|
|
||||||
* Fixed cygwin build
|
|
||||||
|
|
||||||
version 0.11.0 (released 2024-07-31)
|
|
||||||
* Deprecations and Removals:
|
|
||||||
* Dropped support for DSA
|
|
||||||
* Deprecated Blowfish cipher (will be removed in next release)
|
|
||||||
* Deprecated SSH_BIND_OPTIONS_{RSA,ECDSA}KEY in favor of generic HOSTKEY
|
|
||||||
* Removed the usage of deprecated OpenSSL APIs (Note: Minimum supported
|
|
||||||
OpenSSL version is 1.1.1)
|
|
||||||
* Disabled preauth compression (zlib) by default
|
|
||||||
* Support for pkcs#11 engines are deprecated, pkcs11-provider is used instead
|
|
||||||
* Deprecation of old async SFTP API
|
|
||||||
* libgcrypt cryptographic backend is deprecated
|
|
||||||
* Deprecation of knownhosts hashing
|
|
||||||
* SFTP Improvements:
|
|
||||||
* Added support for async SFTP IO
|
|
||||||
* Added support for sftp_limits() and applied capping to SFTP read/write
|
|
||||||
operations accordingly
|
|
||||||
* Added sftp_home_directory() API support for sftp extension "home-directory"
|
|
||||||
* Added sftp_lsetstat() API for lsetstat extensions
|
|
||||||
* Added sftp_expand_path() to canonicalize path using expand-path@openssh.com
|
|
||||||
extension
|
|
||||||
* Implemented stat and realpath in sftpserver
|
|
||||||
* Added sftp_readlink() API to support hardlink@openssh.com
|
|
||||||
* New extensible callback based SFTP server
|
|
||||||
* Introduced the posix-rename@openssh.com extension
|
|
||||||
* New functions and features:
|
|
||||||
* Added support for PKCS #11 provider for OpenSSL 3.0
|
|
||||||
* Added testing for GSSAPI Authentication
|
|
||||||
* Implemented proxy jump using libssh
|
|
||||||
* Recategorized loglevels to show fatal errors and alignment with OpenSSH
|
|
||||||
log levels
|
|
||||||
* Added ssh_channel_request_pty_size_modes() API to set terminal modes for
|
|
||||||
PTYs
|
|
||||||
* Added function to check username syntax
|
|
||||||
* Added support to check all keys in authorized_keys instead of one in
|
|
||||||
example server implementation
|
|
||||||
* Handled hostkey similar to OpenSSH
|
|
||||||
* Added ssh_session_socket_close() API in order to not close socket passed
|
|
||||||
through options on error conditions
|
|
||||||
* Added option SSH_BIND_OPTIONS_IMPORT_KEY_STR to read user-supplied key
|
|
||||||
string in ssh_bind_options_set()
|
|
||||||
* Improved log handling around ssh_set_callbacks
|
|
||||||
* Added ssh_set_error_invalid in ssh_options_set()
|
|
||||||
* Prevented signature blob to start with 1 bit in libgcrypt
|
|
||||||
* Added support to unbreak key comparison of Ed25519 keys imported from PEM
|
|
||||||
or OpenSSH container
|
|
||||||
* Added support to calculate missing CRT parameters when building RSA key
|
|
||||||
* Added ssh_pki_export_privkey_base64_format() and
|
|
||||||
ssh_pki_export_privkey_file_format() to support exporting keys in different
|
|
||||||
formats (PEM, OpenSSH)
|
|
||||||
* Added support to compare certificates and handle automatic certificate
|
|
||||||
authentication
|
|
||||||
* Added support to make compile-commands generation conditional
|
|
||||||
* Built fuzzers for normal testing
|
|
||||||
* Avoided passing other events to callbacks when called recursively
|
|
||||||
* Added control master and path options
|
|
||||||
* Refactored channel_rcv_data, check for errors and report more useful errors
|
|
||||||
* Added support to connect to other host addresses than just the first one
|
|
||||||
* Terminated the server properly when the MaxAuthTries is reached
|
|
||||||
* Added support for no-more-sessions@openssh.com request in both client and
|
|
||||||
server
|
|
||||||
* Added callback to support forwarded-tcpip requests
|
|
||||||
* Bumped minimal CMake version to 3.12
|
|
||||||
* Added support for MBedTLS 3.6.x
|
|
||||||
* Added support for +,-,^ modifiers in front of algorithm lists in options
|
|
||||||
* Added callbacks for channel open response, and channel request response
|
|
||||||
* Replaced chroot() from chroot_wrapper internal library with chroot()
|
|
||||||
from priv_wrapper package
|
|
||||||
* Added a placeholder for non-expanded identities
|
|
||||||
* Improved handling of channel transfer window sizes
|
|
||||||
|
|
||||||
version 0.10.6 (released 2023-12-18)
|
version 0.10.6 (released 2023-12-18)
|
||||||
* Fix CVE-2023-6004: Command injection using proxycommand
|
* Fix CVE-2023-6004: Command injection using proxycommand
|
||||||
* Fix CVE-2023-48795: Potential downgrade attack using strict kex
|
* Fix CVE-2023-48795: Potential downgrade attack using strict kex
|
||||||
@@ -152,6 +75,9 @@ version 0.10.0 (released 2022-08-26)
|
|||||||
* Deprecated old pubkey, privatekey API
|
* Deprecated old pubkey, privatekey API
|
||||||
* Avoided some needless large stack buffers to minimize memory footprint
|
* Avoided some needless large stack buffers to minimize memory footprint
|
||||||
* Removed support for OpenSSL < 1.0.1
|
* Removed support for OpenSSL < 1.0.1
|
||||||
|
* Fixed parsing username@host in login name
|
||||||
|
* Free global init mutex in the destructor on Windows
|
||||||
|
* Fixed PEM parsing in mbedtls to support both legacy and new PKCS8 formats
|
||||||
|
|
||||||
version 0.9.6 (released 2021-08-26)
|
version 0.9.6 (released 2021-08-26)
|
||||||
* CVE-2021-3634: Fix possible heap-buffer overflow when rekeying with
|
* CVE-2021-3634: Fix possible heap-buffer overflow when rekeying with
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.12.0)
|
cmake_minimum_required(VERSION 3.3.0)
|
||||||
|
cmake_policy(SET CMP0048 NEW)
|
||||||
|
|
||||||
# Specify search path for CMake modules to be loaded by include()
|
# Specify search path for CMake modules to be loaded by include()
|
||||||
# and find_package()
|
# and find_package()
|
||||||
@@ -9,7 +10,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
|
|||||||
include(DefineCMakeDefaults)
|
include(DefineCMakeDefaults)
|
||||||
include(DefineCompilerFlags)
|
include(DefineCompilerFlags)
|
||||||
|
|
||||||
project(libssh VERSION 0.11.1 LANGUAGES C CXX)
|
project(libssh VERSION 0.10.6 LANGUAGES C)
|
||||||
|
|
||||||
# global needed variable
|
# global needed variable
|
||||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||||
@@ -21,7 +22,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
|
|||||||
# Increment AGE. Set REVISION to 0
|
# Increment AGE. Set REVISION to 0
|
||||||
# If the source code was changed, but there were no interface changes:
|
# If the source code was changed, but there were no interface changes:
|
||||||
# Increment REVISION.
|
# Increment REVISION.
|
||||||
set(LIBRARY_VERSION "4.10.1")
|
set(LIBRARY_VERSION "4.9.6")
|
||||||
set(LIBRARY_SOVERSION "4")
|
set(LIBRARY_SOVERSION "4")
|
||||||
|
|
||||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||||
@@ -48,12 +49,32 @@ endif (WITH_ZLIB)
|
|||||||
|
|
||||||
if (WITH_GCRYPT)
|
if (WITH_GCRYPT)
|
||||||
find_package(GCrypt 1.5.0 REQUIRED)
|
find_package(GCrypt 1.5.0 REQUIRED)
|
||||||
message(WARNING "libgcrypt cryptographic backend is deprecated and will be removed in future releases.")
|
if (NOT GCRYPT_FOUND)
|
||||||
|
message(FATAL_ERROR "Could not find GCrypt")
|
||||||
|
endif (NOT GCRYPT_FOUND)
|
||||||
elseif(WITH_MBEDTLS)
|
elseif(WITH_MBEDTLS)
|
||||||
find_package(MbedTLS REQUIRED)
|
find_package(MbedTLS REQUIRED)
|
||||||
else()
|
if (NOT MBEDTLS_FOUND)
|
||||||
find_package(OpenSSL 1.1.1 REQUIRED)
|
message(FATAL_ERROR "Could not find mbedTLS")
|
||||||
endif()
|
endif (NOT MBEDTLS_FOUND)
|
||||||
|
else (WITH_GCRYPT)
|
||||||
|
find_package(OpenSSL 1.0.1)
|
||||||
|
if (OPENSSL_FOUND)
|
||||||
|
# On CMake < 3.16, OPENSSL_CRYPTO_LIBRARIES is usually a synonym for OPENSSL_CRYPTO_LIBRARY, but is not defined
|
||||||
|
# when building on Windows outside of Cygwin. We provide the synonym here, if FindOpenSSL didn't define it already.
|
||||||
|
if (NOT DEFINED OPENSSL_CRYPTO_LIBRARIES)
|
||||||
|
set(OPENSSL_CRYPTO_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||||
|
endif (NOT DEFINED OPENSSL_CRYPTO_LIBRARIES)
|
||||||
|
else (OPENSSL_FOUND)
|
||||||
|
find_package(GCrypt)
|
||||||
|
if (NOT GCRYPT_FOUND)
|
||||||
|
find_package(MbedTLS)
|
||||||
|
if (NOT MBEDTLS_FOUND)
|
||||||
|
message(FATAL_ERROR "Could not find OpenSSL, GCrypt or mbedTLS")
|
||||||
|
endif (NOT MBEDTLS_FOUND)
|
||||||
|
endif (NOT GCRYPT_FOUND)
|
||||||
|
endif (OPENSSL_FOUND)
|
||||||
|
endif(WITH_GCRYPT)
|
||||||
|
|
||||||
if (UNIT_TESTING)
|
if (UNIT_TESTING)
|
||||||
find_package(CMocka REQUIRED)
|
find_package(CMocka REQUIRED)
|
||||||
@@ -68,6 +89,13 @@ if (WITH_GSSAPI)
|
|||||||
find_package(GSSAPI)
|
find_package(GSSAPI)
|
||||||
endif (WITH_GSSAPI)
|
endif (WITH_GSSAPI)
|
||||||
|
|
||||||
|
if (WITH_PKCS11_URI)
|
||||||
|
find_package(softhsm)
|
||||||
|
if (NOT SOFTHSM_FOUND)
|
||||||
|
message(SEND_ERROR "Could not find softhsm module!")
|
||||||
|
endif (NOT SOFTHSM_FOUND)
|
||||||
|
endif (WITH_PKCS11_URI)
|
||||||
|
|
||||||
if (WITH_NACL)
|
if (WITH_NACL)
|
||||||
find_package(NaCl)
|
find_package(NaCl)
|
||||||
if (NOT NACL_FOUND)
|
if (NOT NACL_FOUND)
|
||||||
@@ -75,6 +103,8 @@ if (WITH_NACL)
|
|||||||
endif (NOT NACL_FOUND)
|
endif (NOT NACL_FOUND)
|
||||||
endif (WITH_NACL)
|
endif (WITH_NACL)
|
||||||
|
|
||||||
|
find_package(Argp)
|
||||||
|
|
||||||
# Disable symbol versioning in non UNIX platforms
|
# Disable symbol versioning in non UNIX platforms
|
||||||
if (UNIX)
|
if (UNIX)
|
||||||
find_package(ABIMap 0.3.1)
|
find_package(ABIMap 0.3.1)
|
||||||
@@ -86,10 +116,6 @@ endif (UNIX)
|
|||||||
include(ConfigureChecks.cmake)
|
include(ConfigureChecks.cmake)
|
||||||
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||||
|
|
||||||
if (NOT HAVE_ARGP_PARSE)
|
|
||||||
find_package(Argp)
|
|
||||||
endif (NOT HAVE_ARGP_PARSE)
|
|
||||||
|
|
||||||
# check subdirectories
|
# check subdirectories
|
||||||
add_subdirectory(doc)
|
add_subdirectory(doc)
|
||||||
add_subdirectory(include)
|
add_subdirectory(include)
|
||||||
@@ -188,35 +214,16 @@ if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
|||||||
endif(UPDATE_ABI)
|
endif(UPDATE_ABI)
|
||||||
endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
||||||
|
|
||||||
# Coverage
|
|
||||||
if (WITH_COVERAGE)
|
|
||||||
include(CodeCoverage)
|
|
||||||
setup_target_for_coverage_lcov(
|
|
||||||
NAME "coverage"
|
|
||||||
EXECUTABLE make test
|
|
||||||
DEPENDENCIES ssh tests)
|
|
||||||
set(GCOVR_ADDITIONAL_ARGS --xml-pretty --exclude-unreachable-branches --print-summary)
|
|
||||||
setup_target_for_coverage_gcovr_xml(
|
|
||||||
NAME "coverage_xml"
|
|
||||||
EXECUTABLE make test
|
|
||||||
DEPENDENCIES ssh tests)
|
|
||||||
endif (WITH_COVERAGE)
|
|
||||||
|
|
||||||
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source DEPENDS ${_SYMBOL_TARGET} VERBATIM)
|
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source DEPENDS ${_SYMBOL_TARGET} VERBATIM)
|
||||||
|
|
||||||
get_directory_property(hasParent PARENT_DIRECTORY)
|
# Link compile database for clangd
|
||||||
if(NOT(hasParent))
|
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink
|
||||||
# Link compile database for clangd if we are the master project
|
"${CMAKE_BINARY_DIR}/compile_commands.json"
|
||||||
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink
|
"${CMAKE_SOURCE_DIR}/compile_commands.json")
|
||||||
"${CMAKE_BINARY_DIR}/compile_commands.json"
|
|
||||||
"${CMAKE_SOURCE_DIR}/compile_commands.json")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
message(STATUS "********************************************")
|
message(STATUS "********************************************")
|
||||||
message(STATUS "********** ${PROJECT_NAME} build options : **********")
|
message(STATUS "********** ${PROJECT_NAME} build options : **********")
|
||||||
|
|
||||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
|
||||||
message(STATUS "Coverage: ${WITH_COVERAGE}")
|
|
||||||
message(STATUS "zlib support: ${WITH_ZLIB}")
|
message(STATUS "zlib support: ${WITH_ZLIB}")
|
||||||
message(STATUS "libgcrypt support: ${WITH_GCRYPT}")
|
message(STATUS "libgcrypt support: ${WITH_GCRYPT}")
|
||||||
message(STATUS "libmbedTLS support: ${WITH_MBEDTLS}")
|
message(STATUS "libmbedTLS support: ${WITH_MBEDTLS}")
|
||||||
@@ -226,14 +233,13 @@ message(STATUS "Server support : ${WITH_SERVER}")
|
|||||||
message(STATUS "GSSAPI support : ${WITH_GSSAPI}")
|
message(STATUS "GSSAPI support : ${WITH_GSSAPI}")
|
||||||
message(STATUS "GEX support : ${WITH_GEX}")
|
message(STATUS "GEX support : ${WITH_GEX}")
|
||||||
message(STATUS "Support insecure none cipher and MAC : ${WITH_INSECURE_NONE}")
|
message(STATUS "Support insecure none cipher and MAC : ${WITH_INSECURE_NONE}")
|
||||||
message(STATUS "Support exec : ${WITH_EXEC}")
|
|
||||||
message(STATUS "Pcap debugging support : ${WITH_PCAP}")
|
message(STATUS "Pcap debugging support : ${WITH_PCAP}")
|
||||||
message(STATUS "Build shared library: ${BUILD_SHARED_LIBS}")
|
message(STATUS "Build shared library: ${BUILD_SHARED_LIBS}")
|
||||||
message(STATUS "Unit testing: ${UNIT_TESTING}")
|
message(STATUS "Unit testing: ${UNIT_TESTING}")
|
||||||
message(STATUS "Client code testing: ${CLIENT_TESTING}")
|
message(STATUS "Client code testing: ${CLIENT_TESTING}")
|
||||||
message(STATUS "Blowfish cipher support: ${HAVE_BLOWFISH}")
|
message(STATUS "Blowfish cipher support: ${WITH_BLOWFISH_CIPHER}")
|
||||||
message(STATUS "PKCS #11 URI support: ${WITH_PKCS11_URI}")
|
message(STATUS "PKCS #11 URI support: ${WITH_PKCS11_URI}")
|
||||||
message(STATUS "With PKCS #11 provider support: ${WITH_PKCS11_PROVIDER}")
|
message(STATUS "DSA support: ${WITH_DSA}")
|
||||||
set(_SERVER_TESTING OFF)
|
set(_SERVER_TESTING OFF)
|
||||||
if (WITH_SERVER)
|
if (WITH_SERVER)
|
||||||
set(_SERVER_TESTING ${SERVER_TESTING})
|
set(_SERVER_TESTING ${SERVER_TESTING})
|
||||||
|
|||||||
@@ -478,45 +478,6 @@ Macros like `STATUS_NOT_OK_RETURN` that change control flow (return/goto/etc)
|
|||||||
from within the macro are considered bad, because they look like function calls
|
from within the macro are considered bad, because they look like function calls
|
||||||
that never change control flow. Please do not introduce them.
|
that never change control flow. Please do not introduce them.
|
||||||
|
|
||||||
### Switch/case indentation
|
|
||||||
|
|
||||||
The `case` should not be indented to avoid wasting too much horizontal space.
|
|
||||||
When the case block contains local variables that need to be wrapped in braces,
|
|
||||||
they should not be indented again either.
|
|
||||||
|
|
||||||
Good example:
|
|
||||||
|
|
||||||
switch (x) {
|
|
||||||
case 0:
|
|
||||||
do_stuff();
|
|
||||||
break;
|
|
||||||
case 1: {
|
|
||||||
int y;
|
|
||||||
do_stuff();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
do_other_stuff();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bad example:
|
|
||||||
|
|
||||||
switch (x) {
|
|
||||||
case 0:
|
|
||||||
do_stuff();
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
int y;
|
|
||||||
do_stuff();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
do_other_stuff();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Have fun and happy libssh hacking!
|
Have fun and happy libssh hacking!
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
|
|||||||
|
|
||||||
# SOURCE GENERATOR
|
# SOURCE GENERATOR
|
||||||
set(CPACK_SOURCE_GENERATOR "TXZ")
|
set(CPACK_SOURCE_GENERATOR "TXZ")
|
||||||
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]bare/;/[.]git/;/[.]git;/[.]clangd/;/[.]cache/;.gitignore;/build*;/obj*;tags;cscope.*;compile_commands.json;.*\.patch")
|
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]git;/[.]clangd/;/[.]cache/;.gitignore;/build*;/obj*;tags;cscope.*;compile_commands.json;.*\.patch")
|
||||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
||||||
|
|
||||||
### NSIS INSTALLER
|
### NSIS INSTALLER
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ if (UNIX)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_c_compiler_flag("-std=gnu99" SUPPORTED_COMPILER_FLAGS)
|
||||||
add_c_compiler_flag("-Wpedantic" SUPPORTED_COMPILER_FLAGS)
|
add_c_compiler_flag("-Wpedantic" SUPPORTED_COMPILER_FLAGS)
|
||||||
add_c_compiler_flag("-Wall" SUPPORTED_COMPILER_FLAGS)
|
add_c_compiler_flag("-Wall" SUPPORTED_COMPILER_FLAGS)
|
||||||
add_c_compiler_flag("-Wshadow" SUPPORTED_COMPILER_FLAGS)
|
add_c_compiler_flag("-Wshadow" SUPPORTED_COMPILER_FLAGS)
|
||||||
@@ -42,13 +43,6 @@ if (UNIX)
|
|||||||
add_c_compiler_flag("-Wno-format-zero-length" SUPPORTED_COMPILER_FLAGS)
|
add_c_compiler_flag("-Wno-format-zero-length" SUPPORTED_COMPILER_FLAGS)
|
||||||
add_c_compiler_flag("-Wmissing-field-initializers" SUPPORTED_COMPILER_FLAGS)
|
add_c_compiler_flag("-Wmissing-field-initializers" SUPPORTED_COMPILER_FLAGS)
|
||||||
add_c_compiler_flag("-Wsign-compare" SUPPORTED_COMPILER_FLAGS)
|
add_c_compiler_flag("-Wsign-compare" SUPPORTED_COMPILER_FLAGS)
|
||||||
add_c_compiler_flag("-Wold-style-definition" SUPPORTED_COMPILER_FLAGS)
|
|
||||||
add_c_compiler_flag("-Werror=old-style-definition" SUPPORTED_COMPILER_FLAGS)
|
|
||||||
add_c_compiler_flag("-Wimplicit-int" SUPPORTED_COMPILER_FLAGS)
|
|
||||||
add_c_compiler_flag("-Werror=implicit-int" SUPPORTED_COMPILER_FLAGS)
|
|
||||||
add_c_compiler_flag("-Wint-conversion" SUPPORTED_COMPILER_FLAGS)
|
|
||||||
add_c_compiler_flag("-Werror=int-conversion" SUPPORTED_COMPILER_FLAGS)
|
|
||||||
add_c_compiler_flag("-Werror=unused-variable" SUPPORTED_COMPILER_FLAGS)
|
|
||||||
|
|
||||||
check_c_compiler_flag("-Wformat" REQUIRED_FLAGS_WFORMAT)
|
check_c_compiler_flag("-Wformat" REQUIRED_FLAGS_WFORMAT)
|
||||||
if (REQUIRED_FLAGS_WFORMAT)
|
if (REQUIRED_FLAGS_WFORMAT)
|
||||||
|
|||||||
@@ -44,8 +44,6 @@ int main(void){ return 0; }
|
|||||||
endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2)
|
endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2)
|
||||||
|
|
||||||
# HEADER FILES
|
# HEADER FILES
|
||||||
check_function_exists(argp_parse HAVE_ARGP_PARSE)
|
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${ARGP_INCLUDE_DIR})
|
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${ARGP_INCLUDE_DIR})
|
||||||
check_include_file(argp.h HAVE_ARGP_H)
|
check_include_file(argp.h HAVE_ARGP_H)
|
||||||
unset(CMAKE_REQUIRED_INCLUDES)
|
unset(CMAKE_REQUIRED_INCLUDES)
|
||||||
@@ -64,7 +62,6 @@ check_include_file(arpa/inet.h HAVE_ARPA_INET_H)
|
|||||||
check_include_file(byteswap.h HAVE_BYTESWAP_H)
|
check_include_file(byteswap.h HAVE_BYTESWAP_H)
|
||||||
check_include_file(glob.h HAVE_GLOB_H)
|
check_include_file(glob.h HAVE_GLOB_H)
|
||||||
check_include_file(valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H)
|
check_include_file(valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H)
|
||||||
check_include_file(ifaddrs.h HAVE_IFADDRS_H)
|
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
check_include_file(io.h HAVE_IO_H)
|
check_include_file(io.h HAVE_IO_H)
|
||||||
@@ -78,32 +75,78 @@ endif (WIN32)
|
|||||||
|
|
||||||
if (OPENSSL_FOUND)
|
if (OPENSSL_FOUND)
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
set(CMAKE_REQUIRED_LIBRARIES OpenSSL::Crypto)
|
|
||||||
|
|
||||||
check_include_file(openssl/des.h HAVE_OPENSSL_DES_H)
|
check_include_file(openssl/des.h HAVE_OPENSSL_DES_H)
|
||||||
if (NOT HAVE_OPENSSL_DES_H)
|
if (NOT HAVE_OPENSSL_DES_H)
|
||||||
message(FATAL_ERROR "Could not detect openssl/des.h")
|
message(FATAL_ERROR "Could not detect openssl/des.h")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
check_include_file(openssl/aes.h HAVE_OPENSSL_AES_H)
|
check_include_file(openssl/aes.h HAVE_OPENSSL_AES_H)
|
||||||
if (NOT HAVE_OPENSSL_AES_H)
|
if (NOT HAVE_OPENSSL_AES_H)
|
||||||
message(FATAL_ERROR "Could not detect openssl/aes.h")
|
message(FATAL_ERROR "Could not detect openssl/aes.h")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WITH_BLOWFISH_CIPHER)
|
if (WITH_BLOWFISH_CIPHER)
|
||||||
check_include_file(openssl/blowfish.h HAVE_BLOWFISH)
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
|
check_include_file(openssl/blowfish.h HAVE_OPENSSL_BLOWFISH_H)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
check_include_file(openssl/ecdh.h HAVE_OPENSSL_ECDH_H)
|
check_include_file(openssl/ecdh.h HAVE_OPENSSL_ECDH_H)
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
check_include_file(openssl/ec.h HAVE_OPENSSL_EC_H)
|
check_include_file(openssl/ec.h HAVE_OPENSSL_EC_H)
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
check_include_file(openssl/ecdsa.h HAVE_OPENSSL_ECDSA_H)
|
check_include_file(openssl/ecdsa.h HAVE_OPENSSL_ECDSA_H)
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
||||||
check_function_exists(EVP_KDF_CTX_new_id HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID)
|
check_function_exists(EVP_KDF_CTX_new_id HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID)
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
||||||
check_function_exists(EVP_KDF_CTX_new HAVE_OPENSSL_EVP_KDF_CTX_NEW)
|
check_function_exists(EVP_KDF_CTX_new HAVE_OPENSSL_EVP_KDF_CTX_NEW)
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
||||||
check_function_exists(FIPS_mode HAVE_OPENSSL_FIPS_MODE)
|
check_function_exists(FIPS_mode HAVE_OPENSSL_FIPS_MODE)
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
||||||
check_function_exists(RAND_priv_bytes HAVE_OPENSSL_RAND_PRIV_BYTES)
|
check_function_exists(RAND_priv_bytes HAVE_OPENSSL_RAND_PRIV_BYTES)
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
||||||
|
check_function_exists(EVP_DigestSign HAVE_OPENSSL_EVP_DIGESTSIGN)
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
||||||
|
check_function_exists(EVP_DigestVerify HAVE_OPENSSL_EVP_DIGESTVERIFY)
|
||||||
|
|
||||||
|
check_function_exists(OPENSSL_ia32cap_loc HAVE_OPENSSL_IA32CAP_LOC)
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
||||||
|
check_symbol_exists(EVP_PKEY_ED25519 "openssl/evp.h" FOUND_OPENSSL_ED25519)
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
||||||
check_function_exists(EVP_chacha20 HAVE_OPENSSL_EVP_CHACHA20)
|
check_function_exists(EVP_chacha20 HAVE_OPENSSL_EVP_CHACHA20)
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
||||||
|
check_symbol_exists(EVP_PKEY_POLY1305 "openssl/evp.h" HAVE_OPENSSL_EVP_POLY1305)
|
||||||
|
|
||||||
|
if (HAVE_OPENSSL_EVP_DIGESTSIGN AND HAVE_OPENSSL_EVP_DIGESTVERIFY AND
|
||||||
|
FOUND_OPENSSL_ED25519)
|
||||||
|
set(HAVE_OPENSSL_ED25519 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
||||||
|
check_symbol_exists(EVP_PKEY_X25519 "openssl/evp.h" HAVE_OPENSSL_X25519)
|
||||||
|
|
||||||
unset(CMAKE_REQUIRED_INCLUDES)
|
unset(CMAKE_REQUIRED_INCLUDES)
|
||||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||||
endif()
|
endif()
|
||||||
@@ -127,6 +170,12 @@ if (NOT WITH_GCRYPT AND NOT WITH_MBEDTLS)
|
|||||||
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
if (WITH_DSA)
|
||||||
|
if (NOT WITH_MBEDTLS)
|
||||||
|
set(HAVE_DSA 1)
|
||||||
|
endif (NOT WITH_MBEDTLS)
|
||||||
|
endif()
|
||||||
|
|
||||||
# FUNCTIONS
|
# FUNCTIONS
|
||||||
|
|
||||||
check_function_exists(isblank HAVE_ISBLANK)
|
check_function_exists(isblank HAVE_ISBLANK)
|
||||||
@@ -236,10 +285,6 @@ if (MBEDTLS_FOUND)
|
|||||||
set(CMAKE_REQUIRED_INCLUDES "${MBEDTLS_INCLUDE_DIR}/mbedtls")
|
set(CMAKE_REQUIRED_INCLUDES "${MBEDTLS_INCLUDE_DIR}/mbedtls")
|
||||||
check_include_file(chacha20.h HAVE_MBEDTLS_CHACHA20_H)
|
check_include_file(chacha20.h HAVE_MBEDTLS_CHACHA20_H)
|
||||||
check_include_file(poly1305.h HAVE_MBEDTLS_POLY1305_H)
|
check_include_file(poly1305.h HAVE_MBEDTLS_POLY1305_H)
|
||||||
if (WITH_BLOWFISH_CIPHER)
|
|
||||||
check_include_file(blowfish.h HAVE_BLOWFISH)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
unset(CMAKE_REQUIRED_INCLUDES)
|
unset(CMAKE_REQUIRED_INCLUDES)
|
||||||
|
|
||||||
endif (MBEDTLS_FOUND)
|
endif (MBEDTLS_FOUND)
|
||||||
@@ -444,22 +489,22 @@ if (WITH_PKCS11_URI)
|
|||||||
if (WITH_GCRYPT)
|
if (WITH_GCRYPT)
|
||||||
message(FATAL_ERROR "PKCS #11 is not supported for gcrypt.")
|
message(FATAL_ERROR "PKCS #11 is not supported for gcrypt.")
|
||||||
set(WITH_PKCS11_URI 0)
|
set(WITH_PKCS11_URI 0)
|
||||||
elseif (WITH_MBEDTLS)
|
endif()
|
||||||
|
if (WITH_MBEDTLS)
|
||||||
message(FATAL_ERROR "PKCS #11 is not supported for mbedcrypto")
|
message(FATAL_ERROR "PKCS #11 is not supported for mbedcrypto")
|
||||||
set(WITH_PKCS11_URI 0)
|
set(WITH_PKCS11_URI 0)
|
||||||
elseif (OPENSSL_FOUND AND OPENSSL_VERSION VERSION_GREATER_EQUAL "3.0.0")
|
endif()
|
||||||
find_library(PKCS11_PROVIDER
|
if (HAVE_OPENSSL AND NOT OPENSSL_VERSION VERSION_GREATER_EQUAL "1.1.1")
|
||||||
NAMES
|
message(FATAL_ERROR "PKCS #11 requires at least OpenSSL 1.1.1")
|
||||||
pkcs11.so
|
set(WITH_PKCS11_URI 0)
|
||||||
PATH_SUFFIXES
|
endif()
|
||||||
ossl-modules
|
endif()
|
||||||
)
|
|
||||||
if (NOT PKCS11_PROVIDER)
|
if (WITH_MBEDTLS)
|
||||||
set(WITH_PKCS11_PROVIDER 0)
|
if (WITH_DSA)
|
||||||
message(WARNING "Could not find pkcs11 provider! Falling back to engines")
|
message(FATAL_ERROR "DSA is not supported with mbedTLS crypto")
|
||||||
message(WARNING "The support for engines is deprecated in OpenSSL and will be removed from libssh in the future releases.")
|
set(HAVE_DSA 0)
|
||||||
endif (NOT PKCS11_PROVIDER)
|
endif()
|
||||||
endif ()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# ENDIAN
|
# ENDIAN
|
||||||
|
|||||||
@@ -5,18 +5,17 @@ option(WITH_SERVER "Build with SSH server support" ON)
|
|||||||
option(WITH_DEBUG_CRYPTO "Build with crypto debug output" OFF)
|
option(WITH_DEBUG_CRYPTO "Build with crypto debug output" OFF)
|
||||||
option(WITH_DEBUG_PACKET "Build with packet debug output" OFF)
|
option(WITH_DEBUG_PACKET "Build with packet debug output" OFF)
|
||||||
option(WITH_DEBUG_CALLTRACE "Build with calltrace debug output" ON)
|
option(WITH_DEBUG_CALLTRACE "Build with calltrace debug output" ON)
|
||||||
option(WITH_GCRYPT "Compile against libgcrypt (deprecated)" OFF)
|
option(WITH_DSA "Build with DSA" OFF)
|
||||||
|
option(WITH_GCRYPT "Compile against libgcrypt" OFF)
|
||||||
option(WITH_MBEDTLS "Compile against libmbedtls" OFF)
|
option(WITH_MBEDTLS "Compile against libmbedtls" OFF)
|
||||||
option(WITH_BLOWFISH_CIPHER "Compile with blowfish support" OFF)
|
option(WITH_BLOWFISH_CIPHER "Compile with blowfish support" OFF)
|
||||||
option(WITH_PCAP "Compile with Pcap generation support" ON)
|
option(WITH_PCAP "Compile with Pcap generation support" ON)
|
||||||
option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
|
option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
|
||||||
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||||
option(WITH_PKCS11_URI "Build with PKCS#11 URI support" OFF)
|
option(WITH_PKCS11_URI "Build with PKCS#11 URI support" OFF)
|
||||||
option(WITH_PKCS11_PROVIDER "Use the PKCS#11 provider for accessing pkcs11 objects" OFF)
|
|
||||||
option(UNIT_TESTING "Build with unit tests" OFF)
|
option(UNIT_TESTING "Build with unit tests" OFF)
|
||||||
option(CLIENT_TESTING "Build with client tests; requires openssh" OFF)
|
option(CLIENT_TESTING "Build with client tests; requires openssh" OFF)
|
||||||
option(SERVER_TESTING "Build with server tests; requires openssh and dropbear" OFF)
|
option(SERVER_TESTING "Build with server tests; requires openssh and dropbear" OFF)
|
||||||
option(GSSAPI_TESTING "Build with GSSAPI tests; requires krb5-server,krb5-libs and krb5-workstation" OFF)
|
|
||||||
option(WITH_BENCHMARKS "Build benchmarks tools; enables unit testing and client tests" OFF)
|
option(WITH_BENCHMARKS "Build benchmarks tools; enables unit testing and client tests" OFF)
|
||||||
option(WITH_EXAMPLES "Build examples" ON)
|
option(WITH_EXAMPLES "Build examples" ON)
|
||||||
option(WITH_NACL "Build with libnacl (curve25519)" ON)
|
option(WITH_NACL "Build with libnacl (curve25519)" ON)
|
||||||
@@ -24,7 +23,6 @@ option(WITH_SYMBOL_VERSIONING "Build with symbol versioning" ON)
|
|||||||
option(WITH_ABI_BREAK "Allow ABI break" OFF)
|
option(WITH_ABI_BREAK "Allow ABI break" OFF)
|
||||||
option(WITH_GEX "Enable DH Group exchange mechanisms" ON)
|
option(WITH_GEX "Enable DH Group exchange mechanisms" ON)
|
||||||
option(WITH_INSECURE_NONE "Enable insecure none cipher and MAC algorithms (not suitable for production!)" OFF)
|
option(WITH_INSECURE_NONE "Enable insecure none cipher and MAC algorithms (not suitable for production!)" OFF)
|
||||||
option(WITH_EXEC "Enable libssh to execute arbitrary commands from configuration files or options (match exec, proxy commands and OpenSSH-based proxy-jumps)." ON)
|
|
||||||
option(FUZZ_TESTING "Build with fuzzer for the server and client (automatically enables none cipher!)" OFF)
|
option(FUZZ_TESTING "Build with fuzzer for the server and client (automatically enables none cipher!)" OFF)
|
||||||
option(PICKY_DEVELOPER "Build with picky developer flags" OFF)
|
option(PICKY_DEVELOPER "Build with picky developer flags" OFF)
|
||||||
|
|
||||||
@@ -39,7 +37,7 @@ if (WITH_BENCHMARKS)
|
|||||||
set(CLIENT_TESTING ON)
|
set(CLIENT_TESTING ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNIT_TESTING OR CLIENT_TESTING OR SERVER_TESTING OR GSSAPI_TESTING)
|
if (UNIT_TESTING OR CLIENT_TESTING OR SERVER_TESTING)
|
||||||
set(BUILD_STATIC_LIB ON)
|
set(BUILD_STATIC_LIB ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -62,7 +60,3 @@ endif (NOT GLOBAL_CLIENT_CONFIG)
|
|||||||
if (FUZZ_TESTING)
|
if (FUZZ_TESTING)
|
||||||
set(WITH_INSECURE_NONE ON)
|
set(WITH_INSECURE_NONE ON)
|
||||||
endif (FUZZ_TESTING)
|
endif (FUZZ_TESTING)
|
||||||
|
|
||||||
if (WIN32)
|
|
||||||
set(WITH_EXEC 0)
|
|
||||||
endif(WIN32)
|
|
||||||
|
|||||||
10
INSTALL
10
INSTALL
@@ -7,13 +7,11 @@
|
|||||||
In order to build libssh, you need to install several components:
|
In order to build libssh, you need to install several components:
|
||||||
|
|
||||||
- A C compiler
|
- A C compiler
|
||||||
- [CMake](https://www.cmake.org) >= 3.12.0
|
- [CMake](https://www.cmake.org) >= 3.3.0
|
||||||
|
- [openssl](https://www.openssl.org) >= 1.0.1
|
||||||
|
or
|
||||||
|
- [gcrypt](https://www.gnu.org/directory/Security/libgcrypt.html) >= 1.4
|
||||||
- [libz](https://www.zlib.net) >= 1.2
|
- [libz](https://www.zlib.net) >= 1.2
|
||||||
- [openssl](https://www.openssl.org) >= 1.1.1
|
|
||||||
or
|
|
||||||
- [gcrypt](https://www.gnu.org/directory/Security/libgcrypt.html) >= 1.5
|
|
||||||
or
|
|
||||||
- [Mbed TLS](https://www.trustedfirmware.org/projects/mbed-tls/)
|
|
||||||
|
|
||||||
optional:
|
optional:
|
||||||
- [cmocka](https://cmocka.org/) >= 1.1.0
|
- [cmocka](https://cmocka.org/) >= 1.1.0
|
||||||
|
|||||||
@@ -116,9 +116,5 @@ function(ADD_CMOCKA_TEST _TARGET_NAME)
|
|||||||
add_test(${_TARGET_NAME}
|
add_test(${_TARGET_NAME}
|
||||||
${TARGET_SYSTEM_EMULATOR} ${_TARGET_NAME}
|
${TARGET_SYSTEM_EMULATOR} ${_TARGET_NAME}
|
||||||
)
|
)
|
||||||
if (WITH_COVERAGE)
|
|
||||||
include(CodeCoverage)
|
|
||||||
append_coverage_compiler_flags_to_target(${_TARGET_NAME})
|
|
||||||
endif (WITH_COVERAGE)
|
|
||||||
|
|
||||||
endfunction (ADD_CMOCKA_TEST)
|
endfunction (ADD_CMOCKA_TEST)
|
||||||
|
|||||||
@@ -1,750 +0,0 @@
|
|||||||
# Copyright (c) 2012 - 2017, Lars Bilke
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
# are permitted provided that the following conditions are met:
|
|
||||||
#
|
|
||||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
# list of conditions and the following disclaimer.
|
|
||||||
#
|
|
||||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer in the documentation
|
|
||||||
# and/or other materials provided with the distribution.
|
|
||||||
#
|
|
||||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
# may be used to endorse or promote products derived from this software without
|
|
||||||
# specific prior written permission.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
#
|
|
||||||
# CHANGES:
|
|
||||||
#
|
|
||||||
# 2012-01-31, Lars Bilke
|
|
||||||
# - Enable Code Coverage
|
|
||||||
#
|
|
||||||
# 2013-09-17, Joakim Söderberg
|
|
||||||
# - Added support for Clang.
|
|
||||||
# - Some additional usage instructions.
|
|
||||||
#
|
|
||||||
# 2016-02-03, Lars Bilke
|
|
||||||
# - Refactored functions to use named parameters
|
|
||||||
#
|
|
||||||
# 2017-06-02, Lars Bilke
|
|
||||||
# - Merged with modified version from github.com/ufz/ogs
|
|
||||||
#
|
|
||||||
# 2019-05-06, Anatolii Kurotych
|
|
||||||
# - Remove unnecessary --coverage flag
|
|
||||||
#
|
|
||||||
# 2019-12-13, FeRD (Frank Dana)
|
|
||||||
# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor
|
|
||||||
# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments.
|
|
||||||
# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY
|
|
||||||
# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list
|
|
||||||
# - Set lcov basedir with -b argument
|
|
||||||
# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be
|
|
||||||
# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().)
|
|
||||||
# - Delete output dir, .info file on 'make clean'
|
|
||||||
# - Remove Python detection, since version mismatches will break gcovr
|
|
||||||
# - Minor cleanup (lowercase function names, update examples...)
|
|
||||||
#
|
|
||||||
# 2019-12-19, FeRD (Frank Dana)
|
|
||||||
# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets
|
|
||||||
#
|
|
||||||
# 2020-01-19, Bob Apthorpe
|
|
||||||
# - Added gfortran support
|
|
||||||
#
|
|
||||||
# 2020-02-17, FeRD (Frank Dana)
|
|
||||||
# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters
|
|
||||||
# in EXCLUDEs, and remove manual escaping from gcovr targets
|
|
||||||
#
|
|
||||||
# 2021-01-19, Robin Mueller
|
|
||||||
# - Add CODE_COVERAGE_VERBOSE option which will allow to print out commands which are run
|
|
||||||
# - Added the option for users to set the GCOVR_ADDITIONAL_ARGS variable to supply additional
|
|
||||||
# flags to the gcovr command
|
|
||||||
#
|
|
||||||
# 2020-05-04, Mihchael Davis
|
|
||||||
# - Add -fprofile-abs-path to make gcno files contain absolute paths
|
|
||||||
# - Fix BASE_DIRECTORY not working when defined
|
|
||||||
# - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines
|
|
||||||
#
|
|
||||||
# 2021-05-10, Martin Stump
|
|
||||||
# - Check if the generator is multi-config before warning about non-Debug builds
|
|
||||||
#
|
|
||||||
# 2022-02-22, Marko Wehle
|
|
||||||
# - Change gcovr output from -o <filename> for --xml <filename> and --html <filename> output respectively.
|
|
||||||
# This will allow for Multiple Output Formats at the same time by making use of GCOVR_ADDITIONAL_ARGS, e.g. GCOVR_ADDITIONAL_ARGS "--txt".
|
|
||||||
#
|
|
||||||
# 2022-09-28, Sebastian Mueller
|
|
||||||
# - fix append_coverage_compiler_flags_to_target to correctly add flags
|
|
||||||
# - replace "-fprofile-arcs -ftest-coverage" with "--coverage" (equivalent)
|
|
||||||
#
|
|
||||||
# USAGE:
|
|
||||||
#
|
|
||||||
# 1. Copy this file into your cmake modules path.
|
|
||||||
#
|
|
||||||
# 2. Add the following line to your CMakeLists.txt (best inside an if-condition
|
|
||||||
# using a CMake option() to enable it just optionally):
|
|
||||||
# include(CodeCoverage)
|
|
||||||
#
|
|
||||||
# 3. Append necessary compiler flags for all supported source files:
|
|
||||||
# append_coverage_compiler_flags()
|
|
||||||
# Or for specific target:
|
|
||||||
# append_coverage_compiler_flags_to_target(YOUR_TARGET_NAME)
|
|
||||||
#
|
|
||||||
# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og
|
|
||||||
#
|
|
||||||
# 4. If you need to exclude additional directories from the report, specify them
|
|
||||||
# using full paths in the COVERAGE_EXCLUDES variable before calling
|
|
||||||
# setup_target_for_coverage_*().
|
|
||||||
# Example:
|
|
||||||
# set(COVERAGE_EXCLUDES
|
|
||||||
# '${PROJECT_SOURCE_DIR}/src/dir1/*'
|
|
||||||
# '/path/to/my/src/dir2/*')
|
|
||||||
# Or, use the EXCLUDE argument to setup_target_for_coverage_*().
|
|
||||||
# Example:
|
|
||||||
# setup_target_for_coverage_lcov(
|
|
||||||
# NAME coverage
|
|
||||||
# EXECUTABLE testrunner
|
|
||||||
# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*")
|
|
||||||
#
|
|
||||||
# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set
|
|
||||||
# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR)
|
|
||||||
# Example:
|
|
||||||
# set(COVERAGE_EXCLUDES "dir1/*")
|
|
||||||
# setup_target_for_coverage_gcovr_html(
|
|
||||||
# NAME coverage
|
|
||||||
# EXECUTABLE testrunner
|
|
||||||
# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src"
|
|
||||||
# EXCLUDE "dir2/*")
|
|
||||||
#
|
|
||||||
# 5. Use the functions described below to create a custom make target which
|
|
||||||
# runs your test executable and produces a code coverage report.
|
|
||||||
#
|
|
||||||
# 6. Build a Debug build:
|
|
||||||
# cmake -DCMAKE_BUILD_TYPE=Debug ..
|
|
||||||
# make
|
|
||||||
# make my_coverage_target
|
|
||||||
#
|
|
||||||
|
|
||||||
include(CMakeParseArguments)
|
|
||||||
|
|
||||||
option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE)
|
|
||||||
|
|
||||||
# Check prereqs
|
|
||||||
find_program( GCOV_PATH gcov )
|
|
||||||
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
|
|
||||||
find_program( FASTCOV_PATH NAMES fastcov fastcov.py )
|
|
||||||
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
|
|
||||||
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
|
|
||||||
find_program( CPPFILT_PATH NAMES c++filt )
|
|
||||||
|
|
||||||
if(NOT GCOV_PATH)
|
|
||||||
message(FATAL_ERROR "gcov not found! Aborting...")
|
|
||||||
endif() # NOT GCOV_PATH
|
|
||||||
|
|
||||||
# Check supported compiler (Clang, GNU and Flang)
|
|
||||||
get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
|
|
||||||
foreach(LANG ${LANGUAGES})
|
|
||||||
if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
|
|
||||||
if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3)
|
|
||||||
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
|
|
||||||
endif()
|
|
||||||
elseif(NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "GNU"
|
|
||||||
AND NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(LLVM)?[Ff]lang")
|
|
||||||
message(FATAL_ERROR "Compiler is not GNU or Flang! Aborting...")
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
set(COVERAGE_COMPILER_FLAGS "-g --coverage -fprofile-update=atomic"
|
|
||||||
CACHE INTERNAL "")
|
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
|
||||||
include(CheckCXXCompilerFlag)
|
|
||||||
check_cxx_compiler_flag(-fprofile-abs-path HAVE_cxx_fprofile_abs_path)
|
|
||||||
if(HAVE_cxx_fprofile_abs_path)
|
|
||||||
set(COVERAGE_CXX_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
if(CMAKE_C_COMPILER_ID MATCHES "(GNU|Clang)")
|
|
||||||
include(CheckCCompilerFlag)
|
|
||||||
check_c_compiler_flag(-fprofile-abs-path HAVE_c_fprofile_abs_path)
|
|
||||||
if(HAVE_c_fprofile_abs_path)
|
|
||||||
set(COVERAGE_C_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CMAKE_Fortran_FLAGS_COVERAGE
|
|
||||||
${COVERAGE_COMPILER_FLAGS}
|
|
||||||
CACHE STRING "Flags used by the Fortran compiler during coverage builds."
|
|
||||||
FORCE )
|
|
||||||
set(CMAKE_CXX_FLAGS_COVERAGE
|
|
||||||
${COVERAGE_COMPILER_FLAGS}
|
|
||||||
CACHE STRING "Flags used by the C++ compiler during coverage builds."
|
|
||||||
FORCE )
|
|
||||||
set(CMAKE_C_FLAGS_COVERAGE
|
|
||||||
${COVERAGE_COMPILER_FLAGS}
|
|
||||||
CACHE STRING "Flags used by the C compiler during coverage builds."
|
|
||||||
FORCE )
|
|
||||||
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
|
||||||
""
|
|
||||||
CACHE STRING "Flags used for linking binaries during coverage builds."
|
|
||||||
FORCE )
|
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
|
|
||||||
""
|
|
||||||
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
|
|
||||||
FORCE )
|
|
||||||
mark_as_advanced(
|
|
||||||
CMAKE_Fortran_FLAGS_COVERAGE
|
|
||||||
CMAKE_CXX_FLAGS_COVERAGE
|
|
||||||
CMAKE_C_FLAGS_COVERAGE
|
|
||||||
CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
|
||||||
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
|
|
||||||
|
|
||||||
get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
|
||||||
if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG))
|
|
||||||
message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
|
|
||||||
endif() # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG)
|
|
||||||
|
|
||||||
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
|
|
||||||
link_libraries(gcov)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Defines a target for running and collection code coverage information
|
|
||||||
# Builds dependencies, runs the given executable and outputs reports.
|
|
||||||
# NOTE! The executable should always have a ZERO as exit code otherwise
|
|
||||||
# the coverage generation will not complete.
|
|
||||||
#
|
|
||||||
# setup_target_for_coverage_lcov(
|
|
||||||
# NAME testrunner_coverage # New target name
|
|
||||||
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
|
||||||
# DEPENDENCIES testrunner # Dependencies to build first
|
|
||||||
# BASE_DIRECTORY "../" # Base directory for report
|
|
||||||
# # (defaults to PROJECT_SOURCE_DIR)
|
|
||||||
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
|
||||||
# # to BASE_DIRECTORY, with CMake 3.4+)
|
|
||||||
# NO_DEMANGLE # Don't demangle C++ symbols
|
|
||||||
# # even if c++filt is found
|
|
||||||
# )
|
|
||||||
function(setup_target_for_coverage_lcov)
|
|
||||||
|
|
||||||
set(options NO_DEMANGLE SONARQUBE)
|
|
||||||
set(oneValueArgs BASE_DIRECTORY NAME)
|
|
||||||
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
|
|
||||||
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
||||||
|
|
||||||
if(NOT LCOV_PATH)
|
|
||||||
message(FATAL_ERROR "lcov not found! Aborting...")
|
|
||||||
endif() # NOT LCOV_PATH
|
|
||||||
|
|
||||||
if(NOT GENHTML_PATH)
|
|
||||||
message(FATAL_ERROR "genhtml not found! Aborting...")
|
|
||||||
endif() # NOT GENHTML_PATH
|
|
||||||
|
|
||||||
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
|
||||||
if(DEFINED Coverage_BASE_DIRECTORY)
|
|
||||||
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
|
||||||
else()
|
|
||||||
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Collect excludes (CMake 3.4+: Also compute absolute paths)
|
|
||||||
set(LCOV_EXCLUDES "")
|
|
||||||
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES})
|
|
||||||
if(CMAKE_VERSION VERSION_GREATER 3.4)
|
|
||||||
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
|
|
||||||
endif()
|
|
||||||
list(APPEND LCOV_EXCLUDES "${EXCLUDE}")
|
|
||||||
endforeach()
|
|
||||||
list(REMOVE_DUPLICATES LCOV_EXCLUDES)
|
|
||||||
|
|
||||||
# Conditional arguments
|
|
||||||
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
|
|
||||||
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Setting up commands which will be run to generate coverage data.
|
|
||||||
# Cleanup lcov
|
|
||||||
set(LCOV_CLEAN_CMD
|
|
||||||
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory .
|
|
||||||
-b ${BASEDIR} --zerocounters
|
|
||||||
)
|
|
||||||
# Create baseline to make sure untouched files show up in the report
|
|
||||||
set(LCOV_BASELINE_CMD
|
|
||||||
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b
|
|
||||||
${BASEDIR} -o ${Coverage_NAME}.base
|
|
||||||
)
|
|
||||||
# Run tests
|
|
||||||
set(LCOV_EXEC_TESTS_CMD
|
|
||||||
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
|
||||||
)
|
|
||||||
# Capturing lcov counters and generating report
|
|
||||||
set(LCOV_CAPTURE_CMD
|
|
||||||
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b
|
|
||||||
${BASEDIR} --capture --output-file ${Coverage_NAME}.capture
|
|
||||||
)
|
|
||||||
# add baseline counters
|
|
||||||
set(LCOV_BASELINE_COUNT_CMD
|
|
||||||
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base
|
|
||||||
-a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total
|
|
||||||
)
|
|
||||||
# filter collected data to final coverage report
|
|
||||||
set(LCOV_FILTER_CMD
|
|
||||||
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove
|
|
||||||
${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info
|
|
||||||
)
|
|
||||||
# Generate HTML output
|
|
||||||
set(LCOV_GEN_HTML_CMD
|
|
||||||
${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o
|
|
||||||
${Coverage_NAME} ${Coverage_NAME}.info
|
|
||||||
)
|
|
||||||
if(${Coverage_SONARQUBE})
|
|
||||||
# Generate SonarQube output
|
|
||||||
set(GCOVR_XML_CMD
|
|
||||||
${GCOVR_PATH} --sonarqube ${Coverage_NAME}_sonarqube.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
|
|
||||||
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
|
|
||||||
)
|
|
||||||
set(GCOVR_XML_CMD_COMMAND
|
|
||||||
COMMAND ${GCOVR_XML_CMD}
|
|
||||||
)
|
|
||||||
set(GCOVR_XML_CMD_BYPRODUCTS ${Coverage_NAME}_sonarqube.xml)
|
|
||||||
set(GCOVR_XML_CMD_COMMENT COMMENT "SonarQube code coverage info report saved in ${Coverage_NAME}_sonarqube.xml.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
if(CODE_COVERAGE_VERBOSE)
|
|
||||||
message(STATUS "Executed command report")
|
|
||||||
message(STATUS "Command to clean up lcov: ")
|
|
||||||
string(REPLACE ";" " " LCOV_CLEAN_CMD_SPACED "${LCOV_CLEAN_CMD}")
|
|
||||||
message(STATUS "${LCOV_CLEAN_CMD_SPACED}")
|
|
||||||
|
|
||||||
message(STATUS "Command to create baseline: ")
|
|
||||||
string(REPLACE ";" " " LCOV_BASELINE_CMD_SPACED "${LCOV_BASELINE_CMD}")
|
|
||||||
message(STATUS "${LCOV_BASELINE_CMD_SPACED}")
|
|
||||||
|
|
||||||
message(STATUS "Command to run the tests: ")
|
|
||||||
string(REPLACE ";" " " LCOV_EXEC_TESTS_CMD_SPACED "${LCOV_EXEC_TESTS_CMD}")
|
|
||||||
message(STATUS "${LCOV_EXEC_TESTS_CMD_SPACED}")
|
|
||||||
|
|
||||||
message(STATUS "Command to capture counters and generate report: ")
|
|
||||||
string(REPLACE ";" " " LCOV_CAPTURE_CMD_SPACED "${LCOV_CAPTURE_CMD}")
|
|
||||||
message(STATUS "${LCOV_CAPTURE_CMD_SPACED}")
|
|
||||||
|
|
||||||
message(STATUS "Command to add baseline counters: ")
|
|
||||||
string(REPLACE ";" " " LCOV_BASELINE_COUNT_CMD_SPACED "${LCOV_BASELINE_COUNT_CMD}")
|
|
||||||
message(STATUS "${LCOV_BASELINE_COUNT_CMD_SPACED}")
|
|
||||||
|
|
||||||
message(STATUS "Command to filter collected data: ")
|
|
||||||
string(REPLACE ";" " " LCOV_FILTER_CMD_SPACED "${LCOV_FILTER_CMD}")
|
|
||||||
message(STATUS "${LCOV_FILTER_CMD_SPACED}")
|
|
||||||
|
|
||||||
message(STATUS "Command to generate lcov HTML output: ")
|
|
||||||
string(REPLACE ";" " " LCOV_GEN_HTML_CMD_SPACED "${LCOV_GEN_HTML_CMD}")
|
|
||||||
message(STATUS "${LCOV_GEN_HTML_CMD_SPACED}")
|
|
||||||
|
|
||||||
if(${Coverage_SONARQUBE})
|
|
||||||
message(STATUS "Command to generate SonarQube XML output: ")
|
|
||||||
string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}")
|
|
||||||
message(STATUS "${GCOVR_XML_CMD_SPACED}")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Setup target
|
|
||||||
add_custom_target(${Coverage_NAME}
|
|
||||||
COMMAND ${LCOV_CLEAN_CMD}
|
|
||||||
COMMAND ${LCOV_BASELINE_CMD}
|
|
||||||
COMMAND ${LCOV_EXEC_TESTS_CMD}
|
|
||||||
COMMAND ${LCOV_CAPTURE_CMD}
|
|
||||||
COMMAND ${LCOV_BASELINE_COUNT_CMD}
|
|
||||||
COMMAND ${LCOV_FILTER_CMD}
|
|
||||||
COMMAND ${LCOV_GEN_HTML_CMD}
|
|
||||||
${GCOVR_XML_CMD_COMMAND}
|
|
||||||
|
|
||||||
# Set output files as GENERATED (will be removed on 'make clean')
|
|
||||||
BYPRODUCTS
|
|
||||||
${Coverage_NAME}.base
|
|
||||||
${Coverage_NAME}.capture
|
|
||||||
${Coverage_NAME}.total
|
|
||||||
${Coverage_NAME}.info
|
|
||||||
${GCOVR_XML_CMD_BYPRODUCTS}
|
|
||||||
${Coverage_NAME}/index.html
|
|
||||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
|
||||||
DEPENDS ${Coverage_DEPENDENCIES}
|
|
||||||
VERBATIM # Protect arguments to commands
|
|
||||||
COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
|
|
||||||
)
|
|
||||||
|
|
||||||
# Show where to find the lcov info report
|
|
||||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
|
||||||
COMMAND ;
|
|
||||||
COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
|
|
||||||
${GCOVR_XML_CMD_COMMENT}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Show info where to find the report
|
|
||||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
|
||||||
COMMAND ;
|
|
||||||
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
|
|
||||||
)
|
|
||||||
|
|
||||||
endfunction() # setup_target_for_coverage_lcov
|
|
||||||
|
|
||||||
# Defines a target for running and collection code coverage information
|
|
||||||
# Builds dependencies, runs the given executable and outputs reports.
|
|
||||||
# NOTE! The executable should always have a ZERO as exit code otherwise
|
|
||||||
# the coverage generation will not complete.
|
|
||||||
#
|
|
||||||
# setup_target_for_coverage_gcovr_xml(
|
|
||||||
# NAME ctest_coverage # New target name
|
|
||||||
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
|
||||||
# DEPENDENCIES executable_target # Dependencies to build first
|
|
||||||
# BASE_DIRECTORY "../" # Base directory for report
|
|
||||||
# # (defaults to PROJECT_SOURCE_DIR)
|
|
||||||
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
|
||||||
# # to BASE_DIRECTORY, with CMake 3.4+)
|
|
||||||
# )
|
|
||||||
# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the
|
|
||||||
# GCVOR command.
|
|
||||||
function(setup_target_for_coverage_gcovr_xml)
|
|
||||||
|
|
||||||
set(options NONE)
|
|
||||||
set(oneValueArgs BASE_DIRECTORY NAME)
|
|
||||||
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
|
||||||
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
||||||
|
|
||||||
if(NOT GCOVR_PATH)
|
|
||||||
message(FATAL_ERROR "gcovr not found! Aborting...")
|
|
||||||
endif() # NOT GCOVR_PATH
|
|
||||||
|
|
||||||
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
|
||||||
if(DEFINED Coverage_BASE_DIRECTORY)
|
|
||||||
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
|
||||||
else()
|
|
||||||
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Collect excludes (CMake 3.4+: Also compute absolute paths)
|
|
||||||
set(GCOVR_EXCLUDES "")
|
|
||||||
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
|
|
||||||
if(CMAKE_VERSION VERSION_GREATER 3.4)
|
|
||||||
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
|
|
||||||
endif()
|
|
||||||
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
|
|
||||||
endforeach()
|
|
||||||
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
|
|
||||||
|
|
||||||
# Combine excludes to several -e arguments
|
|
||||||
set(GCOVR_EXCLUDE_ARGS "")
|
|
||||||
foreach(EXCLUDE ${GCOVR_EXCLUDES})
|
|
||||||
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
|
|
||||||
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
# Set up commands which will be run to generate coverage data
|
|
||||||
# Run tests
|
|
||||||
set(GCOVR_XML_EXEC_TESTS_CMD
|
|
||||||
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
|
||||||
)
|
|
||||||
# Running gcovr
|
|
||||||
set(GCOVR_XML_CMD
|
|
||||||
${GCOVR_PATH} --xml ${Coverage_NAME}.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
|
|
||||||
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
if(CODE_COVERAGE_VERBOSE)
|
|
||||||
message(STATUS "Executed command report")
|
|
||||||
|
|
||||||
message(STATUS "Command to run tests: ")
|
|
||||||
string(REPLACE ";" " " GCOVR_XML_EXEC_TESTS_CMD_SPACED "${GCOVR_XML_EXEC_TESTS_CMD}")
|
|
||||||
message(STATUS "${GCOVR_XML_EXEC_TESTS_CMD_SPACED}")
|
|
||||||
|
|
||||||
message(STATUS "Command to generate gcovr XML coverage data: ")
|
|
||||||
string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}")
|
|
||||||
message(STATUS "${GCOVR_XML_CMD_SPACED}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_custom_target(${Coverage_NAME}
|
|
||||||
COMMAND ${GCOVR_XML_EXEC_TESTS_CMD}
|
|
||||||
COMMAND ${GCOVR_XML_CMD}
|
|
||||||
|
|
||||||
BYPRODUCTS ${Coverage_NAME}.xml
|
|
||||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
|
||||||
DEPENDS ${Coverage_DEPENDENCIES}
|
|
||||||
VERBATIM # Protect arguments to commands
|
|
||||||
COMMENT "Running gcovr to produce Cobertura code coverage report."
|
|
||||||
)
|
|
||||||
|
|
||||||
# Show info where to find the report
|
|
||||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
|
||||||
COMMAND ;
|
|
||||||
COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
|
|
||||||
)
|
|
||||||
endfunction() # setup_target_for_coverage_gcovr_xml
|
|
||||||
|
|
||||||
# Defines a target for running and collection code coverage information
|
|
||||||
# Builds dependencies, runs the given executable and outputs reports.
|
|
||||||
# NOTE! The executable should always have a ZERO as exit code otherwise
|
|
||||||
# the coverage generation will not complete.
|
|
||||||
#
|
|
||||||
# setup_target_for_coverage_gcovr_html(
|
|
||||||
# NAME ctest_coverage # New target name
|
|
||||||
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
|
||||||
# DEPENDENCIES executable_target # Dependencies to build first
|
|
||||||
# BASE_DIRECTORY "../" # Base directory for report
|
|
||||||
# # (defaults to PROJECT_SOURCE_DIR)
|
|
||||||
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
|
||||||
# # to BASE_DIRECTORY, with CMake 3.4+)
|
|
||||||
# )
|
|
||||||
# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the
|
|
||||||
# GCVOR command.
|
|
||||||
function(setup_target_for_coverage_gcovr_html)
|
|
||||||
|
|
||||||
set(options NONE)
|
|
||||||
set(oneValueArgs BASE_DIRECTORY NAME)
|
|
||||||
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
|
||||||
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
||||||
|
|
||||||
if(NOT GCOVR_PATH)
|
|
||||||
message(FATAL_ERROR "gcovr not found! Aborting...")
|
|
||||||
endif() # NOT GCOVR_PATH
|
|
||||||
|
|
||||||
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
|
||||||
if(DEFINED Coverage_BASE_DIRECTORY)
|
|
||||||
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
|
||||||
else()
|
|
||||||
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Collect excludes (CMake 3.4+: Also compute absolute paths)
|
|
||||||
set(GCOVR_EXCLUDES "")
|
|
||||||
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
|
|
||||||
if(CMAKE_VERSION VERSION_GREATER 3.4)
|
|
||||||
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
|
|
||||||
endif()
|
|
||||||
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
|
|
||||||
endforeach()
|
|
||||||
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
|
|
||||||
|
|
||||||
# Combine excludes to several -e arguments
|
|
||||||
set(GCOVR_EXCLUDE_ARGS "")
|
|
||||||
foreach(EXCLUDE ${GCOVR_EXCLUDES})
|
|
||||||
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
|
|
||||||
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
# Set up commands which will be run to generate coverage data
|
|
||||||
# Run tests
|
|
||||||
set(GCOVR_HTML_EXEC_TESTS_CMD
|
|
||||||
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
|
||||||
)
|
|
||||||
# Create folder
|
|
||||||
set(GCOVR_HTML_FOLDER_CMD
|
|
||||||
${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
|
|
||||||
)
|
|
||||||
# Running gcovr
|
|
||||||
set(GCOVR_HTML_CMD
|
|
||||||
${GCOVR_PATH} --html ${Coverage_NAME}/index.html --html-details -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
|
|
||||||
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
if(CODE_COVERAGE_VERBOSE)
|
|
||||||
message(STATUS "Executed command report")
|
|
||||||
|
|
||||||
message(STATUS "Command to run tests: ")
|
|
||||||
string(REPLACE ";" " " GCOVR_HTML_EXEC_TESTS_CMD_SPACED "${GCOVR_HTML_EXEC_TESTS_CMD}")
|
|
||||||
message(STATUS "${GCOVR_HTML_EXEC_TESTS_CMD_SPACED}")
|
|
||||||
|
|
||||||
message(STATUS "Command to create a folder: ")
|
|
||||||
string(REPLACE ";" " " GCOVR_HTML_FOLDER_CMD_SPACED "${GCOVR_HTML_FOLDER_CMD}")
|
|
||||||
message(STATUS "${GCOVR_HTML_FOLDER_CMD_SPACED}")
|
|
||||||
|
|
||||||
message(STATUS "Command to generate gcovr HTML coverage data: ")
|
|
||||||
string(REPLACE ";" " " GCOVR_HTML_CMD_SPACED "${GCOVR_HTML_CMD}")
|
|
||||||
message(STATUS "${GCOVR_HTML_CMD_SPACED}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_custom_target(${Coverage_NAME}
|
|
||||||
COMMAND ${GCOVR_HTML_EXEC_TESTS_CMD}
|
|
||||||
COMMAND ${GCOVR_HTML_FOLDER_CMD}
|
|
||||||
COMMAND ${GCOVR_HTML_CMD}
|
|
||||||
|
|
||||||
BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory
|
|
||||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
|
||||||
DEPENDS ${Coverage_DEPENDENCIES}
|
|
||||||
VERBATIM # Protect arguments to commands
|
|
||||||
COMMENT "Running gcovr to produce HTML code coverage report."
|
|
||||||
)
|
|
||||||
|
|
||||||
# Show info where to find the report
|
|
||||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
|
||||||
COMMAND ;
|
|
||||||
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
|
|
||||||
)
|
|
||||||
|
|
||||||
endfunction() # setup_target_for_coverage_gcovr_html
|
|
||||||
|
|
||||||
# Defines a target for running and collection code coverage information
|
|
||||||
# Builds dependencies, runs the given executable and outputs reports.
|
|
||||||
# NOTE! The executable should always have a ZERO as exit code otherwise
|
|
||||||
# the coverage generation will not complete.
|
|
||||||
#
|
|
||||||
# setup_target_for_coverage_fastcov(
|
|
||||||
# NAME testrunner_coverage # New target name
|
|
||||||
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
|
||||||
# DEPENDENCIES testrunner # Dependencies to build first
|
|
||||||
# BASE_DIRECTORY "../" # Base directory for report
|
|
||||||
# # (defaults to PROJECT_SOURCE_DIR)
|
|
||||||
# EXCLUDE "src/dir1/" "src/dir2/" # Patterns to exclude.
|
|
||||||
# NO_DEMANGLE # Don't demangle C++ symbols
|
|
||||||
# # even if c++filt is found
|
|
||||||
# SKIP_HTML # Don't create html report
|
|
||||||
# POST_CMD perl -i -pe s!${PROJECT_SOURCE_DIR}/!!g ctest_coverage.json # E.g. for stripping source dir from file paths
|
|
||||||
# )
|
|
||||||
function(setup_target_for_coverage_fastcov)
|
|
||||||
|
|
||||||
set(options NO_DEMANGLE SKIP_HTML)
|
|
||||||
set(oneValueArgs BASE_DIRECTORY NAME)
|
|
||||||
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES FASTCOV_ARGS GENHTML_ARGS POST_CMD)
|
|
||||||
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
||||||
|
|
||||||
if(NOT FASTCOV_PATH)
|
|
||||||
message(FATAL_ERROR "fastcov not found! Aborting...")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT Coverage_SKIP_HTML AND NOT GENHTML_PATH)
|
|
||||||
message(FATAL_ERROR "genhtml not found! Aborting...")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
|
||||||
if(Coverage_BASE_DIRECTORY)
|
|
||||||
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
|
||||||
else()
|
|
||||||
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Collect excludes (Patterns, not paths, for fastcov)
|
|
||||||
set(FASTCOV_EXCLUDES "")
|
|
||||||
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_FASTCOV_EXCLUDES})
|
|
||||||
list(APPEND FASTCOV_EXCLUDES "${EXCLUDE}")
|
|
||||||
endforeach()
|
|
||||||
list(REMOVE_DUPLICATES FASTCOV_EXCLUDES)
|
|
||||||
|
|
||||||
# Conditional arguments
|
|
||||||
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
|
|
||||||
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Set up commands which will be run to generate coverage data
|
|
||||||
set(FASTCOV_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS})
|
|
||||||
|
|
||||||
set(FASTCOV_CAPTURE_CMD ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH}
|
|
||||||
--search-directory ${BASEDIR}
|
|
||||||
--process-gcno
|
|
||||||
--output ${Coverage_NAME}.json
|
|
||||||
--exclude ${FASTCOV_EXCLUDES}
|
|
||||||
)
|
|
||||||
|
|
||||||
set(FASTCOV_CONVERT_CMD ${FASTCOV_PATH}
|
|
||||||
-C ${Coverage_NAME}.json --lcov --output ${Coverage_NAME}.info
|
|
||||||
)
|
|
||||||
|
|
||||||
if(Coverage_SKIP_HTML)
|
|
||||||
set(FASTCOV_HTML_CMD ";")
|
|
||||||
else()
|
|
||||||
set(FASTCOV_HTML_CMD ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS}
|
|
||||||
-o ${Coverage_NAME} ${Coverage_NAME}.info
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(FASTCOV_POST_CMD ";")
|
|
||||||
if(Coverage_POST_CMD)
|
|
||||||
set(FASTCOV_POST_CMD ${Coverage_POST_CMD})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(CODE_COVERAGE_VERBOSE)
|
|
||||||
message(STATUS "Code coverage commands for target ${Coverage_NAME} (fastcov):")
|
|
||||||
|
|
||||||
message(" Running tests:")
|
|
||||||
string(REPLACE ";" " " FASTCOV_EXEC_TESTS_CMD_SPACED "${FASTCOV_EXEC_TESTS_CMD}")
|
|
||||||
message(" ${FASTCOV_EXEC_TESTS_CMD_SPACED}")
|
|
||||||
|
|
||||||
message(" Capturing fastcov counters and generating report:")
|
|
||||||
string(REPLACE ";" " " FASTCOV_CAPTURE_CMD_SPACED "${FASTCOV_CAPTURE_CMD}")
|
|
||||||
message(" ${FASTCOV_CAPTURE_CMD_SPACED}")
|
|
||||||
|
|
||||||
message(" Converting fastcov .json to lcov .info:")
|
|
||||||
string(REPLACE ";" " " FASTCOV_CONVERT_CMD_SPACED "${FASTCOV_CONVERT_CMD}")
|
|
||||||
message(" ${FASTCOV_CONVERT_CMD_SPACED}")
|
|
||||||
|
|
||||||
if(NOT Coverage_SKIP_HTML)
|
|
||||||
message(" Generating HTML report: ")
|
|
||||||
string(REPLACE ";" " " FASTCOV_HTML_CMD_SPACED "${FASTCOV_HTML_CMD}")
|
|
||||||
message(" ${FASTCOV_HTML_CMD_SPACED}")
|
|
||||||
endif()
|
|
||||||
if(Coverage_POST_CMD)
|
|
||||||
message(" Running post command: ")
|
|
||||||
string(REPLACE ";" " " FASTCOV_POST_CMD_SPACED "${FASTCOV_POST_CMD}")
|
|
||||||
message(" ${FASTCOV_POST_CMD_SPACED}")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Setup target
|
|
||||||
add_custom_target(${Coverage_NAME}
|
|
||||||
|
|
||||||
# Cleanup fastcov
|
|
||||||
COMMAND ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH}
|
|
||||||
--search-directory ${BASEDIR}
|
|
||||||
--zerocounters
|
|
||||||
|
|
||||||
COMMAND ${FASTCOV_EXEC_TESTS_CMD}
|
|
||||||
COMMAND ${FASTCOV_CAPTURE_CMD}
|
|
||||||
COMMAND ${FASTCOV_CONVERT_CMD}
|
|
||||||
COMMAND ${FASTCOV_HTML_CMD}
|
|
||||||
COMMAND ${FASTCOV_POST_CMD}
|
|
||||||
|
|
||||||
# Set output files as GENERATED (will be removed on 'make clean')
|
|
||||||
BYPRODUCTS
|
|
||||||
${Coverage_NAME}.info
|
|
||||||
${Coverage_NAME}.json
|
|
||||||
${Coverage_NAME}/index.html # report directory
|
|
||||||
|
|
||||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
|
||||||
DEPENDS ${Coverage_DEPENDENCIES}
|
|
||||||
VERBATIM # Protect arguments to commands
|
|
||||||
COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report."
|
|
||||||
)
|
|
||||||
|
|
||||||
set(INFO_MSG "fastcov code coverage info report saved in ${Coverage_NAME}.info and ${Coverage_NAME}.json.")
|
|
||||||
if(NOT Coverage_SKIP_HTML)
|
|
||||||
string(APPEND INFO_MSG " Open ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html in your browser to view the coverage report.")
|
|
||||||
endif()
|
|
||||||
# Show where to find the fastcov info report
|
|
||||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E echo ${INFO_MSG}
|
|
||||||
)
|
|
||||||
|
|
||||||
endfunction() # setup_target_for_coverage_fastcov
|
|
||||||
|
|
||||||
function(append_coverage_compiler_flags)
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
|
||||||
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
|
||||||
message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
|
|
||||||
endfunction() # append_coverage_compiler_flags
|
|
||||||
|
|
||||||
# Setup coverage for specific library
|
|
||||||
function(append_coverage_compiler_flags_to_target name)
|
|
||||||
separate_arguments(_flag_list NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}")
|
|
||||||
target_compile_options(${name} PRIVATE ${_flag_list})
|
|
||||||
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
|
|
||||||
target_link_libraries(${name} PRIVATE gcov)
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
@@ -50,28 +50,15 @@ file(READ ${HEADERS_LIST_FILE} HEADERS_LIST)
|
|||||||
|
|
||||||
set(symbols)
|
set(symbols)
|
||||||
foreach(header ${HEADERS_LIST})
|
foreach(header ${HEADERS_LIST})
|
||||||
file(READ ${header} header_content)
|
|
||||||
|
|
||||||
# Filter only lines containing the FILTER_PATTERN
|
# Filter only lines containing the FILTER_PATTERN
|
||||||
# separated from the function name with one optional newline
|
file(STRINGS ${header} contain_filter
|
||||||
string(REGEX MATCHALL
|
REGEX "^.*${FILTER_PATTERN}.*[(]"
|
||||||
"${FILTER_PATTERN}[^(\n]*\n?[^(\n]*[(]"
|
|
||||||
contain_filter
|
|
||||||
"${header_content}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Remove the optional newline now
|
|
||||||
string(REGEX REPLACE
|
|
||||||
"(.+)\n?(.*)"
|
|
||||||
"\\1\\2"
|
|
||||||
oneline
|
|
||||||
"${contain_filter}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Remove function-like macros
|
# Remove function-like macros
|
||||||
# and anything with two underscores that sounds suspicious
|
foreach(line ${contain_filter})
|
||||||
foreach(line ${oneline})
|
if (NOT ${line} MATCHES ".*#[ ]*define")
|
||||||
if (NOT ${line} MATCHES ".*(#[ ]*define|__)")
|
|
||||||
list(APPEND not_macro ${line})
|
list(APPEND not_macro ${line})
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|||||||
@@ -220,12 +220,13 @@
|
|||||||
|
|
||||||
# Search for python which is required
|
# Search for python which is required
|
||||||
if (ABIMap_FIND_REQURIED)
|
if (ABIMap_FIND_REQURIED)
|
||||||
find_package(Python REQUIRED)
|
find_package(PythonInterp REQUIRED)
|
||||||
else()
|
else()
|
||||||
find_package(Python)
|
find_package(PythonInterp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (TARGET Python::Interpreter)
|
|
||||||
|
if (PYTHONINTERP_FOUND)
|
||||||
# Search for abimap tool used to generate the map files
|
# Search for abimap tool used to generate the map files
|
||||||
find_program(ABIMAP_EXECUTABLE NAMES abimap DOC "path to the abimap executable")
|
find_program(ABIMAP_EXECUTABLE NAMES abimap DOC "path to the abimap executable")
|
||||||
mark_as_advanced(ABIMAP_EXECUTABLE)
|
mark_as_advanced(ABIMAP_EXECUTABLE)
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ if (ARGP_LIBRARY)
|
|||||||
endif (ARGP_LIBRARY)
|
endif (ARGP_LIBRARY)
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
include(FindPackageHandleStandardArgs)
|
||||||
find_package_handle_standard_args(Argp DEFAULT_MSG ARGP_LIBRARIES ARGP_INCLUDE_DIR)
|
find_package_handle_standard_args(ARGP DEFAULT_MSG ARGP_LIBRARIES ARGP_INCLUDE_DIR)
|
||||||
|
|
||||||
# show the ARGP_INCLUDE_DIR and ARGP_LIBRARIES variables only in the advanced view
|
# show the ARGP_INCLUDE_DIR and ARGP_LIBRARIES variables only in the advanced view
|
||||||
mark_as_advanced(ARGP_INCLUDE_DIR ARGP_LIBRARIES)
|
mark_as_advanced(ARGP_INCLUDE_DIR ARGP_LIBRARIES)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ set(_MBEDTLS_ROOT_HINTS_AND_PATHS
|
|||||||
|
|
||||||
find_path(MBEDTLS_INCLUDE_DIR
|
find_path(MBEDTLS_INCLUDE_DIR
|
||||||
NAMES
|
NAMES
|
||||||
mbedtls/ssl.h
|
mbedtls/config.h
|
||||||
HINTS
|
HINTS
|
||||||
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
|
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
|
||||||
PATH_SUFFIXES
|
PATH_SUFFIXES
|
||||||
@@ -73,14 +73,6 @@ set(MBEDTLS_LIBRARIES ${MBEDTLS_SSL_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY}
|
|||||||
${MBEDTLS_X509_LIBRARY})
|
${MBEDTLS_X509_LIBRARY})
|
||||||
|
|
||||||
if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
|
if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
|
||||||
# mbedtls 2.8
|
|
||||||
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX
|
|
||||||
"^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
|
|
||||||
|
|
||||||
string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+.[0-9]+.[0-9]+).*"
|
|
||||||
"\\1" MBEDTLS_VERSION "${_mbedtls_version_str}")
|
|
||||||
elseif (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h")
|
|
||||||
# mbedtls 3.6
|
|
||||||
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX
|
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX
|
||||||
"^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
|
"^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
|
||||||
|
|
||||||
@@ -101,8 +93,8 @@ if (MBEDTLS_VERSION)
|
|||||||
in the system variable MBEDTLS_ROOT_DIR"
|
in the system variable MBEDTLS_ROOT_DIR"
|
||||||
)
|
)
|
||||||
else (MBEDTLS_VERSION)
|
else (MBEDTLS_VERSION)
|
||||||
find_package_handle_standard_args(MbedTLS
|
find_package_handle_standard_args(MBedTLS
|
||||||
"Could NOT find mbedTLS, try to set the path to mbedTLS root folder in
|
"Could NOT find mbedTLS, try to set the path to mbedLS root folder in
|
||||||
the system variable MBEDTLS_ROOT_DIR"
|
the system variable MBEDTLS_ROOT_DIR"
|
||||||
MBEDTLS_INCLUDE_DIR
|
MBEDTLS_INCLUDE_DIR
|
||||||
MBEDTLS_LIBRARIES)
|
MBEDTLS_LIBRARIES)
|
||||||
|
|||||||
@@ -58,15 +58,15 @@
|
|||||||
/* Define to 1 if you have the <stdint.h> header file. */
|
/* Define to 1 if you have the <stdint.h> header file. */
|
||||||
#cmakedefine HAVE_STDINT_H 1
|
#cmakedefine HAVE_STDINT_H 1
|
||||||
|
|
||||||
/* Define to 1 if you have the <ifaddrs.h> header file. */
|
|
||||||
#cmakedefine HAVE_IFADDRS_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <openssl/aes.h> header file. */
|
/* Define to 1 if you have the <openssl/aes.h> header file. */
|
||||||
#cmakedefine HAVE_OPENSSL_AES_H 1
|
#cmakedefine HAVE_OPENSSL_AES_H 1
|
||||||
|
|
||||||
/* Define to 1 if you have the <wspiapi.h> header file. */
|
/* Define to 1 if you have the <wspiapi.h> header file. */
|
||||||
#cmakedefine HAVE_WSPIAPI_H 1
|
#cmakedefine HAVE_WSPIAPI_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <openssl/blowfish.h> header file. */
|
||||||
|
#cmakedefine HAVE_OPENSSL_BLOWFISH_H 1
|
||||||
|
|
||||||
/* Define to 1 if you have the <openssl/des.h> header file. */
|
/* Define to 1 if you have the <openssl/des.h> header file. */
|
||||||
#cmakedefine HAVE_OPENSSL_DES_H 1
|
#cmakedefine HAVE_OPENSSL_DES_H 1
|
||||||
|
|
||||||
@@ -91,9 +91,21 @@
|
|||||||
/* Define to 1 if you have elliptic curve cryptography */
|
/* Define to 1 if you have elliptic curve cryptography */
|
||||||
#cmakedefine HAVE_ECC 1
|
#cmakedefine HAVE_ECC 1
|
||||||
|
|
||||||
/* Define to 1 if you have gl_flags as a glob_t struct member */
|
/* Define to 1 if you have DSA */
|
||||||
|
#cmakedefine HAVE_DSA 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have gl_flags as a glob_t sturct member */
|
||||||
#cmakedefine HAVE_GLOB_GL_FLAGS_MEMBER 1
|
#cmakedefine HAVE_GLOB_GL_FLAGS_MEMBER 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have OpenSSL with Ed25519 support */
|
||||||
|
#cmakedefine HAVE_OPENSSL_ED25519 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have OpenSSL with X25519 support */
|
||||||
|
#cmakedefine HAVE_OPENSSL_X25519 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have OpenSSL with Poly1305 support */
|
||||||
|
#cmakedefine HAVE_OPENSSL_EVP_POLY1305 1
|
||||||
|
|
||||||
/* Define to 1 if you have gcrypt with ChaCha20/Poly1305 support */
|
/* Define to 1 if you have gcrypt with ChaCha20/Poly1305 support */
|
||||||
#cmakedefine HAVE_GCRYPT_CHACHA_POLY 1
|
#cmakedefine HAVE_GCRYPT_CHACHA_POLY 1
|
||||||
|
|
||||||
@@ -108,6 +120,15 @@
|
|||||||
/* Define to 1 if you have the `FIPS_mode' function. */
|
/* Define to 1 if you have the `FIPS_mode' function. */
|
||||||
#cmakedefine HAVE_OPENSSL_FIPS_MODE 1
|
#cmakedefine HAVE_OPENSSL_FIPS_MODE 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `EVP_DigestSign' function. */
|
||||||
|
#cmakedefine HAVE_OPENSSL_EVP_DIGESTSIGN 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `EVP_DigestVerify' function. */
|
||||||
|
#cmakedefine HAVE_OPENSSL_EVP_DIGESTVERIFY 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `OPENSSL_ia32cap_loc' function. */
|
||||||
|
#cmakedefine HAVE_OPENSSL_IA32CAP_LOC 1
|
||||||
|
|
||||||
/* Define to 1 if you have the `snprintf' function. */
|
/* Define to 1 if you have the `snprintf' function. */
|
||||||
#cmakedefine HAVE_SNPRINTF 1
|
#cmakedefine HAVE_SNPRINTF 1
|
||||||
|
|
||||||
@@ -180,9 +201,6 @@
|
|||||||
/* Define to 1 if you have the `cmocka_set_test_filter' function. */
|
/* Define to 1 if you have the `cmocka_set_test_filter' function. */
|
||||||
#cmakedefine HAVE_CMOCKA_SET_TEST_FILTER 1
|
#cmakedefine HAVE_CMOCKA_SET_TEST_FILTER 1
|
||||||
|
|
||||||
/* Define to 1 if we have support for blowfish */
|
|
||||||
#cmakedefine HAVE_BLOWFISH 1
|
|
||||||
|
|
||||||
/*************************** LIBRARIES ***************************/
|
/*************************** LIBRARIES ***************************/
|
||||||
|
|
||||||
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
||||||
@@ -234,14 +252,9 @@
|
|||||||
/* Define to 1 if you want to enable DH group exchange algorithms */
|
/* Define to 1 if you want to enable DH group exchange algorithms */
|
||||||
#cmakedefine WITH_GEX 1
|
#cmakedefine WITH_GEX 1
|
||||||
|
|
||||||
/* Define to 1 if you want to enable insecure none cipher and MAC */
|
/* Define to 1 if you want to enable none cipher and MAC */
|
||||||
#cmakedefine WITH_INSECURE_NONE 1
|
#cmakedefine WITH_INSECURE_NONE 1
|
||||||
|
|
||||||
/* Define to 1 if you want to allow libssh to execute arbitrary commands from
|
|
||||||
* configuration files or options (match exec, proxy commands and OpenSSH-based
|
|
||||||
* proxy-jumps). */
|
|
||||||
#cmakedefine WITH_EXEC 1
|
|
||||||
|
|
||||||
/* Define to 1 if you want to enable blowfish cipher support */
|
/* Define to 1 if you want to enable blowfish cipher support */
|
||||||
#cmakedefine WITH_BLOWFISH_CIPHER 1
|
#cmakedefine WITH_BLOWFISH_CIPHER 1
|
||||||
|
|
||||||
@@ -263,9 +276,6 @@
|
|||||||
/* Define to 1 if you want to enable PKCS #11 URI support */
|
/* Define to 1 if you want to enable PKCS #11 URI support */
|
||||||
#cmakedefine WITH_PKCS11_URI 1
|
#cmakedefine WITH_PKCS11_URI 1
|
||||||
|
|
||||||
/* Define to 1 if we want to build a support for PKCS #11 provider. */
|
|
||||||
#cmakedefine WITH_PKCS11_PROVIDER 1
|
|
||||||
|
|
||||||
/*************************** ENDIAN *****************************/
|
/*************************** ENDIAN *****************************/
|
||||||
|
|
||||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ if (DOXYGEN_FOUND)
|
|||||||
set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C YES)
|
set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C YES)
|
||||||
set(DOXYGEN_MARKDOWN_SUPPORT YES)
|
set(DOXYGEN_MARKDOWN_SUPPORT YES)
|
||||||
set(DOXYGEN_FULL_PATH_NAMES NO)
|
set(DOXYGEN_FULL_PATH_NAMES NO)
|
||||||
set(DOXYGEN_GENERATE_TAGFILE "tags.xml")
|
|
||||||
|
|
||||||
set(DOXYGEN_PREDEFINED DOXYGEN
|
set(DOXYGEN_PREDEFINED DOXYGEN
|
||||||
WITH_SERVER
|
WITH_SERVER
|
||||||
@@ -36,44 +35,6 @@ if (DOXYGEN_FOUND)
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/folderclosed.svg
|
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/folderclosed.svg
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/folderopen.svg
|
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/folderopen.svg
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/that_style/js/striped_bg.js)
|
${CMAKE_CURRENT_SOURCE_DIR}/that_style/js/striped_bg.js)
|
||||||
set(DOXYGEN_EXCLUDE_PATTERNS */src/external/* fe25519.h ge25519.h sc25519.h
|
|
||||||
blf.h)
|
|
||||||
set(DOXYGEN_EXCLUDE_SYMBOLS_STRUCTS chacha20_poly1305_keysched,dh_ctx,dh_ctx,dh_keypair,error_struct,
|
|
||||||
packet_struct,pem_get_password_struct,ssh_tokens_st,
|
|
||||||
sftp_attributes_struct,sftp_client_message_struct,
|
|
||||||
sftp_dir_struct,sftp_ext_struct,sftp_file_struct,sftp_message_struct,
|
|
||||||
sftp_packet_struct,sftp_request_queue_struct,sftp_session_struct,
|
|
||||||
sftp_status_message_struct,ssh_agent_state_struct,
|
|
||||||
ssh_agent_struct,ssh_auth_auto_state_struct,ssh_auth_request,
|
|
||||||
ssh_bind_config_keyword_table_s,ssh_bind_config_match_keyword_table_s,
|
|
||||||
ssh_bind_struct,ssh_buffer_struct,ssh_channel_callbacks_struct,
|
|
||||||
ssh_channel_read_termination_struct,ssh_channel_request,
|
|
||||||
ssh_channel_request_open,ssh_channel_struct,ssh_cipher_struct,
|
|
||||||
ssh_common_struct,ssh_config_keyword_table_s,
|
|
||||||
ssh_config_match_keyword_table_s,ssh_connector_struct,
|
|
||||||
ssh_counter_struct,ssh_crypto_struct,ssh_event_fd_wrapper,
|
|
||||||
ssh_event_struct,ssh_global_request,ssh_gssapi_struct,ssh_hmac_struct,
|
|
||||||
ssh_iterator,ssh_kbdint_struct,ssh_kex_struct,ssh_key_struct,
|
|
||||||
ssh_knownhosts_entry,ssh_list,ssh_mac_ctx_struct,ssh_message_struct,
|
|
||||||
ssh_packet_callbacks_struct,ssh_packet_header,ssh_poll_ctx_struct,
|
|
||||||
ssh_poll_handle_struct,ssh_pollfd_struct,ssh_private_key_struct,
|
|
||||||
ssh_public_key_struct,ssh_scp_struct,ssh_service_request,
|
|
||||||
ssh_session_struct,ssh_signature_struct,ssh_socket_struct,
|
|
||||||
ssh_string_struct,ssh_threads_callbacks_struct,ssh_timestamp,)
|
|
||||||
set(DOXYGEN_EXCLUDE_SYMBOLS_MACRO SSH_FXP*,SSH_SOCKET*,SERVERBANNER,SOCKOPT_TYPE_ARG4,SSH_FILEXFER*,
|
|
||||||
SSH_FXF*,SSH_S_*,SFTP_*,NSS_BUFLEN_PASSWD,CLOCK,MAX_LINE_SIZE,
|
|
||||||
PKCS11_URI,KNOWNHOSTS_MAXTYPES,)
|
|
||||||
set(DOXYGEN_EXCLUDE_SYMBOLS_TYPEDEFS sftp_attributes,sftp_client_message,sftp_dir,sftp_ext,sftp_file,
|
|
||||||
sftp_message,sftp_packet,sftp_request_queue,sftp_session,
|
|
||||||
sftp_status_message,sftp_statvfs_t,poll_fn,ssh_callback_int,
|
|
||||||
ssh_callback_data,ssh_callback_int_int,ssh_message_callback,
|
|
||||||
ssh_channel_callback_int,ssh_channel_callback_data,ssh_callbacks,
|
|
||||||
ssh_gssapi_select_oid_callback,ssh_gssapi_accept_sec_ctx_callback,
|
|
||||||
ssh_gssapi_verify_mic_callback,ssh_server_callbacks,ssh_socket_callbacks,
|
|
||||||
ssh_packet_callbacks,ssh_channel_callbacks,ssh_bind,ssh_bind_callbacks,)
|
|
||||||
set(DOXYGEN_EXCLUDE_SYMBOLS ${DOXYGEN_EXCLUDE_SYMBOLS_STRUCTS}
|
|
||||||
${DOXYGEN_EXCLUDE_SYMBOLS_MACRO}
|
|
||||||
${DOXYGEN_EXCLUDE_SYMBOLS_TYPEDEFS})
|
|
||||||
|
|
||||||
# This updates the Doxyfile if we do changes here
|
# This updates the Doxyfile if we do changes here
|
||||||
set(_doxyfile_template "${CMAKE_BINARY_DIR}/CMakeDoxyfile.in")
|
set(_doxyfile_template "${CMAKE_BINARY_DIR}/CMakeDoxyfile.in")
|
||||||
@@ -84,8 +45,6 @@ if (DOXYGEN_FOUND)
|
|||||||
${CMAKE_SOURCE_DIR}/include/libssh
|
${CMAKE_SOURCE_DIR}/include/libssh
|
||||||
${CMAKE_SOURCE_DIR}/src
|
${CMAKE_SOURCE_DIR}/src
|
||||||
${CMAKE_CURRENT_SOURCE_DIR})
|
${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
add_custom_target(docs_coverage COMMAND ${CMAKE_SOURCE_DIR}/doc/doc_coverage.sh ${CMAKE_BINARY_DIR})
|
|
||||||
endif() # DOXYGEN_FOUND
|
endif() # DOXYGEN_FOUND
|
||||||
|
|
||||||
endif() # CMAKE_VERSION
|
endif() # CMAKE_VERSION
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
################################################################################
|
|
||||||
# .doc_coverage.sh #
|
|
||||||
# Script to detect overall documentation coverage of libssh. The script uses #
|
|
||||||
# doxygen to generate the documentation then parses it's output. #
|
|
||||||
# #
|
|
||||||
# maintainer: Norbert Pocs <npocs@redhat.com> #
|
|
||||||
################################################################################
|
|
||||||
BUILD_DIR="$1"
|
|
||||||
DOXYFILE_PATH="$BUILD_DIR/doc/Doxyfile.docs"
|
|
||||||
INDEX_XML_PATH="$BUILD_DIR/doc/xml/index.xml"
|
|
||||||
# filters
|
|
||||||
F_EXCLUDE_FILES=' wrapper.h legacy.h crypto.h priv.h chacha.h curve25519.h '
|
|
||||||
F_UNDOC_FUNC='(function).*is not documented'
|
|
||||||
F_FUNC='kind="function"'
|
|
||||||
F_HEADERS='libssh_8h_|group__libssh__'
|
|
||||||
F_CUT_BEFORE='.*<name>'
|
|
||||||
F_CUT_AFTER='<\/name><\/member>'
|
|
||||||
# Doxygen options
|
|
||||||
O_QUIET='QUIET=YES'
|
|
||||||
O_GEN_XML='GENERATE_XML=YES'
|
|
||||||
|
|
||||||
# check if build dir given
|
|
||||||
if [ $# -eq 0 ]; then
|
|
||||||
echo "Please provide the build directory e.g.: ./build"
|
|
||||||
exit 255
|
|
||||||
fi
|
|
||||||
|
|
||||||
# modify doxyfile to our needs:
|
|
||||||
# QUIET - less output
|
|
||||||
# GENERATE_XML - xml needed to inspect all the functions
|
|
||||||
# (note: the options are needed to be on separate lines)
|
|
||||||
# We want to exclude irrelevant files
|
|
||||||
MOD_DOXYFILE=$(cat "$DOXYFILE_PATH"; echo "$O_QUIET"; echo "$O_GEN_XML")
|
|
||||||
MOD_DOXYFILE=${MOD_DOXYFILE//EXCLUDE_PATTERNS.*=/EXCLUDE_PATTERNS=$F_EXCLUDE_FILES/g}
|
|
||||||
|
|
||||||
# call doxygen to get the warning messages
|
|
||||||
# and also generate the xml for inspection
|
|
||||||
DOXY_WARNINGS=$(echo "$MOD_DOXYFILE" | doxygen - 2>&1)
|
|
||||||
|
|
||||||
# get the number of undocumented functions
|
|
||||||
UNDOC_FUNC=$(echo "$DOXY_WARNINGS" | grep -cE "$F_UNDOC_FUNC")
|
|
||||||
|
|
||||||
# filter out the lines consisting of functions of our interest
|
|
||||||
FUNC_LINES=$(grep "$F_FUNC" "$INDEX_XML_PATH" | grep -E "$F_HEADERS")
|
|
||||||
# cut the irrelevant information and leave just the function names
|
|
||||||
ALL_FUNC=$(echo "$FUNC_LINES" | sed -e "s/$F_CUT_BEFORE//g" -e "s/$F_CUT_AFTER//")
|
|
||||||
# remove duplicates and get the number of functions
|
|
||||||
ALL_FUNC=$(echo "$ALL_FUNC" | sort - | uniq | wc -l)
|
|
||||||
|
|
||||||
# percentage of the documented functions
|
|
||||||
awk "BEGIN {printf \"Documentation coverage is %.2f%\n\", 100 - (${UNDOC_FUNC}/${ALL_FUNC}*100)}"
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
A SSH session goes through the following steps:
|
A SSH session goes through the following steps:
|
||||||
|
|
||||||
- Before connecting to the server, you can set up if you wish one or other
|
- Before connecting to the server, you can set up if you wish one or other
|
||||||
server public key authentication, i.e. RSA, ED25519 or ECDSA. You can choose
|
server public key authentication, i.e. DSA or RSA. You can choose
|
||||||
cryptographic algorithms you trust and compression algorithms if any. You
|
cryptographic algorithms you trust and compression algorithms if any. You
|
||||||
must of course set up the hostname.
|
must of course set up the hostname.
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ A SSH session goes through the following steps:
|
|||||||
file.
|
file.
|
||||||
|
|
||||||
- The client must authenticate: the classical ways are password, or
|
- The client must authenticate: the classical ways are password, or
|
||||||
public keys (from ecdsa, ed25519 and rsa key-pairs generated by openssh).
|
public keys (from dsa and rsa key-pairs generated by openssh).
|
||||||
If a SSH agent is running, it is possible to use it.
|
If a SSH agent is running, it is possible to use it.
|
||||||
|
|
||||||
- Now that the user has been authenticated, you must open one or several
|
- Now that the user has been authenticated, you must open one or several
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ libssh is a Free Software / Open Source project. The libssh library
|
|||||||
is distributed under LGPL license. The libssh project has nothing to do with
|
is distributed under LGPL license. The libssh project has nothing to do with
|
||||||
"libssh2", which is a completely different and independent project.
|
"libssh2", which is a completely different and independent project.
|
||||||
|
|
||||||
libssh can run on top of either libcrypto, mbedtls or libgcrypt (deprecated)
|
libssh can run on top of either libgcrypt or libcrypto,
|
||||||
general-purpose cryptographic libraries.
|
two general-purpose cryptographic libraries.
|
||||||
|
|
||||||
This tutorial concentrates for its main part on the "client" side of libssh.
|
This tutorial concentrates for its main part on the "client" side of libssh.
|
||||||
To learn how to accept incoming SSH connections (how to write a SSH server),
|
To learn how to accept incoming SSH connections (how to write a SSH server),
|
||||||
@@ -44,10 +44,6 @@ Table of contents:
|
|||||||
|
|
||||||
@subpage libssh_tutor_threads
|
@subpage libssh_tutor_threads
|
||||||
|
|
||||||
@subpage libssh_tutor_pkcs11
|
|
||||||
|
|
||||||
@subpage libssh_tutor_sftp_aio
|
|
||||||
|
|
||||||
@subpage libssh_tutor_todo
|
@subpage libssh_tutor_todo
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ the interesting functions as you go.
|
|||||||
The libssh library provides:
|
The libssh library provides:
|
||||||
|
|
||||||
- <strong>Key Exchange Methods</strong>: <i>curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
|
- <strong>Key Exchange Methods</strong>: <i>curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
|
||||||
- <strong>Public Key Algorithms</strong>: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, ssh-rsa, rsa-sha2-512, rsa-sha2-256
|
- <strong>Public Key Algorithms</strong>: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, ssh-rsa, rsa-sha2-512, rsa-sha2-256,ssh-dss
|
||||||
- <strong>Ciphers</strong>: <i>aes256-ctr, aes192-ctr, aes128-ctr</i>, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, blowfish-cbc
|
- <strong>Ciphers</strong>: <i>aes256-ctr, aes192-ctr, aes128-ctr</i>, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, blowfish-cbc
|
||||||
- <strong>Compression Schemes</strong>: zlib, <i>zlib@openssh.com</i>, none
|
- <strong>Compression Schemes</strong>: zlib, <i>zlib@openssh.com</i>, none
|
||||||
- <strong>MAC hashes</strong>: hmac-sha1, hmac-sha2-256, hmac-sha2-512, hmac-md5
|
- <strong>MAC hashes</strong>: hmac-sha1, hmac-sha2-256, hmac-sha2-512, hmac-md5
|
||||||
@@ -33,7 +33,7 @@ The libssh library provides:
|
|||||||
- <strong>Thread-safe</strong>: Just don't share sessions
|
- <strong>Thread-safe</strong>: Just don't share sessions
|
||||||
- <strong>Non-blocking</strong>: it can be used both blocking and non-blocking
|
- <strong>Non-blocking</strong>: it can be used both blocking and non-blocking
|
||||||
- <strong>Your sockets</strong>: the app hands over the socket, or uses libssh sockets
|
- <strong>Your sockets</strong>: the app hands over the socket, or uses libssh sockets
|
||||||
- <b>OpenSSL</b>, <b>MBedTLS</b> or <b>gcrypt</b> (deprecated): builds with either
|
- <b>OpenSSL</b> or <b>gcrypt</b>: builds with either
|
||||||
|
|
||||||
@section main-additional-features Additional Features
|
@section main-additional-features Additional Features
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ objects stored on the tokens can be uniquely identified is called PKCS #11 URI
|
|||||||
(Uniform Resource Identifier) and is defined in RFC 7512
|
(Uniform Resource Identifier) and is defined in RFC 7512
|
||||||
(https://tools.ietf.org/html/rfc7512).
|
(https://tools.ietf.org/html/rfc7512).
|
||||||
|
|
||||||
# Pre-requisites (OpenSSL < 3.0):
|
Pre-requisites:
|
||||||
|
|
||||||
OpenSSL 1.x defines an abstract layer called the "engine" to achieve
|
OpenSSL defines an abstract layer called the "engine" to achieve cryptographic
|
||||||
cryptographic acceleration. The engine_pkcs11 module acts like an interface
|
acceleration. The engine_pkcs11 module acts like an interface between the PKCS #11
|
||||||
between the PKCS #11 modules and the OpenSSL application.
|
modules and the OpenSSL engine.
|
||||||
|
|
||||||
To build and use libssh with PKCS #11 support:
|
To build and use libssh with PKCS #11 support:
|
||||||
1. Enable the cmake option: $ cmake -DWITH_PKCS11_URI=ON
|
1. Enable the cmake option: $ cmake -DWITH_PKCS11_URI=ON
|
||||||
@@ -21,23 +21,6 @@ To build and use libssh with PKCS #11 support:
|
|||||||
3. Install and configure engine_pkcs11 (https://github.com/OpenSC/libp11).
|
3. Install and configure engine_pkcs11 (https://github.com/OpenSC/libp11).
|
||||||
4. Plug in a working smart card or configure softhsm (https://www.opendnssec.org/softhsm).
|
4. Plug in a working smart card or configure softhsm (https://www.opendnssec.org/softhsm).
|
||||||
|
|
||||||
@warning The support for Engines was deprecated in OpenSSL 3.0 so this approach
|
|
||||||
is deprecated in libssh 0.11.x.
|
|
||||||
|
|
||||||
# Pre-requisites (OpenSSL 3.0.8+)
|
|
||||||
|
|
||||||
The OpenSSL 3.0 is deprecating usage of low-level engines in favor of high-level
|
|
||||||
"providers" to provide alternative implementation of cryptographic operations
|
|
||||||
or acceleration.
|
|
||||||
|
|
||||||
To build and use libssh with PKCS #11 support using OpenSSL providers:
|
|
||||||
1. Install and configure pkcs11 provider (https://github.com/latchset/pkcs11-provider).
|
|
||||||
2. Enable the cmake options: $ cmake -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
|
|
||||||
3. Build with OpenSSL.
|
|
||||||
4. Plug in a working smart card or configure softhsm (https://www.opendnssec.org/softhsm).
|
|
||||||
|
|
||||||
# New API functions
|
|
||||||
|
|
||||||
The functions ssh_pki_import_pubkey_file() and ssh_pki_import_privkey_file() that
|
The functions ssh_pki_import_pubkey_file() and ssh_pki_import_privkey_file() that
|
||||||
import the public and private keys from files respectively are now modified to support
|
import the public and private keys from files respectively are now modified to support
|
||||||
PKCS #11 URIs. These functions automatically detect if the provided filename is a file path
|
PKCS #11 URIs. These functions automatically detect if the provided filename is a file path
|
||||||
@@ -48,7 +31,7 @@ corresponding to the PKCS #11 URI are loaded from the PKCS #11 device.
|
|||||||
If you wish to authenticate using public keys on your own, follow the steps mentioned under
|
If you wish to authenticate using public keys on your own, follow the steps mentioned under
|
||||||
"Authentication with public keys" in Chapter 2 - A deeper insight into authentication.
|
"Authentication with public keys" in Chapter 2 - A deeper insight into authentication.
|
||||||
|
|
||||||
The function pki_uri_import() is used to populate the public/private ssh_key from the
|
The function pki_uri_import() is used to populate the public/private ssh_key from the
|
||||||
engine with PKCS #11 URIs as the look up.
|
engine with PKCS #11 URIs as the look up.
|
||||||
|
|
||||||
Here is a minimalistic example of public key authentication using PKCS #11 URIs:
|
Here is a minimalistic example of public key authentication using PKCS #11 URIs:
|
||||||
@@ -81,10 +64,4 @@ We recommend the users to provide a specific PKCS #11 URI so that it matches onl
|
|||||||
If the engine discovers multiple slots that could potentially contain the private keys referenced
|
If the engine discovers multiple slots that could potentially contain the private keys referenced
|
||||||
by the provided PKCS #11 URI, the engine will not try to authenticate.
|
by the provided PKCS #11 URI, the engine will not try to authenticate.
|
||||||
|
|
||||||
For testing, the SoftHSM PKCS#11 library is used. But it has some issues with
|
|
||||||
OpenSSL initialization/cleanup when used with OpenSSL 3.0 so we are using it
|
|
||||||
indirectly through a p11-kit remoting as described in the following article:
|
|
||||||
|
|
||||||
https://p11-glue.github.io/p11-glue/p11-kit/manual/remoting.html
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|||||||
114
doc/sftp.dox
114
doc/sftp.dox
@@ -139,7 +139,7 @@ Unlike its equivalent in the SCP subsystem, this function does NOT change the
|
|||||||
current directory to the newly created subdirectory.
|
current directory to the newly created subdirectory.
|
||||||
|
|
||||||
|
|
||||||
@subsection sftp_write Writing to a file on the remote computer
|
@subsection sftp_write Copying a file to the remote computer
|
||||||
|
|
||||||
You handle the contents of a remote file just like you would do with a
|
You handle the contents of a remote file just like you would do with a
|
||||||
local file: you open the file in a given mode, move the file pointer in it,
|
local file: you open the file in a given mode, move the file pointer in it,
|
||||||
@@ -203,14 +203,16 @@ int sftp_helloworld(ssh_session session, sftp_session sftp)
|
|||||||
|
|
||||||
@subsection sftp_read Reading a file from the remote computer
|
@subsection sftp_read Reading a file from the remote computer
|
||||||
|
|
||||||
A synchronous read from a remote file is done using sftp_read(). This
|
The nice thing with reading a file over the network through SFTP is that it
|
||||||
section describes how to download a remote file using sftp_read(). The
|
can be done both in a synchronous way or an asynchronous way. If you read the file
|
||||||
next section will discuss more about synchronous/asynchronous read/write
|
asynchronously, your program can do something else while it waits for the
|
||||||
operations using libssh sftp API.
|
results to come.
|
||||||
|
|
||||||
|
Synchronous read is done with sftp_read().
|
||||||
|
|
||||||
Files are normally transferred in chunks. A good chunk size is 16 KB. The following
|
Files are normally transferred in chunks. A good chunk size is 16 KB. The following
|
||||||
example transfers the remote file "/etc/profile" in 16 KB chunks. For each chunk we
|
example transfers the remote file "/etc/profile" in 16 KB chunks. For each chunk we
|
||||||
request, sftp_read() blocks till the data has been received:
|
request, sftp_read blocks till the data has been received:
|
||||||
|
|
||||||
@code
|
@code
|
||||||
// Good chunk size
|
// Good chunk size
|
||||||
@@ -271,39 +273,87 @@ int sftp_read_sync(ssh_session session, sftp_session sftp)
|
|||||||
}
|
}
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
@subsection sftp_aio Performing an asynchronous read/write on a file on the remote computer
|
Asynchronous read is done in two steps, first sftp_async_read_begin(), which
|
||||||
|
returns a "request handle", and then sftp_async_read(), which uses that request handle.
|
||||||
|
If the file has been opened in nonblocking mode, then sftp_async_read()
|
||||||
|
might return SSH_AGAIN, which means that the request hasn't completed yet
|
||||||
|
and that the function should be called again later on. Otherwise,
|
||||||
|
sftp_async_read() waits for the data to come. To open a file in nonblocking mode,
|
||||||
|
call sftp_file_set_nonblocking() right after you opened it. Default is blocking mode.
|
||||||
|
|
||||||
sftp_read() performs a "synchronous" read operation on a remote file.
|
The example below reads a very big file in asynchronous, nonblocking, mode. Each
|
||||||
This means that sftp_read() will first request the server to read some
|
time the data is not ready yet, a counter is incremented.
|
||||||
data from the remote file and then would wait until the server response
|
|
||||||
containing data to read (or an error) arrives at the client side.
|
|
||||||
|
|
||||||
sftp_write() performs a "synchronous" write operation on a remote file.
|
@code
|
||||||
This means that sftp_write() will first request the server to write some
|
// Good chunk size
|
||||||
data to the remote file and then would wait until the server response
|
#define MAX_XFER_BUF_SIZE 16384
|
||||||
containing information about the status of the write operation arrives at the
|
|
||||||
client side.
|
|
||||||
|
|
||||||
If your client program wants to do something other than waiting for the
|
int sftp_read_async(ssh_session session, sftp_session sftp)
|
||||||
response after requesting a read/write, the synchronous sftp_read() and
|
{
|
||||||
sftp_write() can't be used. In such a case the "asynchronous" sftp aio API
|
int access_type;
|
||||||
should be used.
|
sftp_file file;
|
||||||
|
char buffer[MAX_XFER_BUF_SIZE];
|
||||||
|
int async_request;
|
||||||
|
int nbytes;
|
||||||
|
long counter;
|
||||||
|
int rc;
|
||||||
|
|
||||||
Please go through @ref libssh_tutor_sftp_aio for a detailed description
|
access_type = O_RDONLY;
|
||||||
of the sftp aio API.
|
file = sftp_open(sftp, "some_very_big_file",
|
||||||
|
access_type, 0);
|
||||||
|
if (file == NULL) {
|
||||||
|
fprintf(stderr, "Can't open file for reading: %s\n",
|
||||||
|
ssh_get_error(session));
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
sftp_file_set_nonblocking(file);
|
||||||
|
|
||||||
The sftp aio API provides two categories of functions :
|
async_request = sftp_async_read_begin(file, sizeof(buffer));
|
||||||
- sftp_aio_begin_*() : For requesting a read/write from the server.
|
counter = 0L;
|
||||||
- sftp_aio_wait_*() : For waiting for the response of a previously
|
usleep(10000);
|
||||||
issued read/write request from the server.
|
if (async_request >= 0) {
|
||||||
|
nbytes = sftp_async_read(file, buffer, sizeof(buffer),
|
||||||
|
async_request);
|
||||||
|
} else {
|
||||||
|
nbytes = -1;
|
||||||
|
}
|
||||||
|
|
||||||
Hence, the client program can call sftp_aio_begin_*() to request a read/write
|
while (nbytes > 0 || nbytes == SSH_AGAIN) {
|
||||||
and then can perform any number of operations (other than waiting) before
|
if (nbytes > 0) {
|
||||||
calling sftp_aio_wait_*() for waiting for the response of the previously
|
write(1, buffer, nbytes);
|
||||||
issued request.
|
async_request = sftp_async_read_begin(file, sizeof(buffer));
|
||||||
|
} else {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
usleep(10000);
|
||||||
|
|
||||||
We call read/write operations performed in the manner described above as
|
if (async_request >= 0) {
|
||||||
"asynchronous" read/write operations on a remote file.
|
nbytes = sftp_async_read(file, buffer, sizeof(buffer),
|
||||||
|
async_request);
|
||||||
|
} else {
|
||||||
|
nbytes = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbytes < 0) {
|
||||||
|
fprintf(stderr, "Error while reading file: %s\n",
|
||||||
|
ssh_get_error(session));
|
||||||
|
sftp_close(file);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("The counter has reached value: %ld\n", counter);
|
||||||
|
|
||||||
|
rc = sftp_close(file);
|
||||||
|
if (rc != SSH_OK) {
|
||||||
|
fprintf(stderr, "Can't close the read file: %s\n",
|
||||||
|
ssh_get_error(session));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
@subsection sftp_ls Listing the contents of a directory
|
@subsection sftp_ls Listing the contents of a directory
|
||||||
|
|
||||||
|
|||||||
705
doc/sftp_aio.dox
705
doc/sftp_aio.dox
@@ -1,705 +0,0 @@
|
|||||||
/**
|
|
||||||
|
|
||||||
@page libssh_tutor_sftp_aio Chapter 10: The SFTP asynchronous I/O
|
|
||||||
|
|
||||||
@section sftp_aio_api The SFTP asynchronous I/O
|
|
||||||
|
|
||||||
NOTE : Please read @ref libssh_tutor_sftp before reading this page. The
|
|
||||||
synchronous sftp_read() and sftp_write() have been described there.
|
|
||||||
|
|
||||||
SFTP AIO stands for "SFTP Asynchronous Input/Output". This API contains
|
|
||||||
functions which perform async read/write operations on remote files.
|
|
||||||
|
|
||||||
File transfers performed using the asynchronous sftp aio API can be
|
|
||||||
significantly faster than the file transfers performed using the synchronous
|
|
||||||
sftp read/write API (see sftp_read() and sftp_write()).
|
|
||||||
|
|
||||||
The sftp aio API functions are divided into two categories :
|
|
||||||
- sftp_aio_begin_*() [see sftp_aio_begin_read(), sftp_aio_begin_write()]:
|
|
||||||
These functions send a request for an i/o operation to the server and
|
|
||||||
provide the caller an sftp aio handle corresponding to the sent request.
|
|
||||||
|
|
||||||
- sftp_aio_wait_*() [see sftp_aio_wait_read(), sftp_aio_wait_write()]:
|
|
||||||
These functions wait for the server response corresponding to a previously
|
|
||||||
issued request. Which request ? the request corresponding to the sftp aio
|
|
||||||
handle supplied by the caller to these functions.
|
|
||||||
|
|
||||||
Conceptually, you can think of the sftp aio handle as a request identifier.
|
|
||||||
|
|
||||||
Technically, the sftp_aio_begin_*() functions dynamically allocate memory to
|
|
||||||
store information about the i/o request they send and provide the caller a
|
|
||||||
handle to this memory, we call this handle an sftp aio handle.
|
|
||||||
|
|
||||||
sftp_aio_wait_*() functions use the information stored in that memory (handled
|
|
||||||
by the caller supplied sftp aio handle) to identify a request, and then they
|
|
||||||
wait for that request's response. These functions also release the memory
|
|
||||||
handled by the caller supplied sftp aio handle (except when they return
|
|
||||||
SSH_AGAIN).
|
|
||||||
|
|
||||||
sftp_aio_free() can also be used to release the memory handled by an sftp aio
|
|
||||||
handle but unlike the sftp_aio_wait_*() functions, it doesn't wait for a
|
|
||||||
response. This should be used to release the memory corresponding to an sftp
|
|
||||||
aio handle when some failure occurs. An example has been provided at the
|
|
||||||
end of this page to show the usage of sftp_aio_free().
|
|
||||||
|
|
||||||
To begin with, this tutorial will provide basic examples that describe the
|
|
||||||
usage of sftp aio API to perform a single read/write operation.
|
|
||||||
|
|
||||||
The later sections describe the usage of the sftp aio API to obtain faster file
|
|
||||||
transfers as compared to the transfers performed using the synchronous sftp
|
|
||||||
read/write API.
|
|
||||||
|
|
||||||
On encountering an error, the sftp aio API functions set the sftp and ssh
|
|
||||||
errors just like any other libssh sftp API function. These errors can be
|
|
||||||
obtained using sftp_get_error(), ssh_get_error() and ssh_get_error_code().
|
|
||||||
The code examples provided on this page ignore error handling for the sake of
|
|
||||||
brevity.
|
|
||||||
|
|
||||||
@subsection sftp_aio_read Using the sftp aio API for reading (a basic example)
|
|
||||||
|
|
||||||
For performing an async read operation on a sftp file (see sftp_open()),
|
|
||||||
the first step is to call sftp_aio_begin_read() to send a read request to the
|
|
||||||
server. The caller is provided an sftp aio handle corresponding to the sent
|
|
||||||
read request.
|
|
||||||
|
|
||||||
The second step is to pass a pointer to this aio handle to
|
|
||||||
sftp_aio_wait_read(), this function waits for the server response which
|
|
||||||
indicates the success/failure of the read request. On success, the response
|
|
||||||
indicates EOF or contains the data read from the sftp file.
|
|
||||||
|
|
||||||
The following code example shows how a read operation can be performed
|
|
||||||
on an sftp file using the sftp aio API.
|
|
||||||
|
|
||||||
@code
|
|
||||||
ssize_t read_chunk(sftp_file file, void *buf, size_t to_read)
|
|
||||||
{
|
|
||||||
ssize_t bytes_requested, bytes_read;
|
|
||||||
|
|
||||||
// Variable to store an sftp aio handle
|
|
||||||
sftp_aio aio = NULL;
|
|
||||||
|
|
||||||
// Send a read request to the sftp server
|
|
||||||
bytes_requested = sftp_aio_begin_read(file, to_read, &aio);
|
|
||||||
if (bytes_requested == SSH_ERROR) {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here its possible that (bytes_requested < to_read) as specified in
|
|
||||||
// the function documentation of sftp_aio_begin_read()
|
|
||||||
|
|
||||||
// Wait for the response of the read request corresponding to the
|
|
||||||
// sftp aio handle stored in the aio variable.
|
|
||||||
bytes_read = sftp_aio_wait_read(&aio, buf, to_read);
|
|
||||||
if (bytes_read == SSH_ERROR) {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes_read;
|
|
||||||
}
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
@subsection sftp_aio_write Using the sftp aio API for writing (a basic example)
|
|
||||||
|
|
||||||
For performing an async write operation on a sftp file (see sftp_open()),
|
|
||||||
the first step is to call sftp_aio_begin_write() to send a write request to
|
|
||||||
the server. The caller is provided an sftp aio handle corresponding to the
|
|
||||||
sent write request.
|
|
||||||
|
|
||||||
The second step is to pass a pointer to this aio handle to
|
|
||||||
sftp_aio_wait_write(), this function waits for the server response which
|
|
||||||
indicates the success/failure of the write request.
|
|
||||||
|
|
||||||
The following code example shows how a write operation can be performed on an
|
|
||||||
sftp file using the sftp aio API.
|
|
||||||
|
|
||||||
@code
|
|
||||||
ssize_t write_chunk(sftp_file file, void *buf, size_t to_write)
|
|
||||||
{
|
|
||||||
ssize_t bytes_requested, bytes_written;
|
|
||||||
|
|
||||||
// Variable to store an sftp aio handle
|
|
||||||
sftp_aio aio = NULL;
|
|
||||||
|
|
||||||
// Send a write request to the sftp server
|
|
||||||
bytes_requested = sftp_aio_begin_write(file, buf, to_write, &aio);
|
|
||||||
if (bytes_requested == SSH_ERROR) {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here its possible that (bytes_requested < to_write) as specified in
|
|
||||||
// the function documentation of sftp_aio_begin_write()
|
|
||||||
|
|
||||||
// Wait for the response of the write request corresponding to
|
|
||||||
// the sftp aio handle stored in the aio variable.
|
|
||||||
bytes_written = sftp_aio_wait_write(&aio);
|
|
||||||
if (bytes_written == SSH_ERROR) {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes_written;
|
|
||||||
}
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
@subsection sftp_aio_actual_use Using the sftp aio API to speed up a transfer
|
|
||||||
|
|
||||||
The above examples were provided to introduce the sftp aio API.
|
|
||||||
This is not how the sftp aio API is intended to be used, because the
|
|
||||||
above usage offers no advantage over the synchronous sftp read/write API
|
|
||||||
which does the same thing i.e issue a request and then immediately wait for
|
|
||||||
its response.
|
|
||||||
|
|
||||||
The facility that the sftp aio API provides is that the user can do
|
|
||||||
anything between issuing a request and getting the corresponding response.
|
|
||||||
Any number of operations can be performed after calling sftp_aio_begin_*()
|
|
||||||
[which issues a request] and before calling sftp_aio_wait_*() [which waits
|
|
||||||
for a response]
|
|
||||||
|
|
||||||
The code can leverage this feature by calling sftp_aio_begin_*() multiple times
|
|
||||||
to issue multiple requests before calling sftp_aio_wait_*() to wait for the
|
|
||||||
response of an earlier issued request. This approach will keep a certain number
|
|
||||||
of requests outstanding at the client side.
|
|
||||||
|
|
||||||
After issuing those requests, while the client code does something else (for
|
|
||||||
example waiting for an outstanding request's response, processing an obtained
|
|
||||||
response, issuing another request or any other operation the client wants
|
|
||||||
to perform), at the same time :
|
|
||||||
|
|
||||||
- Some of those outstanding requests may be travelling over the
|
|
||||||
network towards the server.
|
|
||||||
|
|
||||||
- Some of the outstanding requests may have reached the server and may
|
|
||||||
be queued for processing at the server side.
|
|
||||||
|
|
||||||
- Some of the outstanding requests may have been processed and the
|
|
||||||
corresponding responses may be travelling over the network towards the
|
|
||||||
client.
|
|
||||||
|
|
||||||
- Some of the responses corresponding to the outstanding requests may
|
|
||||||
have already reached the client side.
|
|
||||||
|
|
||||||
Clearly in this case, operations that the client performs and operations
|
|
||||||
involved in transfer/processing of a outstanding request can occur in
|
|
||||||
parallel. Also, operations involved in transfer/processing of two or more
|
|
||||||
outstanding requests may also occur in parallel (for example when one request
|
|
||||||
travels to the server, another request's response may be incoming towards the
|
|
||||||
client). Such kind of parallelism makes the overall transfer faster as compared
|
|
||||||
to a transfer performed using the synchronous sftp read/write API.
|
|
||||||
|
|
||||||
When the synchronous sftp read/write API is used to perform a transfer,
|
|
||||||
a strict sequence is followed:
|
|
||||||
|
|
||||||
- The client issues a single read/write request.
|
|
||||||
- Then waits for its response.
|
|
||||||
- On obtaining the response, the client processes it.
|
|
||||||
- After the processing ends, the client issues the next read/write request.
|
|
||||||
|
|
||||||
A file transfer performed in this manner would be slower than the case where
|
|
||||||
multiple read/write requests are kept outstanding at the client side. Because
|
|
||||||
here at any given time, operations related to transfer/processing of only one
|
|
||||||
request/response pair occurs. This is in contrast to the multiple outstanding
|
|
||||||
requests scenario where operations related to transfer/processing of multiple
|
|
||||||
request/response pairs may occur at the same time.
|
|
||||||
|
|
||||||
Although it's true that keeping multiple requests outstanding can speed up a
|
|
||||||
transfer, those outstanding requests come at a cost of increased memory
|
|
||||||
consumption both at the client side and the server side. Hence care must be
|
|
||||||
taken to use a reasonable limit for the number of requests kept outstanding.
|
|
||||||
|
|
||||||
The further sections provide code examples to show how uploads/downloads
|
|
||||||
can be performed using the sftp aio API and the concept of outstanding requests
|
|
||||||
discussed in this section. In those code examples, error handling has been
|
|
||||||
ignored and at some places pseudo code has been used for the sake of brevity.
|
|
||||||
|
|
||||||
The complete code for performing uploads/downloads using the sftp aio API,
|
|
||||||
can be found at https://gitlab.com/libssh/libssh-mirror/-/tree/master.
|
|
||||||
|
|
||||||
- libssh benchmarks for uploads performed using the sftp aio API [See
|
|
||||||
tests/benchmarks/bench_sftp.c]
|
|
||||||
- libssh benchmarks for downloads performed using the sftp aio API. [See
|
|
||||||
tests/benchmarks/bench_sftp.c]
|
|
||||||
- libssh sftp ft API code for performing a local to remote transfer (upload).
|
|
||||||
[See src/sftp_ft.c]
|
|
||||||
- libssh sftp ft API code for performing a remote to local transfer
|
|
||||||
(download). [See src/sftp_ft.c]
|
|
||||||
|
|
||||||
@subsection sftp_aio_cap Capping applied by the sftp aio API
|
|
||||||
|
|
||||||
Before the code examples for uploads and downloads, its important
|
|
||||||
to know about the capping applied by the sftp aio API.
|
|
||||||
|
|
||||||
sftp_aio_begin_read() caps the number of bytes the caller can request
|
|
||||||
to read from the remote file. That cap is the value of the max_read_length
|
|
||||||
field of the sftp_limits_t returned by sftp_limits(). Say that cap is LIM
|
|
||||||
and the caller passes x as the number of bytes to read to
|
|
||||||
sftp_aio_begin_read(), then (assuming no error occurs) :
|
|
||||||
|
|
||||||
- if x <= LIM, then sftp_aio_begin_read() will request the server
|
|
||||||
to read x bytes from the remote file, and will return x.
|
|
||||||
|
|
||||||
- if x > LIM, then sftp_aio_begin_read() will request the server
|
|
||||||
to read LIM bytes from the remote file and will return LIM.
|
|
||||||
|
|
||||||
Hence to request server to read x bytes (> LIM), the caller would have
|
|
||||||
to call sftp_aio_begin_read() multiple times, typically in a loop and
|
|
||||||
break out of the loop when the summation of return values of the multiple
|
|
||||||
sftp_aio_begin_read() calls becomes equal to x.
|
|
||||||
|
|
||||||
For the sake of simplicity, the code example for download in the upcoming
|
|
||||||
section would always ask sftp_aio_begin_read() to read x <= LIM bytes,
|
|
||||||
so that its return value is guaranteed to be x, unless an error occurs.
|
|
||||||
|
|
||||||
Similarly, sftp_aio_begin_write() caps the number of bytes the caller
|
|
||||||
can request to write to the remote file. That cap is the value of
|
|
||||||
max_write_length field of the sftp_limits_t returned by sftp_limits().
|
|
||||||
Say that cap is LIM and the caller passes x as the number of bytes to
|
|
||||||
write to sftp_aio_begin_write(), then (assuming no error occurs) :
|
|
||||||
|
|
||||||
- if x <= LIM, then sftp_aio_begin_write() will request the server
|
|
||||||
to write x bytes to the remote file, and will return x.
|
|
||||||
|
|
||||||
- if x > LIM, then sftp_aio_begin_write() will request the server
|
|
||||||
to write LIM bytes to the remote file and will return LIM.
|
|
||||||
|
|
||||||
Hence to request server to write x bytes (> LIM), the caller would have
|
|
||||||
to call sftp_aio_begin_write() multiple times, typically in a loop and
|
|
||||||
break out of the loop when the summation of return values of the multiple
|
|
||||||
sftp_aio_begin_write() calls becomes equal to x.
|
|
||||||
|
|
||||||
For the sake of simplicity, the code example for upload in the upcoming
|
|
||||||
section would always ask sftp_aio_begin_write() to write x <= LIM bytes,
|
|
||||||
so that its return value is guaranteed to be x, unless an error occurs.
|
|
||||||
|
|
||||||
@subsection sftp_aio_download_example Performing a download using the sftp aio API
|
|
||||||
|
|
||||||
Terminologies used in the following code snippets :
|
|
||||||
|
|
||||||
- sftp : The sftp_session opened using sftp_new() and initialised using
|
|
||||||
sftp_init()
|
|
||||||
|
|
||||||
- file : The sftp file handle of the remote file to download data
|
|
||||||
from. (See sftp_open())
|
|
||||||
|
|
||||||
- file_size : the size of the sftp file to download. This size can be obtained
|
|
||||||
by statting the remote file to download (e.g by using sftp_stat())
|
|
||||||
|
|
||||||
- We will need to maintain a queue which will be used to store the sftp aio
|
|
||||||
handles corresponding to the outstanding requests.
|
|
||||||
|
|
||||||
First, we issue the read requests while ensuring that their count
|
|
||||||
doesn't exceed a particular limit decided by us, and the number of bytes
|
|
||||||
requested don't exceed the size of the file to download.
|
|
||||||
|
|
||||||
@code
|
|
||||||
sftp_aio aio = NULL;
|
|
||||||
|
|
||||||
// Chunk size to use for the transfer
|
|
||||||
size_t chunk_size;
|
|
||||||
|
|
||||||
// For the limits structure that would be used
|
|
||||||
// by the code to set the chunk size
|
|
||||||
sftp_limits_t lim = NULL;
|
|
||||||
|
|
||||||
// Max number of requests to keep outstanding at a time
|
|
||||||
size_t in_flight_requests = 5;
|
|
||||||
|
|
||||||
// Number of bytes for which requests have been sent
|
|
||||||
size_t total_bytes_requested = 0;
|
|
||||||
|
|
||||||
// Number of bytes which have been downloaded
|
|
||||||
size_t bytes_downloaded = 0;
|
|
||||||
|
|
||||||
// Buffer to use for the download
|
|
||||||
char *buffer = NULL;
|
|
||||||
|
|
||||||
// Helper variables
|
|
||||||
size_t to_read;
|
|
||||||
ssize_t bytes_requested;
|
|
||||||
|
|
||||||
// Get the sftp limits
|
|
||||||
lim = sftp_limits(sftp);
|
|
||||||
if (lim == NULL) {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the chunk size for download = the max limit for reading
|
|
||||||
// The reason for this has been given in the "Capping applied by
|
|
||||||
// the sftp aio API" section (Its to make the code simpler)
|
|
||||||
//
|
|
||||||
// Assigning a size_t type variable a uint64_t type value here,
|
|
||||||
// theoretically could cause an overflow, but practically
|
|
||||||
// max_read_length would never exceed SIZE_MAX so its okay.
|
|
||||||
chunk_size = lim->max_read_length;
|
|
||||||
|
|
||||||
buffer = malloc(chunk_size);
|
|
||||||
if (buffer == NULL) {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
... // Code to open the remote file (to download) using sftp_open().
|
|
||||||
... // Code to stat the remote file's file size.
|
|
||||||
... // Code to open the local file in which downloaded data is to be stored.
|
|
||||||
... // Code to initialize the queue which will be used to store sftp aio
|
|
||||||
// handles.
|
|
||||||
|
|
||||||
for (i = 0;
|
|
||||||
i < in_flight_requests && total_bytes_requested < file_size;
|
|
||||||
++i) {
|
|
||||||
to_read = file_size - total_bytes_requested;
|
|
||||||
if (to_read > chunk_size) {
|
|
||||||
to_read = chunk_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Issue a read request
|
|
||||||
bytes_requested = sftp_aio_begin_read(file, to_read, &aio);
|
|
||||||
if (bytes_requested == SSH_ERROR) {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((size_t)bytes_requested < to_read) {
|
|
||||||
// Should not happen for this code, as the to_read is <=
|
|
||||||
// max limit for reading (chunk size), so there is no reason
|
|
||||||
// for sftp_aio_begin_read() to return a lesser value.
|
|
||||||
}
|
|
||||||
|
|
||||||
total_bytes_requested += (size_t)bytes_requested;
|
|
||||||
|
|
||||||
// Pseudo code
|
|
||||||
ENQUEUE aio in the queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
At this point, at max in_flight_requests number of requests may be
|
|
||||||
outstanding. Now we wait for the response corresponding to the earliest
|
|
||||||
issued outstanding request.
|
|
||||||
|
|
||||||
On getting that response, we issue another read request if there are
|
|
||||||
still some bytes in the sftp file (to download) for which we haven't sent the
|
|
||||||
read request. (This happens when total_bytes_requested < file_size)
|
|
||||||
|
|
||||||
This issuing of another read request (under a condition) is done to
|
|
||||||
keep the number of outstanding requests equal to the value of the
|
|
||||||
in_flight_requests variable.
|
|
||||||
|
|
||||||
This process has to be repeated for every remaining outstanding request.
|
|
||||||
|
|
||||||
@code
|
|
||||||
while (the queue is not empty) {
|
|
||||||
// Pseudo code
|
|
||||||
aio = DEQUEUE an sftp aio handle from the queue of sftp aio handles;
|
|
||||||
|
|
||||||
// Wait for the response of the request corresponding to the aio
|
|
||||||
bytes_read = sftp_aio_wait_read(&aio, buffer, chunk_size);
|
|
||||||
if (bytes_read == SSH_ERROR) {
|
|
||||||
//handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes_downloaded += bytes_read;
|
|
||||||
if (bytes_read != chunk_size && bytes_downloaded != file_size) {
|
|
||||||
// A short read encountered on the remote file before reaching EOF,
|
|
||||||
// short read before reaching EOF should never happen for the sftp aio
|
|
||||||
// API which respects the max limit for reading. This probably
|
|
||||||
// indicates a bad server.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pseudo code
|
|
||||||
WRITE bytes_read bytes from the buffer into the local file
|
|
||||||
in which downloaded data is to be stored ;
|
|
||||||
|
|
||||||
if (total_bytes_requested == file_size) {
|
|
||||||
// no need to issue more read requests
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// else issue a read request
|
|
||||||
to_read = file_size - total_bytes_requested;
|
|
||||||
if (to_read > chunk_size) {
|
|
||||||
to_read = chunk_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes_requested = sftp_aio_begin_read(file, to_read, &aio);
|
|
||||||
if (bytes_requested == SSH_ERROR) {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((size_t)bytes_requested < to_read) {
|
|
||||||
// Should not happen for this code, as the to_read is <=
|
|
||||||
// max limit for reading (chunk size), so there is no reason
|
|
||||||
// for sftp_aio_begin_read() to return a lesser value.
|
|
||||||
}
|
|
||||||
|
|
||||||
total_bytes_requested += bytes_requested;
|
|
||||||
|
|
||||||
// Pseudo code
|
|
||||||
ENQUEUE aio in the queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buffer);
|
|
||||||
sftp_limits_free(lim);
|
|
||||||
|
|
||||||
... // Code to destroy the queue which was used to store the sftp aio
|
|
||||||
// handles.
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
After exiting the while (the queue is not empty) loop, the download
|
|
||||||
would've been complete (assuming no error occurs).
|
|
||||||
|
|
||||||
@subsection sftp_aio_upload_example Performing an upload using the sftp aio API
|
|
||||||
|
|
||||||
Terminologies used in the following code snippets :
|
|
||||||
|
|
||||||
- sftp : The sftp_session opened using sftp_new() and initialised using
|
|
||||||
sftp_init()
|
|
||||||
|
|
||||||
- file : The sftp file handle of the remote file in which uploaded data
|
|
||||||
is to be stored. (See sftp_open())
|
|
||||||
|
|
||||||
- file_size : The size of the local file to upload. This size can be
|
|
||||||
obtained by statting the local file to upload (e.g by using stat())
|
|
||||||
|
|
||||||
- We will need maintain a queue which will be used to store the sftp aio
|
|
||||||
handles corresponding to the outstanding requests.
|
|
||||||
|
|
||||||
First, we issue the write requests while ensuring that their count
|
|
||||||
doesn't exceed a particular limit decided by us, and the number of bytes
|
|
||||||
requested to write don't exceed the size of the file to upload.
|
|
||||||
|
|
||||||
@code
|
|
||||||
sftp_aio aio = NULL;
|
|
||||||
|
|
||||||
// The chunk size to use for the transfer
|
|
||||||
size_t chunk_size;
|
|
||||||
|
|
||||||
// For the limits structure that would be used by
|
|
||||||
// the code to set the chunk size
|
|
||||||
sftp_limits_t lim = NULL;
|
|
||||||
|
|
||||||
// Max number of requests to keep outstanding at a time
|
|
||||||
size_t in_flight_requests = 5;
|
|
||||||
|
|
||||||
// Total number of bytes for which write requests have been sent
|
|
||||||
size_t total_bytes_requested = 0;
|
|
||||||
|
|
||||||
// Buffer to use for the upload
|
|
||||||
char *buffer = NULL;
|
|
||||||
|
|
||||||
// Helper variables
|
|
||||||
size_t to_write;
|
|
||||||
ssize_t bytes_requested;
|
|
||||||
|
|
||||||
// Get the sftp limits
|
|
||||||
lim = sftp_limits(sftp);
|
|
||||||
if (lim == NULL) {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the chunk size for upload = the max limit for writing.
|
|
||||||
// The reason for this has been given in the "Capping applied by
|
|
||||||
// the sftp aio API" section (Its to make the code simpler)
|
|
||||||
//
|
|
||||||
// Assigning a size_t type variable a uint64_t type value here,
|
|
||||||
// theoretically could cause an overflow, but practically
|
|
||||||
// max_write_length would never exceed SIZE_MAX so its okay.
|
|
||||||
chunk_size = lim->max_write_length;
|
|
||||||
|
|
||||||
buffer = malloc(chunk_size);
|
|
||||||
if (buffer == NULL) {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
... // Code to open the local file (to upload) [e.g using open(), fopen()].
|
|
||||||
... // Code to stat the local file's file size [e.g using stat()].
|
|
||||||
... // Code to open the remote file in which uploaded data will be stored [see
|
|
||||||
// sftp_open()].
|
|
||||||
... // Code to initialize the queue which will be used to store sftp aio
|
|
||||||
// handles.
|
|
||||||
|
|
||||||
for (i = 0;
|
|
||||||
i < in_flight_requests && total_bytes_requested < file_size;
|
|
||||||
++i) {
|
|
||||||
to_write = file_size - total_bytes_requested;
|
|
||||||
if (to_write > chunk_size) {
|
|
||||||
to_write = chunk_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pseudo code
|
|
||||||
READ to_write bytes from the local file (to upload) into the buffer;
|
|
||||||
|
|
||||||
bytes_requested = sftp_aio_begin_write(file, buffer, to_write, &aio);
|
|
||||||
if (bytes_requested == SSH_ERROR) {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((size_t)bytes_requested < to_write) {
|
|
||||||
// Should not happen for this code, as the to_write is <=
|
|
||||||
// max limit for writing (chunk size), so there is no reason
|
|
||||||
// for sftp_aio_begin_write() to return a lesser value.
|
|
||||||
}
|
|
||||||
|
|
||||||
total_bytes_requested += (size_t)bytes_requested;
|
|
||||||
|
|
||||||
// Pseudo code
|
|
||||||
ENQUEUE aio in the queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
At this point, at max in_flight_requests number of requests may be
|
|
||||||
outstanding. Now we wait for the response corresponding to the earliest
|
|
||||||
issued outstanding request.
|
|
||||||
|
|
||||||
On getting that response, we issue another write request if there are
|
|
||||||
still some bytes in the local file (to upload) for which we haven't sent
|
|
||||||
the write request. (This happens when total_bytes_requested < file_size)
|
|
||||||
|
|
||||||
This issuing of another write request (under a condition) is done to
|
|
||||||
keep the number of outstanding requests equal to the value of the
|
|
||||||
in_flight_requests variable.
|
|
||||||
|
|
||||||
This process has to be repeated for every remaining outstanding request.
|
|
||||||
|
|
||||||
@code
|
|
||||||
while (the queue is not empty) {
|
|
||||||
// Pseudo code
|
|
||||||
aio = DEQUEUE an sftp aio handle from the queue of sftp aio handles;
|
|
||||||
|
|
||||||
// Wait for the response of the request corresponding to the aio
|
|
||||||
bytes_written = sftp_aio_wait_write(&aio);
|
|
||||||
if (bytes_written == SSH_ERROR) {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
// sftp_aio_wait_write() won't report a short write, so no need
|
|
||||||
// to check for a short write here.
|
|
||||||
|
|
||||||
if (total_bytes_requested == file_size) {
|
|
||||||
// no need to issue more write requests
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// else issue a write request
|
|
||||||
to_write = file_size - total_bytes_requested;
|
|
||||||
if (to_write > chunk_size) {
|
|
||||||
to_write = chunk_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pseudo code
|
|
||||||
READ to_write bytes from the local file (to upload) into a buffer;
|
|
||||||
|
|
||||||
bytes_requested = sftp_aio_begin_write(file, buffer, to_write, &aio);
|
|
||||||
if (bytes_requested == SSH_ERROR) {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((size_t)bytes_requested < to_write) {
|
|
||||||
// Should not happen for this code, as the to_write is <=
|
|
||||||
// max limit for writing (chunk size), so there is no reason
|
|
||||||
// for sftp_aio_begin_write() to return a lesser value.
|
|
||||||
}
|
|
||||||
|
|
||||||
total_bytes_requested += (size_t)bytes_requested;
|
|
||||||
|
|
||||||
// Pseudo code
|
|
||||||
ENQUEUE aio in the queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buffer);
|
|
||||||
|
|
||||||
... // Code to destroy the queue which was used to store the sftp aio
|
|
||||||
// handles.
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
After exiting the while (the queue is not empty) loop, the upload
|
|
||||||
would've been complete (assuming no error occurs).
|
|
||||||
|
|
||||||
@subsection sftp_aio_free Example showing the usage of sftp_aio_free()
|
|
||||||
|
|
||||||
The purpose of sftp_aio_free() was discussed at the beginning of this page,
|
|
||||||
the following code example shows how it can be used during cleanup.
|
|
||||||
|
|
||||||
@code
|
|
||||||
void print_sftp_error(sftp_session sftp)
|
|
||||||
{
|
|
||||||
if (sftp == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "sftp error : %d\n", sftp_get_error(sftp));
|
|
||||||
fprintf(stderr, "ssh error : %s\n", ssh_get_error(sftp->session));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns 0 on success, -1 on error
|
|
||||||
int write_strings(sftp_file file)
|
|
||||||
{
|
|
||||||
const char * strings[] = {
|
|
||||||
"This is the first string",
|
|
||||||
"This is the second string",
|
|
||||||
"This is the third string",
|
|
||||||
"This is the fourth string"
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t string_count = sizeof(strings) / sizeof(strings[0]);
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
sftp_session sftp = NULL;
|
|
||||||
sftp_aio aio = NULL;
|
|
||||||
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (file == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
... // Code to initialize the queue which will be used to store sftp aio
|
|
||||||
// handles
|
|
||||||
|
|
||||||
sftp = file->sftp;
|
|
||||||
for (i = 0; i < string_count; ++i) {
|
|
||||||
rc = sftp_aio_begin_write(file,
|
|
||||||
strings[i],
|
|
||||||
strlen(strings[i]),
|
|
||||||
&aio);
|
|
||||||
if (rc == SSH_ERROR) {
|
|
||||||
print_sftp_error(sftp);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pseudo code
|
|
||||||
ENQUEUE aio in the queue of sftp aio handles
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < string_count; ++i) {
|
|
||||||
// Pseudo code
|
|
||||||
aio = DEQUEUE an sftp aio handle from the queue of sftp aio handles;
|
|
||||||
|
|
||||||
rc = sftp_aio_wait_write(&aio);
|
|
||||||
if (rc == SSH_ERROR) {
|
|
||||||
print_sftp_error(sftp);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
... // Code to destroy the queue in which sftp aio handles were
|
|
||||||
// stored
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err:
|
|
||||||
|
|
||||||
while (queue is not empty) {
|
|
||||||
// Pseudo code
|
|
||||||
aio = DEQUEUE an sftp aio handle from the queue of sftp aio handles;
|
|
||||||
|
|
||||||
sftp_aio_free(aio);
|
|
||||||
}
|
|
||||||
|
|
||||||
... // Code to destroy the queue in which sftp aio handles were
|
|
||||||
// stored.
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
*/
|
|
||||||
@@ -65,17 +65,8 @@ to as a "pty", for "pseudo-teletype". The remote processes won't see the
|
|||||||
difference with a real text-oriented terminal.
|
difference with a real text-oriented terminal.
|
||||||
|
|
||||||
If needed, you request the pty with the function ssh_channel_request_pty().
|
If needed, you request the pty with the function ssh_channel_request_pty().
|
||||||
If you want define its dimensions (number of rows and columns),
|
Then you define its dimensions (number of rows and columns)
|
||||||
call ssh_channel_request_pty_size() instead. It's also possible to change
|
with ssh_channel_change_pty_size().
|
||||||
the dimensions after creating the pty with ssh_channel_change_pty_size().
|
|
||||||
|
|
||||||
These two functions configure the pty using the same terminal modes that
|
|
||||||
stdin has. If stdin isn't a TTY, they use default modes that configure
|
|
||||||
the pty with in canonical mode and e.g. preserving CR and LF characters.
|
|
||||||
If you want to change the terminal modes used by the pty (e.g. to change
|
|
||||||
CRLF handling), use ssh_channel_request_pty_size_modes(). This function
|
|
||||||
accepts an additional "modes" buffer that is expected to contain encoded
|
|
||||||
terminal modes according to RFC 4254 section 8.
|
|
||||||
|
|
||||||
Be your session interactive or not, the next step is to request a
|
Be your session interactive or not, the next step is to request a
|
||||||
shell with ssh_channel_request_shell().
|
shell with ssh_channel_request_shell().
|
||||||
|
|||||||
@@ -29,12 +29,6 @@ if (UNIX AND NOT WIN32)
|
|||||||
add_executable(samplesftp samplesftp.c ${examples_SRCS})
|
add_executable(samplesftp samplesftp.c ${examples_SRCS})
|
||||||
target_compile_options(samplesftp PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
target_compile_options(samplesftp PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||||
target_link_libraries(samplesftp ssh::ssh)
|
target_link_libraries(samplesftp ssh::ssh)
|
||||||
|
|
||||||
if (WITH_SERVER)
|
|
||||||
add_executable(sample_sftpserver sample_sftpserver.c ${examples_SRCS})
|
|
||||||
target_compile_options(sample_sftpserver PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
|
||||||
target_link_libraries(sample_sftpserver ssh::ssh ${ARGP_LIBRARIES})
|
|
||||||
endif (WITH_SERVER)
|
|
||||||
endif (WITH_SFTP)
|
endif (WITH_SFTP)
|
||||||
|
|
||||||
add_executable(ssh-client ssh_client.c ${examples_SRCS})
|
add_executable(ssh-client ssh_client.c ${examples_SRCS})
|
||||||
|
|||||||
@@ -27,14 +27,14 @@ int main(void)
|
|||||||
rv = ssh_pki_generate(SSH_KEYTYPE_ED25519, 0, &key);
|
rv = ssh_pki_generate(SSH_KEYTYPE_ED25519, 0, &key);
|
||||||
if (rv != SSH_OK) {
|
if (rv != SSH_OK) {
|
||||||
fprintf(stderr, "Failed to generate private key");
|
fprintf(stderr, "Failed to generate private key");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write it to a file testkey in the current directory */
|
/* Write it to a file testkey in the current dirrectory */
|
||||||
rv = ssh_pki_export_privkey_file(key, NULL, NULL, NULL, "testkey");
|
rv = ssh_pki_export_privkey_file(key, NULL, NULL, NULL, "testkey");
|
||||||
if (rv != SSH_OK) {
|
if (rv != SSH_OK) {
|
||||||
fprintf(stderr, "Failed to write private key file");
|
fprintf(stderr, "Failed to write private key file");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ struct arguments_st {
|
|||||||
unsigned long bits;
|
unsigned long bits;
|
||||||
char *file;
|
char *file;
|
||||||
char *passphrase;
|
char *passphrase;
|
||||||
char *format;
|
|
||||||
int action_list;
|
int action_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,6 +52,7 @@ static struct argp_option options[] = {
|
|||||||
"Accepted values are: "
|
"Accepted values are: "
|
||||||
"1024, 2048, 3072 (default), 4096, and 8192 for TYPE=\"rsa\"; "
|
"1024, 2048, 3072 (default), 4096, and 8192 for TYPE=\"rsa\"; "
|
||||||
"256 (default), 384, and 521 for TYPE=\"ecdsa\"; "
|
"256 (default), 384, and 521 for TYPE=\"ecdsa\"; "
|
||||||
|
"1024 (default) and 2048 for TYPE=\"dsa\"; "
|
||||||
"can be omitted for TYPE=\"ed25519\" "
|
"can be omitted for TYPE=\"ed25519\" "
|
||||||
"(it will be ignored if provided).\n",
|
"(it will be ignored if provided).\n",
|
||||||
.group = 0
|
.group = 0
|
||||||
@@ -86,7 +86,7 @@ static struct argp_option options[] = {
|
|||||||
.flags = 0,
|
.flags = 0,
|
||||||
.doc = "The type of the key to be generated. "
|
.doc = "The type of the key to be generated. "
|
||||||
"Accepted values are: "
|
"Accepted values are: "
|
||||||
"\"rsa\", \"ecdsa\", and \"ed25519\".\n",
|
"\"rsa\", \"ecdsa\", \"ed25519\", and \"dsa\".\n",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -97,16 +97,6 @@ static struct argp_option options[] = {
|
|||||||
.doc = "List the Fingerprint of the given key\n",
|
.doc = "List the Fingerprint of the given key\n",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.name = "format",
|
|
||||||
.key = 'm',
|
|
||||||
.arg = "FORMAT",
|
|
||||||
.flags = 0,
|
|
||||||
.doc = "Write the file in specific format. The supported values are "
|
|
||||||
"'PEM'and 'OpenSSH' file format. By default Ed25519 "
|
|
||||||
"keys are exported in OpenSSH format and others in PEM.\n",
|
|
||||||
.group = 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
/* End of the options */
|
/* End of the options */
|
||||||
0
|
0
|
||||||
@@ -163,6 +153,9 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
|
|||||||
if (!strcmp(arg, "rsa")) {
|
if (!strcmp(arg, "rsa")) {
|
||||||
arguments->type = SSH_KEYTYPE_RSA;
|
arguments->type = SSH_KEYTYPE_RSA;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(arg, "dsa")) {
|
||||||
|
arguments->type = SSH_KEYTYPE_DSS;
|
||||||
|
}
|
||||||
else if (!strcmp(arg, "ecdsa")) {
|
else if (!strcmp(arg, "ecdsa")) {
|
||||||
arguments->type = SSH_KEYTYPE_ECDSA;
|
arguments->type = SSH_KEYTYPE_ECDSA;
|
||||||
}
|
}
|
||||||
@@ -179,9 +172,6 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
|
|||||||
case 'l':
|
case 'l':
|
||||||
arguments->action_list = 1;
|
arguments->action_list = 1;
|
||||||
break;
|
break;
|
||||||
case 'm':
|
|
||||||
arguments->format = strdup(arg);
|
|
||||||
break;
|
|
||||||
case ARGP_KEY_ARG:
|
case ARGP_KEY_ARG:
|
||||||
if (state->arg_num > 0) {
|
if (state->arg_num > 0) {
|
||||||
/* Too many arguments. */
|
/* Too many arguments. */
|
||||||
@@ -263,6 +253,29 @@ static int validate_args(struct arguments_st *args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case SSH_KEYTYPE_DSS:
|
||||||
|
switch (args->bits) {
|
||||||
|
case 0:
|
||||||
|
/* If not provided, use default value */
|
||||||
|
args->bits = 1024;
|
||||||
|
break;
|
||||||
|
case 1024:
|
||||||
|
case 2048:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Error: Invalid bits parameter provided\n");
|
||||||
|
rc = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (args->file == NULL) {
|
||||||
|
args->file = strdup("id_dsa");
|
||||||
|
if (args->file == NULL) {
|
||||||
|
rc = ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case SSH_KEYTYPE_ED25519:
|
case SSH_KEYTYPE_ED25519:
|
||||||
/* Ignore value and overwrite with a zero */
|
/* Ignore value and overwrite with a zero */
|
||||||
@@ -310,7 +323,6 @@ list_fingerprint(char *file)
|
|||||||
rc = ssh_get_publickey_hash(key, SSH_PUBLICKEY_HASH_SHA256, &hash, &hlen);
|
rc = ssh_get_publickey_hash(key, SSH_PUBLICKEY_HASH_SHA256, &hash, &hlen);
|
||||||
if (rc != SSH_OK) {
|
if (rc != SSH_OK) {
|
||||||
fprintf(stderr, "Failed to get key fingerprint\n");
|
fprintf(stderr, "Failed to get key fingerprint\n");
|
||||||
ssh_key_free(key);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ssh_print_hash(SSH_PUBLICKEY_HASH_SHA256, hash, hlen);
|
ssh_print_hash(SSH_PUBLICKEY_HASH_SHA256, hash, hlen);
|
||||||
@@ -397,36 +409,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write the private key */
|
/* Write the private key */
|
||||||
if (arguments.format != NULL) {
|
rc = ssh_pki_export_privkey_file(key, arguments.passphrase, NULL, NULL,
|
||||||
if (strcasecmp(arguments.format, "PEM") == 0) {
|
arguments.file);
|
||||||
rc = ssh_pki_export_privkey_file_format(key,
|
|
||||||
arguments.passphrase,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
arguments.file,
|
|
||||||
SSH_FILE_FORMAT_PEM);
|
|
||||||
} else if (strcasecmp(arguments.format, "OpenSSH") == 0) {
|
|
||||||
rc = ssh_pki_export_privkey_file_format(key,
|
|
||||||
arguments.passphrase,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
arguments.file,
|
|
||||||
SSH_FILE_FORMAT_OPENSSH);
|
|
||||||
} else {
|
|
||||||
rc = ssh_pki_export_privkey_file_format(key,
|
|
||||||
arguments.passphrase,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
arguments.file,
|
|
||||||
SSH_FILE_FORMAT_DEFAULT);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rc = ssh_pki_export_privkey_file(key,
|
|
||||||
arguments.passphrase,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
arguments.file);
|
|
||||||
}
|
|
||||||
if (rc != SSH_OK) {
|
if (rc != SSH_OK) {
|
||||||
fprintf(stderr, "Error: Failed to write private key file");
|
fprintf(stderr, "Error: Failed to write private key file");
|
||||||
goto end;
|
goto end;
|
||||||
|
|||||||
@@ -229,11 +229,11 @@ static int open_location(struct location *loc, int flag) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else if (loc->path != NULL) {
|
} else {
|
||||||
loc->file = fopen(loc->path, flag == READ ? "r":"w");
|
loc->file = fopen(loc->path, flag == READ ? "r":"w");
|
||||||
if (!loc->file) {
|
if (!loc->file) {
|
||||||
if (errno == EISDIR) {
|
if (errno == EISDIR) {
|
||||||
if (chdir(loc->path)) {
|
if (loc->path != NULL && chdir(loc->path)) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Error changing directory to %s: %s\n",
|
"Error changing directory to %s: %s\n",
|
||||||
loc->path, strerror(errno));
|
loc->path, strerror(errno));
|
||||||
|
|||||||
@@ -142,12 +142,20 @@ static struct argp_option options[] = {
|
|||||||
.doc = "Set the host key.",
|
.doc = "Set the host key.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "dsakey",
|
||||||
|
.key = 'd',
|
||||||
|
.arg = "FILE",
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "Set the dsa key.",
|
||||||
|
.group = 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "rsakey",
|
.name = "rsakey",
|
||||||
.key = 'r',
|
.key = 'r',
|
||||||
.arg = "FILE",
|
.arg = "FILE",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.doc = "Set the rsa host key (deprecated alias to 'k').",
|
.doc = "Set the rsa key.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -172,11 +180,15 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
|||||||
case 'p':
|
case 'p':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'd':
|
||||||
/* deprecated */
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg);
|
||||||
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg);
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
||||||
break;
|
break;
|
||||||
@@ -225,7 +237,7 @@ int main(int argc, char **argv){
|
|||||||
sshbind=ssh_bind_new();
|
sshbind=ssh_bind_new();
|
||||||
session=ssh_new();
|
session=ssh_new();
|
||||||
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, "sshd_rsa");
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, "sshd_rsa");
|
||||||
|
|
||||||
#ifdef HAVE_ARGP_H
|
#ifdef HAVE_ARGP_H
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,515 +0,0 @@
|
|||||||
/* This is a sample implementation of a libssh based SSH server */
|
|
||||||
/*
|
|
||||||
Copyright 2014 Audrius Butkevicius
|
|
||||||
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <libssh/callbacks.h>
|
|
||||||
#include <libssh/server.h>
|
|
||||||
#include <libssh/sftp.h>
|
|
||||||
#include <libssh/sftpserver.h>
|
|
||||||
|
|
||||||
#include <poll.h>
|
|
||||||
#ifdef HAVE_ARGP_H
|
|
||||||
#include <argp.h>
|
|
||||||
#endif
|
|
||||||
#include <fcntl.h>
|
|
||||||
#ifdef HAVE_LIBUTIL_H
|
|
||||||
#include <libutil.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_PTY_H
|
|
||||||
#include <pty.h>
|
|
||||||
#endif
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#ifdef HAVE_UTMP_H
|
|
||||||
#include <utmp.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_UTIL_H
|
|
||||||
#include <util.h>
|
|
||||||
#endif
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
/* below are for sftp */
|
|
||||||
#include <sys/statvfs.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#ifndef KEYS_FOLDER
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define KEYS_FOLDER
|
|
||||||
#else
|
|
||||||
#define KEYS_FOLDER "/etc/ssh/"
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define USER "myuser"
|
|
||||||
#define PASS "mypassword"
|
|
||||||
#define BUF_SIZE 1048576
|
|
||||||
#define SESSION_END (SSH_CLOSED | SSH_CLOSED_ERROR)
|
|
||||||
|
|
||||||
static void set_default_keys(ssh_bind sshbind,
|
|
||||||
int rsa_already_set,
|
|
||||||
int ecdsa_already_set)
|
|
||||||
{
|
|
||||||
if (!rsa_already_set)
|
|
||||||
{
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY,
|
|
||||||
KEYS_FOLDER "ssh_host_rsa_key");
|
|
||||||
}
|
|
||||||
if (!ecdsa_already_set)
|
|
||||||
{
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY,
|
|
||||||
KEYS_FOLDER "ssh_host_ecdsa_key");
|
|
||||||
}
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY,
|
|
||||||
KEYS_FOLDER "ssh_host_ed25519_key");
|
|
||||||
}
|
|
||||||
#define DEF_STR_SIZE 1024
|
|
||||||
char authorizedkeys[DEF_STR_SIZE] = {0};
|
|
||||||
#ifdef HAVE_ARGP_H
|
|
||||||
const char *argp_program_version = "libssh sftp server example " SSH_STRINGIFY(LIBSSH_VERSION);
|
|
||||||
const char *argp_program_bug_address = "<libssh@libssh.org>";
|
|
||||||
|
|
||||||
/* Program documentation. */
|
|
||||||
static char doc[] = "Sftp server implemented with 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 a host key. Can be used multiple times. "
|
|
||||||
"Implies no default keys.",
|
|
||||||
.group = 0},
|
|
||||||
{.name = "rsakey",
|
|
||||||
.key = 'r',
|
|
||||||
.arg = "FILE",
|
|
||||||
.flags = 0,
|
|
||||||
.doc = "Set the rsa key.",
|
|
||||||
.group = 0},
|
|
||||||
{.name = "ecdsakey",
|
|
||||||
.key = 'e',
|
|
||||||
.arg = "FILE",
|
|
||||||
.flags = 0,
|
|
||||||
.doc = "Set the ecdsa key.",
|
|
||||||
.group = 0},
|
|
||||||
{.name = "authorizedkeys",
|
|
||||||
.key = 'a',
|
|
||||||
.arg = "FILE",
|
|
||||||
.flags = 0,
|
|
||||||
.doc = "Set the authorized keys file.",
|
|
||||||
.group = 0},
|
|
||||||
{.name = "no-default-keys",
|
|
||||||
.key = 'n',
|
|
||||||
.arg = NULL,
|
|
||||||
.flags = 0,
|
|
||||||
.doc = "Do not set default key locations.",
|
|
||||||
.group = 0},
|
|
||||||
{.name = "verbose",
|
|
||||||
.key = 'v',
|
|
||||||
.arg = NULL,
|
|
||||||
.flags = 0,
|
|
||||||
.doc = "Get verbose output.",
|
|
||||||
.group = 0},
|
|
||||||
{NULL, 0, NULL, 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;
|
|
||||||
static int no_default_keys = 0;
|
|
||||||
static int rsa_already_set = 0, ecdsa_already_set = 0;
|
|
||||||
|
|
||||||
switch (key)
|
|
||||||
{
|
|
||||||
case 'n':
|
|
||||||
no_default_keys = 1;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
|
||||||
break;
|
|
||||||
case 'k':
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
|
||||||
/* We can't track the types of keys being added with this
|
|
||||||
option, so let's ensure we keep the keys we're adding
|
|
||||||
by just not setting the default keys */
|
|
||||||
no_default_keys = 1;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
|
||||||
rsa_already_set = 1;
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
|
||||||
ecdsa_already_set = 1;
|
|
||||||
break;
|
|
||||||
case 'a':
|
|
||||||
strncpy(authorizedkeys, arg, DEF_STR_SIZE - 1);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!no_default_keys)
|
|
||||||
{
|
|
||||||
set_default_keys(sshbind,
|
|
||||||
rsa_already_set,
|
|
||||||
ecdsa_already_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 */
|
|
||||||
|
|
||||||
/* A userdata struct for channel. */
|
|
||||||
struct channel_data_struct
|
|
||||||
{
|
|
||||||
/* Event which is used to poll the above descriptors. */
|
|
||||||
ssh_event event;
|
|
||||||
sftp_session sftp;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* A userdata struct for session. */
|
|
||||||
struct session_data_struct
|
|
||||||
{
|
|
||||||
/* Pointer to the channel the session will allocate. */
|
|
||||||
ssh_channel channel;
|
|
||||||
int auth_attempts;
|
|
||||||
int authenticated;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int auth_password(ssh_session session, const char *user,
|
|
||||||
const char *pass, void *userdata)
|
|
||||||
{
|
|
||||||
struct session_data_struct *sdata = (struct session_data_struct *)userdata;
|
|
||||||
|
|
||||||
(void)session;
|
|
||||||
|
|
||||||
if (strcmp(user, USER) == 0 && strcmp(pass, PASS) == 0)
|
|
||||||
{
|
|
||||||
sdata->authenticated = 1;
|
|
||||||
return SSH_AUTH_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
sdata->auth_attempts++;
|
|
||||||
return SSH_AUTH_DENIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int auth_publickey(ssh_session session,
|
|
||||||
const char *user,
|
|
||||||
struct ssh_key_struct *pubkey,
|
|
||||||
char signature_state,
|
|
||||||
void *userdata)
|
|
||||||
{
|
|
||||||
struct session_data_struct *sdata = (struct session_data_struct *)userdata;
|
|
||||||
|
|
||||||
(void)session;
|
|
||||||
(void)user;
|
|
||||||
|
|
||||||
if (signature_state == SSH_PUBLICKEY_STATE_NONE)
|
|
||||||
{
|
|
||||||
return SSH_AUTH_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signature_state != SSH_PUBLICKEY_STATE_VALID)
|
|
||||||
{
|
|
||||||
return SSH_AUTH_DENIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// valid so far. Now look through authorized keys for a match
|
|
||||||
if (authorizedkeys[0])
|
|
||||||
{
|
|
||||||
ssh_key key = NULL;
|
|
||||||
int result;
|
|
||||||
struct stat buf;
|
|
||||||
|
|
||||||
if (stat(authorizedkeys, &buf) == 0)
|
|
||||||
{
|
|
||||||
result = ssh_pki_import_pubkey_file(authorizedkeys, &key);
|
|
||||||
if ((result != SSH_OK) || (key == NULL))
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"Unable to import public key file %s\n",
|
|
||||||
authorizedkeys);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = ssh_key_cmp(key, pubkey, SSH_KEY_CMP_PUBLIC);
|
|
||||||
ssh_key_free(key);
|
|
||||||
if (result == 0)
|
|
||||||
{
|
|
||||||
sdata->authenticated = 1;
|
|
||||||
return SSH_AUTH_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no matches
|
|
||||||
sdata->authenticated = 0;
|
|
||||||
return SSH_AUTH_DENIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssh_channel channel_open(ssh_session session, void *userdata)
|
|
||||||
{
|
|
||||||
struct session_data_struct *sdata = (struct session_data_struct *)userdata;
|
|
||||||
|
|
||||||
sdata->channel = ssh_channel_new(session);
|
|
||||||
return sdata->channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_session(ssh_event event, ssh_session session)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
|
|
||||||
/* Our struct holding information about the channel. */
|
|
||||||
struct channel_data_struct cdata = {
|
|
||||||
.sftp = NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Our struct holding information about the session. */
|
|
||||||
struct session_data_struct sdata = {
|
|
||||||
.channel = NULL,
|
|
||||||
.auth_attempts = 0,
|
|
||||||
.authenticated = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ssh_channel_callbacks_struct channel_cb = {
|
|
||||||
.userdata = &(cdata.sftp),
|
|
||||||
.channel_data_function = sftp_channel_default_data_callback,
|
|
||||||
.channel_subsystem_request_function = sftp_channel_default_subsystem_request,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ssh_server_callbacks_struct server_cb = {
|
|
||||||
.userdata = &sdata,
|
|
||||||
.auth_password_function = auth_password,
|
|
||||||
.channel_open_request_session_function = channel_open,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (authorizedkeys[0])
|
|
||||||
{
|
|
||||||
server_cb.auth_pubkey_function = auth_publickey;
|
|
||||||
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
|
|
||||||
|
|
||||||
ssh_callbacks_init(&server_cb);
|
|
||||||
ssh_callbacks_init(&channel_cb);
|
|
||||||
|
|
||||||
ssh_set_server_callbacks(session, &server_cb);
|
|
||||||
|
|
||||||
if (ssh_handle_key_exchange(session) != SSH_OK)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s\n", ssh_get_error(session));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh_event_add_session(event, session);
|
|
||||||
|
|
||||||
n = 0;
|
|
||||||
while (sdata.authenticated == 0 || sdata.channel == NULL) {
|
|
||||||
/* If the user has used up all attempts, or if he hasn't been able to
|
|
||||||
* authenticate in 10 seconds (n * 100ms), disconnect. */
|
|
||||||
if (sdata.auth_attempts >= 3 || n >= 100) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ssh_event_dopoll(event, 100) == SSH_ERROR) {
|
|
||||||
fprintf(stderr, "%s\n", ssh_get_error(session));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh_set_channel_callbacks(sdata.channel, &channel_cb);
|
|
||||||
|
|
||||||
do {
|
|
||||||
/* Poll the main event which takes care of the session, the channel and
|
|
||||||
* even our child process's stdout/stderr (once it's started). */
|
|
||||||
if (ssh_event_dopoll(event, -1) == SSH_ERROR) {
|
|
||||||
ssh_channel_close(sdata.channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If child process's stdout/stderr has been registered with the event,
|
|
||||||
* or the child process hasn't started yet, continue. */
|
|
||||||
if (cdata.event != NULL) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* FIXME The server keeps hanging in the poll above when the client
|
|
||||||
* closes the channel */
|
|
||||||
} while (ssh_channel_is_open(sdata.channel));
|
|
||||||
|
|
||||||
ssh_channel_send_eof(sdata.channel);
|
|
||||||
ssh_channel_close(sdata.channel);
|
|
||||||
|
|
||||||
/* Wait up to 5 seconds for the client to terminate the session. */
|
|
||||||
for (n = 0; n < 50 && (ssh_get_status(session) & SESSION_END) == 0; n++) {
|
|
||||||
ssh_event_dopoll(event, 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SIGCHLD handler for cleaning up dead children. */
|
|
||||||
static void sigchld_handler(int signo)
|
|
||||||
{
|
|
||||||
(void)signo;
|
|
||||||
|
|
||||||
while (waitpid(-1, NULL, WNOHANG) > 0)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
ssh_bind sshbind = NULL;
|
|
||||||
ssh_session session = NULL;
|
|
||||||
ssh_event event = NULL;
|
|
||||||
struct sigaction sa;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* Set up SIGCHLD handler. */
|
|
||||||
sa.sa_handler = sigchld_handler;
|
|
||||||
sigemptyset(&sa.sa_mask);
|
|
||||||
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
|
|
||||||
if (sigaction(SIGCHLD, &sa, NULL) != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Failed to register SIGCHLD handler\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ssh_init();
|
|
||||||
if (rc < 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "ssh_init failed\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
sshbind = ssh_bind_new();
|
|
||||||
if (sshbind == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "ssh_bind_new failed\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_ARGP_H
|
|
||||||
argp_parse(&argp, argc, argv, 0, 0, sshbind);
|
|
||||||
#else
|
|
||||||
(void)argc;
|
|
||||||
(void)argv;
|
|
||||||
|
|
||||||
set_default_keys(sshbind, 0, 0);
|
|
||||||
#endif /* HAVE_ARGP_H */
|
|
||||||
|
|
||||||
if (ssh_bind_listen(sshbind) < 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s\n", ssh_get_error(sshbind));
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
session = ssh_new();
|
|
||||||
if (session == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Failed to allocate session\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Blocks until there is a new incoming connection. */
|
|
||||||
if (ssh_bind_accept(sshbind, session) != SSH_ERROR)
|
|
||||||
{
|
|
||||||
switch (fork())
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
/* Remove the SIGCHLD handler inherited from parent. */
|
|
||||||
sa.sa_handler = SIG_DFL;
|
|
||||||
sigaction(SIGCHLD, &sa, NULL);
|
|
||||||
/* Remove socket binding, which allows us to restart the
|
|
||||||
* parent process, without terminating existing sessions. */
|
|
||||||
ssh_bind_free(sshbind);
|
|
||||||
|
|
||||||
event = ssh_event_new();
|
|
||||||
if (event != NULL)
|
|
||||||
{
|
|
||||||
/* Blocks until the SSH session ends by either
|
|
||||||
* child process exiting, or client disconnecting. */
|
|
||||||
handle_session(event, session);
|
|
||||||
ssh_event_free(event);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Could not create polling context\n");
|
|
||||||
}
|
|
||||||
ssh_disconnect(session);
|
|
||||||
ssh_free(session);
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
case -1:
|
|
||||||
fprintf(stderr, "Failed to fork\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s\n", ssh_get_error(sshbind));
|
|
||||||
}
|
|
||||||
/* Since the session has been passed to a child fork, do some cleaning
|
|
||||||
* up at the parent process. */
|
|
||||||
ssh_disconnect(session);
|
|
||||||
ssh_free(session);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
ssh_bind_free(sshbind);
|
|
||||||
ssh_finalize();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -33,13 +33,16 @@ clients must be made or how a client should react.
|
|||||||
#define BUF_SIZE 65536
|
#define BUF_SIZE 65536
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int verbosity;
|
||||||
|
static char *destination;
|
||||||
|
|
||||||
static void do_sftp(ssh_session session) {
|
static void do_sftp(ssh_session session) {
|
||||||
sftp_session sftp = sftp_new(session);
|
sftp_session sftp = sftp_new(session);
|
||||||
sftp_dir dir;
|
sftp_dir dir;
|
||||||
sftp_attributes file;
|
sftp_attributes file;
|
||||||
sftp_statvfs_t sftpstatvfs;
|
sftp_statvfs_t sftpstatvfs;
|
||||||
struct statvfs sysstatvfs;
|
struct statvfs sysstatvfs;
|
||||||
sftp_file source;
|
sftp_file fichier;
|
||||||
sftp_file to;
|
sftp_file to;
|
||||||
int len = 1;
|
int len = 1;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
@@ -186,8 +189,8 @@ static void do_sftp(ssh_session session) {
|
|||||||
/* the small buffer size was intended to stress the library. of course, you
|
/* the small buffer size was intended to stress the library. of course, you
|
||||||
* can use a buffer till 20kbytes without problem */
|
* can use a buffer till 20kbytes without problem */
|
||||||
|
|
||||||
source = sftp_open(sftp, "/usr/bin/ssh", O_RDONLY, 0);
|
fichier = sftp_open(sftp, "/usr/bin/ssh", O_RDONLY, 0);
|
||||||
if (!source) {
|
if (!fichier) {
|
||||||
fprintf(stderr, "Error opening /usr/bin/ssh: %s\n",
|
fprintf(stderr, "Error opening /usr/bin/ssh: %s\n",
|
||||||
ssh_get_error(session));
|
ssh_get_error(session));
|
||||||
goto end;
|
goto end;
|
||||||
@@ -198,16 +201,16 @@ static void do_sftp(ssh_session session) {
|
|||||||
if (!to) {
|
if (!to) {
|
||||||
fprintf(stderr, "Error opening ssh-copy for writing: %s\n",
|
fprintf(stderr, "Error opening ssh-copy for writing: %s\n",
|
||||||
ssh_get_error(session));
|
ssh_get_error(session));
|
||||||
sftp_close(source);
|
sftp_close(fichier);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((len = sftp_read(source, data, 4096)) > 0) {
|
while ((len = sftp_read(fichier, data, 4096)) > 0) {
|
||||||
if (sftp_write(to, data, len) != len) {
|
if (sftp_write(to, data, len) != len) {
|
||||||
fprintf(stderr, "Error writing %d bytes: %s\n",
|
fprintf(stderr, "Error writing %d bytes: %s\n",
|
||||||
len, ssh_get_error(session));
|
len, ssh_get_error(session));
|
||||||
sftp_close(to);
|
sftp_close(to);
|
||||||
sftp_close(source);
|
sftp_close(fichier);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,10 +220,10 @@ static void do_sftp(ssh_session session) {
|
|||||||
fprintf(stderr, "Error reading file: %s\n", ssh_get_error(session));
|
fprintf(stderr, "Error reading file: %s\n", ssh_get_error(session));
|
||||||
}
|
}
|
||||||
|
|
||||||
sftp_close(source);
|
sftp_close(fichier);
|
||||||
sftp_close(to);
|
sftp_close(to);
|
||||||
printf("file closed\n");
|
printf("fichiers ferm\n");
|
||||||
to = sftp_open(sftp, "/tmp/large_file", O_WRONLY|O_CREAT, 0644);
|
to = sftp_open(sftp, "/tmp/grosfichier", O_WRONLY|O_CREAT, 0644);
|
||||||
|
|
||||||
for (i = 0; i < 1000; ++i) {
|
for (i = 0; i < 1000; ++i) {
|
||||||
len = sftp_write(to, data, sizeof(data));
|
len = sftp_write(to, data, sizeof(data));
|
||||||
@@ -241,63 +244,50 @@ static void usage(const char *argv0) {
|
|||||||
fprintf(stderr, "Usage : %s [-v] remotehost\n"
|
fprintf(stderr, "Usage : %s [-v] remotehost\n"
|
||||||
"sample sftp test client - libssh-%s\n"
|
"sample sftp test client - libssh-%s\n"
|
||||||
"Options :\n"
|
"Options :\n"
|
||||||
" -l user : log in as user\n"
|
|
||||||
" -p port : connect to port\n"
|
|
||||||
" -v : increase log verbosity\n",
|
" -v : increase log verbosity\n",
|
||||||
argv0,
|
argv0,
|
||||||
ssh_version(0));
|
ssh_version(0));
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
static int opts(int argc, char **argv) {
|
||||||
{
|
int i;
|
||||||
ssh_session session = NULL;
|
|
||||||
char *destination = NULL;
|
|
||||||
int auth = 0;
|
|
||||||
int state;
|
|
||||||
|
|
||||||
ssh_init();
|
while ((i = getopt(argc, argv, "v")) != -1) {
|
||||||
session = ssh_new();
|
switch(i) {
|
||||||
|
case 'v':
|
||||||
|
verbosity++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "unknown option %c\n", optopt);
|
||||||
|
usage(argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ssh_options_getopt(session, &argc, argv)) {
|
destination = argv[optind];
|
||||||
fprintf(stderr,
|
if (destination == NULL) {
|
||||||
"Error parsing command line: %s\n",
|
|
||||||
ssh_get_error(session));
|
|
||||||
ssh_free(session);
|
|
||||||
ssh_finalize();
|
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
ssh_session session;
|
||||||
|
|
||||||
|
if (opts(argc, argv) < 0) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (argc < 1) {
|
|
||||||
usage(argv[0]);
|
session = connect_ssh(destination, NULL, verbosity);
|
||||||
|
if (session == NULL) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
destination = argv[1];
|
|
||||||
|
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_HOST, destination) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
auth = authenticate_console(session);
|
|
||||||
if (auth != SSH_AUTH_SUCCESS) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
do_sftp(session);
|
do_sftp(session);
|
||||||
ssh_disconnect(session);
|
ssh_disconnect(session);
|
||||||
ssh_free(session);
|
ssh_free(session);
|
||||||
|
|
||||||
ssh_finalize();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -172,12 +172,20 @@ static struct argp_option options[] = {
|
|||||||
.doc = "Set the host key.",
|
.doc = "Set the host key.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "dsakey",
|
||||||
|
.key = 'd',
|
||||||
|
.arg = "FILE",
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "Set the dsa key.",
|
||||||
|
.group = 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "rsakey",
|
.name = "rsakey",
|
||||||
.key = 'r',
|
.key = 'r',
|
||||||
.arg = "FILE",
|
.arg = "FILE",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.doc = "Set the rsa key (deprecated alias for 'k').",
|
.doc = "Set the rsa key.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -210,10 +218,15 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
|||||||
case 'p':
|
case 'p':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'd':
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg);
|
||||||
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg);
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
||||||
break;
|
break;
|
||||||
@@ -265,7 +278,8 @@ int main(int argc, char **argv){
|
|||||||
sshbind=ssh_bind_new();
|
sshbind=ssh_bind_new();
|
||||||
session=ssh_new();
|
session=ssh_new();
|
||||||
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, KEYS_FOLDER "ssh_host_rsa_key");
|
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
|
#ifdef HAVE_ARGP_H
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -112,12 +112,20 @@ static struct argp_option options[] = {
|
|||||||
.doc = "Set the host key.",
|
.doc = "Set the host key.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "dsakey",
|
||||||
|
.key = 'd',
|
||||||
|
.arg = "FILE",
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "Set the dsa key.",
|
||||||
|
.group = 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "rsakey",
|
.name = "rsakey",
|
||||||
.key = 'r',
|
.key = 'r',
|
||||||
.arg = "FILE",
|
.arg = "FILE",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.doc = "Set the rsa key (deprecated alias for 'k').",
|
.doc = "Set the rsa key.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -143,10 +151,15 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
|||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
||||||
port = atoi(arg);
|
port = atoi(arg);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'd':
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg);
|
||||||
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg);
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
||||||
break;
|
break;
|
||||||
@@ -293,8 +306,10 @@ int main(int argc, char **argv){
|
|||||||
sshbind=ssh_bind_new();
|
sshbind=ssh_bind_new();
|
||||||
session=ssh_new();
|
session=ssh_new();
|
||||||
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY,
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY,
|
||||||
KEYS_FOLDER "ssh_host_rsa_key");
|
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
|
#ifdef HAVE_ARGP_H
|
||||||
/*
|
/*
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -94,6 +94,7 @@ static void usage(void)
|
|||||||
"Options :\n"
|
"Options :\n"
|
||||||
" -l user : log in as user\n"
|
" -l user : log in as user\n"
|
||||||
" -p port : connect to port\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"
|
" -r : use RSA to verify host public key\n"
|
||||||
" -F file : parse configuration file instead of default one\n"
|
" -F file : parse configuration file instead of default one\n"
|
||||||
#ifdef WITH_PCAP
|
#ifdef WITH_PCAP
|
||||||
@@ -297,41 +298,25 @@ static void shell(ssh_session session)
|
|||||||
static void batch_shell(ssh_session session)
|
static void batch_shell(ssh_session session)
|
||||||
{
|
{
|
||||||
ssh_channel channel;
|
ssh_channel channel;
|
||||||
char *buffer = NULL;
|
char buffer[PATH_MAX];
|
||||||
size_t i, s, n;
|
size_t i;
|
||||||
|
int s = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < MAXCMD && cmds[i]; ++i) {
|
||||||
|
s += snprintf(buffer + s, sizeof(buffer) - s, "%s ", cmds[i]);
|
||||||
|
}
|
||||||
|
|
||||||
channel = ssh_channel_new(session);
|
channel = ssh_channel_new(session);
|
||||||
if (channel == NULL) {
|
if (channel == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = 0;
|
|
||||||
for (i = 0; i < MAXCMD && cmds[i]; ++i) {
|
|
||||||
/* Including space after cmds[i] */
|
|
||||||
n += strlen(cmds[i]) + 1;
|
|
||||||
}
|
|
||||||
/* Trailing \0 */
|
|
||||||
n += 1;
|
|
||||||
|
|
||||||
buffer = malloc(n);
|
|
||||||
if (buffer == NULL) {
|
|
||||||
ssh_channel_free(channel);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = 0;
|
|
||||||
for (i = 0; i < MAXCMD && cmds[i]; ++i) {
|
|
||||||
s += snprintf(buffer + s, n - s, "%s ", cmds[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh_channel_open_session(channel);
|
ssh_channel_open_session(channel);
|
||||||
if (ssh_channel_request_exec(channel, buffer)) {
|
if (ssh_channel_request_exec(channel, buffer)) {
|
||||||
printf("Error executing '%s' : %s\n", buffer, ssh_get_error(session));
|
printf("Error executing '%s' : %s\n", buffer, ssh_get_error(session));
|
||||||
free(buffer);
|
|
||||||
ssh_channel_free(channel);
|
ssh_channel_free(channel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
free(buffer);
|
|
||||||
select_loop(session, channel);
|
select_loop(session, channel);
|
||||||
ssh_channel_free(channel);
|
ssh_channel_free(channel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,10 +45,36 @@ The goal is to show the API in action.
|
|||||||
#define BUF_SIZE 1048576
|
#define BUF_SIZE 1048576
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef KEYS_FOLDER
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define KEYS_FOLDER
|
||||||
|
#else
|
||||||
|
#define KEYS_FOLDER "/etc/ssh/"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SESSION_END (SSH_CLOSED | SSH_CLOSED_ERROR)
|
#define SESSION_END (SSH_CLOSED | SSH_CLOSED_ERROR)
|
||||||
#define SFTP_SERVER_PATH "/usr/lib/sftp-server"
|
#define SFTP_SERVER_PATH "/usr/lib/sftp-server"
|
||||||
#define AUTH_KEYS_MAX_LINE_SIZE 2048
|
|
||||||
|
|
||||||
|
static void set_default_keys(ssh_bind sshbind,
|
||||||
|
int rsa_already_set,
|
||||||
|
int dsa_already_set,
|
||||||
|
int ecdsa_already_set) {
|
||||||
|
if (!rsa_already_set) {
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY,
|
||||||
|
KEYS_FOLDER "ssh_host_rsa_key");
|
||||||
|
}
|
||||||
|
if (!dsa_already_set) {
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY,
|
||||||
|
KEYS_FOLDER "ssh_host_dsa_key");
|
||||||
|
}
|
||||||
|
if (!ecdsa_already_set) {
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY,
|
||||||
|
KEYS_FOLDER "ssh_host_ecdsa_key");
|
||||||
|
}
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY,
|
||||||
|
KEYS_FOLDER "ssh_host_ed25519_key");
|
||||||
|
}
|
||||||
#define DEF_STR_SIZE 1024
|
#define DEF_STR_SIZE 1024
|
||||||
char authorizedkeys[DEF_STR_SIZE] = {0};
|
char authorizedkeys[DEF_STR_SIZE] = {0};
|
||||||
char username[128] = "myuser";
|
char username[128] = "myuser";
|
||||||
@@ -83,12 +109,20 @@ static struct argp_option options[] = {
|
|||||||
"Implies no default keys.",
|
"Implies no default keys.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "dsakey",
|
||||||
|
.key = 'd',
|
||||||
|
.arg = "FILE",
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "Set the dsa key.",
|
||||||
|
.group = 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "rsakey",
|
.name = "rsakey",
|
||||||
.key = 'r',
|
.key = 'r',
|
||||||
.arg = "FILE",
|
.arg = "FILE",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.doc = "Set the rsa key (deprecated alias for 'k').",
|
.doc = "Set the rsa key.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -96,7 +130,7 @@ static struct argp_option options[] = {
|
|||||||
.key = 'e',
|
.key = 'e',
|
||||||
.arg = "FILE",
|
.arg = "FILE",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.doc = "Set the ecdsa key (deprecated alias for 'k').",
|
.doc = "Set the ecdsa key.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -123,6 +157,14 @@ static struct argp_option options[] = {
|
|||||||
.doc = "Set expected password.",
|
.doc = "Set expected password.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "no-default-keys",
|
||||||
|
.key = 'n',
|
||||||
|
.arg = NULL,
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "Do not set default key locations.",
|
||||||
|
.group = 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "verbose",
|
.name = "verbose",
|
||||||
.key = 'v',
|
.key = 'v',
|
||||||
@@ -135,53 +177,75 @@ static struct argp_option options[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Parse a single option. */
|
/* Parse a single option. */
|
||||||
static error_t
|
static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
||||||
parse_opt(int key, char *arg, struct argp_state *state)
|
|
||||||
{
|
|
||||||
/* Get the input argument from argp_parse, which we
|
/* Get the input argument from argp_parse, which we
|
||||||
* know is a pointer to our arguments structure. */
|
* know is a pointer to our arguments structure. */
|
||||||
ssh_bind sshbind = state->input;
|
ssh_bind sshbind = state->input;
|
||||||
|
static int no_default_keys = 0;
|
||||||
|
static int rsa_already_set = 0, dsa_already_set = 0, ecdsa_already_set = 0;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'p':
|
case 'n':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
no_default_keys = 1;
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'p':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'd':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg);
|
||||||
break;
|
dsa_already_set = 1;
|
||||||
case 'e':
|
break;
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
case 'k':
|
||||||
break;
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
case 'a':
|
/* We can't track the types of keys being added with this
|
||||||
strncpy(authorizedkeys, arg, DEF_STR_SIZE - 1);
|
option, so let's ensure we keep the keys we're adding
|
||||||
break;
|
by just not setting the default keys */
|
||||||
case 'u':
|
no_default_keys = 1;
|
||||||
strncpy(username, arg, sizeof(username) - 1);
|
break;
|
||||||
break;
|
case 'r':
|
||||||
case 'P':
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg);
|
||||||
strncpy(password, arg, sizeof(password) - 1);
|
rsa_already_set = 1;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'e':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY, arg);
|
||||||
break;
|
ecdsa_already_set = 1;
|
||||||
case ARGP_KEY_ARG:
|
break;
|
||||||
if (state->arg_num >= 1) {
|
case 'a':
|
||||||
/* Too many arguments. */
|
strncpy(authorizedkeys, arg, DEF_STR_SIZE-1);
|
||||||
argp_usage(state);
|
break;
|
||||||
}
|
case 'u':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg);
|
strncpy(username, arg, sizeof(username) - 1);
|
||||||
break;
|
break;
|
||||||
case ARGP_KEY_END:
|
case 'P':
|
||||||
if (state->arg_num < 1) {
|
strncpy(password, arg, sizeof(password) - 1);
|
||||||
/* Not enough arguments. */
|
break;
|
||||||
argp_usage(state);
|
case 'v':
|
||||||
}
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
|
||||||
break;
|
"3");
|
||||||
default:
|
break;
|
||||||
return ARGP_ERR_UNKNOWN;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!no_default_keys) {
|
||||||
|
set_default_keys(sshbind,
|
||||||
|
rsa_already_set,
|
||||||
|
dsa_already_set,
|
||||||
|
ecdsa_already_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ARGP_ERR_UNKNOWN;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -189,17 +253,21 @@ parse_opt(int key, char *arg, struct argp_state *state)
|
|||||||
/* Our argp parser. */
|
/* Our argp parser. */
|
||||||
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||||
#else
|
#else
|
||||||
static int
|
static int parse_opt(int argc, char **argv, ssh_bind sshbind) {
|
||||||
parse_opt(int argc, char **argv, ssh_bind sshbind)
|
|
||||||
{
|
|
||||||
int no_default_keys = 0;
|
int no_default_keys = 0;
|
||||||
int rsa_already_set = 0;
|
int rsa_already_set = 0;
|
||||||
|
int dsa_already_set = 0;
|
||||||
int ecdsa_already_set = 0;
|
int ecdsa_already_set = 0;
|
||||||
int key;
|
int key;
|
||||||
|
|
||||||
while((key = getopt(argc, argv, "a:e:k:p:P:r:u:v")) != -1) {
|
while((key = getopt(argc, argv, "a:d:e:k:np:P:r:u:v")) != -1) {
|
||||||
if (key == 'p') {
|
if (key == 'n') {
|
||||||
|
no_default_keys = 1;
|
||||||
|
} else if (key == 'p') {
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, optarg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, optarg);
|
||||||
|
} else if (key == 'd') {
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, optarg);
|
||||||
|
dsa_already_set = 1;
|
||||||
} else if (key == 'k') {
|
} else if (key == 'k') {
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
|
||||||
/* We can't track the types of keys being added with this
|
/* We can't track the types of keys being added with this
|
||||||
@@ -207,10 +275,10 @@ parse_opt(int argc, char **argv, ssh_bind sshbind)
|
|||||||
by just not setting the default keys */
|
by just not setting the default keys */
|
||||||
no_default_keys = 1;
|
no_default_keys = 1;
|
||||||
} else if (key == 'r') {
|
} else if (key == 'r') {
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, optarg);
|
||||||
rsa_already_set = 1;
|
rsa_already_set = 1;
|
||||||
} else if (key == 'e') {
|
} else if (key == 'e') {
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY, optarg);
|
||||||
ecdsa_already_set = 1;
|
ecdsa_already_set = 1;
|
||||||
} else if (key == 'a') {
|
} else if (key == 'a') {
|
||||||
strncpy(authorizedkeys, optarg, DEF_STR_SIZE-1);
|
strncpy(authorizedkeys, optarg, DEF_STR_SIZE-1);
|
||||||
@@ -231,12 +299,14 @@ parse_opt(int argc, char **argv, ssh_bind sshbind)
|
|||||||
"libssh %s -- a Secure Shell protocol implementation\n"
|
"libssh %s -- a Secure Shell protocol implementation\n"
|
||||||
"\n"
|
"\n"
|
||||||
" -a, --authorizedkeys=FILE Set the authorized keys file.\n"
|
" -a, --authorizedkeys=FILE Set the authorized keys file.\n"
|
||||||
" -e, --ecdsakey=FILE Set the ecdsa key (deprecated alias for 'k').\n"
|
" -d, --dsakey=FILE Set the dsa key.\n"
|
||||||
|
" -e, --ecdsakey=FILE Set the ecdsa key.\n"
|
||||||
" -k, --hostkey=FILE Set a host key. Can be used multiple times.\n"
|
" -k, --hostkey=FILE Set a host key. Can be used multiple times.\n"
|
||||||
" Implies no default keys.\n"
|
" Implies no default keys.\n"
|
||||||
|
" -n, --no-default-keys Do not set default key locations.\n"
|
||||||
" -p, --port=PORT Set the port to bind.\n"
|
" -p, --port=PORT Set the port to bind.\n"
|
||||||
" -P, --pass=PASSWORD Set expected password.\n"
|
" -P, --pass=PASSWORD Set expected password.\n"
|
||||||
" -r, --rsakey=FILE Set the rsa key (deprecated alias for 'k').\n"
|
" -r, --rsakey=FILE Set the rsa key.\n"
|
||||||
" -u, --user=USERNAME Set expected username.\n"
|
" -u, --user=USERNAME Set expected username.\n"
|
||||||
" -v, --verbose Get verbose output.\n"
|
" -v, --verbose Get verbose output.\n"
|
||||||
" -?, --help Give this help list\n"
|
" -?, --help Give this help list\n"
|
||||||
@@ -259,6 +329,7 @@ parse_opt(int argc, char **argv, ssh_bind sshbind)
|
|||||||
if (!no_default_keys) {
|
if (!no_default_keys) {
|
||||||
set_default_keys(sshbind,
|
set_default_keys(sshbind,
|
||||||
rsa_already_set,
|
rsa_already_set,
|
||||||
|
dsa_already_set,
|
||||||
ecdsa_already_set);
|
ecdsa_already_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,74 +363,49 @@ struct session_data_struct {
|
|||||||
int authenticated;
|
int authenticated;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int data_function(ssh_session session, ssh_channel channel, void *data,
|
||||||
data_function(ssh_session session,
|
uint32_t len, int is_stderr, void *userdata) {
|
||||||
ssh_channel channel,
|
struct channel_data_struct *cdata = (struct channel_data_struct *) userdata;
|
||||||
void *data,
|
|
||||||
uint32_t len,
|
|
||||||
int is_stderr,
|
|
||||||
void *userdata)
|
|
||||||
{
|
|
||||||
struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
|
|
||||||
|
|
||||||
(void)session;
|
(void) session;
|
||||||
(void)channel;
|
(void) channel;
|
||||||
(void)is_stderr;
|
(void) is_stderr;
|
||||||
|
|
||||||
if (len == 0 || cdata->pid < 1 || kill(cdata->pid, 0) < 0) {
|
if (len == 0 || cdata->pid < 1 || kill(cdata->pid, 0) < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return write(cdata->child_stdin, (char *)data, len);
|
return write(cdata->child_stdin, (char *) data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int pty_request(ssh_session session, ssh_channel channel,
|
||||||
pty_request(ssh_session session,
|
const char *term, int cols, int rows, int py, int px,
|
||||||
ssh_channel channel,
|
void *userdata) {
|
||||||
const char *term,
|
|
||||||
int cols,
|
|
||||||
int rows,
|
|
||||||
int py,
|
|
||||||
int px,
|
|
||||||
void *userdata)
|
|
||||||
{
|
|
||||||
struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
|
struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
|
||||||
int rc;
|
|
||||||
|
|
||||||
(void)session;
|
(void) session;
|
||||||
(void)channel;
|
(void) channel;
|
||||||
(void)term;
|
(void) term;
|
||||||
|
|
||||||
cdata->winsize->ws_row = rows;
|
cdata->winsize->ws_row = rows;
|
||||||
cdata->winsize->ws_col = cols;
|
cdata->winsize->ws_col = cols;
|
||||||
cdata->winsize->ws_xpixel = px;
|
cdata->winsize->ws_xpixel = px;
|
||||||
cdata->winsize->ws_ypixel = py;
|
cdata->winsize->ws_ypixel = py;
|
||||||
|
|
||||||
rc = openpty(&cdata->pty_master,
|
if (openpty(&cdata->pty_master, &cdata->pty_slave, NULL, NULL,
|
||||||
&cdata->pty_slave,
|
cdata->winsize) != 0) {
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
cdata->winsize);
|
|
||||||
if (rc != 0) {
|
|
||||||
fprintf(stderr, "Failed to open pty\n");
|
fprintf(stderr, "Failed to open pty\n");
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int pty_resize(ssh_session session, ssh_channel channel, int cols,
|
||||||
pty_resize(ssh_session session,
|
int rows, int py, int px, void *userdata) {
|
||||||
ssh_channel channel,
|
|
||||||
int cols,
|
|
||||||
int rows,
|
|
||||||
int py,
|
|
||||||
int px,
|
|
||||||
void *userdata)
|
|
||||||
{
|
|
||||||
struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
|
struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
|
||||||
|
|
||||||
(void)session;
|
(void) session;
|
||||||
(void)channel;
|
(void) channel;
|
||||||
|
|
||||||
cdata->winsize->ws_row = rows;
|
cdata->winsize->ws_row = rows;
|
||||||
cdata->winsize->ws_col = cols;
|
cdata->winsize->ws_col = cols;
|
||||||
@@ -373,36 +419,30 @@ pty_resize(ssh_session session,
|
|||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int exec_pty(const char *mode, const char *command,
|
||||||
exec_pty(const char *mode,
|
struct channel_data_struct *cdata) {
|
||||||
const char *command,
|
switch(cdata->pid = fork()) {
|
||||||
struct channel_data_struct *cdata)
|
case -1:
|
||||||
{
|
close(cdata->pty_master);
|
||||||
cdata->pid = fork();
|
close(cdata->pty_slave);
|
||||||
switch (cdata->pid) {
|
fprintf(stderr, "Failed to fork\n");
|
||||||
case -1:
|
return SSH_ERROR;
|
||||||
close(cdata->pty_master);
|
case 0:
|
||||||
close(cdata->pty_slave);
|
close(cdata->pty_master);
|
||||||
fprintf(stderr, "Failed to fork\n");
|
if (login_tty(cdata->pty_slave) != 0) {
|
||||||
return SSH_ERROR;
|
exit(1);
|
||||||
case 0:
|
}
|
||||||
close(cdata->pty_master);
|
execl("/bin/sh", "sh", mode, command, NULL);
|
||||||
if (login_tty(cdata->pty_slave) != 0) {
|
exit(0);
|
||||||
exit(1);
|
default:
|
||||||
}
|
close(cdata->pty_slave);
|
||||||
execl("/bin/sh", "sh", mode, command, NULL);
|
/* pty fd is bi-directional */
|
||||||
exit(0);
|
cdata->child_stdout = cdata->child_stdin = cdata->pty_master;
|
||||||
default:
|
|
||||||
close(cdata->pty_slave);
|
|
||||||
/* pty fd is bi-directional */
|
|
||||||
cdata->child_stdout = cdata->child_stdin = cdata->pty_master;
|
|
||||||
}
|
}
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int exec_nopty(const char *command, struct channel_data_struct *cdata) {
|
||||||
exec_nopty(const char *command, struct channel_data_struct *cdata)
|
|
||||||
{
|
|
||||||
int in[2], out[2], err[2];
|
int in[2], out[2], err[2];
|
||||||
|
|
||||||
/* Do the plumbing to be able to talk with the child process. */
|
/* Do the plumbing to be able to talk with the child process. */
|
||||||
@@ -416,24 +456,23 @@ exec_nopty(const char *command, struct channel_data_struct *cdata)
|
|||||||
goto stderr_failed;
|
goto stderr_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
cdata->pid = fork();
|
switch(cdata->pid = fork()) {
|
||||||
switch (cdata->pid) {
|
case -1:
|
||||||
case -1:
|
goto fork_failed;
|
||||||
goto fork_failed;
|
case 0:
|
||||||
case 0:
|
/* Finish the plumbing in the child process. */
|
||||||
/* Finish the plumbing in the child process. */
|
close(in[1]);
|
||||||
close(in[1]);
|
close(out[0]);
|
||||||
close(out[0]);
|
close(err[0]);
|
||||||
close(err[0]);
|
dup2(in[0], STDIN_FILENO);
|
||||||
dup2(in[0], STDIN_FILENO);
|
dup2(out[1], STDOUT_FILENO);
|
||||||
dup2(out[1], STDOUT_FILENO);
|
dup2(err[1], STDERR_FILENO);
|
||||||
dup2(err[1], STDERR_FILENO);
|
close(in[0]);
|
||||||
close(in[0]);
|
close(out[1]);
|
||||||
close(out[1]);
|
close(err[1]);
|
||||||
close(err[1]);
|
/* exec the requested command. */
|
||||||
/* exec the requested command. */
|
execl("/bin/sh", "sh", "-c", command, NULL);
|
||||||
execl("/bin/sh", "sh", "-c", command, NULL);
|
exit(0);
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(in[0]);
|
close(in[0]);
|
||||||
@@ -459,18 +498,15 @@ stdin_failed:
|
|||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int exec_request(ssh_session session, ssh_channel channel,
|
||||||
exec_request(ssh_session session,
|
const char *command, void *userdata) {
|
||||||
ssh_channel channel,
|
struct channel_data_struct *cdata = (struct channel_data_struct *) userdata;
|
||||||
const char *command,
|
|
||||||
void *userdata)
|
|
||||||
{
|
|
||||||
struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
|
|
||||||
|
|
||||||
(void)session;
|
|
||||||
(void)channel;
|
|
||||||
|
|
||||||
if (cdata->pid > 0) {
|
(void) session;
|
||||||
|
(void) channel;
|
||||||
|
|
||||||
|
if(cdata->pid > 0) {
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,15 +516,14 @@ exec_request(ssh_session session,
|
|||||||
return exec_nopty(command, cdata);
|
return exec_nopty(command, cdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int shell_request(ssh_session session, ssh_channel channel,
|
||||||
shell_request(ssh_session session, ssh_channel channel, void *userdata)
|
void *userdata) {
|
||||||
{
|
struct channel_data_struct *cdata = (struct channel_data_struct *) userdata;
|
||||||
struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
|
|
||||||
|
|
||||||
(void)session;
|
(void) session;
|
||||||
(void)channel;
|
(void) channel;
|
||||||
|
|
||||||
if (cdata->pid > 0) {
|
if(cdata->pid > 0) {
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,28 +534,20 @@ shell_request(ssh_session session, ssh_channel channel, void *userdata)
|
|||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int subsystem_request(ssh_session session, ssh_channel channel,
|
||||||
subsystem_request(ssh_session session,
|
const char *subsystem, void *userdata) {
|
||||||
ssh_channel channel,
|
/* subsystem requests behave simillarly to exec requests. */
|
||||||
const char *subsystem,
|
|
||||||
void *userdata)
|
|
||||||
{
|
|
||||||
/* subsystem requests behave similarly to exec requests. */
|
|
||||||
if (strcmp(subsystem, "sftp") == 0) {
|
if (strcmp(subsystem, "sftp") == 0) {
|
||||||
return exec_request(session, channel, SFTP_SERVER_PATH, userdata);
|
return exec_request(session, channel, SFTP_SERVER_PATH, userdata);
|
||||||
}
|
}
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int auth_password(ssh_session session, const char *user,
|
||||||
auth_password(ssh_session session,
|
const char *pass, void *userdata) {
|
||||||
const char *user,
|
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
|
||||||
const char *pass,
|
|
||||||
void *userdata)
|
|
||||||
{
|
|
||||||
struct session_data_struct *sdata = (struct session_data_struct *)userdata;
|
|
||||||
|
|
||||||
(void)session;
|
(void) session;
|
||||||
|
|
||||||
if (strcmp(user, username) == 0 && strcmp(pass, password) == 0) {
|
if (strcmp(user, username) == 0 && strcmp(pass, password) == 0) {
|
||||||
sdata->authenticated = 1;
|
sdata->authenticated = 1;
|
||||||
@@ -531,26 +558,16 @@ auth_password(ssh_session session,
|
|||||||
return SSH_AUTH_DENIED;
|
return SSH_AUTH_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int auth_publickey(ssh_session session,
|
||||||
auth_publickey(ssh_session session,
|
const char *user,
|
||||||
const char *user,
|
struct ssh_key_struct *pubkey,
|
||||||
struct ssh_key_struct *pubkey,
|
char signature_state,
|
||||||
char signature_state,
|
void *userdata)
|
||||||
void *userdata)
|
|
||||||
{
|
{
|
||||||
struct session_data_struct *sdata = (struct session_data_struct *)userdata;
|
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
|
||||||
ssh_key key = NULL;
|
|
||||||
FILE *fp = NULL;
|
|
||||||
char line[AUTH_KEYS_MAX_LINE_SIZE] = {0};
|
|
||||||
char *p = NULL;
|
|
||||||
const char *q = NULL;
|
|
||||||
unsigned int lineno = 0;
|
|
||||||
int result;
|
|
||||||
int i;
|
|
||||||
enum ssh_keytypes_e type;
|
|
||||||
|
|
||||||
(void)user;
|
(void) user;
|
||||||
(void)session;
|
(void) session;
|
||||||
|
|
||||||
if (signature_state == SSH_PUBLICKEY_STATE_NONE) {
|
if (signature_state == SSH_PUBLICKEY_STATE_NONE) {
|
||||||
return SSH_AUTH_SUCCESS;
|
return SSH_AUTH_SUCCESS;
|
||||||
@@ -560,107 +577,45 @@ auth_publickey(ssh_session session,
|
|||||||
return SSH_AUTH_DENIED;
|
return SSH_AUTH_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = fopen(authorizedkeys, "r");
|
// valid so far. Now look through authorized keys for a match
|
||||||
if (fp == NULL) {
|
if (authorizedkeys[0]) {
|
||||||
fprintf(stderr, "Error: opening authorized keys file %s failed, reason: %s\n",
|
ssh_key key = NULL;
|
||||||
authorizedkeys, strerror(errno));
|
int result;
|
||||||
return SSH_AUTH_DENIED;
|
struct stat buf;
|
||||||
}
|
|
||||||
|
|
||||||
while (fgets(line, sizeof(line), fp)) {
|
if (stat(authorizedkeys, &buf) == 0) {
|
||||||
lineno++;
|
result = ssh_pki_import_pubkey_file( authorizedkeys, &key );
|
||||||
|
if ((result != SSH_OK) || (key==NULL)) {
|
||||||
/* Skip leading whitespace and ignore comments */
|
fprintf(stderr,
|
||||||
p = line;
|
"Unable to import public key file %s\n",
|
||||||
|
authorizedkeys);
|
||||||
for (i = 0; i < AUTH_KEYS_MAX_LINE_SIZE; i++) {
|
} else {
|
||||||
if (!isspace((int)p[i])) {
|
result = ssh_key_cmp( key, pubkey, SSH_KEY_CMP_PUBLIC );
|
||||||
break;
|
ssh_key_free(key);
|
||||||
|
if (result == 0) {
|
||||||
|
sdata->authenticated = 1;
|
||||||
|
return SSH_AUTH_SUCCESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i >= AUTH_KEYS_MAX_LINE_SIZE) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"warning: The line %d in %s too long! Skipping.\n",
|
|
||||||
lineno,
|
|
||||||
authorizedkeys);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p[i] == '#' || p[i] == '\0' || p[i] == '\n') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
q = &p[i];
|
|
||||||
for (; i < AUTH_KEYS_MAX_LINE_SIZE; i++) {
|
|
||||||
if (isspace((int)p[i])) {
|
|
||||||
p[i] = '\0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type = ssh_key_type_from_name(q);
|
|
||||||
|
|
||||||
i++;
|
|
||||||
if (i >= AUTH_KEYS_MAX_LINE_SIZE) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"warning: The line %d in %s too long! Skipping.\n",
|
|
||||||
lineno,
|
|
||||||
authorizedkeys);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
q = &p[i];
|
|
||||||
for (; i < AUTH_KEYS_MAX_LINE_SIZE; i++) {
|
|
||||||
if (isspace((int)p[i])) {
|
|
||||||
p[i] = '\0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = ssh_pki_import_pubkey_base64(q, type, &key);
|
|
||||||
if (result != SSH_OK) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Warning: Cannot import key on line no. %d in authorized keys file: %s\n",
|
|
||||||
lineno,
|
|
||||||
authorizedkeys);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = ssh_key_cmp(key, pubkey, SSH_KEY_CMP_PUBLIC);
|
|
||||||
ssh_key_free(key);
|
|
||||||
if (result == 0) {
|
|
||||||
sdata->authenticated = 1;
|
|
||||||
fclose(fp);
|
|
||||||
return SSH_AUTH_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (ferror(fp) != 0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Error: Reading from authorized keys file %s failed, reason: %s\n",
|
|
||||||
authorizedkeys, strerror(errno));
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
/* no matches */
|
// no matches
|
||||||
|
sdata->authenticated = 0;
|
||||||
return SSH_AUTH_DENIED;
|
return SSH_AUTH_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssh_channel
|
static ssh_channel channel_open(ssh_session session, void *userdata) {
|
||||||
channel_open(ssh_session session, void *userdata)
|
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
|
||||||
{
|
|
||||||
struct session_data_struct *sdata = (struct session_data_struct *)userdata;
|
|
||||||
|
|
||||||
sdata->channel = ssh_channel_new(session);
|
sdata->channel = ssh_channel_new(session);
|
||||||
return sdata->channel;
|
return sdata->channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int process_stdout(socket_t fd, int revents, void *userdata) {
|
||||||
process_stdout(socket_t fd, int revents, void *userdata)
|
|
||||||
{
|
|
||||||
char buf[BUF_SIZE];
|
char buf[BUF_SIZE];
|
||||||
int n = -1;
|
int n = -1;
|
||||||
ssh_channel channel = (ssh_channel)userdata;
|
ssh_channel channel = (ssh_channel) userdata;
|
||||||
|
|
||||||
if (channel != NULL && (revents & POLLIN) != 0) {
|
if (channel != NULL && (revents & POLLIN) != 0) {
|
||||||
n = read(fd, buf, BUF_SIZE);
|
n = read(fd, buf, BUF_SIZE);
|
||||||
@@ -672,12 +627,10 @@ process_stdout(socket_t fd, int revents, void *userdata)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int process_stderr(socket_t fd, int revents, void *userdata) {
|
||||||
process_stderr(socket_t fd, int revents, void *userdata)
|
|
||||||
{
|
|
||||||
char buf[BUF_SIZE];
|
char buf[BUF_SIZE];
|
||||||
int n = -1;
|
int n = -1;
|
||||||
ssh_channel channel = (ssh_channel)userdata;
|
ssh_channel channel = (ssh_channel) userdata;
|
||||||
|
|
||||||
if (channel != NULL && (revents & POLLIN) != 0) {
|
if (channel != NULL && (revents & POLLIN) != 0) {
|
||||||
n = read(fd, buf, BUF_SIZE);
|
n = read(fd, buf, BUF_SIZE);
|
||||||
@@ -689,9 +642,7 @@ process_stderr(socket_t fd, int revents, void *userdata)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void handle_session(ssh_event event, ssh_session session) {
|
||||||
handle_session(ssh_event event, ssh_session session)
|
|
||||||
{
|
|
||||||
int n;
|
int n;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
@@ -804,8 +755,8 @@ handle_session(ssh_event event, ssh_session session)
|
|||||||
ssh_channel_close(sdata.channel);
|
ssh_channel_close(sdata.channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (ssh_channel_is_open(sdata.channel) &&
|
} while(ssh_channel_is_open(sdata.channel) &&
|
||||||
(cdata.pid == 0 || waitpid(cdata.pid, &rc, WNOHANG) == 0));
|
(cdata.pid == 0 || waitpid(cdata.pid, &rc, WNOHANG) == 0));
|
||||||
|
|
||||||
close(cdata.pty_master);
|
close(cdata.pty_master);
|
||||||
close(cdata.child_stdin);
|
close(cdata.child_stdin);
|
||||||
@@ -838,14 +789,12 @@ handle_session(ssh_event event, ssh_session session)
|
|||||||
|
|
||||||
#ifdef WITH_FORK
|
#ifdef WITH_FORK
|
||||||
/* SIGCHLD handler for cleaning up dead children. */
|
/* SIGCHLD handler for cleaning up dead children. */
|
||||||
static void sigchld_handler(int signo)
|
static void sigchld_handler(int signo) {
|
||||||
{
|
(void) signo;
|
||||||
(void)signo;
|
|
||||||
while (waitpid(-1, NULL, WNOHANG) > 0);
|
while (waitpid(-1, NULL, WNOHANG) > 0);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static void *session_thread(void *arg)
|
static void *session_thread(void *arg) {
|
||||||
{
|
|
||||||
ssh_session session = arg;
|
ssh_session session = arg;
|
||||||
ssh_event event;
|
ssh_event event;
|
||||||
|
|
||||||
@@ -864,10 +813,9 @@ static void *session_thread(void *arg)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv) {
|
||||||
{
|
ssh_bind sshbind;
|
||||||
ssh_bind sshbind = NULL;
|
ssh_session session;
|
||||||
ssh_session session = NULL;
|
|
||||||
int rc;
|
int rc;
|
||||||
#ifdef WITH_FORK
|
#ifdef WITH_FORK
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
@@ -905,8 +853,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
#endif /* HAVE_ARGP_H */
|
#endif /* HAVE_ARGP_H */
|
||||||
|
|
||||||
rc = ssh_bind_listen(sshbind);
|
if(ssh_bind_listen(sshbind) < 0) {
|
||||||
if (rc < 0) {
|
|
||||||
fprintf(stderr, "%s\n", ssh_get_error(sshbind));
|
fprintf(stderr, "%s\n", ssh_get_error(sshbind));
|
||||||
ssh_bind_free(sshbind);
|
ssh_bind_free(sshbind);
|
||||||
ssh_finalize();
|
ssh_finalize();
|
||||||
@@ -921,36 +868,34 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Blocks until there is a new incoming connection. */
|
/* Blocks until there is a new incoming connection. */
|
||||||
rc = ssh_bind_accept(sshbind, session);
|
if(ssh_bind_accept(sshbind, session) != SSH_ERROR) {
|
||||||
if (rc != SSH_ERROR) {
|
|
||||||
#ifdef WITH_FORK
|
#ifdef WITH_FORK
|
||||||
ssh_event event;
|
ssh_event event;
|
||||||
|
|
||||||
pid_t pid = fork();
|
switch(fork()) {
|
||||||
switch (pid) {
|
case 0:
|
||||||
case 0:
|
/* Remove the SIGCHLD handler inherited from parent. */
|
||||||
/* Remove the SIGCHLD handler inherited from parent. */
|
sa.sa_handler = SIG_DFL;
|
||||||
sa.sa_handler = SIG_DFL;
|
sigaction(SIGCHLD, &sa, NULL);
|
||||||
sigaction(SIGCHLD, &sa, NULL);
|
/* Remove socket binding, which allows us to restart the
|
||||||
/* Remove socket binding, which allows us to restart the
|
* parent process, without terminating existing sessions. */
|
||||||
* parent process, without terminating existing sessions. */
|
ssh_bind_free(sshbind);
|
||||||
ssh_bind_free(sshbind);
|
|
||||||
|
|
||||||
event = ssh_event_new();
|
event = ssh_event_new();
|
||||||
if (event != NULL) {
|
if (event != NULL) {
|
||||||
/* Blocks until the SSH session ends by either
|
/* Blocks until the SSH session ends by either
|
||||||
* child process exiting, or client disconnecting. */
|
* child process exiting, or client disconnecting. */
|
||||||
handle_session(event, session);
|
handle_session(event, session);
|
||||||
ssh_event_free(event);
|
ssh_event_free(event);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Could not create polling context\n");
|
fprintf(stderr, "Could not create polling context\n");
|
||||||
}
|
}
|
||||||
ssh_disconnect(session);
|
ssh_disconnect(session);
|
||||||
ssh_free(session);
|
ssh_free(session);
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
case -1:
|
case -1:
|
||||||
fprintf(stderr, "Failed to fork\n");
|
fprintf(stderr, "Failed to fork\n");
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
pthread_t tid;
|
pthread_t tid;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ clients must be made or how a client should react.
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Example:
|
Example:
|
||||||
./sshd_direct-tcpip -v -p 2022 -r serverkey.rsa 127.0.0.1
|
./sshd_direct-tcpip -v -p 2022 -d serverkey.dsa -r serverkey.rsa 127.0.0.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -94,9 +94,6 @@ cleanup_push(struct cleanup_node_struct** head_ref,
|
|||||||
{
|
{
|
||||||
// Allocate memory for node
|
// Allocate memory for node
|
||||||
struct cleanup_node_struct *new_node = malloc(sizeof *new_node);
|
struct cleanup_node_struct *new_node = malloc(sizeof *new_node);
|
||||||
if (new_node == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*head_ref != NULL) {
|
if (*head_ref != NULL) {
|
||||||
new_node->next = *head_ref;
|
new_node->next = *head_ref;
|
||||||
@@ -526,7 +523,7 @@ message_callback(UNUSED_PARAM(ssh_session session),
|
|||||||
}
|
}
|
||||||
|
|
||||||
pFd = malloc(sizeof *pFd);
|
pFd = malloc(sizeof *pFd);
|
||||||
cb_chan = calloc(1, sizeof *cb_chan);
|
cb_chan = malloc(sizeof *cb_chan);
|
||||||
event_fd_data = malloc(sizeof *event_fd_data);
|
event_fd_data = malloc(sizeof *event_fd_data);
|
||||||
if (pFd == NULL || cb_chan == NULL || event_fd_data == NULL) {
|
if (pFd == NULL || cb_chan == NULL || event_fd_data == NULL) {
|
||||||
SAFE_FREE(pFd);
|
SAFE_FREE(pFd);
|
||||||
@@ -589,12 +586,20 @@ static struct argp_option options[] = {
|
|||||||
.doc = "Set the host key.",
|
.doc = "Set the host key.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "dsakey",
|
||||||
|
.key = 'd',
|
||||||
|
.arg = "FILE",
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "Set the dsa key.",
|
||||||
|
.group = 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "rsakey",
|
.name = "rsakey",
|
||||||
.key = 'r',
|
.key = 'r',
|
||||||
.arg = "FILE",
|
.arg = "FILE",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.doc = "Set the rsa key (deprecated alias for 'k').",
|
.doc = "Set the rsa key.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -621,10 +626,15 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
|||||||
case 'p':
|
case 'p':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'd':
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg);
|
||||||
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg);
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "1");
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "1");
|
||||||
break;
|
break;
|
||||||
@@ -675,7 +685,8 @@ main(int argc, char **argv)
|
|||||||
session = ssh_new();
|
session = ssh_new();
|
||||||
mainloop = ssh_event_new();
|
mainloop = ssh_event_new();
|
||||||
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, KEYS_FOLDER "ssh_host_rsa_key");
|
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
|
#ifdef HAVE_ARGP_H
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -20,13 +20,6 @@ if (WITH_SERVER)
|
|||||||
${libssh_HDRS}
|
${libssh_HDRS}
|
||||||
server.h
|
server.h
|
||||||
)
|
)
|
||||||
|
|
||||||
if (WITH_SFTP)
|
|
||||||
set(libssh_HDRS
|
|
||||||
${libssh_HDRS}
|
|
||||||
sftpserver.h
|
|
||||||
)
|
|
||||||
endif (WITH_SFTP)
|
|
||||||
endif (WITH_SERVER)
|
endif (WITH_SERVER)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
|
|||||||
@@ -39,9 +39,11 @@ struct ssh_bind_struct {
|
|||||||
char *wanted_methods[SSH_KEX_METHODS];
|
char *wanted_methods[SSH_KEX_METHODS];
|
||||||
char *banner;
|
char *banner;
|
||||||
char *ecdsakey;
|
char *ecdsakey;
|
||||||
|
char *dsakey;
|
||||||
char *rsakey;
|
char *rsakey;
|
||||||
char *ed25519key;
|
char *ed25519key;
|
||||||
ssh_key ecdsa;
|
ssh_key ecdsa;
|
||||||
|
ssh_key dsa;
|
||||||
ssh_key rsa;
|
ssh_key rsa;
|
||||||
ssh_key ed25519;
|
ssh_key ed25519;
|
||||||
char *bindaddr;
|
char *bindaddr;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: blf.h,v 1.8 2021/11/29 01:04:45 djm Exp $ */
|
/* $OpenBSD: blf.h,v 1.7 2007/03/14 17:59:41 grunk Exp $ */
|
||||||
/*
|
/*
|
||||||
* Blowfish - a fast block cipher designed by Bruce Schneier
|
* Blowfish - a fast block cipher designed by Bruce Schneier
|
||||||
*
|
*
|
||||||
@@ -13,7 +13,10 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Niels Provos.
|
||||||
|
* 4. The name of the author may not be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len);
|
|||||||
|
|
||||||
void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len);
|
void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len);
|
||||||
int ssh_buffer_allocate_size(struct ssh_buffer_struct *buffer, uint32_t len);
|
int ssh_buffer_allocate_size(struct ssh_buffer_struct *buffer, uint32_t len);
|
||||||
|
int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||||
|
const char *format,
|
||||||
|
size_t argc,
|
||||||
|
va_list ap);
|
||||||
int _ssh_buffer_pack(struct ssh_buffer_struct *buffer,
|
int _ssh_buffer_pack(struct ssh_buffer_struct *buffer,
|
||||||
const char *format,
|
const char *format,
|
||||||
size_t argc,
|
size_t argc,
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
|
|
||||||
#include <libssh/libssh.h>
|
#include <libssh/libssh.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -139,26 +138,6 @@ typedef ssh_channel (*ssh_channel_open_request_x11_callback) (ssh_session sessio
|
|||||||
typedef ssh_channel (*ssh_channel_open_request_auth_agent_callback) (ssh_session session,
|
typedef ssh_channel (*ssh_channel_open_request_auth_agent_callback) (ssh_session session,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handles an SSH new channel open "forwarded-tcpip" request. This
|
|
||||||
* happens when the server forwards an incoming TCP connection on a port it was
|
|
||||||
* previously requested to listen on. This is a client-side API
|
|
||||||
* @param session current session handler
|
|
||||||
* @param destination_address the address that the TCP connection connected to
|
|
||||||
* @param destination_port the port that the TCP connection connected to
|
|
||||||
* @param originator_address the originator IP address
|
|
||||||
* @param originator_port the originator port
|
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
|
||||||
* @returns a valid ssh_channel handle if the request is to be allowed
|
|
||||||
* @returns NULL if the request should not be allowed
|
|
||||||
* @warning The channel pointer returned by this callback must be closed by the
|
|
||||||
* application.
|
|
||||||
*/
|
|
||||||
typedef ssh_channel (*ssh_channel_open_request_forwarded_tcpip_callback) (ssh_session session,
|
|
||||||
const char *destination_address, int destination_port,
|
|
||||||
const char *originator_address, int originator_port,
|
|
||||||
void *userdata);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The structure to replace libssh functions with appropriate callbacks.
|
* The structure to replace libssh functions with appropriate callbacks.
|
||||||
*/
|
*/
|
||||||
@@ -192,11 +171,6 @@ struct ssh_callbacks_struct {
|
|||||||
/** This function will be called when an incoming "auth-agent" request is received.
|
/** This function will be called when an incoming "auth-agent" request is received.
|
||||||
*/
|
*/
|
||||||
ssh_channel_open_request_auth_agent_callback channel_open_request_auth_agent_function;
|
ssh_channel_open_request_auth_agent_callback channel_open_request_auth_agent_function;
|
||||||
/**
|
|
||||||
* This function will be called when an incoming "forwarded-tcpip"
|
|
||||||
* request is received.
|
|
||||||
*/
|
|
||||||
ssh_channel_open_request_forwarded_tcpip_callback channel_open_request_forwarded_tcpip_function;
|
|
||||||
};
|
};
|
||||||
typedef struct ssh_callbacks_struct *ssh_callbacks;
|
typedef struct ssh_callbacks_struct *ssh_callbacks;
|
||||||
|
|
||||||
@@ -283,7 +257,6 @@ typedef ssh_channel (*ssh_channel_open_request_session_callback) (ssh_session se
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief handle the beginning of a GSSAPI authentication, server side.
|
* @brief handle the beginning of a GSSAPI authentication, server side.
|
||||||
* Callback should select the oid and also acquire the server credential.
|
|
||||||
* @param session current session handler
|
* @param session current session handler
|
||||||
* @param user the username of the client
|
* @param user the username of the client
|
||||||
* @param n_oid number of available oids
|
* @param n_oid number of available oids
|
||||||
@@ -366,7 +339,6 @@ struct ssh_server_callbacks_struct {
|
|||||||
*/
|
*/
|
||||||
ssh_channel_open_request_session_callback channel_open_request_session_function;
|
ssh_channel_open_request_session_callback channel_open_request_session_function;
|
||||||
/** This function will be called when a new gssapi authentication is attempted.
|
/** This function will be called when a new gssapi authentication is attempted.
|
||||||
* This should select the oid and acquire credential for the server.
|
|
||||||
*/
|
*/
|
||||||
ssh_gssapi_select_oid_callback gssapi_select_oid_function;
|
ssh_gssapi_select_oid_callback gssapi_select_oid_function;
|
||||||
/** This function will be called when a gssapi token comes in.
|
/** This function will be called when a gssapi token comes in.
|
||||||
@@ -825,28 +797,6 @@ typedef int (*ssh_channel_write_wontblock_callback) (ssh_session session,
|
|||||||
uint32_t bytes,
|
uint32_t bytes,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief SSH channel open callback. Called when a channel open succeeds or fails.
|
|
||||||
* @param session Current session handler
|
|
||||||
* @param channel the actual channel
|
|
||||||
* @param is_success is 1 when the open succeeds, and 0 otherwise.
|
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
|
||||||
*/
|
|
||||||
typedef void (*ssh_channel_open_resp_callback) (ssh_session session,
|
|
||||||
ssh_channel channel,
|
|
||||||
bool is_success,
|
|
||||||
void *userdata);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief SSH channel request response callback. Called when a response to the pending request is received.
|
|
||||||
* @param session Current session handler
|
|
||||||
* @param channel the actual channel
|
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
|
||||||
*/
|
|
||||||
typedef void (*ssh_channel_request_resp_callback) (ssh_session session,
|
|
||||||
ssh_channel channel,
|
|
||||||
void *userdata);
|
|
||||||
|
|
||||||
struct ssh_channel_callbacks_struct {
|
struct ssh_channel_callbacks_struct {
|
||||||
/** DON'T SET THIS use ssh_callbacks_init() instead. */
|
/** DON'T SET THIS use ssh_callbacks_init() instead. */
|
||||||
size_t size;
|
size_t size;
|
||||||
@@ -914,14 +864,6 @@ struct ssh_channel_callbacks_struct {
|
|||||||
* not to block.
|
* not to block.
|
||||||
*/
|
*/
|
||||||
ssh_channel_write_wontblock_callback channel_write_wontblock_function;
|
ssh_channel_write_wontblock_callback channel_write_wontblock_function;
|
||||||
/**
|
|
||||||
* This functions will be called when the channel has received a channel open confirmation or failure.
|
|
||||||
*/
|
|
||||||
ssh_channel_open_resp_callback channel_open_response_function;
|
|
||||||
/**
|
|
||||||
* This functions will be called when the channel has received the response to the pending request.
|
|
||||||
*/
|
|
||||||
ssh_channel_request_resp_callback channel_request_response_function;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct ssh_channel_callbacks_struct *ssh_channel_callbacks;
|
typedef struct ssh_channel_callbacks_struct *ssh_channel_callbacks;
|
||||||
@@ -1058,7 +1000,6 @@ LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_pthread(void);
|
|||||||
* @see ssh_threads_set_callbacks
|
* @see ssh_threads_set_callbacks
|
||||||
*/
|
*/
|
||||||
LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void);
|
LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void);
|
||||||
/** @} */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the logging callback function.
|
* @brief Set the logging callback function.
|
||||||
@@ -1076,45 +1017,7 @@ LIBSSH_API int ssh_set_log_callback(ssh_logging_callback cb);
|
|||||||
*/
|
*/
|
||||||
LIBSSH_API ssh_logging_callback ssh_get_log_callback(void);
|
LIBSSH_API ssh_logging_callback ssh_get_log_callback(void);
|
||||||
|
|
||||||
/**
|
/** @} */
|
||||||
* @brief SSH proxyjump before connection callback. Called before calling
|
|
||||||
* ssh_connect()
|
|
||||||
* @param session Jump session handler
|
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
|
||||||
*
|
|
||||||
* @return 0 on success, < 0 on error.
|
|
||||||
*/
|
|
||||||
typedef int (*ssh_jump_before_connection_callback)(ssh_session session,
|
|
||||||
void *userdata);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief SSH proxyjump verify knownhost callback. Verify the host.
|
|
||||||
* If not specified default function will be used.
|
|
||||||
* @param session Jump session handler
|
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
|
||||||
*
|
|
||||||
* @return 0 on success, < 0 on error.
|
|
||||||
*/
|
|
||||||
typedef int (*ssh_jump_verify_knownhost_callback)(ssh_session session,
|
|
||||||
void *userdata);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief SSH proxyjump user authentication callback. Authenticate the user.
|
|
||||||
* @param session Jump session handler
|
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
|
||||||
*
|
|
||||||
* @return 0 on success, < 0 on error.
|
|
||||||
*/
|
|
||||||
typedef int (*ssh_jump_authenticate_callback)(ssh_session session,
|
|
||||||
void *userdata);
|
|
||||||
|
|
||||||
struct ssh_jump_callbacks_struct {
|
|
||||||
void *userdata;
|
|
||||||
ssh_jump_before_connection_callback before_connection;
|
|
||||||
ssh_jump_verify_knownhost_callback verify_knownhost;
|
|
||||||
ssh_jump_authenticate_callback authenticate;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -80,12 +80,7 @@ struct ssh_channel_struct {
|
|||||||
ssh_buffer stdout_buffer;
|
ssh_buffer stdout_buffer;
|
||||||
ssh_buffer stderr_buffer;
|
ssh_buffer stderr_buffer;
|
||||||
void *userarg;
|
void *userarg;
|
||||||
struct {
|
int exit_status;
|
||||||
bool status;
|
|
||||||
uint32_t code;
|
|
||||||
char *signal;
|
|
||||||
bool core_dumped;
|
|
||||||
} exit;
|
|
||||||
enum ssh_channel_request_state_e request_state;
|
enum ssh_channel_request_state_e request_state;
|
||||||
struct ssh_list *callbacks; /* list of ssh_channel_callbacks */
|
struct ssh_list *callbacks; /* list of ssh_channel_callbacks */
|
||||||
|
|
||||||
|
|||||||
@@ -62,10 +62,6 @@ enum ssh_config_opcode_e {
|
|||||||
SOC_PUBKEYACCEPTEDKEYTYPES,
|
SOC_PUBKEYACCEPTEDKEYTYPES,
|
||||||
SOC_REKEYLIMIT,
|
SOC_REKEYLIMIT,
|
||||||
SOC_IDENTITYAGENT,
|
SOC_IDENTITYAGENT,
|
||||||
SOC_IDENTITIESONLY,
|
|
||||||
SOC_CONTROLMASTER,
|
|
||||||
SOC_CONTROLPATH,
|
|
||||||
SOC_CERTIFICATE,
|
|
||||||
|
|
||||||
SOC_MAX /* Keep this one last in the list */
|
SOC_MAX /* Keep this one last in the list */
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,9 +30,6 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "libssh/libssh.h"
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
char *ssh_config_get_cmd(char **str);
|
char *ssh_config_get_cmd(char **str);
|
||||||
|
|
||||||
char *ssh_config_get_token(char **str);
|
char *ssh_config_get_token(char **str);
|
||||||
@@ -52,32 +49,14 @@ int ssh_config_get_yesno(char **str, int notfound);
|
|||||||
* be stored or NULL if we do not care about the result.
|
* be stored or NULL if we do not care about the result.
|
||||||
* @param[out] port Pointer to the location, where the new port will
|
* @param[out] port Pointer to the location, where the new port will
|
||||||
* be stored or NULL if we do not care about the result.
|
* be stored or NULL if we do not care about the result.
|
||||||
* @param[in] ignore_port Set to true if we should not attempt to parse
|
|
||||||
* port number.
|
|
||||||
*
|
*
|
||||||
* @returns SSH_OK if the provided string is in format of SSH URI,
|
* @returns SSH_OK if the provided string is in format of SSH URI,
|
||||||
* SSH_ERROR on failure
|
* SSH_ERROR on failure
|
||||||
*/
|
*/
|
||||||
int ssh_config_parse_uri(const char *tok,
|
int ssh_config_parse_uri(const char *tok,
|
||||||
char **username,
|
char **username,
|
||||||
char **hostname,
|
char **hostname,
|
||||||
char **port,
|
char **port);
|
||||||
bool ignore_port);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief: Parse the ProxyJump configuration line and if parsing,
|
|
||||||
* stores the result in the configuration option
|
|
||||||
*
|
|
||||||
* @param[in] session The ssh session
|
|
||||||
* @param[in] s The string to be parsed.
|
|
||||||
* @param[in] do_parsing Whether to parse or not.
|
|
||||||
*
|
|
||||||
* @returns SSH_OK if the provided string is formatted and parsed correctly
|
|
||||||
* SSH_ERROR on failure
|
|
||||||
*/
|
|
||||||
int ssh_config_parse_proxy_jump(ssh_session session,
|
|
||||||
const char *s,
|
|
||||||
bool do_parsing);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,9 +86,9 @@ enum ssh_key_exchange_e {
|
|||||||
|
|
||||||
enum ssh_cipher_e {
|
enum ssh_cipher_e {
|
||||||
SSH_NO_CIPHER=0,
|
SSH_NO_CIPHER=0,
|
||||||
#ifdef HAVE_BLOWFISH
|
#ifdef WITH_BLOWFISH_CIPHER
|
||||||
SSH_BLOWFISH_CBC,
|
SSH_BLOWFISH_CBC,
|
||||||
#endif /* HAVE_BLOWFISH */
|
#endif /* WITH_BLOWFISH_CIPHER */
|
||||||
SSH_3DES_CBC,
|
SSH_3DES_CBC,
|
||||||
SSH_AES128_CBC,
|
SSH_AES128_CBC,
|
||||||
SSH_AES192_CBC,
|
SSH_AES192_CBC,
|
||||||
@@ -111,7 +111,11 @@ struct ssh_crypto_struct {
|
|||||||
#endif /* WITH_GEX */
|
#endif /* WITH_GEX */
|
||||||
#ifdef HAVE_ECDH
|
#ifdef HAVE_ECDH
|
||||||
#ifdef HAVE_OPENSSL_ECC
|
#ifdef HAVE_OPENSSL_ECC
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
EC_KEY *ecdh_privkey;
|
EC_KEY *ecdh_privkey;
|
||||||
#else
|
#else
|
||||||
EVP_PKEY *ecdh_privkey;
|
EVP_PKEY *ecdh_privkey;
|
||||||
@@ -223,7 +227,7 @@ int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
|
|||||||
size_t requested_len);
|
size_t requested_len);
|
||||||
|
|
||||||
int secure_memcmp(const void *s1, const void *s2, size_t n);
|
int secure_memcmp(const void *s1, const void *s2, size_t n);
|
||||||
#if defined(HAVE_LIBCRYPTO) && !defined(WITH_PKCS11_PROVIDER)
|
#ifdef HAVE_LIBCRYPTO
|
||||||
ENGINE *pki_get_engine(void);
|
ENGINE *pki_get_engine(void);
|
||||||
#endif /* HAVE_LIBCRYPTO */
|
#endif /* HAVE_LIBCRYPTO */
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,7 @@
|
|||||||
#define GSSAPI_H_
|
#define GSSAPI_H_
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#ifdef WITH_GSSAPI
|
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
#include <gssapi/gssapi.h>
|
|
||||||
|
|
||||||
/* all OID begin with the tag identifier + length */
|
/* all OID begin with the tag identifier + length */
|
||||||
#define SSH_OID_TAG 06
|
#define SSH_OID_TAG 06
|
||||||
@@ -35,32 +33,6 @@ typedef struct ssh_gssapi_struct *ssh_gssapi;
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** current state of an GSSAPI authentication */
|
|
||||||
enum ssh_gssapi_state_e {
|
|
||||||
SSH_GSSAPI_STATE_NONE, /* no status */
|
|
||||||
SSH_GSSAPI_STATE_RCV_TOKEN, /* Expecting a token */
|
|
||||||
SSH_GSSAPI_STATE_RCV_MIC, /* Expecting a MIC */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ssh_gssapi_struct{
|
|
||||||
enum ssh_gssapi_state_e state; /* current state */
|
|
||||||
struct gss_OID_desc_struct mech; /* mechanism being elected for auth */
|
|
||||||
gss_cred_id_t server_creds; /* credentials of server */
|
|
||||||
gss_cred_id_t client_creds; /* creds delegated by the client */
|
|
||||||
gss_ctx_id_t ctx; /* the authentication context */
|
|
||||||
gss_name_t client_name; /* Identity of the client */
|
|
||||||
char *user; /* username of client */
|
|
||||||
char *canonic_user; /* canonic form of the client's username */
|
|
||||||
char *service; /* name of the service */
|
|
||||||
struct {
|
|
||||||
gss_name_t server_name; /* identity of server */
|
|
||||||
OM_uint32 flags; /* flags used for init context */
|
|
||||||
gss_OID oid; /* mech being used for authentication */
|
|
||||||
gss_cred_id_t creds; /* creds used to initialize context */
|
|
||||||
gss_cred_id_t client_deleg_creds; /* delegated creds (const, not freeable) */
|
|
||||||
} client;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef WITH_SERVER
|
#ifdef WITH_SERVER
|
||||||
int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n_oid, ssh_string *oids);
|
int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n_oid, ssh_string *oids);
|
||||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server);
|
SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server);
|
||||||
@@ -72,15 +44,10 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client);
|
|||||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response);
|
SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response);
|
||||||
|
|
||||||
|
|
||||||
int ssh_gssapi_init(ssh_session session);
|
|
||||||
void ssh_gssapi_log_error(int verb, const char *msg_a, int maj_stat, int min_stat);
|
|
||||||
int ssh_gssapi_auth_mic(ssh_session session);
|
int ssh_gssapi_auth_mic(ssh_session session);
|
||||||
void ssh_gssapi_free(ssh_session session);
|
|
||||||
char *ssh_gssapi_name_to_char(gss_name_t name);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WITH_GSSAPI */
|
|
||||||
#endif /* GSSAPI_H */
|
#endif /* GSSAPI_H */
|
||||||
|
|||||||
@@ -45,10 +45,6 @@ int ssh_kex_select_methods(ssh_session session);
|
|||||||
int ssh_verify_existing_algo(enum ssh_kex_types_e algo, const char *name);
|
int ssh_verify_existing_algo(enum ssh_kex_types_e algo, const char *name);
|
||||||
char *ssh_keep_known_algos(enum ssh_kex_types_e algo, const char *list);
|
char *ssh_keep_known_algos(enum ssh_kex_types_e algo, const char *list);
|
||||||
char *ssh_keep_fips_algos(enum ssh_kex_types_e algo, const char *list);
|
char *ssh_keep_fips_algos(enum ssh_kex_types_e algo, const char *list);
|
||||||
char *ssh_add_to_default_algos(enum ssh_kex_types_e algo, const char *list);
|
|
||||||
char *ssh_remove_from_default_algos(enum ssh_kex_types_e algo,
|
|
||||||
const char *list);
|
|
||||||
char *ssh_prefix_default_algos(enum ssh_kex_types_e algo, const char *list);
|
|
||||||
char **ssh_space_tokenize(const char *chain);
|
char **ssh_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);
|
char *ssh_find_matching(const char *in_d, const char *what_d);
|
||||||
|
|||||||
@@ -29,22 +29,36 @@ struct ssh_public_key_struct {
|
|||||||
int type;
|
int type;
|
||||||
const char *type_c; /* Don't free it ! it is static */
|
const char *type_c; /* Don't free it ! it is static */
|
||||||
#if defined(HAVE_LIBGCRYPT)
|
#if defined(HAVE_LIBGCRYPT)
|
||||||
|
gcry_sexp_t dsa_pub;
|
||||||
gcry_sexp_t rsa_pub;
|
gcry_sexp_t rsa_pub;
|
||||||
#elif defined(HAVE_LIBCRYPTO)
|
#elif defined(HAVE_LIBCRYPTO)
|
||||||
|
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
DSA *dsa_pub;
|
||||||
|
RSA *rsa_pub;
|
||||||
|
#else /* OPENSSL_VERSION_NUMBER */
|
||||||
EVP_PKEY *key_pub;
|
EVP_PKEY *key_pub;
|
||||||
|
#endif
|
||||||
#elif defined(HAVE_LIBMBEDCRYPTO)
|
#elif defined(HAVE_LIBMBEDCRYPTO)
|
||||||
mbedtls_pk_context *rsa_pub;
|
mbedtls_pk_context *rsa_pub;
|
||||||
|
void *dsa_pub;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ssh_private_key_struct {
|
struct ssh_private_key_struct {
|
||||||
int type;
|
int type;
|
||||||
#if defined(HAVE_LIBGCRYPT)
|
#if defined(HAVE_LIBGCRYPT)
|
||||||
|
gcry_sexp_t dsa_priv;
|
||||||
gcry_sexp_t rsa_priv;
|
gcry_sexp_t rsa_priv;
|
||||||
#elif defined(HAVE_LIBCRYPTO)
|
#elif defined(HAVE_LIBCRYPTO)
|
||||||
|
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
DSA *dsa_priv;
|
||||||
|
RSA *rsa_priv;
|
||||||
|
#else
|
||||||
EVP_PKEY *key_priv;
|
EVP_PKEY *key_priv;
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
#elif defined(HAVE_LIBMBEDCRYPTO)
|
#elif defined(HAVE_LIBMBEDCRYPTO)
|
||||||
mbedtls_pk_context *rsa_priv;
|
mbedtls_pk_context *rsa_priv;
|
||||||
|
void *dsa_priv;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,13 @@
|
|||||||
|
|
||||||
#ifdef HAVE_LIBCRYPTO
|
#ifdef HAVE_LIBCRYPTO
|
||||||
|
|
||||||
#include "libssh/libssh.h"
|
#include <openssl/dsa.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
#include <openssl/md5.h>
|
#include <openssl/md5.h>
|
||||||
#include <openssl/hmac.h>
|
#include <openssl/hmac.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
#include <openssl/ec.h>
|
|
||||||
|
|
||||||
typedef EVP_MD_CTX* SHACTX;
|
typedef EVP_MD_CTX* SHACTX;
|
||||||
typedef EVP_MD_CTX* SHA256CTX;
|
typedef EVP_MD_CTX* SHA256CTX;
|
||||||
@@ -54,15 +53,8 @@ typedef EVP_MD_CTX* HMACCTX;
|
|||||||
#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE
|
#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Use ssh_crypto_free() to release memory allocated by bignum_bn2dec(),
|
|
||||||
bignum_bn2hex() and other functions that use crypto-library functions that
|
|
||||||
are documented to allocate memory that needs to be de-allocate with
|
|
||||||
OPENSSL_free. */
|
|
||||||
#define ssh_crypto_free(x) OPENSSL_free(x)
|
|
||||||
|
|
||||||
#include <openssl/bn.h>
|
#include <openssl/bn.h>
|
||||||
#include <openssl/opensslv.h>
|
#include <openssl/opensslv.h>
|
||||||
|
|
||||||
typedef BIGNUM* bignum;
|
typedef BIGNUM* bignum;
|
||||||
typedef const BIGNUM* const_bignum;
|
typedef const BIGNUM* const_bignum;
|
||||||
typedef BN_CTX* bignum_CTX;
|
typedef BN_CTX* bignum_CTX;
|
||||||
@@ -119,8 +111,6 @@ typedef BN_CTX* bignum_CTX;
|
|||||||
#define ssh_fips_mode() false
|
#define ssh_fips_mode() false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ssh_string pki_key_make_ecpoint_string(const EC_GROUP *g, const EC_POINT *p);
|
|
||||||
int pki_key_ecgroup_name_to_nid(const char *group);
|
|
||||||
#endif /* HAVE_LIBCRYPTO */
|
#endif /* HAVE_LIBCRYPTO */
|
||||||
|
|
||||||
#endif /* LIBCRYPTO_H_ */
|
#endif /* LIBCRYPTO_H_ */
|
||||||
|
|||||||
@@ -48,8 +48,6 @@ typedef gcry_md_hd_t HMACCTX;
|
|||||||
|
|
||||||
#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE
|
#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE
|
||||||
|
|
||||||
#define ssh_crypto_free(x) gcry_free(x)
|
|
||||||
|
|
||||||
typedef gcry_mpi_t bignum;
|
typedef gcry_mpi_t bignum;
|
||||||
typedef const struct gcry_mpi *const_bignum;
|
typedef const struct gcry_mpi *const_bignum;
|
||||||
typedef void* bignum_CTX;
|
typedef void* bignum_CTX;
|
||||||
|
|||||||
@@ -34,7 +34,6 @@
|
|||||||
#include <mbedtls/cipher.h>
|
#include <mbedtls/cipher.h>
|
||||||
#include <mbedtls/entropy.h>
|
#include <mbedtls/entropy.h>
|
||||||
#include <mbedtls/ctr_drbg.h>
|
#include <mbedtls/ctr_drbg.h>
|
||||||
#include <mbedtls/platform.h>
|
|
||||||
|
|
||||||
typedef mbedtls_md_context_t *SHACTX;
|
typedef mbedtls_md_context_t *SHACTX;
|
||||||
typedef mbedtls_md_context_t *SHA256CTX;
|
typedef mbedtls_md_context_t *SHA256CTX;
|
||||||
@@ -59,8 +58,6 @@ typedef mbedtls_md_context_t *HMACCTX;
|
|||||||
|
|
||||||
#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE
|
#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE
|
||||||
|
|
||||||
#define ssh_crypto_free(x) mbedtls_free(x)
|
|
||||||
|
|
||||||
typedef mbedtls_mpi *bignum;
|
typedef mbedtls_mpi *bignum;
|
||||||
typedef const mbedtls_mpi *const_bignum;
|
typedef const mbedtls_mpi *const_bignum;
|
||||||
typedef void* bignum_CTX;
|
typedef void* bignum_CTX;
|
||||||
@@ -81,7 +78,7 @@ extern "C" {
|
|||||||
|
|
||||||
bignum ssh_mbedcry_bn_new(void);
|
bignum ssh_mbedcry_bn_new(void);
|
||||||
void ssh_mbedcry_bn_free(bignum num);
|
void ssh_mbedcry_bn_free(bignum num);
|
||||||
char *ssh_mbedcry_bn2num(const_bignum num, int radix);
|
unsigned char *ssh_mbedcry_bn2num(const_bignum num, int radix);
|
||||||
int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom);
|
int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom);
|
||||||
int ssh_mbedcry_is_bit_set(bignum num, size_t pos);
|
int ssh_mbedcry_is_bit_set(bignum num, size_t pos);
|
||||||
int ssh_mbedcry_rand_range(bignum dest, bignum max);
|
int ssh_mbedcry_rand_range(bignum dest, bignum max);
|
||||||
@@ -107,7 +104,7 @@ int ssh_mbedcry_hex2bn(bignum *dest, char *data);
|
|||||||
} while(0)
|
} while(0)
|
||||||
#define bignum_bn2dec(num) ssh_mbedcry_bn2num(num, 10)
|
#define bignum_bn2dec(num) ssh_mbedcry_bn2num(num, 10)
|
||||||
#define bignum_dec2bn(data, bn) mbedtls_mpi_read_string(bn, 10, data)
|
#define bignum_dec2bn(data, bn) mbedtls_mpi_read_string(bn, 10, data)
|
||||||
#define bignum_bn2hex(num, dest) (*dest)=(unsigned char *)ssh_mbedcry_bn2num(num, 16)
|
#define bignum_bn2hex(num, dest) (*dest)=ssh_mbedcry_bn2num(num, 16)
|
||||||
#define bignum_hex2bn(data, dest) ssh_mbedcry_hex2bn(dest, data)
|
#define bignum_hex2bn(data, dest) ssh_mbedcry_hex2bn(dest, data)
|
||||||
#define bignum_rand(rnd, bits) ssh_mbedcry_rand((rnd), (bits), 0, 1)
|
#define bignum_rand(rnd, bits) ssh_mbedcry_rand((rnd), (bits), 0, 1)
|
||||||
#define bignum_rand_range(rnd, max) ssh_mbedcry_rand_range(rnd, max)
|
#define bignum_rand_range(rnd, max) ssh_mbedcry_rand_range(rnd, max)
|
||||||
@@ -129,7 +126,7 @@ int ssh_mbedcry_hex2bn(bignum *dest, char *data);
|
|||||||
*(dest) = bignum_new(); \
|
*(dest) = bignum_new(); \
|
||||||
} \
|
} \
|
||||||
if (*(dest) != NULL) { \
|
if (*(dest) != NULL) { \
|
||||||
mbedtls_mpi_copy(*(dest), orig); \
|
mbedtls_mpi_copy(orig, *(dest)); \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the SSH Library
|
* This file is part of the SSH Library
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003-2024 by Aris Adamantiadis and the libssh team
|
* Copyright (c) 2003-2023 by Aris Adamantiadis and the libssh team
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@@ -50,13 +50,18 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#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;
|
typedef int mode_t;
|
||||||
#else /* _MSC_VER */
|
#else /* _MSC_VER */
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#endif /* _MSC_VER */
|
#endif /* _MSC_VER */
|
||||||
|
|
||||||
@@ -191,8 +196,7 @@ enum ssh_global_requests_e {
|
|||||||
SSH_GLOBAL_REQUEST_UNKNOWN=0,
|
SSH_GLOBAL_REQUEST_UNKNOWN=0,
|
||||||
SSH_GLOBAL_REQUEST_TCPIP_FORWARD,
|
SSH_GLOBAL_REQUEST_TCPIP_FORWARD,
|
||||||
SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD,
|
SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD,
|
||||||
SSH_GLOBAL_REQUEST_KEEPALIVE,
|
SSH_GLOBAL_REQUEST_KEEPALIVE
|
||||||
SSH_GLOBAL_REQUEST_NO_MORE_SESSIONS
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ssh_publickey_state_e {
|
enum ssh_publickey_state_e {
|
||||||
@@ -273,12 +277,12 @@ enum ssh_error_types_e {
|
|||||||
/* some types for keys */
|
/* some types for keys */
|
||||||
enum ssh_keytypes_e{
|
enum ssh_keytypes_e{
|
||||||
SSH_KEYTYPE_UNKNOWN=0,
|
SSH_KEYTYPE_UNKNOWN=0,
|
||||||
SSH_KEYTYPE_DSS=1, /* deprecated */
|
SSH_KEYTYPE_DSS=1,
|
||||||
SSH_KEYTYPE_RSA,
|
SSH_KEYTYPE_RSA,
|
||||||
SSH_KEYTYPE_RSA1,
|
SSH_KEYTYPE_RSA1,
|
||||||
SSH_KEYTYPE_ECDSA, /* deprecated */
|
SSH_KEYTYPE_ECDSA, /* deprecated */
|
||||||
SSH_KEYTYPE_ED25519,
|
SSH_KEYTYPE_ED25519,
|
||||||
SSH_KEYTYPE_DSS_CERT01, /* deprecated */
|
SSH_KEYTYPE_DSS_CERT01,
|
||||||
SSH_KEYTYPE_RSA_CERT01,
|
SSH_KEYTYPE_RSA_CERT01,
|
||||||
SSH_KEYTYPE_ECDSA_P256,
|
SSH_KEYTYPE_ECDSA_P256,
|
||||||
SSH_KEYTYPE_ECDSA_P384,
|
SSH_KEYTYPE_ECDSA_P384,
|
||||||
@@ -295,8 +299,7 @@ enum ssh_keytypes_e{
|
|||||||
|
|
||||||
enum ssh_keycmp_e {
|
enum ssh_keycmp_e {
|
||||||
SSH_KEY_CMP_PUBLIC = 0,
|
SSH_KEY_CMP_PUBLIC = 0,
|
||||||
SSH_KEY_CMP_PRIVATE = 1,
|
SSH_KEY_CMP_PRIVATE
|
||||||
SSH_KEY_CMP_CERTIFICATE = 2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SSH_ADDRSTRLEN 46
|
#define SSH_ADDRSTRLEN 46
|
||||||
@@ -325,16 +328,16 @@ enum {
|
|||||||
/** No logging at all
|
/** No logging at all
|
||||||
*/
|
*/
|
||||||
SSH_LOG_NOLOG=0,
|
SSH_LOG_NOLOG=0,
|
||||||
/** Only unrecoverable errors
|
/** Only warnings
|
||||||
*/
|
*/
|
||||||
SSH_LOG_WARNING,
|
SSH_LOG_WARNING,
|
||||||
/** Information for the users
|
/** High level protocol information
|
||||||
*/
|
*/
|
||||||
SSH_LOG_PROTOCOL,
|
SSH_LOG_PROTOCOL,
|
||||||
/** Debug information, to see what is going on
|
/** Lower level protocol infomations, packet level
|
||||||
*/
|
*/
|
||||||
SSH_LOG_PACKET,
|
SSH_LOG_PACKET,
|
||||||
/** Trace information and recoverable error messages
|
/** Every function path
|
||||||
*/
|
*/
|
||||||
SSH_LOG_FUNCTIONS
|
SSH_LOG_FUNCTIONS
|
||||||
};
|
};
|
||||||
@@ -350,7 +353,7 @@ enum {
|
|||||||
|
|
||||||
/** No logging at all */
|
/** No logging at all */
|
||||||
#define SSH_LOG_NONE 0
|
#define SSH_LOG_NONE 0
|
||||||
/** Show only fatal warnings */
|
/** Show only warnings */
|
||||||
#define SSH_LOG_WARN 1
|
#define SSH_LOG_WARN 1
|
||||||
/** Get some information what's going on */
|
/** Get some information what's going on */
|
||||||
#define SSH_LOG_INFO 2
|
#define SSH_LOG_INFO 2
|
||||||
@@ -361,64 +364,50 @@ enum {
|
|||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
enum ssh_control_master_options_e {
|
|
||||||
SSH_CONTROL_MASTER_NO,
|
|
||||||
SSH_CONTROL_MASTER_AUTO,
|
|
||||||
SSH_CONTROL_MASTER_YES,
|
|
||||||
SSH_CONTROL_MASTER_ASK,
|
|
||||||
SSH_CONTROL_MASTER_AUTOASK
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ssh_options_e {
|
enum ssh_options_e {
|
||||||
SSH_OPTIONS_HOST,
|
SSH_OPTIONS_HOST,
|
||||||
SSH_OPTIONS_PORT,
|
SSH_OPTIONS_PORT,
|
||||||
SSH_OPTIONS_PORT_STR,
|
SSH_OPTIONS_PORT_STR,
|
||||||
SSH_OPTIONS_FD,
|
SSH_OPTIONS_FD,
|
||||||
SSH_OPTIONS_USER,
|
SSH_OPTIONS_USER,
|
||||||
SSH_OPTIONS_SSH_DIR,
|
SSH_OPTIONS_SSH_DIR,
|
||||||
SSH_OPTIONS_IDENTITY,
|
SSH_OPTIONS_IDENTITY,
|
||||||
SSH_OPTIONS_ADD_IDENTITY,
|
SSH_OPTIONS_ADD_IDENTITY,
|
||||||
SSH_OPTIONS_KNOWNHOSTS,
|
SSH_OPTIONS_KNOWNHOSTS,
|
||||||
SSH_OPTIONS_TIMEOUT,
|
SSH_OPTIONS_TIMEOUT,
|
||||||
SSH_OPTIONS_TIMEOUT_USEC,
|
SSH_OPTIONS_TIMEOUT_USEC,
|
||||||
SSH_OPTIONS_SSH1,
|
SSH_OPTIONS_SSH1,
|
||||||
SSH_OPTIONS_SSH2,
|
SSH_OPTIONS_SSH2,
|
||||||
SSH_OPTIONS_LOG_VERBOSITY,
|
SSH_OPTIONS_LOG_VERBOSITY,
|
||||||
SSH_OPTIONS_LOG_VERBOSITY_STR,
|
SSH_OPTIONS_LOG_VERBOSITY_STR,
|
||||||
SSH_OPTIONS_CIPHERS_C_S,
|
SSH_OPTIONS_CIPHERS_C_S,
|
||||||
SSH_OPTIONS_CIPHERS_S_C,
|
SSH_OPTIONS_CIPHERS_S_C,
|
||||||
SSH_OPTIONS_COMPRESSION_C_S,
|
SSH_OPTIONS_COMPRESSION_C_S,
|
||||||
SSH_OPTIONS_COMPRESSION_S_C,
|
SSH_OPTIONS_COMPRESSION_S_C,
|
||||||
SSH_OPTIONS_PROXYCOMMAND,
|
SSH_OPTIONS_PROXYCOMMAND,
|
||||||
SSH_OPTIONS_BINDADDR,
|
SSH_OPTIONS_BINDADDR,
|
||||||
SSH_OPTIONS_STRICTHOSTKEYCHECK,
|
SSH_OPTIONS_STRICTHOSTKEYCHECK,
|
||||||
SSH_OPTIONS_COMPRESSION,
|
SSH_OPTIONS_COMPRESSION,
|
||||||
SSH_OPTIONS_COMPRESSION_LEVEL,
|
SSH_OPTIONS_COMPRESSION_LEVEL,
|
||||||
SSH_OPTIONS_KEY_EXCHANGE,
|
SSH_OPTIONS_KEY_EXCHANGE,
|
||||||
SSH_OPTIONS_HOSTKEYS,
|
SSH_OPTIONS_HOSTKEYS,
|
||||||
SSH_OPTIONS_GSSAPI_SERVER_IDENTITY,
|
SSH_OPTIONS_GSSAPI_SERVER_IDENTITY,
|
||||||
SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY,
|
SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY,
|
||||||
SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS,
|
SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS,
|
||||||
SSH_OPTIONS_HMAC_C_S,
|
SSH_OPTIONS_HMAC_C_S,
|
||||||
SSH_OPTIONS_HMAC_S_C,
|
SSH_OPTIONS_HMAC_S_C,
|
||||||
SSH_OPTIONS_PASSWORD_AUTH,
|
SSH_OPTIONS_PASSWORD_AUTH,
|
||||||
SSH_OPTIONS_PUBKEY_AUTH,
|
SSH_OPTIONS_PUBKEY_AUTH,
|
||||||
SSH_OPTIONS_KBDINT_AUTH,
|
SSH_OPTIONS_KBDINT_AUTH,
|
||||||
SSH_OPTIONS_GSSAPI_AUTH,
|
SSH_OPTIONS_GSSAPI_AUTH,
|
||||||
SSH_OPTIONS_GLOBAL_KNOWNHOSTS,
|
SSH_OPTIONS_GLOBAL_KNOWNHOSTS,
|
||||||
SSH_OPTIONS_NODELAY,
|
SSH_OPTIONS_NODELAY,
|
||||||
SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES,
|
SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES,
|
||||||
SSH_OPTIONS_PROCESS_CONFIG,
|
SSH_OPTIONS_PROCESS_CONFIG,
|
||||||
SSH_OPTIONS_REKEY_DATA,
|
SSH_OPTIONS_REKEY_DATA,
|
||||||
SSH_OPTIONS_REKEY_TIME,
|
SSH_OPTIONS_REKEY_TIME,
|
||||||
SSH_OPTIONS_RSA_MIN_SIZE,
|
SSH_OPTIONS_RSA_MIN_SIZE,
|
||||||
SSH_OPTIONS_IDENTITY_AGENT,
|
SSH_OPTIONS_IDENTITY_AGENT,
|
||||||
SSH_OPTIONS_IDENTITIES_ONLY,
|
|
||||||
SSH_OPTIONS_CONTROL_MASTER,
|
|
||||||
SSH_OPTIONS_CONTROL_PATH,
|
|
||||||
SSH_OPTIONS_CERTIFICATE,
|
|
||||||
SSH_OPTIONS_PROXYJUMP,
|
|
||||||
SSH_OPTIONS_PROXYJUMP_CB_LIST_APPEND,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -456,19 +445,8 @@ LIBSSH_API int ssh_blocking_flush(ssh_session session, int timeout);
|
|||||||
LIBSSH_API ssh_channel ssh_channel_accept_x11(ssh_channel channel, int timeout_ms);
|
LIBSSH_API ssh_channel ssh_channel_accept_x11(ssh_channel channel, int timeout_ms);
|
||||||
LIBSSH_API int ssh_channel_change_pty_size(ssh_channel channel,int cols,int rows);
|
LIBSSH_API int ssh_channel_change_pty_size(ssh_channel channel,int cols,int rows);
|
||||||
LIBSSH_API int ssh_channel_close(ssh_channel channel);
|
LIBSSH_API int ssh_channel_close(ssh_channel channel);
|
||||||
#define SSH_CHANNEL_FREE(x) \
|
|
||||||
do { \
|
|
||||||
if ((x) != NULL) { \
|
|
||||||
ssh_channel_free(x); \
|
|
||||||
(x) = NULL; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
LIBSSH_API void ssh_channel_free(ssh_channel channel);
|
LIBSSH_API void ssh_channel_free(ssh_channel channel);
|
||||||
LIBSSH_API int ssh_channel_get_exit_state(ssh_channel channel,
|
LIBSSH_API int ssh_channel_get_exit_status(ssh_channel channel);
|
||||||
uint32_t *pexit_code,
|
|
||||||
char **pexit_signal,
|
|
||||||
int *pcore_dumped);
|
|
||||||
SSH_DEPRECATED LIBSSH_API int ssh_channel_get_exit_status(ssh_channel channel);
|
|
||||||
LIBSSH_API ssh_session ssh_channel_get_session(ssh_channel channel);
|
LIBSSH_API ssh_session ssh_channel_get_session(ssh_channel channel);
|
||||||
LIBSSH_API int ssh_channel_is_closed(ssh_channel channel);
|
LIBSSH_API int ssh_channel_is_closed(ssh_channel channel);
|
||||||
LIBSSH_API int ssh_channel_is_eof(ssh_channel channel);
|
LIBSSH_API int ssh_channel_is_eof(ssh_channel channel);
|
||||||
@@ -492,8 +470,6 @@ LIBSSH_API int ssh_channel_request_exec(ssh_channel channel, const char *cmd);
|
|||||||
LIBSSH_API int ssh_channel_request_pty(ssh_channel channel);
|
LIBSSH_API int ssh_channel_request_pty(ssh_channel channel);
|
||||||
LIBSSH_API int ssh_channel_request_pty_size(ssh_channel channel, const char *term,
|
LIBSSH_API int ssh_channel_request_pty_size(ssh_channel channel, const char *term,
|
||||||
int cols, int rows);
|
int cols, int rows);
|
||||||
LIBSSH_API int ssh_channel_request_pty_size_modes(ssh_channel channel, const char *term,
|
|
||||||
int cols, int rows, const unsigned char* modes, size_t modes_len);
|
|
||||||
LIBSSH_API int ssh_channel_request_shell(ssh_channel channel);
|
LIBSSH_API int ssh_channel_request_shell(ssh_channel channel);
|
||||||
LIBSSH_API int ssh_channel_request_send_signal(ssh_channel channel, const char *signum);
|
LIBSSH_API int ssh_channel_request_send_signal(ssh_channel channel, const char *signum);
|
||||||
LIBSSH_API int ssh_channel_request_send_break(ssh_channel channel, uint32_t length);
|
LIBSSH_API int ssh_channel_request_send_break(ssh_channel channel, uint32_t length);
|
||||||
@@ -557,7 +533,6 @@ 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_hexa(const unsigned char *what, size_t len);
|
||||||
LIBSSH_API char *ssh_get_issue_banner(ssh_session session);
|
LIBSSH_API char *ssh_get_issue_banner(ssh_session session);
|
||||||
LIBSSH_API int ssh_get_openssh_version(ssh_session session);
|
LIBSSH_API int ssh_get_openssh_version(ssh_session session);
|
||||||
LIBSSH_API int ssh_request_no_more_sessions(ssh_session session);
|
|
||||||
|
|
||||||
LIBSSH_API int ssh_get_server_publickey(ssh_session session, ssh_key *key);
|
LIBSSH_API int ssh_get_server_publickey(ssh_session session, ssh_key *key);
|
||||||
|
|
||||||
@@ -701,12 +676,6 @@ typedef int (*ssh_auth_callback) (const char *prompt, char *buf, size_t len,
|
|||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
enum ssh_file_format_e {
|
|
||||||
SSH_FILE_FORMAT_DEFAULT = 0,
|
|
||||||
SSH_FILE_FORMAT_OPENSSH,
|
|
||||||
SSH_FILE_FORMAT_PEM,
|
|
||||||
};
|
|
||||||
|
|
||||||
LIBSSH_API ssh_key ssh_key_new(void);
|
LIBSSH_API ssh_key ssh_key_new(void);
|
||||||
#define SSH_KEY_FREE(x) \
|
#define SSH_KEY_FREE(x) \
|
||||||
do { if ((x) != NULL) { ssh_key_free(x); x = NULL; } } while(0)
|
do { if ((x) != NULL) { ssh_key_free(x); x = NULL; } } while(0)
|
||||||
@@ -733,13 +702,6 @@ LIBSSH_API int ssh_pki_export_privkey_base64(const ssh_key privkey,
|
|||||||
ssh_auth_callback auth_fn,
|
ssh_auth_callback auth_fn,
|
||||||
void *auth_data,
|
void *auth_data,
|
||||||
char **b64_key);
|
char **b64_key);
|
||||||
LIBSSH_API int
|
|
||||||
ssh_pki_export_privkey_base64_format(const ssh_key privkey,
|
|
||||||
const char *passphrase,
|
|
||||||
ssh_auth_callback auth_fn,
|
|
||||||
void *auth_data,
|
|
||||||
char **b64_key,
|
|
||||||
enum ssh_file_format_e format);
|
|
||||||
LIBSSH_API int ssh_pki_import_privkey_file(const char *filename,
|
LIBSSH_API int ssh_pki_import_privkey_file(const char *filename,
|
||||||
const char *passphrase,
|
const char *passphrase,
|
||||||
ssh_auth_callback auth_fn,
|
ssh_auth_callback auth_fn,
|
||||||
@@ -750,13 +712,6 @@ LIBSSH_API int ssh_pki_export_privkey_file(const ssh_key privkey,
|
|||||||
ssh_auth_callback auth_fn,
|
ssh_auth_callback auth_fn,
|
||||||
void *auth_data,
|
void *auth_data,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
LIBSSH_API int
|
|
||||||
ssh_pki_export_privkey_file_format(const ssh_key privkey,
|
|
||||||
const char *passphrase,
|
|
||||||
ssh_auth_callback auth_fn,
|
|
||||||
void *auth_data,
|
|
||||||
const char *filename,
|
|
||||||
enum ssh_file_format_e format);
|
|
||||||
|
|
||||||
LIBSSH_API int ssh_pki_copy_cert_to_privkey(const ssh_key cert_key,
|
LIBSSH_API int ssh_pki_copy_cert_to_privkey(const ssh_key cert_key,
|
||||||
ssh_key privkey);
|
ssh_key privkey);
|
||||||
@@ -812,8 +767,10 @@ LIBSSH_API int ssh_userauth_try_publickey(ssh_session session,
|
|||||||
LIBSSH_API int ssh_userauth_publickey(ssh_session session,
|
LIBSSH_API int ssh_userauth_publickey(ssh_session session,
|
||||||
const char *username,
|
const char *username,
|
||||||
const ssh_key privkey);
|
const ssh_key privkey);
|
||||||
|
#ifndef _WIN32
|
||||||
LIBSSH_API int ssh_userauth_agent(ssh_session session,
|
LIBSSH_API int ssh_userauth_agent(ssh_session session,
|
||||||
const char *username);
|
const char *username);
|
||||||
|
#endif
|
||||||
LIBSSH_API int ssh_userauth_publickey_auto_get_current_identity(ssh_session session,
|
LIBSSH_API int ssh_userauth_publickey_auto_get_current_identity(ssh_session session,
|
||||||
char** value);
|
char** value);
|
||||||
LIBSSH_API int ssh_userauth_publickey_auto(ssh_session session,
|
LIBSSH_API int ssh_userauth_publickey_auto(ssh_session session,
|
||||||
|
|||||||
@@ -498,22 +498,8 @@ public:
|
|||||||
return_throwable;
|
return_throwable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
int getExitStatus(){
|
||||||
* @deprecated Please use getExitState()
|
return ssh_channel_get_exit_status(channel);
|
||||||
*/
|
|
||||||
int getExitStatus() {
|
|
||||||
uint32_t exit_status = (uint32_t)-1;
|
|
||||||
ssh_channel_get_exit_state(channel, &exit_status, NULL, NULL);
|
|
||||||
return exit_status;
|
|
||||||
}
|
|
||||||
void_throwable getExitState(uint32_t & pexit_code,
|
|
||||||
char **pexit_signal,
|
|
||||||
int & pcore_dumped) {
|
|
||||||
ssh_throw(ssh_channel_get_exit_state(channel,
|
|
||||||
&pexit_code,
|
|
||||||
pexit_signal,
|
|
||||||
&pcore_dumped));
|
|
||||||
return_throwable;
|
|
||||||
}
|
}
|
||||||
Session &getSession(){
|
Session &getSession(){
|
||||||
return *session;
|
return *session;
|
||||||
@@ -601,12 +587,9 @@ public:
|
|||||||
ssh_throw(err);
|
ssh_throw(err);
|
||||||
return_throwable;
|
return_throwable;
|
||||||
}
|
}
|
||||||
void_throwable requestPty(const char *term=NULL, int cols=0, int rows=0,
|
void_throwable requestPty(const char *term=NULL, int cols=0, int rows=0){
|
||||||
const unsigned char* modes=NULL, size_t modes_len=0){
|
|
||||||
int err;
|
int err;
|
||||||
if(term != NULL && cols != 0 && rows != 0 && modes != NULL)
|
if(term != NULL && cols != 0 && rows != 0)
|
||||||
err=ssh_channel_request_pty_size_modes(channel,term,cols,rows,modes,modes_len);
|
|
||||||
else if(term != NULL && cols != 0 && rows != 0)
|
|
||||||
err=ssh_channel_request_pty_size(channel,term,cols,rows);
|
err=ssh_channel_request_pty_size(channel,term,cols,rows);
|
||||||
else
|
else
|
||||||
err=ssh_channel_request_pty(channel);
|
err=ssh_channel_request_pty(channel);
|
||||||
|
|||||||
@@ -21,22 +21,6 @@
|
|||||||
#ifndef MISC_H_
|
#ifndef MISC_H_
|
||||||
#define MISC_H_
|
#define MISC_H_
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
|
|
||||||
# ifdef _MSC_VER
|
|
||||||
# ifndef _SSIZE_T_DEFINED
|
|
||||||
# undef ssize_t
|
|
||||||
# include <BaseTsd.h>
|
|
||||||
typedef _W64 SSIZE_T ssize_t;
|
|
||||||
# define _SSIZE_T_DEFINED
|
|
||||||
# endif /* _SSIZE_T_DEFINED */
|
|
||||||
# endif /* _MSC_VER */
|
|
||||||
|
|
||||||
#else
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -66,12 +50,6 @@ struct ssh_iterator {
|
|||||||
const void *data;
|
const void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ssh_jump_info_struct {
|
|
||||||
char *hostname;
|
|
||||||
char *username;
|
|
||||||
int port;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ssh_timestamp {
|
struct ssh_timestamp {
|
||||||
long seconds;
|
long seconds;
|
||||||
long useconds;
|
long useconds;
|
||||||
@@ -107,14 +85,13 @@ const void *_ssh_list_pop_head(struct ssh_list *list);
|
|||||||
#define ssh_list_pop_head(type, ssh_list)\
|
#define ssh_list_pop_head(type, ssh_list)\
|
||||||
((type)_ssh_list_pop_head(ssh_list))
|
((type)_ssh_list_pop_head(ssh_list))
|
||||||
|
|
||||||
#define SSH_LIST_FREE(x) \
|
|
||||||
do { if ((x) != NULL) { ssh_list_free(x); (x) = NULL; } } while(0)
|
|
||||||
|
|
||||||
int ssh_make_milliseconds(unsigned long sec, unsigned long usec);
|
int ssh_make_milliseconds(unsigned long sec, unsigned long usec);
|
||||||
void ssh_timestamp_init(struct ssh_timestamp *ts);
|
void ssh_timestamp_init(struct ssh_timestamp *ts);
|
||||||
int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout);
|
int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout);
|
||||||
int ssh_timeout_update(struct ssh_timestamp *ts, int timeout);
|
int ssh_timeout_update(struct ssh_timestamp *ts, int timeout);
|
||||||
|
|
||||||
|
int ssh_match_group(const char *group, const char *object);
|
||||||
|
|
||||||
void uint64_inc(unsigned char *counter);
|
void uint64_inc(unsigned char *counter);
|
||||||
|
|
||||||
void ssh_log_hexdump(const char *descr, const unsigned char *what, size_t len);
|
void ssh_log_hexdump(const char *descr, const unsigned char *what, size_t len);
|
||||||
@@ -127,14 +104,7 @@ int ssh_tmpname(char *name);
|
|||||||
|
|
||||||
char *ssh_strreplace(const char *src, const char *pattern, const char *repl);
|
char *ssh_strreplace(const char *src, const char *pattern, const char *repl);
|
||||||
|
|
||||||
ssize_t ssh_readn(int fd, void *buf, size_t nbytes);
|
|
||||||
ssize_t ssh_writen(int fd, const void *buf, size_t nbytes);
|
|
||||||
|
|
||||||
int ssh_check_hostname_syntax(const char *hostname);
|
int ssh_check_hostname_syntax(const char *hostname);
|
||||||
int ssh_check_username_syntax(const char *username);
|
|
||||||
|
|
||||||
void ssh_proxyjumps_free(struct ssh_list *proxy_jump_list);
|
|
||||||
bool ssh_libssh_proxy_jumps(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,12 +29,9 @@ int ssh_config_parse_file(ssh_session session, const char *filename);
|
|||||||
int ssh_config_parse_string(ssh_session session, const char *input);
|
int ssh_config_parse_string(ssh_session session, const char *input);
|
||||||
int ssh_options_set_algo(ssh_session session,
|
int ssh_options_set_algo(ssh_session session,
|
||||||
enum ssh_kex_types_e algo,
|
enum ssh_kex_types_e algo,
|
||||||
const char *list,
|
const char *list);
|
||||||
char **place);
|
|
||||||
int ssh_options_apply(ssh_session session);
|
int ssh_options_apply(ssh_session session);
|
||||||
|
|
||||||
char *ssh_options_get_algo(ssh_session session, enum ssh_kex_types_e algo);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#endif
|
#endif
|
||||||
#include "libssh/crypto.h"
|
#include "libssh/crypto.h"
|
||||||
#ifdef HAVE_LIBCRYPTO
|
#if defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_ED25519)
|
||||||
/* If using OpenSSL implementation, define the signature length which would be
|
/* If using OpenSSL implementation, define the signature length which would be
|
||||||
* defined in libssh/ed25519.h otherwise */
|
* defined in libssh/ed25519.h otherwise */
|
||||||
#define ED25519_SIG_LEN 64
|
#define ED25519_SIG_LEN 64
|
||||||
@@ -57,24 +57,40 @@ struct ssh_key_struct {
|
|||||||
const char *type_c; /* Don't free it ! it is static */
|
const char *type_c; /* Don't free it ! it is static */
|
||||||
int ecdsa_nid;
|
int ecdsa_nid;
|
||||||
#if defined(HAVE_LIBGCRYPT)
|
#if defined(HAVE_LIBGCRYPT)
|
||||||
|
gcry_sexp_t dsa;
|
||||||
gcry_sexp_t rsa;
|
gcry_sexp_t rsa;
|
||||||
gcry_sexp_t ecdsa;
|
gcry_sexp_t ecdsa;
|
||||||
#elif defined(HAVE_LIBMBEDCRYPTO)
|
#elif defined(HAVE_LIBMBEDCRYPTO)
|
||||||
mbedtls_pk_context *pk;
|
mbedtls_pk_context *rsa;
|
||||||
mbedtls_ecdsa_context *ecdsa;
|
mbedtls_ecdsa_context *ecdsa;
|
||||||
|
void *dsa;
|
||||||
#elif defined(HAVE_LIBCRYPTO)
|
#elif defined(HAVE_LIBCRYPTO)
|
||||||
|
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
DSA *dsa;
|
||||||
|
RSA *rsa;
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* Move into the #if above
|
||||||
|
*/
|
||||||
|
# if defined(HAVE_OPENSSL_ECC)
|
||||||
|
EC_KEY *ecdsa;
|
||||||
|
# else
|
||||||
|
void *ecdsa;
|
||||||
|
# endif /* HAVE_OPENSSL_EC_H */
|
||||||
/* This holds either ENGINE key for PKCS#11 support or just key in
|
/* This holds either ENGINE key for PKCS#11 support or just key in
|
||||||
* high-level format */
|
* high-level format required by OpenSSL 3.0 */
|
||||||
EVP_PKEY *key;
|
EVP_PKEY *key;
|
||||||
|
#endif /* HAVE_LIBGCRYPT */
|
||||||
|
#if defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_ED25519)
|
||||||
uint8_t *ed25519_pubkey;
|
uint8_t *ed25519_pubkey;
|
||||||
uint8_t *ed25519_privkey;
|
uint8_t *ed25519_privkey;
|
||||||
#endif /* HAVE_LIBGCRYPT */
|
#else
|
||||||
#ifndef HAVE_LIBCRYPTO
|
|
||||||
ed25519_pubkey *ed25519_pubkey;
|
ed25519_pubkey *ed25519_pubkey;
|
||||||
ed25519_privkey *ed25519_privkey;
|
ed25519_privkey *ed25519_privkey;
|
||||||
#endif /* HAVE_LIBCRYPTO */
|
#endif
|
||||||
ssh_string sk_application;
|
ssh_string sk_application;
|
||||||
ssh_buffer cert;
|
void *cert;
|
||||||
enum ssh_keytypes_e cert_type;
|
enum ssh_keytypes_e cert_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -83,15 +99,16 @@ struct ssh_signature_struct {
|
|||||||
enum ssh_digest_e hash_type;
|
enum ssh_digest_e hash_type;
|
||||||
const char *type_c;
|
const char *type_c;
|
||||||
#if defined(HAVE_LIBGCRYPT)
|
#if defined(HAVE_LIBGCRYPT)
|
||||||
|
gcry_sexp_t dsa_sig;
|
||||||
gcry_sexp_t rsa_sig;
|
gcry_sexp_t rsa_sig;
|
||||||
gcry_sexp_t ecdsa_sig;
|
gcry_sexp_t ecdsa_sig;
|
||||||
#elif defined(HAVE_LIBMBEDCRYPTO)
|
#elif defined(HAVE_LIBMBEDCRYPTO)
|
||||||
ssh_string rsa_sig;
|
ssh_string rsa_sig;
|
||||||
struct mbedtls_ecdsa_sig ecdsa_sig;
|
struct mbedtls_ecdsa_sig ecdsa_sig;
|
||||||
#endif /* HAVE_LIBGCRYPT */
|
#endif /* HAVE_LIBGCRYPT */
|
||||||
#ifndef HAVE_LIBCRYPTO
|
#if !defined(HAVE_LIBCRYPTO) || !defined(HAVE_OPENSSL_ED25519)
|
||||||
ed25519_signature *ed25519_sig;
|
ed25519_signature *ed25519_sig;
|
||||||
#endif /* HAVE_LIBGCRYPT */
|
#endif
|
||||||
ssh_string raw_sig;
|
ssh_string raw_sig;
|
||||||
|
|
||||||
/* Security Key specific additions */
|
/* Security Key specific additions */
|
||||||
@@ -121,11 +138,12 @@ enum ssh_digest_e ssh_key_hash_from_name(const char *name);
|
|||||||
((t) >= SSH_KEYTYPE_ECDSA_P256 && (t) <= SSH_KEYTYPE_ECDSA_P521)
|
((t) >= SSH_KEYTYPE_ECDSA_P256 && (t) <= SSH_KEYTYPE_ECDSA_P521)
|
||||||
|
|
||||||
#define is_cert_type(kt)\
|
#define is_cert_type(kt)\
|
||||||
((kt) == SSH_KEYTYPE_RSA_CERT01 ||\
|
((kt) == SSH_KEYTYPE_DSS_CERT01 ||\
|
||||||
(kt) == SSH_KEYTYPE_SK_ECDSA_CERT01 ||\
|
(kt) == SSH_KEYTYPE_RSA_CERT01 ||\
|
||||||
(kt) == SSH_KEYTYPE_SK_ED25519_CERT01 ||\
|
(kt) == SSH_KEYTYPE_SK_ECDSA_CERT01 ||\
|
||||||
((kt) >= SSH_KEYTYPE_ECDSA_P256_CERT01 &&\
|
(kt) == SSH_KEYTYPE_SK_ED25519_CERT01 ||\
|
||||||
(kt) <= SSH_KEYTYPE_ED25519_CERT01))
|
((kt) >= SSH_KEYTYPE_ECDSA_P256_CERT01 &&\
|
||||||
|
(kt) <= SSH_KEYTYPE_ED25519_CERT01))
|
||||||
|
|
||||||
/* SSH Signature Functions */
|
/* SSH Signature Functions */
|
||||||
ssh_signature ssh_signature_new(void);
|
ssh_signature ssh_signature_new(void);
|
||||||
@@ -153,10 +171,6 @@ int ssh_pki_import_pubkey_blob(const ssh_string key_blob,
|
|||||||
int ssh_pki_import_cert_blob(const ssh_string cert_blob,
|
int ssh_pki_import_cert_blob(const ssh_string cert_blob,
|
||||||
ssh_key *pkey);
|
ssh_key *pkey);
|
||||||
|
|
||||||
/* SSH Private Key Functions */
|
|
||||||
int ssh_pki_export_privkey_blob(const ssh_key key,
|
|
||||||
ssh_string *pblob);
|
|
||||||
|
|
||||||
|
|
||||||
/* SSH Signing Functions */
|
/* SSH Signing Functions */
|
||||||
ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf,
|
ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf,
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ int bcrypt_pbkdf(const char *pass,
|
|||||||
|
|
||||||
#define RSA_HEADER_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
|
#define RSA_HEADER_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
|
||||||
#define RSA_HEADER_END "-----END 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 ECDSA_HEADER_BEGIN "-----BEGIN EC PRIVATE KEY-----"
|
#define ECDSA_HEADER_BEGIN "-----BEGIN EC PRIVATE KEY-----"
|
||||||
#define ECDSA_HEADER_END "-----END EC PRIVATE KEY-----"
|
#define ECDSA_HEADER_END "-----END EC PRIVATE KEY-----"
|
||||||
#define OPENSSH_HEADER_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----"
|
#define OPENSSH_HEADER_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----"
|
||||||
@@ -63,6 +65,7 @@ enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
|
|||||||
/* SSH Key Functions */
|
/* SSH Key Functions */
|
||||||
ssh_key pki_key_dup(const ssh_key key, int demote);
|
ssh_key pki_key_dup(const ssh_key key, int demote);
|
||||||
int pki_key_generate_rsa(ssh_key key, int parameter);
|
int pki_key_generate_rsa(ssh_key key, int parameter);
|
||||||
|
int pki_key_generate_dss(ssh_key key, int parameter);
|
||||||
int pki_key_generate_ecdsa(ssh_key key, int parameter);
|
int pki_key_generate_ecdsa(ssh_key key, int parameter);
|
||||||
int pki_key_generate_ed25519(ssh_key key);
|
int pki_key_generate_ed25519(ssh_key key);
|
||||||
|
|
||||||
@@ -88,13 +91,24 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type,
|
|||||||
ssh_key *pkey);
|
ssh_key *pkey);
|
||||||
|
|
||||||
/* SSH Public Key Functions */
|
/* SSH Public Key Functions */
|
||||||
|
int pki_pubkey_build_dss(ssh_key key,
|
||||||
|
ssh_string p,
|
||||||
|
ssh_string q,
|
||||||
|
ssh_string g,
|
||||||
|
ssh_string pubkey);
|
||||||
int pki_pubkey_build_rsa(ssh_key key,
|
int pki_pubkey_build_rsa(ssh_key key,
|
||||||
ssh_string e,
|
ssh_string e,
|
||||||
ssh_string n);
|
ssh_string n);
|
||||||
int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e);
|
int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e);
|
||||||
ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type);
|
ssh_string pki_publickey_to_blob(const ssh_key key);
|
||||||
|
|
||||||
/* SSH Private Key Functions */
|
/* SSH Private Key Functions */
|
||||||
|
int pki_privkey_build_dss(ssh_key key,
|
||||||
|
ssh_string p,
|
||||||
|
ssh_string q,
|
||||||
|
ssh_string g,
|
||||||
|
ssh_string pubkey,
|
||||||
|
ssh_string privkey);
|
||||||
int pki_privkey_build_rsa(ssh_key key,
|
int pki_privkey_build_rsa(ssh_key key,
|
||||||
ssh_string n,
|
ssh_string n,
|
||||||
ssh_string e,
|
ssh_string e,
|
||||||
@@ -106,6 +120,7 @@ int pki_privkey_build_ecdsa(ssh_key key,
|
|||||||
int nid,
|
int nid,
|
||||||
ssh_string e,
|
ssh_string e,
|
||||||
ssh_string exp);
|
ssh_string exp);
|
||||||
|
ssh_string pki_publickey_to_blob(const ssh_key key);
|
||||||
|
|
||||||
/* SSH Signature Functions */
|
/* SSH Signature Functions */
|
||||||
ssh_signature pki_sign_data(const ssh_key privkey,
|
ssh_signature pki_sign_data(const ssh_key privkey,
|
||||||
@@ -131,18 +146,15 @@ ssh_signature pki_do_sign_hash(const ssh_key privkey,
|
|||||||
const unsigned char *hash,
|
const unsigned char *hash,
|
||||||
size_t hlen,
|
size_t hlen,
|
||||||
enum ssh_digest_e hash_type);
|
enum ssh_digest_e hash_type);
|
||||||
#ifndef HAVE_LIBCRYPTO
|
|
||||||
int pki_ed25519_sign(const ssh_key privkey, ssh_signature sig,
|
int pki_ed25519_sign(const ssh_key privkey, ssh_signature sig,
|
||||||
const unsigned char *hash, size_t hlen);
|
const unsigned char *hash, size_t hlen);
|
||||||
int pki_ed25519_verify(const ssh_key pubkey, ssh_signature sig,
|
int pki_ed25519_verify(const ssh_key pubkey, ssh_signature sig,
|
||||||
const unsigned char *hash, size_t hlen);
|
const unsigned char *hash, size_t hlen);
|
||||||
#endif /* HAVE_LIBCRYPTO */
|
|
||||||
int pki_ed25519_key_cmp(const ssh_key k1,
|
int pki_ed25519_key_cmp(const ssh_key k1,
|
||||||
const ssh_key k2,
|
const ssh_key k2,
|
||||||
enum ssh_keycmp_e what);
|
enum ssh_keycmp_e what);
|
||||||
int pki_ed25519_key_dup(ssh_key new_key, const ssh_key key);
|
int pki_ed25519_key_dup(ssh_key new_key, const ssh_key key);
|
||||||
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key);
|
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key);
|
||||||
int pki_ed25519_private_key_to_blob(ssh_buffer buffer, const ssh_key privkey);
|
|
||||||
ssh_string pki_ed25519_signature_to_blob(ssh_signature sig);
|
ssh_string pki_ed25519_signature_to_blob(ssh_signature sig);
|
||||||
int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob);
|
int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob);
|
||||||
int pki_privkey_build_ed25519(ssh_key key,
|
int pki_privkey_build_ed25519(ssh_key key,
|
||||||
|
|||||||
@@ -47,10 +47,6 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif /* !defined(HAVE_STRTOULL) */
|
#endif /* !defined(HAVE_STRTOULL) */
|
||||||
|
|
||||||
#ifdef HAVE_TERMIOS_H
|
|
||||||
#include <termios.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -166,20 +162,6 @@ int ssh_gettimeofday(struct timeval *__p, void *__t);
|
|||||||
|
|
||||||
#define _XCLOSESOCKET closesocket
|
#define _XCLOSESOCKET closesocket
|
||||||
|
|
||||||
# ifdef HAVE_IO_H
|
|
||||||
# include <io.h>
|
|
||||||
# undef open
|
|
||||||
# define open _open
|
|
||||||
# undef close
|
|
||||||
# define close _close
|
|
||||||
# undef read
|
|
||||||
# define read _read
|
|
||||||
# undef write
|
|
||||||
# define write _write
|
|
||||||
# undef unlink
|
|
||||||
# define unlink _unlink
|
|
||||||
# endif /* HAVE_IO_H */
|
|
||||||
|
|
||||||
#else /* _WIN32 */
|
#else /* _WIN32 */
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -274,10 +256,6 @@ void ssh_log_common(struct ssh_common_struct *common,
|
|||||||
const char *function,
|
const char *function,
|
||||||
const char *format, ...) PRINTF_ATTRIBUTE(4, 5);
|
const char *format, ...) PRINTF_ATTRIBUTE(4, 5);
|
||||||
|
|
||||||
void _ssh_remove_legacy_log_cb(void);
|
|
||||||
|
|
||||||
/* log.c */
|
|
||||||
void _ssh_reset_log_cb(void);
|
|
||||||
|
|
||||||
/* ERROR HANDLING */
|
/* ERROR HANDLING */
|
||||||
|
|
||||||
@@ -312,7 +290,6 @@ int ssh_auth_reply_success(ssh_session session, int partial);
|
|||||||
/* client.c */
|
/* client.c */
|
||||||
|
|
||||||
int ssh_send_banner(ssh_session session, int is_server);
|
int ssh_send_banner(ssh_session session, int is_server);
|
||||||
void ssh_session_socket_close(ssh_session session);
|
|
||||||
|
|
||||||
/* connect.c */
|
/* connect.c */
|
||||||
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||||
@@ -330,12 +307,6 @@ int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen);
|
|||||||
int match_pattern_list(const char *string, const char *pattern,
|
int match_pattern_list(const char *string, const char *pattern,
|
||||||
size_t len, int dolower);
|
size_t len, int dolower);
|
||||||
int match_hostname(const char *host, const char *pattern, unsigned int len);
|
int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||||
#ifndef _WIN32
|
|
||||||
int match_cidr_address_list(const char *address,
|
|
||||||
const char *addrlist,
|
|
||||||
int sa_family);
|
|
||||||
#endif
|
|
||||||
int match_group(const char *group, const char *object);
|
|
||||||
|
|
||||||
/* connector.c */
|
/* connector.c */
|
||||||
int ssh_connector_set_event(ssh_connector connector, ssh_event event);
|
int ssh_connector_set_event(ssh_connector connector, ssh_event event);
|
||||||
@@ -467,10 +438,6 @@ bool is_ssh_initialized(void);
|
|||||||
#define SSH_ERRNO_MSG_MAX 1024
|
#define SSH_ERRNO_MSG_MAX 1024
|
||||||
char *ssh_strerror(int err_num, char *buf, size_t buflen);
|
char *ssh_strerror(int err_num, char *buf, size_t buflen);
|
||||||
|
|
||||||
/** 55 defined options (5 bytes each) + terminator */
|
|
||||||
#define SSH_TTY_MODES_MAX_BUFSIZE (55 * 5 + 1)
|
|
||||||
int encode_current_tty_opts(unsigned char *buf, size_t buflen);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -36,29 +36,28 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum ssh_bind_options_e {
|
enum ssh_bind_options_e {
|
||||||
SSH_BIND_OPTIONS_BINDADDR,
|
SSH_BIND_OPTIONS_BINDADDR,
|
||||||
SSH_BIND_OPTIONS_BINDPORT,
|
SSH_BIND_OPTIONS_BINDPORT,
|
||||||
SSH_BIND_OPTIONS_BINDPORT_STR,
|
SSH_BIND_OPTIONS_BINDPORT_STR,
|
||||||
SSH_BIND_OPTIONS_HOSTKEY,
|
SSH_BIND_OPTIONS_HOSTKEY,
|
||||||
SSH_BIND_OPTIONS_DSAKEY, /* deprecated */
|
SSH_BIND_OPTIONS_DSAKEY,
|
||||||
SSH_BIND_OPTIONS_RSAKEY, /* deprecated */
|
SSH_BIND_OPTIONS_RSAKEY,
|
||||||
SSH_BIND_OPTIONS_BANNER,
|
SSH_BIND_OPTIONS_BANNER,
|
||||||
SSH_BIND_OPTIONS_LOG_VERBOSITY,
|
SSH_BIND_OPTIONS_LOG_VERBOSITY,
|
||||||
SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
|
SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
|
||||||
SSH_BIND_OPTIONS_ECDSAKEY, /* deprecated */
|
SSH_BIND_OPTIONS_ECDSAKEY,
|
||||||
SSH_BIND_OPTIONS_IMPORT_KEY,
|
SSH_BIND_OPTIONS_IMPORT_KEY,
|
||||||
SSH_BIND_OPTIONS_KEY_EXCHANGE,
|
SSH_BIND_OPTIONS_KEY_EXCHANGE,
|
||||||
SSH_BIND_OPTIONS_CIPHERS_C_S,
|
SSH_BIND_OPTIONS_CIPHERS_C_S,
|
||||||
SSH_BIND_OPTIONS_CIPHERS_S_C,
|
SSH_BIND_OPTIONS_CIPHERS_S_C,
|
||||||
SSH_BIND_OPTIONS_HMAC_C_S,
|
SSH_BIND_OPTIONS_HMAC_C_S,
|
||||||
SSH_BIND_OPTIONS_HMAC_S_C,
|
SSH_BIND_OPTIONS_HMAC_S_C,
|
||||||
SSH_BIND_OPTIONS_CONFIG_DIR,
|
SSH_BIND_OPTIONS_CONFIG_DIR,
|
||||||
SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES,
|
SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||||
SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS,
|
SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS,
|
||||||
SSH_BIND_OPTIONS_PROCESS_CONFIG,
|
SSH_BIND_OPTIONS_PROCESS_CONFIG,
|
||||||
SSH_BIND_OPTIONS_MODULI,
|
SSH_BIND_OPTIONS_MODULI,
|
||||||
SSH_BIND_OPTIONS_RSA_MIN_SIZE,
|
SSH_BIND_OPTIONS_RSA_MIN_SIZE,
|
||||||
SSH_BIND_OPTIONS_IMPORT_KEY_STR,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct ssh_bind_struct* ssh_bind;
|
typedef struct ssh_bind_struct* ssh_bind;
|
||||||
@@ -223,9 +222,6 @@ LIBSSH_API int ssh_server_init_kex(ssh_session session);
|
|||||||
/**
|
/**
|
||||||
* @brief Free a ssh servers bind.
|
* @brief Free a ssh servers bind.
|
||||||
*
|
*
|
||||||
* Note that this will also free options that have been set on the bind,
|
|
||||||
* including keys set with SSH_BIND_OPTIONS_IMPORT_KEY.
|
|
||||||
*
|
|
||||||
* @param ssh_bind_o The ssh server bind to free.
|
* @param ssh_bind_o The ssh server bind to free.
|
||||||
*/
|
*/
|
||||||
LIBSSH_API void ssh_bind_free(ssh_bind ssh_bind_o);
|
LIBSSH_API void ssh_bind_free(ssh_bind ssh_bind_o);
|
||||||
@@ -296,7 +292,7 @@ LIBSSH_API const char *ssh_message_auth_user(ssh_message msg);
|
|||||||
*
|
*
|
||||||
* @param[in] msg The message to get the password from.
|
* @param[in] msg The message to get the password from.
|
||||||
*
|
*
|
||||||
* @return The password or NULL if an error occurred.
|
* @return The username or NULL if an error occurred.
|
||||||
*
|
*
|
||||||
* @see ssh_message_get()
|
* @see ssh_message_get()
|
||||||
* @see ssh_message_type()
|
* @see ssh_message_type()
|
||||||
|
|||||||
@@ -71,18 +71,15 @@ enum ssh_pending_call_e {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* libssh calls may block an undefined amount of time */
|
/* libssh calls may block an undefined amount of time */
|
||||||
#define SSH_SESSION_FLAG_BLOCKING 0x0001
|
#define SSH_SESSION_FLAG_BLOCKING 1
|
||||||
|
|
||||||
/* Client successfully authenticated */
|
/* Client successfully authenticated */
|
||||||
#define SSH_SESSION_FLAG_AUTHENTICATED 0x0002
|
#define SSH_SESSION_FLAG_AUTHENTICATED 2
|
||||||
|
|
||||||
/* Do not accept new session channels (no-more-sessions@openssh.com) */
|
|
||||||
#define SSH_SESSION_FLAG_NO_MORE_SESSIONS 0x0004
|
|
||||||
|
|
||||||
/* The KEXINIT message can be sent first by either of the parties so this flag
|
/* The KEXINIT message can be sent first by either of the parties so this flag
|
||||||
* indicates that the message was already sent to make sure it is sent and avoid
|
* indicates that the message was already sent to make sure it is sent and avoid
|
||||||
* sending it twice during key exchange to simplify the state machine. */
|
* sending it twice during key exchange to simplify the state machine. */
|
||||||
#define SSH_SESSION_FLAG_KEXINIT_SENT 0x0008
|
#define SSH_SESSION_FLAG_KEXINIT_SENT 4
|
||||||
|
|
||||||
/* The current SSH2 session implements the "strict KEX" feature and should behave
|
/* The current SSH2 session implements the "strict KEX" feature and should behave
|
||||||
* differently on SSH2_MSG_NEWKEYS. */
|
* differently on SSH2_MSG_NEWKEYS. */
|
||||||
@@ -112,7 +109,6 @@ enum ssh_pending_call_e {
|
|||||||
#define SSH_OPT_EXP_FLAG_GLOBAL_KNOWNHOSTS 0x2
|
#define SSH_OPT_EXP_FLAG_GLOBAL_KNOWNHOSTS 0x2
|
||||||
#define SSH_OPT_EXP_FLAG_PROXYCOMMAND 0x4
|
#define SSH_OPT_EXP_FLAG_PROXYCOMMAND 0x4
|
||||||
#define SSH_OPT_EXP_FLAG_IDENTITY 0x8
|
#define SSH_OPT_EXP_FLAG_IDENTITY 0x8
|
||||||
#define SSH_OPT_EXP_FLAG_CONTROL_PATH 0x10
|
|
||||||
|
|
||||||
/* extensions flags */
|
/* extensions flags */
|
||||||
/* negotiation enabled */
|
/* negotiation enabled */
|
||||||
@@ -140,7 +136,6 @@ struct ssh_session_struct {
|
|||||||
uint32_t send_seq;
|
uint32_t send_seq;
|
||||||
uint32_t recv_seq;
|
uint32_t recv_seq;
|
||||||
struct ssh_timestamp last_rekey_time;
|
struct ssh_timestamp last_rekey_time;
|
||||||
bool proxy_root;
|
|
||||||
|
|
||||||
int connected;
|
int connected;
|
||||||
/* !=0 when the user got a session handle */
|
/* !=0 when the user got a session handle */
|
||||||
@@ -213,6 +208,7 @@ struct ssh_session_struct {
|
|||||||
/* server host keys */
|
/* server host keys */
|
||||||
struct {
|
struct {
|
||||||
ssh_key rsa_key;
|
ssh_key rsa_key;
|
||||||
|
ssh_key dsa_key;
|
||||||
ssh_key ecdsa_key;
|
ssh_key ecdsa_key;
|
||||||
ssh_key ed25519_key;
|
ssh_key ed25519_key;
|
||||||
/* The type of host key wanted by client */
|
/* The type of host key wanted by client */
|
||||||
@@ -238,10 +234,6 @@ struct ssh_session_struct {
|
|||||||
struct {
|
struct {
|
||||||
struct ssh_list *identity;
|
struct ssh_list *identity;
|
||||||
struct ssh_list *identity_non_exp;
|
struct ssh_list *identity_non_exp;
|
||||||
struct ssh_list *certificate;
|
|
||||||
struct ssh_list *certificate_non_exp;
|
|
||||||
struct ssh_list *proxy_jumps;
|
|
||||||
struct ssh_list *proxy_jumps_user_cb;
|
|
||||||
char *username;
|
char *username;
|
||||||
char *host;
|
char *host;
|
||||||
char *bindaddr; /* bind the client to an ip addr */
|
char *bindaddr; /* bind the client to an ip addr */
|
||||||
@@ -251,6 +243,8 @@ struct ssh_session_struct {
|
|||||||
char *wanted_methods[SSH_KEX_METHODS];
|
char *wanted_methods[SSH_KEX_METHODS];
|
||||||
char *pubkey_accepted_types;
|
char *pubkey_accepted_types;
|
||||||
char *ProxyCommand;
|
char *ProxyCommand;
|
||||||
|
char *custombanner;
|
||||||
|
char *moduli_file;
|
||||||
char *agent_socket;
|
char *agent_socket;
|
||||||
unsigned long timeout; /* seconds */
|
unsigned long timeout; /* seconds */
|
||||||
unsigned long timeout_usec;
|
unsigned long timeout_usec;
|
||||||
@@ -269,17 +263,7 @@ struct ssh_session_struct {
|
|||||||
uint64_t rekey_data;
|
uint64_t rekey_data;
|
||||||
uint32_t rekey_time;
|
uint32_t rekey_time;
|
||||||
int rsa_min_size;
|
int rsa_min_size;
|
||||||
bool identities_only;
|
|
||||||
int control_master;
|
|
||||||
char *control_path;
|
|
||||||
} opts;
|
} opts;
|
||||||
|
|
||||||
/* server options */
|
|
||||||
struct {
|
|
||||||
char *custombanner;
|
|
||||||
char *moduli_file;
|
|
||||||
} server_opts;
|
|
||||||
|
|
||||||
/* counters */
|
/* counters */
|
||||||
ssh_counter socket_counter;
|
ssh_counter socket_counter;
|
||||||
ssh_counter raw_counter;
|
ssh_counter raw_counter;
|
||||||
|
|||||||
@@ -77,8 +77,6 @@ typedef struct sftp_request_queue_struct* sftp_request_queue;
|
|||||||
typedef struct sftp_session_struct* sftp_session;
|
typedef struct sftp_session_struct* sftp_session;
|
||||||
typedef struct sftp_status_message_struct* sftp_status_message;
|
typedef struct sftp_status_message_struct* sftp_status_message;
|
||||||
typedef struct sftp_statvfs_struct* sftp_statvfs_t;
|
typedef struct sftp_statvfs_struct* sftp_statvfs_t;
|
||||||
typedef struct sftp_limits_struct* sftp_limits_t;
|
|
||||||
typedef struct sftp_aio_struct* sftp_aio;
|
|
||||||
|
|
||||||
struct sftp_session_struct {
|
struct sftp_session_struct {
|
||||||
ssh_session session;
|
ssh_session session;
|
||||||
@@ -92,7 +90,6 @@ struct sftp_session_struct {
|
|||||||
void **handles;
|
void **handles;
|
||||||
sftp_ext ext;
|
sftp_ext ext;
|
||||||
sftp_packet read_packet;
|
sftp_packet read_packet;
|
||||||
sftp_limits_t limits;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sftp_packet_struct {
|
struct sftp_packet_struct {
|
||||||
@@ -203,16 +200,6 @@ struct sftp_statvfs_struct {
|
|||||||
uint64_t f_namemax; /** maximum filename length */
|
uint64_t f_namemax; /** maximum filename length */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief SFTP limits structure.
|
|
||||||
*/
|
|
||||||
struct sftp_limits_struct {
|
|
||||||
uint64_t max_packet_length; /** maximum number of bytes in a single sftp packet */
|
|
||||||
uint64_t max_read_length; /** maximum length in a SSH_FXP_READ packet */
|
|
||||||
uint64_t max_write_length; /** maximum length in a SSH_FXP_WRITE packet */
|
|
||||||
uint64_t max_open_handles; /** maximum number of active handles allowed by server */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a new sftp session.
|
* @brief Creates a new sftp session.
|
||||||
*
|
*
|
||||||
@@ -489,18 +476,13 @@ LIBSSH_API void sftp_file_set_blocking(sftp_file handle);
|
|||||||
/**
|
/**
|
||||||
* @brief Read from a file using an opened sftp file handle.
|
* @brief Read from a file using an opened sftp file handle.
|
||||||
*
|
*
|
||||||
* This function caps the length a user is allowed to read from an sftp file.
|
|
||||||
*
|
|
||||||
* The value used for the cap is same as the value of the max_read_length
|
|
||||||
* field of the sftp_limits_t returned by sftp_limits().
|
|
||||||
*
|
|
||||||
* @param file The opened sftp file handle to be read from.
|
* @param file The opened sftp file handle to be read from.
|
||||||
*
|
*
|
||||||
* @param buf Pointer to buffer to receive read data.
|
* @param buf Pointer to buffer to receive read data.
|
||||||
*
|
*
|
||||||
* @param count Size of the buffer in bytes.
|
* @param count Size of the buffer in bytes.
|
||||||
*
|
*
|
||||||
* @return Number of bytes read, < 0 on error with ssh and sftp
|
* @return Number of bytes written, < 0 on error with ssh and sftp
|
||||||
* error set.
|
* error set.
|
||||||
*
|
*
|
||||||
* @see sftp_get_error()
|
* @see sftp_get_error()
|
||||||
@@ -538,8 +520,7 @@ LIBSSH_API ssize_t sftp_read(sftp_file file, void *buf, size_t count);
|
|||||||
* @see sftp_async_read()
|
* @see sftp_async_read()
|
||||||
* @see sftp_open()
|
* @see sftp_open()
|
||||||
*/
|
*/
|
||||||
SSH_DEPRECATED LIBSSH_API int sftp_async_read_begin(sftp_file file,
|
LIBSSH_API int sftp_async_read_begin(sftp_file file, uint32_t len);
|
||||||
uint32_t len);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Wait for an asynchronous read to complete and save the data.
|
* @brief Wait for an asynchronous read to complete and save the data.
|
||||||
@@ -564,19 +545,11 @@ SSH_DEPRECATED LIBSSH_API int sftp_async_read_begin(sftp_file file,
|
|||||||
*
|
*
|
||||||
* @see sftp_async_read_begin()
|
* @see sftp_async_read_begin()
|
||||||
*/
|
*/
|
||||||
SSH_DEPRECATED LIBSSH_API int sftp_async_read(sftp_file file,
|
LIBSSH_API int sftp_async_read(sftp_file file, void *data, uint32_t len, uint32_t id);
|
||||||
void *data,
|
|
||||||
uint32_t len,
|
|
||||||
uint32_t id);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write to a file using an opened sftp file handle.
|
* @brief Write to a file using an opened sftp file handle.
|
||||||
*
|
*
|
||||||
* This function caps the length a user is allowed to write to an sftp file.
|
|
||||||
*
|
|
||||||
* The value used for the cap is same as the value of the max_write_length
|
|
||||||
* field of the sftp_limits_t returned by sftp_limits().
|
|
||||||
*
|
|
||||||
* @param file Open sftp file handle to write to.
|
* @param file Open sftp file handle to write to.
|
||||||
*
|
*
|
||||||
* @param buf Pointer to buffer to write data.
|
* @param buf Pointer to buffer to write data.
|
||||||
@@ -592,229 +565,6 @@ SSH_DEPRECATED LIBSSH_API int sftp_async_read(sftp_file file,
|
|||||||
*/
|
*/
|
||||||
LIBSSH_API 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 Deallocate memory corresponding to a sftp aio handle.
|
|
||||||
*
|
|
||||||
* This function deallocates memory corresponding to the aio handle returned
|
|
||||||
* by the sftp_aio_begin_*() functions. Users can use this function to free
|
|
||||||
* memory corresponding to an aio handle for an outstanding async i/o request
|
|
||||||
* on encountering some error.
|
|
||||||
*
|
|
||||||
* @param aio sftp aio handle corresponding to which memory has
|
|
||||||
* to be deallocated.
|
|
||||||
*
|
|
||||||
* @see sftp_aio_begin_read()
|
|
||||||
* @see sftp_aio_wait_read()
|
|
||||||
* @see sftp_aio_begin_write()
|
|
||||||
* @see sftp_aio_wait_write()
|
|
||||||
*/
|
|
||||||
LIBSSH_API void sftp_aio_free(sftp_aio aio);
|
|
||||||
#define SFTP_AIO_FREE(x) \
|
|
||||||
do { if(x != NULL) {sftp_aio_free(x); x = NULL;} } while(0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Start an asynchronous read from a file using an opened sftp
|
|
||||||
* file handle.
|
|
||||||
*
|
|
||||||
* Its goal is to avoid the slowdowns related to the request/response pattern
|
|
||||||
* of a synchronous read. To do so, you must call 2 functions :
|
|
||||||
*
|
|
||||||
* sftp_aio_begin_read() and sftp_aio_wait_read().
|
|
||||||
*
|
|
||||||
* - The first step is to call sftp_aio_begin_read(). This function sends a
|
|
||||||
* read request to the sftp server, dynamically allocates memory to store
|
|
||||||
* information about the sent request and provides the caller an sftp aio
|
|
||||||
* handle to that memory.
|
|
||||||
*
|
|
||||||
* - The second step is to call sftp_aio_wait_read() and pass it the address
|
|
||||||
* of a location storing the sftp aio handle provided by
|
|
||||||
* sftp_aio_begin_read().
|
|
||||||
*
|
|
||||||
* These two functions do not close the open sftp file handle passed to
|
|
||||||
* sftp_aio_begin_read() irrespective of whether they fail or not.
|
|
||||||
*
|
|
||||||
* It is the responsibility of the caller to ensure that the open sftp file
|
|
||||||
* handle passed to sftp_aio_begin_read() must not be closed before the
|
|
||||||
* corresponding call to sftp_aio_wait_read(). After sftp_aio_wait_read()
|
|
||||||
* returns, it is caller's decision whether to immediately close the file by
|
|
||||||
* calling sftp_close() or to keep it open and perform some more operations
|
|
||||||
* on it.
|
|
||||||
*
|
|
||||||
* This function caps the length a user is allowed to read from an sftp file,
|
|
||||||
* the value of len parameter after capping is returned on success.
|
|
||||||
*
|
|
||||||
* The value used for the cap is same as the value of the max_read_length
|
|
||||||
* field of the sftp_limits_t returned by sftp_limits().
|
|
||||||
*
|
|
||||||
* @param file The opened sftp file handle to be read from.
|
|
||||||
*
|
|
||||||
* @param len Number of bytes to read.
|
|
||||||
*
|
|
||||||
* @param aio Pointer to a location where the sftp aio handle
|
|
||||||
* (corresponding to the sent request) should be stored.
|
|
||||||
*
|
|
||||||
* @returns On success, the number of bytes the server is
|
|
||||||
* requested to read (value of len parameter after
|
|
||||||
* capping). On error, SSH_ERROR with sftp and ssh
|
|
||||||
* errors set.
|
|
||||||
*
|
|
||||||
* @warning When calling this function, the internal file offset is
|
|
||||||
* updated corresponding to the number of bytes requested
|
|
||||||
* to read.
|
|
||||||
*
|
|
||||||
* @warning A call to sftp_aio_begin_read() sends a request to
|
|
||||||
* the server. When the server answers, libssh allocates
|
|
||||||
* memory to store it until sftp_aio_wait_read() is called.
|
|
||||||
* Not calling sftp_aio_wait_read() will lead to memory
|
|
||||||
* leaks.
|
|
||||||
*
|
|
||||||
* @see sftp_aio_wait_read()
|
|
||||||
* @see sftp_aio_free()
|
|
||||||
* @see sftp_open()
|
|
||||||
* @see sftp_close()
|
|
||||||
* @see sftp_get_error()
|
|
||||||
* @see ssh_get_error()
|
|
||||||
*/
|
|
||||||
LIBSSH_API ssize_t sftp_aio_begin_read(sftp_file file,
|
|
||||||
size_t len,
|
|
||||||
sftp_aio *aio);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Wait for an asynchronous read to complete and store the read data
|
|
||||||
* in the supplied buffer.
|
|
||||||
*
|
|
||||||
* A pointer to an sftp aio handle should be passed while calling
|
|
||||||
* this function. Except when the return value is SSH_AGAIN,
|
|
||||||
* this function releases the memory corresponding to the supplied
|
|
||||||
* aio handle and assigns NULL to that aio handle using the passed
|
|
||||||
* pointer to that handle.
|
|
||||||
*
|
|
||||||
* If the file is opened in non-blocking mode and the request hasn't been
|
|
||||||
* executed yet, this function returns SSH_AGAIN and must be called again
|
|
||||||
* using the same sftp aio handle.
|
|
||||||
*
|
|
||||||
* @param aio Pointer to the sftp aio handle returned by
|
|
||||||
* sftp_aio_begin_read().
|
|
||||||
*
|
|
||||||
* @param buf Pointer to the buffer in which read data will be stored.
|
|
||||||
*
|
|
||||||
* @param buf_size Size of the buffer in bytes. It should be bigger or
|
|
||||||
* equal to the length parameter of the
|
|
||||||
* sftp_aio_begin_read() call.
|
|
||||||
*
|
|
||||||
* @return Number of bytes read, 0 on EOF, SSH_ERROR if an error
|
|
||||||
* occurred, SSH_AGAIN if the file is opened in nonblocking
|
|
||||||
* mode and the request hasn't been executed yet.
|
|
||||||
*
|
|
||||||
* @warning A call to this function with an invalid sftp aio handle
|
|
||||||
* may never return.
|
|
||||||
*
|
|
||||||
* @see sftp_aio_begin_read()
|
|
||||||
* @see sftp_aio_free()
|
|
||||||
*/
|
|
||||||
LIBSSH_API ssize_t sftp_aio_wait_read(sftp_aio *aio,
|
|
||||||
void *buf,
|
|
||||||
size_t buf_size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Start an asynchronous write to a file using an opened sftp
|
|
||||||
* file handle.
|
|
||||||
*
|
|
||||||
* Its goal is to avoid the slowdowns related to the request/response pattern
|
|
||||||
* of a synchronous write. To do so, you must call 2 functions :
|
|
||||||
*
|
|
||||||
* sftp_aio_begin_write() and sftp_aio_wait_write().
|
|
||||||
*
|
|
||||||
* - The first step is to call sftp_aio_begin_write(). This function sends a
|
|
||||||
* write request to the sftp server, dynamically allocates memory to store
|
|
||||||
* information about the sent request and provides the caller an sftp aio
|
|
||||||
* handle to that memory.
|
|
||||||
*
|
|
||||||
* - The second step is to call sftp_aio_wait_write() and pass it the address
|
|
||||||
* of a location storing the sftp aio handle provided by
|
|
||||||
* sftp_aio_begin_write().
|
|
||||||
*
|
|
||||||
* These two functions do not close the open sftp file handle passed to
|
|
||||||
* sftp_aio_begin_write() irrespective of whether they fail or not.
|
|
||||||
*
|
|
||||||
* It is the responsibility of the caller to ensure that the open sftp file
|
|
||||||
* handle passed to sftp_aio_begin_write() must not be closed before the
|
|
||||||
* corresponding call to sftp_aio_wait_write(). After sftp_aio_wait_write()
|
|
||||||
* returns, it is caller's decision whether to immediately close the file by
|
|
||||||
* calling sftp_close() or to keep it open and perform some more operations
|
|
||||||
* on it.
|
|
||||||
*
|
|
||||||
* This function caps the length a user is allowed to write to an sftp file,
|
|
||||||
* the value of len parameter after capping is returned on success.
|
|
||||||
*
|
|
||||||
* The value used for the cap is same as the value of the max_write_length
|
|
||||||
* field of the sftp_limits_t returned by sftp_limits().
|
|
||||||
*
|
|
||||||
* @param file The opened sftp file handle to write to.
|
|
||||||
*
|
|
||||||
* @param buf Pointer to the buffer containing data to write.
|
|
||||||
*
|
|
||||||
* @param len Number of bytes to write.
|
|
||||||
*
|
|
||||||
* @param aio Pointer to a location where the sftp aio handle
|
|
||||||
* (corresponding to the sent request) should be stored.
|
|
||||||
*
|
|
||||||
* @returns On success, the number of bytes the server is
|
|
||||||
* requested to write (value of len parameter after
|
|
||||||
* capping). On error, SSH_ERROR with sftp and ssh errors
|
|
||||||
* set.
|
|
||||||
*
|
|
||||||
* @warning When calling this function, the internal file offset is
|
|
||||||
* updated corresponding to the number of bytes requested
|
|
||||||
* to write.
|
|
||||||
*
|
|
||||||
* @warning A call to sftp_aio_begin_write() sends a request to
|
|
||||||
* the server. When the server answers, libssh allocates
|
|
||||||
* memory to store it until sftp_aio_wait_write() is
|
|
||||||
* called. Not calling sftp_aio_wait_write() will lead to
|
|
||||||
* memory leaks.
|
|
||||||
*
|
|
||||||
* @see sftp_aio_wait_write()
|
|
||||||
* @see sftp_aio_free()
|
|
||||||
* @see sftp_open()
|
|
||||||
* @see sftp_close()
|
|
||||||
* @see sftp_get_error()
|
|
||||||
* @see ssh_get_error()
|
|
||||||
*/
|
|
||||||
LIBSSH_API ssize_t sftp_aio_begin_write(sftp_file file,
|
|
||||||
const void *buf,
|
|
||||||
size_t len,
|
|
||||||
sftp_aio *aio);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Wait for an asynchronous write to complete.
|
|
||||||
*
|
|
||||||
* A pointer to an sftp aio handle should be passed while calling
|
|
||||||
* this function. Except when the return value is SSH_AGAIN,
|
|
||||||
* this function releases the memory corresponding to the supplied
|
|
||||||
* aio handle and assigns NULL to that aio handle using the passed
|
|
||||||
* pointer to that handle.
|
|
||||||
*
|
|
||||||
* If the file is opened in non-blocking mode and the request hasn't
|
|
||||||
* been executed yet, this function returns SSH_AGAIN and must be called
|
|
||||||
* again using the same sftp aio handle.
|
|
||||||
*
|
|
||||||
* @param aio Pointer to the sftp aio handle returned by
|
|
||||||
* sftp_aio_begin_write().
|
|
||||||
*
|
|
||||||
* @return Number of bytes written on success, SSH_ERROR
|
|
||||||
* if an error occurred, SSH_AGAIN if the file is
|
|
||||||
* opened in nonblocking mode and the request hasn't
|
|
||||||
* been executed yet.
|
|
||||||
*
|
|
||||||
* @warning A call to this function with an invalid sftp aio handle
|
|
||||||
* may never return.
|
|
||||||
*
|
|
||||||
* @see sftp_aio_begin_write()
|
|
||||||
* @see sftp_aio_free()
|
|
||||||
*/
|
|
||||||
LIBSSH_API ssize_t sftp_aio_wait_write(sftp_aio *aio);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Seek to a specific location in a file.
|
* @brief Seek to a specific location in a file.
|
||||||
*
|
*
|
||||||
@@ -855,7 +605,8 @@ LIBSSH_API unsigned long sftp_tell(sftp_file file);
|
|||||||
* @param file Open sftp file handle.
|
* @param file Open sftp file handle.
|
||||||
*
|
*
|
||||||
* @return The offset of the current byte relative to the beginning
|
* @return The offset of the current byte relative to the beginning
|
||||||
* of the file associated with the file descriptor.
|
* of the file associated with the file descriptor. < 0 on
|
||||||
|
* error.
|
||||||
*/
|
*/
|
||||||
LIBSSH_API uint64_t sftp_tell64(sftp_file file);
|
LIBSSH_API uint64_t sftp_tell64(sftp_file file);
|
||||||
|
|
||||||
@@ -948,29 +699,6 @@ LIBSSH_API int sftp_rename(sftp_session sftp, const char *original, const char
|
|||||||
*/
|
*/
|
||||||
LIBSSH_API 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 This request is like setstat (excluding mode and size) but sets file
|
|
||||||
* attributes on symlinks themselves.
|
|
||||||
*
|
|
||||||
* Note, that this function can only set time values using 32 bit values due to
|
|
||||||
* the restrictions in the SFTP protocol version 3 implemented by libssh.
|
|
||||||
* The support for 64 bit time values was introduced in SFTP version 5, which is
|
|
||||||
* not implemented by libssh nor any major SFTP servers.
|
|
||||||
*
|
|
||||||
* @param sftp The sftp session handle.
|
|
||||||
*
|
|
||||||
* @param file The symbolic link which attributes should be changed.
|
|
||||||
*
|
|
||||||
* @param attr The file attributes structure with the attributes set
|
|
||||||
* which should be changed.
|
|
||||||
*
|
|
||||||
* @return 0 on success, < 0 on error with ssh and sftp error set.
|
|
||||||
*
|
|
||||||
* @see sftp_get_error()
|
|
||||||
*/
|
|
||||||
LIBSSH_API int
|
|
||||||
sftp_lsetstat(sftp_session sftp, const char *file, sftp_attributes attr);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Change the file owner and group
|
* @brief Change the file owner and group
|
||||||
*
|
*
|
||||||
@@ -1051,22 +779,6 @@ LIBSSH_API int sftp_symlink(sftp_session sftp, const char *target, const char *d
|
|||||||
*/
|
*/
|
||||||
LIBSSH_API char *sftp_readlink(sftp_session sftp, const char *path);
|
LIBSSH_API char *sftp_readlink(sftp_session sftp, const char *path);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create a hard link.
|
|
||||||
*
|
|
||||||
* @param sftp The sftp session handle.
|
|
||||||
*
|
|
||||||
* @param oldpath Specifies the pathname of the file for
|
|
||||||
* which the new hardlink is to be created.
|
|
||||||
*
|
|
||||||
* @param newpath Specifies the pathname of the hardlink to be created.
|
|
||||||
*
|
|
||||||
* @return 0 on success, -1 on error with ssh and sftp error set.
|
|
||||||
*
|
|
||||||
* @see sftp_get_error()
|
|
||||||
*/
|
|
||||||
LIBSSH_API int sftp_hardlink(sftp_session sftp, const char *oldpath, const char *newpath);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get information about a mounted file system.
|
* @brief Get information about a mounted file system.
|
||||||
*
|
*
|
||||||
@@ -1114,24 +826,6 @@ LIBSSH_API void sftp_statvfs_free(sftp_statvfs_t statvfs_o);
|
|||||||
*/
|
*/
|
||||||
LIBSSH_API int sftp_fsync(sftp_file file);
|
LIBSSH_API int sftp_fsync(sftp_file file);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get information about the various limits the server might impose.
|
|
||||||
*
|
|
||||||
* @param sftp The sftp session handle.
|
|
||||||
*
|
|
||||||
* @return A limits structure or NULL on error.
|
|
||||||
*
|
|
||||||
* @see sftp_get_error()
|
|
||||||
*/
|
|
||||||
LIBSSH_API sftp_limits_t sftp_limits(sftp_session sftp);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Free the memory of an allocated limits.
|
|
||||||
*
|
|
||||||
* @param limits The limits to free.
|
|
||||||
*/
|
|
||||||
LIBSSH_API void sftp_limits_free(sftp_limits_t limits);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Canonicalize a sftp path.
|
* @brief Canonicalize a sftp path.
|
||||||
*
|
*
|
||||||
@@ -1154,40 +848,6 @@ LIBSSH_API char *sftp_canonicalize_path(sftp_session sftp, const char *path);
|
|||||||
*/
|
*/
|
||||||
LIBSSH_API int sftp_server_version(sftp_session sftp);
|
LIBSSH_API int sftp_server_version(sftp_session sftp);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Canonicalize path using expand-path@openssh.com extension
|
|
||||||
*
|
|
||||||
* @param sftp The sftp session handle.
|
|
||||||
*
|
|
||||||
* @param path The path to be canonicalized.
|
|
||||||
*
|
|
||||||
* @return A pointer to the newly allocated canonicalized path,
|
|
||||||
* NULL on error. The caller needs to free the memory
|
|
||||||
* using ssh_string_free_char().
|
|
||||||
*/
|
|
||||||
LIBSSH_API char *sftp_expand_path(sftp_session sftp, const char *path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the specified user's home directory
|
|
||||||
*
|
|
||||||
* This calls the "home-directory" extension. You should check if the extension
|
|
||||||
* is supported using:
|
|
||||||
*
|
|
||||||
* @code
|
|
||||||
* int supported = sftp_extension_supported(sftp, "home-directory", "1");
|
|
||||||
* @endcode
|
|
||||||
*
|
|
||||||
* @param sftp The sftp session handle.
|
|
||||||
*
|
|
||||||
* @param username username of the user whose home directory is requested.
|
|
||||||
*
|
|
||||||
* @return On success, a newly allocated string containing the
|
|
||||||
* absolute real-path of the home directory of the user.
|
|
||||||
* NULL on error. The caller needs to free the memory
|
|
||||||
* using ssh_string_free_char().
|
|
||||||
*/
|
|
||||||
LIBSSH_API char *sftp_home_directory(sftp_session sftp, const char *username);
|
|
||||||
|
|
||||||
#ifdef WITH_SERVER
|
#ifdef WITH_SERVER
|
||||||
/**
|
/**
|
||||||
* @brief Create a new sftp server session.
|
* @brief Create a new sftp server session.
|
||||||
@@ -1207,7 +867,7 @@ LIBSSH_API sftp_session sftp_server_new(ssh_session session, ssh_channel chan);
|
|||||||
*
|
*
|
||||||
* @return 0 on success, < 0 on error.
|
* @return 0 on success, < 0 on error.
|
||||||
*/
|
*/
|
||||||
SSH_DEPRECATED LIBSSH_API int sftp_server_init(sftp_session sftp);
|
LIBSSH_API int sftp_server_init(sftp_session sftp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Close and deallocate a sftp server session.
|
* @brief Close and deallocate a sftp server session.
|
||||||
|
|||||||
@@ -32,49 +32,6 @@ int buffer_add_attributes(ssh_buffer buffer, sftp_attributes attr);
|
|||||||
sftp_attributes sftp_parse_attr(sftp_session session,
|
sftp_attributes sftp_parse_attr(sftp_session session,
|
||||||
ssh_buffer buf,
|
ssh_buffer buf,
|
||||||
int expectname);
|
int expectname);
|
||||||
/**
|
|
||||||
* @brief Reply to the SSH_FXP_INIT message with the SSH_FXP_VERSION message
|
|
||||||
*
|
|
||||||
* @param client_msg The pointer to client message.
|
|
||||||
*
|
|
||||||
* @return 0 on success, < 0 on error with ssh and sftp error set.
|
|
||||||
*
|
|
||||||
* @see sftp_get_error()
|
|
||||||
*/
|
|
||||||
int sftp_reply_version(sftp_client_message client_msg);
|
|
||||||
/**
|
|
||||||
* @brief Decode the data from channel buffer into sftp read_packet.
|
|
||||||
*
|
|
||||||
* @param sftp The sftp session handle.
|
|
||||||
*
|
|
||||||
* @param data The pointer to the data buffer of channel.
|
|
||||||
* @param len The data buffer length
|
|
||||||
*
|
|
||||||
* @return Length of data decoded.
|
|
||||||
*/
|
|
||||||
int sftp_decode_channel_data_to_packet(sftp_session sftp, void *data, uint32_t len);
|
|
||||||
|
|
||||||
void sftp_set_error(sftp_session sftp, int errnum);
|
|
||||||
|
|
||||||
void sftp_message_free(sftp_message msg);
|
|
||||||
|
|
||||||
int sftp_read_and_dispatch(sftp_session sftp);
|
|
||||||
|
|
||||||
sftp_message sftp_dequeue(sftp_session sftp, uint32_t id);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Assigns a new SFTP ID for new requests and assures there is no collision
|
|
||||||
* between them.
|
|
||||||
* Returns a new ID ready to use in a request
|
|
||||||
*/
|
|
||||||
static inline uint32_t sftp_get_new_id(sftp_session session)
|
|
||||||
{
|
|
||||||
return ++session->id_counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
sftp_status_message parse_status_msg(sftp_message msg);
|
|
||||||
|
|
||||||
void status_msg_free(sftp_status_message status);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the SSH Library
|
|
||||||
*
|
|
||||||
* Copyright (c) 2022 Zeyu Sheng <shengzeyu19_98@163.com>
|
|
||||||
* Copyright (c) 2023 Red Hat, Inc.
|
|
||||||
*
|
|
||||||
* Authors: Jakub Jelen <jjelen@redhat.com>
|
|
||||||
*
|
|
||||||
* This 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.
|
|
||||||
*
|
|
||||||
* This 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 this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SFTP_SERVER_H
|
|
||||||
#define SFTP_SERVER_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
/**
|
|
||||||
* @defgroup libssh_sftp_server The libssh SFTP server API
|
|
||||||
*
|
|
||||||
* @brief SFTP server handling functions
|
|
||||||
*
|
|
||||||
* TODO
|
|
||||||
*
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define SSH_SFTP_CALLBACK(name) \
|
|
||||||
static int name(sftp_client_message message)
|
|
||||||
|
|
||||||
typedef int (*sftp_server_message_callback)(sftp_client_message message);
|
|
||||||
|
|
||||||
struct sftp_message_handler
|
|
||||||
{
|
|
||||||
const char *name;
|
|
||||||
const char *extended_name;
|
|
||||||
uint8_t type;
|
|
||||||
|
|
||||||
sftp_server_message_callback cb;
|
|
||||||
};
|
|
||||||
|
|
||||||
LIBSSH_API int sftp_channel_default_subsystem_request(ssh_session session,
|
|
||||||
ssh_channel channel,
|
|
||||||
const char *subsystem,
|
|
||||||
void *userdata);
|
|
||||||
LIBSSH_API int sftp_channel_default_data_callback(ssh_session session,
|
|
||||||
ssh_channel channel,
|
|
||||||
void *data,
|
|
||||||
uint32_t len,
|
|
||||||
int is_stderr,
|
|
||||||
void *userdata);
|
|
||||||
|
|
||||||
/** @} */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* SFTP_SERVER_H */
|
|
||||||
@@ -37,11 +37,10 @@ void ssh_socket_set_fd(ssh_socket s, socket_t fd);
|
|||||||
socket_t ssh_socket_get_fd(ssh_socket s);
|
socket_t ssh_socket_get_fd(ssh_socket s);
|
||||||
void ssh_socket_set_connected(ssh_socket s, struct ssh_poll_handle_struct *p);
|
void ssh_socket_set_connected(ssh_socket s, struct ssh_poll_handle_struct *p);
|
||||||
int ssh_socket_unix(ssh_socket s, const char *path);
|
int ssh_socket_unix(ssh_socket s, const char *path);
|
||||||
#if WITH_EXEC
|
|
||||||
void ssh_execute_command(const char *command, socket_t in, socket_t out);
|
void ssh_execute_command(const char *command, socket_t in, socket_t out);
|
||||||
|
#ifndef _WIN32
|
||||||
int ssh_socket_connect_proxycommand(ssh_socket s, const char *command);
|
int ssh_socket_connect_proxycommand(ssh_socket s, const char *command);
|
||||||
#endif
|
#endif
|
||||||
int ssh_socket_connect_proxyjump(ssh_socket s);
|
|
||||||
void ssh_socket_close(ssh_socket s);
|
void ssh_socket_close(ssh_socket s);
|
||||||
int ssh_socket_write(ssh_socket s,const void *buffer, uint32_t len);
|
int ssh_socket_write(ssh_socket s,const void *buffer, uint32_t len);
|
||||||
int ssh_socket_is_open(ssh_socket s);
|
int ssh_socket_is_open(ssh_socket s);
|
||||||
|
|||||||
@@ -49,11 +49,6 @@ char *ssh_remove_duplicates(const char *list);
|
|||||||
|
|
||||||
char *ssh_append_without_duplicates(const char *list,
|
char *ssh_append_without_duplicates(const char *list,
|
||||||
const char *appended_list);
|
const char *appended_list);
|
||||||
char *ssh_prefix_without_duplicates(const char *list,
|
|
||||||
const char *prefixed_list);
|
|
||||||
char *ssh_remove_all_matching(const char *list,
|
|
||||||
const char *remove_list);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
4.10.1
|
4.9.6
|
||||||
@@ -1,445 +0,0 @@
|
|||||||
_ssh_log
|
|
||||||
buffer_free
|
|
||||||
buffer_get
|
|
||||||
buffer_get_len
|
|
||||||
buffer_new
|
|
||||||
channel_accept_x11
|
|
||||||
channel_change_pty_size
|
|
||||||
channel_close
|
|
||||||
channel_forward_accept
|
|
||||||
channel_forward_cancel
|
|
||||||
channel_forward_listen
|
|
||||||
channel_free
|
|
||||||
channel_get_exit_status
|
|
||||||
channel_get_session
|
|
||||||
channel_is_closed
|
|
||||||
channel_is_eof
|
|
||||||
channel_is_open
|
|
||||||
channel_new
|
|
||||||
channel_open_forward
|
|
||||||
channel_open_session
|
|
||||||
channel_poll
|
|
||||||
channel_read
|
|
||||||
channel_read_buffer
|
|
||||||
channel_read_nonblocking
|
|
||||||
channel_request_env
|
|
||||||
channel_request_exec
|
|
||||||
channel_request_pty
|
|
||||||
channel_request_pty_size
|
|
||||||
channel_request_send_signal
|
|
||||||
channel_request_sftp
|
|
||||||
channel_request_shell
|
|
||||||
channel_request_subsystem
|
|
||||||
channel_request_x11
|
|
||||||
channel_select
|
|
||||||
channel_send_eof
|
|
||||||
channel_set_blocking
|
|
||||||
channel_write
|
|
||||||
channel_write_stderr
|
|
||||||
privatekey_free
|
|
||||||
privatekey_from_file
|
|
||||||
publickey_free
|
|
||||||
publickey_from_file
|
|
||||||
publickey_from_privatekey
|
|
||||||
publickey_to_string
|
|
||||||
sftp_aio_begin_read
|
|
||||||
sftp_aio_begin_write
|
|
||||||
sftp_aio_free
|
|
||||||
sftp_aio_wait_read
|
|
||||||
sftp_aio_wait_write
|
|
||||||
sftp_async_read
|
|
||||||
sftp_async_read_begin
|
|
||||||
sftp_attributes_free
|
|
||||||
sftp_canonicalize_path
|
|
||||||
sftp_channel_default_data_callback
|
|
||||||
sftp_channel_default_subsystem_request
|
|
||||||
sftp_chmod
|
|
||||||
sftp_chown
|
|
||||||
sftp_client_message_free
|
|
||||||
sftp_client_message_get_data
|
|
||||||
sftp_client_message_get_filename
|
|
||||||
sftp_client_message_get_flags
|
|
||||||
sftp_client_message_get_submessage
|
|
||||||
sftp_client_message_get_type
|
|
||||||
sftp_client_message_set_filename
|
|
||||||
sftp_close
|
|
||||||
sftp_closedir
|
|
||||||
sftp_dir_eof
|
|
||||||
sftp_expand_path
|
|
||||||
sftp_extension_supported
|
|
||||||
sftp_extensions_get_count
|
|
||||||
sftp_extensions_get_data
|
|
||||||
sftp_extensions_get_name
|
|
||||||
sftp_file_set_blocking
|
|
||||||
sftp_file_set_nonblocking
|
|
||||||
sftp_free
|
|
||||||
sftp_fstat
|
|
||||||
sftp_fstatvfs
|
|
||||||
sftp_fsync
|
|
||||||
sftp_get_client_message
|
|
||||||
sftp_get_error
|
|
||||||
sftp_handle
|
|
||||||
sftp_handle_alloc
|
|
||||||
sftp_handle_remove
|
|
||||||
sftp_hardlink
|
|
||||||
sftp_home_directory
|
|
||||||
sftp_init
|
|
||||||
sftp_limits
|
|
||||||
sftp_limits_free
|
|
||||||
sftp_lsetstat
|
|
||||||
sftp_lstat
|
|
||||||
sftp_mkdir
|
|
||||||
sftp_new
|
|
||||||
sftp_new_channel
|
|
||||||
sftp_open
|
|
||||||
sftp_opendir
|
|
||||||
sftp_read
|
|
||||||
sftp_readdir
|
|
||||||
sftp_readlink
|
|
||||||
sftp_rename
|
|
||||||
sftp_reply_attr
|
|
||||||
sftp_reply_data
|
|
||||||
sftp_reply_handle
|
|
||||||
sftp_reply_name
|
|
||||||
sftp_reply_names
|
|
||||||
sftp_reply_names_add
|
|
||||||
sftp_reply_status
|
|
||||||
sftp_rewind
|
|
||||||
sftp_rmdir
|
|
||||||
sftp_seek
|
|
||||||
sftp_seek64
|
|
||||||
sftp_send_client_message
|
|
||||||
sftp_server_free
|
|
||||||
sftp_server_init
|
|
||||||
sftp_server_new
|
|
||||||
sftp_server_version
|
|
||||||
sftp_setstat
|
|
||||||
sftp_stat
|
|
||||||
sftp_statvfs
|
|
||||||
sftp_statvfs_free
|
|
||||||
sftp_symlink
|
|
||||||
sftp_tell
|
|
||||||
sftp_tell64
|
|
||||||
sftp_unlink
|
|
||||||
sftp_utimes
|
|
||||||
sftp_write
|
|
||||||
ssh_accept
|
|
||||||
ssh_add_channel_callbacks
|
|
||||||
ssh_auth_list
|
|
||||||
ssh_basename
|
|
||||||
ssh_bind_accept
|
|
||||||
ssh_bind_accept_fd
|
|
||||||
ssh_bind_fd_toaccept
|
|
||||||
ssh_bind_free
|
|
||||||
ssh_bind_get_fd
|
|
||||||
ssh_bind_listen
|
|
||||||
ssh_bind_new
|
|
||||||
ssh_bind_options_parse_config
|
|
||||||
ssh_bind_options_set
|
|
||||||
ssh_bind_set_blocking
|
|
||||||
ssh_bind_set_callbacks
|
|
||||||
ssh_bind_set_fd
|
|
||||||
ssh_blocking_flush
|
|
||||||
ssh_buffer_add_data
|
|
||||||
ssh_buffer_free
|
|
||||||
ssh_buffer_get
|
|
||||||
ssh_buffer_get_data
|
|
||||||
ssh_buffer_get_len
|
|
||||||
ssh_buffer_new
|
|
||||||
ssh_buffer_reinit
|
|
||||||
ssh_channel_accept_forward
|
|
||||||
ssh_channel_accept_x11
|
|
||||||
ssh_channel_cancel_forward
|
|
||||||
ssh_channel_change_pty_size
|
|
||||||
ssh_channel_close
|
|
||||||
ssh_channel_free
|
|
||||||
ssh_channel_get_exit_state
|
|
||||||
ssh_channel_get_exit_status
|
|
||||||
ssh_channel_get_session
|
|
||||||
ssh_channel_is_closed
|
|
||||||
ssh_channel_is_eof
|
|
||||||
ssh_channel_is_open
|
|
||||||
ssh_channel_listen_forward
|
|
||||||
ssh_channel_new
|
|
||||||
ssh_channel_open_auth_agent
|
|
||||||
ssh_channel_open_forward
|
|
||||||
ssh_channel_open_forward_port
|
|
||||||
ssh_channel_open_forward_unix
|
|
||||||
ssh_channel_open_reverse_forward
|
|
||||||
ssh_channel_open_session
|
|
||||||
ssh_channel_open_x11
|
|
||||||
ssh_channel_poll
|
|
||||||
ssh_channel_poll_timeout
|
|
||||||
ssh_channel_read
|
|
||||||
ssh_channel_read_nonblocking
|
|
||||||
ssh_channel_read_timeout
|
|
||||||
ssh_channel_request_auth_agent
|
|
||||||
ssh_channel_request_env
|
|
||||||
ssh_channel_request_exec
|
|
||||||
ssh_channel_request_pty
|
|
||||||
ssh_channel_request_pty_size
|
|
||||||
ssh_channel_request_pty_size_modes
|
|
||||||
ssh_channel_request_send_break
|
|
||||||
ssh_channel_request_send_exit_signal
|
|
||||||
ssh_channel_request_send_exit_status
|
|
||||||
ssh_channel_request_send_signal
|
|
||||||
ssh_channel_request_sftp
|
|
||||||
ssh_channel_request_shell
|
|
||||||
ssh_channel_request_subsystem
|
|
||||||
ssh_channel_request_x11
|
|
||||||
ssh_channel_select
|
|
||||||
ssh_channel_send_eof
|
|
||||||
ssh_channel_set_blocking
|
|
||||||
ssh_channel_set_counter
|
|
||||||
ssh_channel_window_size
|
|
||||||
ssh_channel_write
|
|
||||||
ssh_channel_write_stderr
|
|
||||||
ssh_clean_pubkey_hash
|
|
||||||
ssh_connect
|
|
||||||
ssh_connector_free
|
|
||||||
ssh_connector_new
|
|
||||||
ssh_connector_set_in_channel
|
|
||||||
ssh_connector_set_in_fd
|
|
||||||
ssh_connector_set_out_channel
|
|
||||||
ssh_connector_set_out_fd
|
|
||||||
ssh_copyright
|
|
||||||
ssh_dirname
|
|
||||||
ssh_disconnect
|
|
||||||
ssh_dump_knownhost
|
|
||||||
ssh_event_add_connector
|
|
||||||
ssh_event_add_fd
|
|
||||||
ssh_event_add_session
|
|
||||||
ssh_event_dopoll
|
|
||||||
ssh_event_free
|
|
||||||
ssh_event_new
|
|
||||||
ssh_event_remove_connector
|
|
||||||
ssh_event_remove_fd
|
|
||||||
ssh_event_remove_session
|
|
||||||
ssh_execute_message_callbacks
|
|
||||||
ssh_finalize
|
|
||||||
ssh_forward_accept
|
|
||||||
ssh_forward_cancel
|
|
||||||
ssh_forward_listen
|
|
||||||
ssh_free
|
|
||||||
ssh_get_cipher_in
|
|
||||||
ssh_get_cipher_out
|
|
||||||
ssh_get_clientbanner
|
|
||||||
ssh_get_disconnect_message
|
|
||||||
ssh_get_error
|
|
||||||
ssh_get_error_code
|
|
||||||
ssh_get_fd
|
|
||||||
ssh_get_fingerprint_hash
|
|
||||||
ssh_get_hexa
|
|
||||||
ssh_get_hmac_in
|
|
||||||
ssh_get_hmac_out
|
|
||||||
ssh_get_issue_banner
|
|
||||||
ssh_get_kex_algo
|
|
||||||
ssh_get_log_callback
|
|
||||||
ssh_get_log_level
|
|
||||||
ssh_get_log_userdata
|
|
||||||
ssh_get_openssh_version
|
|
||||||
ssh_get_poll_flags
|
|
||||||
ssh_get_pubkey
|
|
||||||
ssh_get_pubkey_hash
|
|
||||||
ssh_get_publickey
|
|
||||||
ssh_get_publickey_hash
|
|
||||||
ssh_get_random
|
|
||||||
ssh_get_server_publickey
|
|
||||||
ssh_get_serverbanner
|
|
||||||
ssh_get_status
|
|
||||||
ssh_get_version
|
|
||||||
ssh_getpass
|
|
||||||
ssh_gssapi_get_creds
|
|
||||||
ssh_gssapi_set_creds
|
|
||||||
ssh_handle_key_exchange
|
|
||||||
ssh_init
|
|
||||||
ssh_is_blocking
|
|
||||||
ssh_is_connected
|
|
||||||
ssh_is_server_known
|
|
||||||
ssh_key_cmp
|
|
||||||
ssh_key_dup
|
|
||||||
ssh_key_free
|
|
||||||
ssh_key_is_private
|
|
||||||
ssh_key_is_public
|
|
||||||
ssh_key_new
|
|
||||||
ssh_key_type
|
|
||||||
ssh_key_type_from_name
|
|
||||||
ssh_key_type_to_char
|
|
||||||
ssh_known_hosts_parse_line
|
|
||||||
ssh_knownhosts_entry_free
|
|
||||||
ssh_log
|
|
||||||
ssh_message_auth_interactive_request
|
|
||||||
ssh_message_auth_kbdint_is_response
|
|
||||||
ssh_message_auth_password
|
|
||||||
ssh_message_auth_pubkey
|
|
||||||
ssh_message_auth_publickey
|
|
||||||
ssh_message_auth_publickey_state
|
|
||||||
ssh_message_auth_reply_pk_ok
|
|
||||||
ssh_message_auth_reply_pk_ok_simple
|
|
||||||
ssh_message_auth_reply_success
|
|
||||||
ssh_message_auth_set_methods
|
|
||||||
ssh_message_auth_user
|
|
||||||
ssh_message_channel_request_channel
|
|
||||||
ssh_message_channel_request_command
|
|
||||||
ssh_message_channel_request_env_name
|
|
||||||
ssh_message_channel_request_env_value
|
|
||||||
ssh_message_channel_request_open_destination
|
|
||||||
ssh_message_channel_request_open_destination_port
|
|
||||||
ssh_message_channel_request_open_originator
|
|
||||||
ssh_message_channel_request_open_originator_port
|
|
||||||
ssh_message_channel_request_open_reply_accept
|
|
||||||
ssh_message_channel_request_open_reply_accept_channel
|
|
||||||
ssh_message_channel_request_pty_height
|
|
||||||
ssh_message_channel_request_pty_pxheight
|
|
||||||
ssh_message_channel_request_pty_pxwidth
|
|
||||||
ssh_message_channel_request_pty_term
|
|
||||||
ssh_message_channel_request_pty_width
|
|
||||||
ssh_message_channel_request_reply_success
|
|
||||||
ssh_message_channel_request_subsystem
|
|
||||||
ssh_message_channel_request_x11_auth_cookie
|
|
||||||
ssh_message_channel_request_x11_auth_protocol
|
|
||||||
ssh_message_channel_request_x11_screen_number
|
|
||||||
ssh_message_channel_request_x11_single_connection
|
|
||||||
ssh_message_free
|
|
||||||
ssh_message_get
|
|
||||||
ssh_message_global_request_address
|
|
||||||
ssh_message_global_request_port
|
|
||||||
ssh_message_global_request_reply_success
|
|
||||||
ssh_message_reply_default
|
|
||||||
ssh_message_retrieve
|
|
||||||
ssh_message_service_reply_success
|
|
||||||
ssh_message_service_service
|
|
||||||
ssh_message_subtype
|
|
||||||
ssh_message_type
|
|
||||||
ssh_mkdir
|
|
||||||
ssh_new
|
|
||||||
ssh_options_copy
|
|
||||||
ssh_options_get
|
|
||||||
ssh_options_get_port
|
|
||||||
ssh_options_getopt
|
|
||||||
ssh_options_parse_config
|
|
||||||
ssh_options_set
|
|
||||||
ssh_pcap_file_close
|
|
||||||
ssh_pcap_file_free
|
|
||||||
ssh_pcap_file_new
|
|
||||||
ssh_pcap_file_open
|
|
||||||
ssh_pki_copy_cert_to_privkey
|
|
||||||
ssh_pki_export_privkey_base64
|
|
||||||
ssh_pki_export_privkey_base64_format
|
|
||||||
ssh_pki_export_privkey_file
|
|
||||||
ssh_pki_export_privkey_file_format
|
|
||||||
ssh_pki_export_privkey_to_pubkey
|
|
||||||
ssh_pki_export_pubkey_base64
|
|
||||||
ssh_pki_export_pubkey_file
|
|
||||||
ssh_pki_generate
|
|
||||||
ssh_pki_import_cert_base64
|
|
||||||
ssh_pki_import_cert_file
|
|
||||||
ssh_pki_import_privkey_base64
|
|
||||||
ssh_pki_import_privkey_file
|
|
||||||
ssh_pki_import_pubkey_base64
|
|
||||||
ssh_pki_import_pubkey_file
|
|
||||||
ssh_pki_key_ecdsa_name
|
|
||||||
ssh_print_hash
|
|
||||||
ssh_print_hexa
|
|
||||||
ssh_privatekey_type
|
|
||||||
ssh_publickey_to_file
|
|
||||||
ssh_remove_channel_callbacks
|
|
||||||
ssh_request_no_more_sessions
|
|
||||||
ssh_scp_accept_request
|
|
||||||
ssh_scp_close
|
|
||||||
ssh_scp_deny_request
|
|
||||||
ssh_scp_free
|
|
||||||
ssh_scp_init
|
|
||||||
ssh_scp_leave_directory
|
|
||||||
ssh_scp_new
|
|
||||||
ssh_scp_pull_request
|
|
||||||
ssh_scp_push_directory
|
|
||||||
ssh_scp_push_file
|
|
||||||
ssh_scp_push_file64
|
|
||||||
ssh_scp_read
|
|
||||||
ssh_scp_request_get_filename
|
|
||||||
ssh_scp_request_get_permissions
|
|
||||||
ssh_scp_request_get_size
|
|
||||||
ssh_scp_request_get_size64
|
|
||||||
ssh_scp_request_get_warning
|
|
||||||
ssh_scp_write
|
|
||||||
ssh_select
|
|
||||||
ssh_send_debug
|
|
||||||
ssh_send_ignore
|
|
||||||
ssh_send_issue_banner
|
|
||||||
ssh_send_keepalive
|
|
||||||
ssh_server_init_kex
|
|
||||||
ssh_service_request
|
|
||||||
ssh_session_export_known_hosts_entry
|
|
||||||
ssh_session_get_known_hosts_entry
|
|
||||||
ssh_session_has_known_hosts_entry
|
|
||||||
ssh_session_is_known_server
|
|
||||||
ssh_session_set_disconnect_message
|
|
||||||
ssh_session_update_known_hosts
|
|
||||||
ssh_set_agent_channel
|
|
||||||
ssh_set_agent_socket
|
|
||||||
ssh_set_auth_methods
|
|
||||||
ssh_set_blocking
|
|
||||||
ssh_set_callbacks
|
|
||||||
ssh_set_channel_callbacks
|
|
||||||
ssh_set_counters
|
|
||||||
ssh_set_fd_except
|
|
||||||
ssh_set_fd_toread
|
|
||||||
ssh_set_fd_towrite
|
|
||||||
ssh_set_log_callback
|
|
||||||
ssh_set_log_level
|
|
||||||
ssh_set_log_userdata
|
|
||||||
ssh_set_message_callback
|
|
||||||
ssh_set_pcap_file
|
|
||||||
ssh_set_server_callbacks
|
|
||||||
ssh_silent_disconnect
|
|
||||||
ssh_string_burn
|
|
||||||
ssh_string_copy
|
|
||||||
ssh_string_data
|
|
||||||
ssh_string_fill
|
|
||||||
ssh_string_free
|
|
||||||
ssh_string_free_char
|
|
||||||
ssh_string_from_char
|
|
||||||
ssh_string_get_char
|
|
||||||
ssh_string_len
|
|
||||||
ssh_string_new
|
|
||||||
ssh_string_to_char
|
|
||||||
ssh_threads_get_default
|
|
||||||
ssh_threads_get_noop
|
|
||||||
ssh_threads_get_pthread
|
|
||||||
ssh_threads_set_callbacks
|
|
||||||
ssh_try_publickey_from_file
|
|
||||||
ssh_userauth_agent
|
|
||||||
ssh_userauth_agent_pubkey
|
|
||||||
ssh_userauth_autopubkey
|
|
||||||
ssh_userauth_gssapi
|
|
||||||
ssh_userauth_kbdint
|
|
||||||
ssh_userauth_kbdint_getanswer
|
|
||||||
ssh_userauth_kbdint_getinstruction
|
|
||||||
ssh_userauth_kbdint_getname
|
|
||||||
ssh_userauth_kbdint_getnanswers
|
|
||||||
ssh_userauth_kbdint_getnprompts
|
|
||||||
ssh_userauth_kbdint_getprompt
|
|
||||||
ssh_userauth_kbdint_setanswer
|
|
||||||
ssh_userauth_list
|
|
||||||
ssh_userauth_none
|
|
||||||
ssh_userauth_offer_pubkey
|
|
||||||
ssh_userauth_password
|
|
||||||
ssh_userauth_privatekey_file
|
|
||||||
ssh_userauth_pubkey
|
|
||||||
ssh_userauth_publickey
|
|
||||||
ssh_userauth_publickey_auto
|
|
||||||
ssh_userauth_publickey_auto_get_current_identity
|
|
||||||
ssh_userauth_try_publickey
|
|
||||||
ssh_version
|
|
||||||
ssh_vlog
|
|
||||||
ssh_write_knownhost
|
|
||||||
string_burn
|
|
||||||
string_copy
|
|
||||||
string_data
|
|
||||||
string_fill
|
|
||||||
string_free
|
|
||||||
string_from_char
|
|
||||||
string_len
|
|
||||||
string_new
|
|
||||||
string_to_char
|
|
||||||
@@ -1,445 +0,0 @@
|
|||||||
_ssh_log
|
|
||||||
buffer_free
|
|
||||||
buffer_get
|
|
||||||
buffer_get_len
|
|
||||||
buffer_new
|
|
||||||
channel_accept_x11
|
|
||||||
channel_change_pty_size
|
|
||||||
channel_close
|
|
||||||
channel_forward_accept
|
|
||||||
channel_forward_cancel
|
|
||||||
channel_forward_listen
|
|
||||||
channel_free
|
|
||||||
channel_get_exit_status
|
|
||||||
channel_get_session
|
|
||||||
channel_is_closed
|
|
||||||
channel_is_eof
|
|
||||||
channel_is_open
|
|
||||||
channel_new
|
|
||||||
channel_open_forward
|
|
||||||
channel_open_session
|
|
||||||
channel_poll
|
|
||||||
channel_read
|
|
||||||
channel_read_buffer
|
|
||||||
channel_read_nonblocking
|
|
||||||
channel_request_env
|
|
||||||
channel_request_exec
|
|
||||||
channel_request_pty
|
|
||||||
channel_request_pty_size
|
|
||||||
channel_request_send_signal
|
|
||||||
channel_request_sftp
|
|
||||||
channel_request_shell
|
|
||||||
channel_request_subsystem
|
|
||||||
channel_request_x11
|
|
||||||
channel_select
|
|
||||||
channel_send_eof
|
|
||||||
channel_set_blocking
|
|
||||||
channel_write
|
|
||||||
channel_write_stderr
|
|
||||||
privatekey_free
|
|
||||||
privatekey_from_file
|
|
||||||
publickey_free
|
|
||||||
publickey_from_file
|
|
||||||
publickey_from_privatekey
|
|
||||||
publickey_to_string
|
|
||||||
sftp_aio_begin_read
|
|
||||||
sftp_aio_begin_write
|
|
||||||
sftp_aio_free
|
|
||||||
sftp_aio_wait_read
|
|
||||||
sftp_aio_wait_write
|
|
||||||
sftp_async_read
|
|
||||||
sftp_async_read_begin
|
|
||||||
sftp_attributes_free
|
|
||||||
sftp_canonicalize_path
|
|
||||||
sftp_channel_default_data_callback
|
|
||||||
sftp_channel_default_subsystem_request
|
|
||||||
sftp_chmod
|
|
||||||
sftp_chown
|
|
||||||
sftp_client_message_free
|
|
||||||
sftp_client_message_get_data
|
|
||||||
sftp_client_message_get_filename
|
|
||||||
sftp_client_message_get_flags
|
|
||||||
sftp_client_message_get_submessage
|
|
||||||
sftp_client_message_get_type
|
|
||||||
sftp_client_message_set_filename
|
|
||||||
sftp_close
|
|
||||||
sftp_closedir
|
|
||||||
sftp_dir_eof
|
|
||||||
sftp_expand_path
|
|
||||||
sftp_extension_supported
|
|
||||||
sftp_extensions_get_count
|
|
||||||
sftp_extensions_get_data
|
|
||||||
sftp_extensions_get_name
|
|
||||||
sftp_file_set_blocking
|
|
||||||
sftp_file_set_nonblocking
|
|
||||||
sftp_free
|
|
||||||
sftp_fstat
|
|
||||||
sftp_fstatvfs
|
|
||||||
sftp_fsync
|
|
||||||
sftp_get_client_message
|
|
||||||
sftp_get_error
|
|
||||||
sftp_handle
|
|
||||||
sftp_handle_alloc
|
|
||||||
sftp_handle_remove
|
|
||||||
sftp_hardlink
|
|
||||||
sftp_home_directory
|
|
||||||
sftp_init
|
|
||||||
sftp_limits
|
|
||||||
sftp_limits_free
|
|
||||||
sftp_lsetstat
|
|
||||||
sftp_lstat
|
|
||||||
sftp_mkdir
|
|
||||||
sftp_new
|
|
||||||
sftp_new_channel
|
|
||||||
sftp_open
|
|
||||||
sftp_opendir
|
|
||||||
sftp_read
|
|
||||||
sftp_readdir
|
|
||||||
sftp_readlink
|
|
||||||
sftp_rename
|
|
||||||
sftp_reply_attr
|
|
||||||
sftp_reply_data
|
|
||||||
sftp_reply_handle
|
|
||||||
sftp_reply_name
|
|
||||||
sftp_reply_names
|
|
||||||
sftp_reply_names_add
|
|
||||||
sftp_reply_status
|
|
||||||
sftp_rewind
|
|
||||||
sftp_rmdir
|
|
||||||
sftp_seek
|
|
||||||
sftp_seek64
|
|
||||||
sftp_send_client_message
|
|
||||||
sftp_server_free
|
|
||||||
sftp_server_init
|
|
||||||
sftp_server_new
|
|
||||||
sftp_server_version
|
|
||||||
sftp_setstat
|
|
||||||
sftp_stat
|
|
||||||
sftp_statvfs
|
|
||||||
sftp_statvfs_free
|
|
||||||
sftp_symlink
|
|
||||||
sftp_tell
|
|
||||||
sftp_tell64
|
|
||||||
sftp_unlink
|
|
||||||
sftp_utimes
|
|
||||||
sftp_write
|
|
||||||
ssh_accept
|
|
||||||
ssh_add_channel_callbacks
|
|
||||||
ssh_auth_list
|
|
||||||
ssh_basename
|
|
||||||
ssh_bind_accept
|
|
||||||
ssh_bind_accept_fd
|
|
||||||
ssh_bind_fd_toaccept
|
|
||||||
ssh_bind_free
|
|
||||||
ssh_bind_get_fd
|
|
||||||
ssh_bind_listen
|
|
||||||
ssh_bind_new
|
|
||||||
ssh_bind_options_parse_config
|
|
||||||
ssh_bind_options_set
|
|
||||||
ssh_bind_set_blocking
|
|
||||||
ssh_bind_set_callbacks
|
|
||||||
ssh_bind_set_fd
|
|
||||||
ssh_blocking_flush
|
|
||||||
ssh_buffer_add_data
|
|
||||||
ssh_buffer_free
|
|
||||||
ssh_buffer_get
|
|
||||||
ssh_buffer_get_data
|
|
||||||
ssh_buffer_get_len
|
|
||||||
ssh_buffer_new
|
|
||||||
ssh_buffer_reinit
|
|
||||||
ssh_channel_accept_forward
|
|
||||||
ssh_channel_accept_x11
|
|
||||||
ssh_channel_cancel_forward
|
|
||||||
ssh_channel_change_pty_size
|
|
||||||
ssh_channel_close
|
|
||||||
ssh_channel_free
|
|
||||||
ssh_channel_get_exit_state
|
|
||||||
ssh_channel_get_exit_status
|
|
||||||
ssh_channel_get_session
|
|
||||||
ssh_channel_is_closed
|
|
||||||
ssh_channel_is_eof
|
|
||||||
ssh_channel_is_open
|
|
||||||
ssh_channel_listen_forward
|
|
||||||
ssh_channel_new
|
|
||||||
ssh_channel_open_auth_agent
|
|
||||||
ssh_channel_open_forward
|
|
||||||
ssh_channel_open_forward_port
|
|
||||||
ssh_channel_open_forward_unix
|
|
||||||
ssh_channel_open_reverse_forward
|
|
||||||
ssh_channel_open_session
|
|
||||||
ssh_channel_open_x11
|
|
||||||
ssh_channel_poll
|
|
||||||
ssh_channel_poll_timeout
|
|
||||||
ssh_channel_read
|
|
||||||
ssh_channel_read_nonblocking
|
|
||||||
ssh_channel_read_timeout
|
|
||||||
ssh_channel_request_auth_agent
|
|
||||||
ssh_channel_request_env
|
|
||||||
ssh_channel_request_exec
|
|
||||||
ssh_channel_request_pty
|
|
||||||
ssh_channel_request_pty_size
|
|
||||||
ssh_channel_request_pty_size_modes
|
|
||||||
ssh_channel_request_send_break
|
|
||||||
ssh_channel_request_send_exit_signal
|
|
||||||
ssh_channel_request_send_exit_status
|
|
||||||
ssh_channel_request_send_signal
|
|
||||||
ssh_channel_request_sftp
|
|
||||||
ssh_channel_request_shell
|
|
||||||
ssh_channel_request_subsystem
|
|
||||||
ssh_channel_request_x11
|
|
||||||
ssh_channel_select
|
|
||||||
ssh_channel_send_eof
|
|
||||||
ssh_channel_set_blocking
|
|
||||||
ssh_channel_set_counter
|
|
||||||
ssh_channel_window_size
|
|
||||||
ssh_channel_write
|
|
||||||
ssh_channel_write_stderr
|
|
||||||
ssh_clean_pubkey_hash
|
|
||||||
ssh_connect
|
|
||||||
ssh_connector_free
|
|
||||||
ssh_connector_new
|
|
||||||
ssh_connector_set_in_channel
|
|
||||||
ssh_connector_set_in_fd
|
|
||||||
ssh_connector_set_out_channel
|
|
||||||
ssh_connector_set_out_fd
|
|
||||||
ssh_copyright
|
|
||||||
ssh_dirname
|
|
||||||
ssh_disconnect
|
|
||||||
ssh_dump_knownhost
|
|
||||||
ssh_event_add_connector
|
|
||||||
ssh_event_add_fd
|
|
||||||
ssh_event_add_session
|
|
||||||
ssh_event_dopoll
|
|
||||||
ssh_event_free
|
|
||||||
ssh_event_new
|
|
||||||
ssh_event_remove_connector
|
|
||||||
ssh_event_remove_fd
|
|
||||||
ssh_event_remove_session
|
|
||||||
ssh_execute_message_callbacks
|
|
||||||
ssh_finalize
|
|
||||||
ssh_forward_accept
|
|
||||||
ssh_forward_cancel
|
|
||||||
ssh_forward_listen
|
|
||||||
ssh_free
|
|
||||||
ssh_get_cipher_in
|
|
||||||
ssh_get_cipher_out
|
|
||||||
ssh_get_clientbanner
|
|
||||||
ssh_get_disconnect_message
|
|
||||||
ssh_get_error
|
|
||||||
ssh_get_error_code
|
|
||||||
ssh_get_fd
|
|
||||||
ssh_get_fingerprint_hash
|
|
||||||
ssh_get_hexa
|
|
||||||
ssh_get_hmac_in
|
|
||||||
ssh_get_hmac_out
|
|
||||||
ssh_get_issue_banner
|
|
||||||
ssh_get_kex_algo
|
|
||||||
ssh_get_log_callback
|
|
||||||
ssh_get_log_level
|
|
||||||
ssh_get_log_userdata
|
|
||||||
ssh_get_openssh_version
|
|
||||||
ssh_get_poll_flags
|
|
||||||
ssh_get_pubkey
|
|
||||||
ssh_get_pubkey_hash
|
|
||||||
ssh_get_publickey
|
|
||||||
ssh_get_publickey_hash
|
|
||||||
ssh_get_random
|
|
||||||
ssh_get_server_publickey
|
|
||||||
ssh_get_serverbanner
|
|
||||||
ssh_get_status
|
|
||||||
ssh_get_version
|
|
||||||
ssh_getpass
|
|
||||||
ssh_gssapi_get_creds
|
|
||||||
ssh_gssapi_set_creds
|
|
||||||
ssh_handle_key_exchange
|
|
||||||
ssh_init
|
|
||||||
ssh_is_blocking
|
|
||||||
ssh_is_connected
|
|
||||||
ssh_is_server_known
|
|
||||||
ssh_key_cmp
|
|
||||||
ssh_key_dup
|
|
||||||
ssh_key_free
|
|
||||||
ssh_key_is_private
|
|
||||||
ssh_key_is_public
|
|
||||||
ssh_key_new
|
|
||||||
ssh_key_type
|
|
||||||
ssh_key_type_from_name
|
|
||||||
ssh_key_type_to_char
|
|
||||||
ssh_known_hosts_parse_line
|
|
||||||
ssh_knownhosts_entry_free
|
|
||||||
ssh_log
|
|
||||||
ssh_message_auth_interactive_request
|
|
||||||
ssh_message_auth_kbdint_is_response
|
|
||||||
ssh_message_auth_password
|
|
||||||
ssh_message_auth_pubkey
|
|
||||||
ssh_message_auth_publickey
|
|
||||||
ssh_message_auth_publickey_state
|
|
||||||
ssh_message_auth_reply_pk_ok
|
|
||||||
ssh_message_auth_reply_pk_ok_simple
|
|
||||||
ssh_message_auth_reply_success
|
|
||||||
ssh_message_auth_set_methods
|
|
||||||
ssh_message_auth_user
|
|
||||||
ssh_message_channel_request_channel
|
|
||||||
ssh_message_channel_request_command
|
|
||||||
ssh_message_channel_request_env_name
|
|
||||||
ssh_message_channel_request_env_value
|
|
||||||
ssh_message_channel_request_open_destination
|
|
||||||
ssh_message_channel_request_open_destination_port
|
|
||||||
ssh_message_channel_request_open_originator
|
|
||||||
ssh_message_channel_request_open_originator_port
|
|
||||||
ssh_message_channel_request_open_reply_accept
|
|
||||||
ssh_message_channel_request_open_reply_accept_channel
|
|
||||||
ssh_message_channel_request_pty_height
|
|
||||||
ssh_message_channel_request_pty_pxheight
|
|
||||||
ssh_message_channel_request_pty_pxwidth
|
|
||||||
ssh_message_channel_request_pty_term
|
|
||||||
ssh_message_channel_request_pty_width
|
|
||||||
ssh_message_channel_request_reply_success
|
|
||||||
ssh_message_channel_request_subsystem
|
|
||||||
ssh_message_channel_request_x11_auth_cookie
|
|
||||||
ssh_message_channel_request_x11_auth_protocol
|
|
||||||
ssh_message_channel_request_x11_screen_number
|
|
||||||
ssh_message_channel_request_x11_single_connection
|
|
||||||
ssh_message_free
|
|
||||||
ssh_message_get
|
|
||||||
ssh_message_global_request_address
|
|
||||||
ssh_message_global_request_port
|
|
||||||
ssh_message_global_request_reply_success
|
|
||||||
ssh_message_reply_default
|
|
||||||
ssh_message_retrieve
|
|
||||||
ssh_message_service_reply_success
|
|
||||||
ssh_message_service_service
|
|
||||||
ssh_message_subtype
|
|
||||||
ssh_message_type
|
|
||||||
ssh_mkdir
|
|
||||||
ssh_new
|
|
||||||
ssh_options_copy
|
|
||||||
ssh_options_get
|
|
||||||
ssh_options_get_port
|
|
||||||
ssh_options_getopt
|
|
||||||
ssh_options_parse_config
|
|
||||||
ssh_options_set
|
|
||||||
ssh_pcap_file_close
|
|
||||||
ssh_pcap_file_free
|
|
||||||
ssh_pcap_file_new
|
|
||||||
ssh_pcap_file_open
|
|
||||||
ssh_pki_copy_cert_to_privkey
|
|
||||||
ssh_pki_export_privkey_base64
|
|
||||||
ssh_pki_export_privkey_base64_format
|
|
||||||
ssh_pki_export_privkey_file
|
|
||||||
ssh_pki_export_privkey_file_format
|
|
||||||
ssh_pki_export_privkey_to_pubkey
|
|
||||||
ssh_pki_export_pubkey_base64
|
|
||||||
ssh_pki_export_pubkey_file
|
|
||||||
ssh_pki_generate
|
|
||||||
ssh_pki_import_cert_base64
|
|
||||||
ssh_pki_import_cert_file
|
|
||||||
ssh_pki_import_privkey_base64
|
|
||||||
ssh_pki_import_privkey_file
|
|
||||||
ssh_pki_import_pubkey_base64
|
|
||||||
ssh_pki_import_pubkey_file
|
|
||||||
ssh_pki_key_ecdsa_name
|
|
||||||
ssh_print_hash
|
|
||||||
ssh_print_hexa
|
|
||||||
ssh_privatekey_type
|
|
||||||
ssh_publickey_to_file
|
|
||||||
ssh_remove_channel_callbacks
|
|
||||||
ssh_request_no_more_sessions
|
|
||||||
ssh_scp_accept_request
|
|
||||||
ssh_scp_close
|
|
||||||
ssh_scp_deny_request
|
|
||||||
ssh_scp_free
|
|
||||||
ssh_scp_init
|
|
||||||
ssh_scp_leave_directory
|
|
||||||
ssh_scp_new
|
|
||||||
ssh_scp_pull_request
|
|
||||||
ssh_scp_push_directory
|
|
||||||
ssh_scp_push_file
|
|
||||||
ssh_scp_push_file64
|
|
||||||
ssh_scp_read
|
|
||||||
ssh_scp_request_get_filename
|
|
||||||
ssh_scp_request_get_permissions
|
|
||||||
ssh_scp_request_get_size
|
|
||||||
ssh_scp_request_get_size64
|
|
||||||
ssh_scp_request_get_warning
|
|
||||||
ssh_scp_write
|
|
||||||
ssh_select
|
|
||||||
ssh_send_debug
|
|
||||||
ssh_send_ignore
|
|
||||||
ssh_send_issue_banner
|
|
||||||
ssh_send_keepalive
|
|
||||||
ssh_server_init_kex
|
|
||||||
ssh_service_request
|
|
||||||
ssh_session_export_known_hosts_entry
|
|
||||||
ssh_session_get_known_hosts_entry
|
|
||||||
ssh_session_has_known_hosts_entry
|
|
||||||
ssh_session_is_known_server
|
|
||||||
ssh_session_set_disconnect_message
|
|
||||||
ssh_session_update_known_hosts
|
|
||||||
ssh_set_agent_channel
|
|
||||||
ssh_set_agent_socket
|
|
||||||
ssh_set_auth_methods
|
|
||||||
ssh_set_blocking
|
|
||||||
ssh_set_callbacks
|
|
||||||
ssh_set_channel_callbacks
|
|
||||||
ssh_set_counters
|
|
||||||
ssh_set_fd_except
|
|
||||||
ssh_set_fd_toread
|
|
||||||
ssh_set_fd_towrite
|
|
||||||
ssh_set_log_callback
|
|
||||||
ssh_set_log_level
|
|
||||||
ssh_set_log_userdata
|
|
||||||
ssh_set_message_callback
|
|
||||||
ssh_set_pcap_file
|
|
||||||
ssh_set_server_callbacks
|
|
||||||
ssh_silent_disconnect
|
|
||||||
ssh_string_burn
|
|
||||||
ssh_string_copy
|
|
||||||
ssh_string_data
|
|
||||||
ssh_string_fill
|
|
||||||
ssh_string_free
|
|
||||||
ssh_string_free_char
|
|
||||||
ssh_string_from_char
|
|
||||||
ssh_string_get_char
|
|
||||||
ssh_string_len
|
|
||||||
ssh_string_new
|
|
||||||
ssh_string_to_char
|
|
||||||
ssh_threads_get_default
|
|
||||||
ssh_threads_get_noop
|
|
||||||
ssh_threads_get_pthread
|
|
||||||
ssh_threads_set_callbacks
|
|
||||||
ssh_try_publickey_from_file
|
|
||||||
ssh_userauth_agent
|
|
||||||
ssh_userauth_agent_pubkey
|
|
||||||
ssh_userauth_autopubkey
|
|
||||||
ssh_userauth_gssapi
|
|
||||||
ssh_userauth_kbdint
|
|
||||||
ssh_userauth_kbdint_getanswer
|
|
||||||
ssh_userauth_kbdint_getinstruction
|
|
||||||
ssh_userauth_kbdint_getname
|
|
||||||
ssh_userauth_kbdint_getnanswers
|
|
||||||
ssh_userauth_kbdint_getnprompts
|
|
||||||
ssh_userauth_kbdint_getprompt
|
|
||||||
ssh_userauth_kbdint_setanswer
|
|
||||||
ssh_userauth_list
|
|
||||||
ssh_userauth_none
|
|
||||||
ssh_userauth_offer_pubkey
|
|
||||||
ssh_userauth_password
|
|
||||||
ssh_userauth_privatekey_file
|
|
||||||
ssh_userauth_pubkey
|
|
||||||
ssh_userauth_publickey
|
|
||||||
ssh_userauth_publickey_auto
|
|
||||||
ssh_userauth_publickey_auto_get_current_identity
|
|
||||||
ssh_userauth_try_publickey
|
|
||||||
ssh_version
|
|
||||||
ssh_vlog
|
|
||||||
ssh_write_knownhost
|
|
||||||
string_burn
|
|
||||||
string_copy
|
|
||||||
string_data
|
|
||||||
string_fill
|
|
||||||
string_free
|
|
||||||
string_from_char
|
|
||||||
string_len
|
|
||||||
string_new
|
|
||||||
string_to_char
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
set(LIBSSH_PUBLIC_INCLUDE_DIRS ${libssh_SOURCE_DIR}/include)
|
set(LIBSSH_PUBLIC_INCLUDE_DIRS ${libssh_SOURCE_DIR}/include)
|
||||||
|
|
||||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||||
|
${libssh_BINARY_DIR}/include
|
||||||
${libssh_BINARY_DIR}
|
${libssh_BINARY_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -8,9 +9,17 @@ set(LIBSSH_LINK_LIBRARIES
|
|||||||
${LIBSSH_REQUIRED_LIBRARIES}
|
${LIBSSH_REQUIRED_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (TARGET OpenSSL::Crypto)
|
if (OPENSSL_CRYPTO_LIBRARIES)
|
||||||
list(APPEND LIBSSH_LINK_LIBRARIES OpenSSL::Crypto)
|
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||||
endif ()
|
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||||
|
${OPENSSL_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(LIBSSH_LINK_LIBRARIES
|
||||||
|
${LIBSSH_LINK_LIBRARIES}
|
||||||
|
${OPENSSL_CRYPTO_LIBRARIES}
|
||||||
|
)
|
||||||
|
endif (OPENSSL_CRYPTO_LIBRARIES)
|
||||||
|
|
||||||
if (MBEDTLS_CRYPTO_LIBRARY)
|
if (MBEDTLS_CRYPTO_LIBRARY)
|
||||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||||
@@ -35,7 +44,15 @@ if (GCRYPT_LIBRARIES)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WITH_ZLIB)
|
if (WITH_ZLIB)
|
||||||
list(APPEND LIBSSH_LINK_LIBRARIES ZLIB::ZLIB)
|
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||||
|
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||||
|
${ZLIB_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(LIBSSH_LINK_LIBRARIES
|
||||||
|
${LIBSSH_LINK_LIBRARIES}
|
||||||
|
${ZLIB_LIBRARY}
|
||||||
|
)
|
||||||
endif (WITH_ZLIB)
|
endif (WITH_ZLIB)
|
||||||
|
|
||||||
if (WITH_GSSAPI AND GSSAPI_FOUND)
|
if (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||||
@@ -69,7 +86,7 @@ if (MINGW AND Threads_FOUND)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# The ws2_32 needs to be last for mingw to build
|
# This needs to be last for mingw to build
|
||||||
# https://gitlab.com/libssh/libssh-mirror/-/issues/84
|
# https://gitlab.com/libssh/libssh-mirror/-/issues/84
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
set(LIBSSH_LINK_LIBRARIES
|
set(LIBSSH_LINK_LIBRARIES
|
||||||
@@ -127,7 +144,6 @@ set(libssh_SRCS
|
|||||||
socket.c
|
socket.c
|
||||||
string.c
|
string.c
|
||||||
threads.c
|
threads.c
|
||||||
ttyopts.c
|
|
||||||
wrapper.c
|
wrapper.c
|
||||||
external/bcrypt_pbkdf.c
|
external/bcrypt_pbkdf.c
|
||||||
external/blowfish.c
|
external/blowfish.c
|
||||||
@@ -223,22 +239,33 @@ else (WITH_GCRYPT)
|
|||||||
libcrypto.c
|
libcrypto.c
|
||||||
dh_crypto.c
|
dh_crypto.c
|
||||||
)
|
)
|
||||||
if (NOT HAVE_OPENSSL_EVP_CHACHA20)
|
if (NOT HAVE_OPENSSL_ED25519)
|
||||||
|
set(libssh_SRCS
|
||||||
|
${libssh_SRCS}
|
||||||
|
pki_ed25519.c
|
||||||
|
external/ed25519.c
|
||||||
|
external/fe25519.c
|
||||||
|
external/ge25519.c
|
||||||
|
external/sc25519.c
|
||||||
|
)
|
||||||
|
endif (NOT HAVE_OPENSSL_ED25519)
|
||||||
|
if (NOT (HAVE_OPENSSL_EVP_CHACHA20 AND HAVE_OPENSSL_EVP_POLY1305))
|
||||||
set(libssh_SRCS
|
set(libssh_SRCS
|
||||||
${libssh_SRCS}
|
${libssh_SRCS}
|
||||||
external/chacha.c
|
external/chacha.c
|
||||||
external/poly1305.c
|
external/poly1305.c
|
||||||
chachapoly.c
|
chachapoly.c
|
||||||
)
|
)
|
||||||
endif (NOT HAVE_OPENSSL_EVP_CHACHA20)
|
endif (NOT (HAVE_OPENSSL_EVP_CHACHA20 AND HAVE_OPENSSL_EVP_POLY1305))
|
||||||
|
if(OPENSSL_VERSION VERSION_LESS "1.1.0")
|
||||||
|
set(libssh_SRCS ${libssh_SRCS} libcrypto-compat.c)
|
||||||
|
endif()
|
||||||
endif (WITH_GCRYPT)
|
endif (WITH_GCRYPT)
|
||||||
|
|
||||||
if (WITH_SFTP)
|
if (WITH_SFTP)
|
||||||
set(libssh_SRCS
|
set(libssh_SRCS
|
||||||
${libssh_SRCS}
|
${libssh_SRCS}
|
||||||
sftp.c
|
sftp.c
|
||||||
sftp_common.c
|
|
||||||
sftp_aio.c
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (WITH_SERVER)
|
if (WITH_SERVER)
|
||||||
@@ -280,7 +307,7 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
|
|||||||
endif (WITH_GSSAPI AND GSSAPI_FOUND)
|
endif (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||||
|
|
||||||
if (NOT WITH_NACL)
|
if (NOT WITH_NACL)
|
||||||
if (NOT HAVE_LIBCRYPTO)
|
if (NOT HAVE_LIBCRYPTO OR NOT HAVE_OPENSSL_ED25519)
|
||||||
set(libssh_SRCS
|
set(libssh_SRCS
|
||||||
${libssh_SRCS}
|
${libssh_SRCS}
|
||||||
external/curve25519_ref.c
|
external/curve25519_ref.c
|
||||||
@@ -331,7 +358,6 @@ endif ()
|
|||||||
target_include_directories(ssh
|
target_include_directories(ssh
|
||||||
PUBLIC
|
PUBLIC
|
||||||
$<BUILD_INTERFACE:${libssh_SOURCE_DIR}/include>
|
$<BUILD_INTERFACE:${libssh_SOURCE_DIR}/include>
|
||||||
$<BUILD_INTERFACE:${libssh_BINARY_DIR}/include>
|
|
||||||
$<INSTALL_INTERFACE:include>
|
$<INSTALL_INTERFACE:include>
|
||||||
PRIVATE ${LIBSSH_PRIVATE_INCLUDE_DIRS})
|
PRIVATE ${LIBSSH_PRIVATE_INCLUDE_DIRS})
|
||||||
|
|
||||||
@@ -355,8 +381,6 @@ endif (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT)
|
|||||||
|
|
||||||
set_target_properties(ssh
|
set_target_properties(ssh
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
C_STANDARD
|
|
||||||
99
|
|
||||||
VERSION
|
VERSION
|
||||||
${LIBRARY_VERSION}
|
${LIBRARY_VERSION}
|
||||||
SOVERSION
|
SOVERSION
|
||||||
@@ -373,10 +397,6 @@ if (MINGW)
|
|||||||
target_link_libraries(ssh PRIVATE "-Wl,--enable-stdcall-fixup")
|
target_link_libraries(ssh PRIVATE "-Wl,--enable-stdcall-fixup")
|
||||||
target_compile_definitions(ssh PRIVATE "_POSIX_SOURCE")
|
target_compile_definitions(ssh PRIVATE "_POSIX_SOURCE")
|
||||||
endif ()
|
endif ()
|
||||||
if (WITH_COVERAGE)
|
|
||||||
include(CodeCoverage)
|
|
||||||
append_coverage_compiler_flags_to_target(ssh)
|
|
||||||
endif (WITH_COVERAGE)
|
|
||||||
|
|
||||||
|
|
||||||
install(TARGETS ssh
|
install(TARGETS ssh
|
||||||
@@ -401,7 +421,6 @@ if (BUILD_STATIC_LIB)
|
|||||||
target_include_directories(ssh-static
|
target_include_directories(ssh-static
|
||||||
PUBLIC
|
PUBLIC
|
||||||
$<BUILD_INTERFACE:${libssh_SOURCE_DIR}/include>
|
$<BUILD_INTERFACE:${libssh_SOURCE_DIR}/include>
|
||||||
$<BUILD_INTERFACE:${libssh_BINARY_DIR}/include>
|
|
||||||
$<INSTALL_INTERFACE:include>
|
$<INSTALL_INTERFACE:include>
|
||||||
PRIVATE ${LIBSSH_PRIVATE_INCLUDE_DIRS})
|
PRIVATE ${LIBSSH_PRIVATE_INCLUDE_DIRS})
|
||||||
target_link_libraries(ssh-static
|
target_link_libraries(ssh-static
|
||||||
@@ -429,9 +448,6 @@ if (BUILD_STATIC_LIB)
|
|||||||
if (WIN32)
|
if (WIN32)
|
||||||
target_compile_definitions(ssh-static PUBLIC "LIBSSH_STATIC")
|
target_compile_definitions(ssh-static PUBLIC "LIBSSH_STATIC")
|
||||||
endif (WIN32)
|
endif (WIN32)
|
||||||
if (WITH_COVERAGE)
|
|
||||||
append_coverage_compiler_flags_to_target(ssh-static)
|
|
||||||
endif (WITH_COVERAGE)
|
|
||||||
endif (BUILD_STATIC_LIB)
|
endif (BUILD_STATIC_LIB)
|
||||||
|
|
||||||
message(STATUS "Threads_FOUND=${Threads_FOUND}")
|
message(STATUS "Threads_FOUND=${Threads_FOUND}")
|
||||||
|
|||||||
30
src/agent.c
30
src/agent.c
@@ -275,19 +275,19 @@ static int agent_talk(struct ssh_session_struct *session,
|
|||||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||||
|
|
||||||
len = ssh_buffer_get_len(request);
|
len = ssh_buffer_get_len(request);
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Request length: %" PRIu32, len);
|
SSH_LOG(SSH_LOG_TRACE, "Request length: %u", len);
|
||||||
PUSH_BE_U32(payload, 0, len);
|
PUSH_BE_U32(payload, 0, len);
|
||||||
|
|
||||||
/* send length and then the request packet */
|
/* send length and then the request packet */
|
||||||
if (atomicio(session->agent, payload, 4, 0) == 4) {
|
if (atomicio(session->agent, payload, 4, 0) == 4) {
|
||||||
if (atomicio(session->agent, ssh_buffer_get(request), len, 0)
|
if (atomicio(session->agent, ssh_buffer_get(request), len, 0)
|
||||||
!= len) {
|
!= len) {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "atomicio sending request failed: %s",
|
SSH_LOG(SSH_LOG_WARN, "atomicio sending request failed: %s",
|
||||||
strerror(errno));
|
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"atomicio sending request length failed: %s",
|
"atomicio sending request length failed: %s",
|
||||||
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||||
return -1;
|
return -1;
|
||||||
@@ -295,27 +295,27 @@ static int agent_talk(struct ssh_session_struct *session,
|
|||||||
|
|
||||||
/* wait for response, read the length of the response packet */
|
/* wait for response, read the length of the response packet */
|
||||||
if (atomicio(session->agent, payload, 4, 1) != 4) {
|
if (atomicio(session->agent, payload, 4, 1) != 4) {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "atomicio read response length failed: %s",
|
SSH_LOG(SSH_LOG_WARN, "atomicio read response length failed: %s",
|
||||||
strerror(errno));
|
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = PULL_BE_U32(payload, 0);
|
len = PULL_BE_U32(payload, 0);
|
||||||
if (len > 256 * 1024) {
|
if (len > 256 * 1024) {
|
||||||
ssh_set_error(session, SSH_FATAL,
|
ssh_set_error(session, SSH_FATAL,
|
||||||
"Authentication response too long: %" PRIu32, len);
|
"Authentication response too long: %u", len);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Response length: %" PRIu32, len);
|
SSH_LOG(SSH_LOG_TRACE, "Response length: %u", len);
|
||||||
|
|
||||||
payload = ssh_buffer_allocate(reply, len);
|
payload = ssh_buffer_allocate(reply, len);
|
||||||
if (payload == NULL) {
|
if (payload == NULL) {
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "Not enough space");
|
SSH_LOG(SSH_LOG_WARN, "Not enough space");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atomicio(session->agent, payload, len, 1) != len) {
|
if (atomicio(session->agent, payload, len, 1) != len) {
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"Error reading response from authentication socket.");
|
"Error reading response from authentication socket.");
|
||||||
/* Rollback the unused space */
|
/* Rollback the unused space */
|
||||||
ssh_buffer_pass_bytes_end(reply, len);
|
ssh_buffer_pass_bytes_end(reply, len);
|
||||||
@@ -363,7 +363,7 @@ uint32_t ssh_agent_get_ident_count(struct ssh_session_struct *session)
|
|||||||
rc = ssh_buffer_get_u8(reply, (uint8_t *) &type);
|
rc = ssh_buffer_get_u8(reply, (uint8_t *) &type);
|
||||||
if (rc != sizeof(uint8_t)) {
|
if (rc != sizeof(uint8_t)) {
|
||||||
ssh_set_error(session, SSH_FATAL,
|
ssh_set_error(session, SSH_FATAL,
|
||||||
"Bad authentication reply size: %" PRIu32, rc);
|
"Bad authentication reply size: %d", rc);
|
||||||
SSH_BUFFER_FREE(reply);
|
SSH_BUFFER_FREE(reply);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -371,7 +371,7 @@ uint32_t ssh_agent_get_ident_count(struct ssh_session_struct *session)
|
|||||||
type = bswap_32(type);
|
type = bswap_32(type);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"Answer type: %d, expected answer: %d",
|
"Answer type: %d, expected answer: %d",
|
||||||
type, SSH2_AGENT_IDENTITIES_ANSWER);
|
type, SSH2_AGENT_IDENTITIES_ANSWER);
|
||||||
|
|
||||||
@@ -404,7 +404,9 @@ uint32_t ssh_agent_get_ident_count(struct ssh_session_struct *session)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh_buffer_free(session->agent->ident);
|
if (session->agent->ident) {
|
||||||
|
ssh_buffer_reinit(session->agent->ident);
|
||||||
|
}
|
||||||
session->agent->ident = reply;
|
session->agent->ident = reply;
|
||||||
|
|
||||||
return session->agent->count;
|
return session->agent->count;
|
||||||
@@ -589,7 +591,7 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (agent_failed(type)) {
|
if (agent_failed(type)) {
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "Agent reports failure in signing the key");
|
SSH_LOG(SSH_LOG_WARN, "Agent reports failure in signing the key");
|
||||||
SSH_BUFFER_FREE(reply);
|
SSH_BUFFER_FREE(reply);
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (type != SSH2_AGENT_SIGN_RESPONSE) {
|
} else if (type != SSH2_AGENT_SIGN_RESPONSE) {
|
||||||
|
|||||||
515
src/auth.c
515
src/auth.c
@@ -72,7 +72,7 @@ static int ssh_userauth_request_service(ssh_session session)
|
|||||||
|
|
||||||
rc = ssh_service_request(session, "ssh-userauth");
|
rc = ssh_service_request(session, "ssh-userauth");
|
||||||
if ((rc != SSH_OK) && (rc != SSH_AGAIN)) {
|
if ((rc != SSH_OK) && (rc != SSH_AGAIN)) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"Failed to request \"ssh-userauth\" service");
|
"Failed to request \"ssh-userauth\" service");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +202,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_banner) {
|
|||||||
|
|
||||||
banner = ssh_buffer_get_ssh_string(packet);
|
banner = ssh_buffer_get_ssh_string(packet);
|
||||||
if (banner == NULL) {
|
if (banner == NULL) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"Invalid SSH_USERAUTH_BANNER packet");
|
"Invalid SSH_USERAUTH_BANNER packet");
|
||||||
} else {
|
} else {
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_DEBUG,
|
||||||
@@ -240,7 +240,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_failure) {
|
|||||||
|
|
||||||
if (partial) {
|
if (partial) {
|
||||||
session->auth.state = SSH_AUTH_STATE_PARTIAL;
|
session->auth.state = SSH_AUTH_STATE_PARTIAL;
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_INFO,
|
||||||
"Partial success for '%s'. Authentication that can continue: %s",
|
"Partial success for '%s'. Authentication that can continue: %s",
|
||||||
current_method,
|
current_method,
|
||||||
auth_methods);
|
auth_methods);
|
||||||
@@ -250,7 +250,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_failure) {
|
|||||||
"Access denied for '%s'. Authentication that can continue: %s",
|
"Access denied for '%s'. Authentication that can continue: %s",
|
||||||
current_method,
|
current_method,
|
||||||
auth_methods);
|
auth_methods);
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_INFO,
|
||||||
"%s",
|
"%s",
|
||||||
ssh_get_error(session));
|
ssh_get_error(session));
|
||||||
|
|
||||||
@@ -557,7 +557,6 @@ int ssh_userauth_try_publickey(ssh_session session,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Trying signature type %s", sig_type_c);
|
|
||||||
/* request */
|
/* request */
|
||||||
rc = ssh_buffer_pack(session->out_buffer, "bsssbsS",
|
rc = ssh_buffer_pack(session->out_buffer, "bsssbsS",
|
||||||
SSH2_MSG_USERAUTH_REQUEST,
|
SSH2_MSG_USERAUTH_REQUEST,
|
||||||
@@ -691,7 +690,6 @@ int ssh_userauth_publickey(ssh_session session,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Sending signature type %s", sig_type_c);
|
|
||||||
/* request */
|
/* request */
|
||||||
rc = ssh_buffer_pack(session->out_buffer, "bsssbsS",
|
rc = ssh_buffer_pack(session->out_buffer, "bsssbsS",
|
||||||
SSH2_MSG_USERAUTH_REQUEST,
|
SSH2_MSG_USERAUTH_REQUEST,
|
||||||
@@ -756,17 +754,16 @@ static int ssh_userauth_agent_publickey(ssh_session session,
|
|||||||
bool allowed;
|
bool allowed;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
switch (session->pending_call_state) {
|
switch(session->pending_call_state) {
|
||||||
case SSH_PENDING_CALL_NONE:
|
case SSH_PENDING_CALL_NONE:
|
||||||
break;
|
break;
|
||||||
case SSH_PENDING_CALL_AUTH_AGENT:
|
case SSH_PENDING_CALL_AUTH_AGENT:
|
||||||
goto pending;
|
goto pending;
|
||||||
default:
|
default:
|
||||||
ssh_set_error(session,
|
ssh_set_error(session,
|
||||||
SSH_FATAL,
|
SSH_FATAL,
|
||||||
"Bad call during pending SSH call in %s",
|
"Bad call during pending SSH call in ssh_userauth_try_publickey");
|
||||||
__func__);
|
return SSH_ERROR;
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = ssh_userauth_request_service(session);
|
rc = ssh_userauth_request_service(session);
|
||||||
@@ -810,14 +807,14 @@ static int ssh_userauth_agent_publickey(ssh_session session,
|
|||||||
|
|
||||||
/* request */
|
/* request */
|
||||||
rc = ssh_buffer_pack(session->out_buffer, "bsssbsS",
|
rc = ssh_buffer_pack(session->out_buffer, "bsssbsS",
|
||||||
SSH2_MSG_USERAUTH_REQUEST,
|
SSH2_MSG_USERAUTH_REQUEST,
|
||||||
username ? username : session->opts.username,
|
username ? username : session->opts.username,
|
||||||
"ssh-connection",
|
"ssh-connection",
|
||||||
"publickey",
|
"publickey",
|
||||||
1, /* private key */
|
1, /* private key */
|
||||||
sig_type_c, /* algo */
|
sig_type_c, /* algo */
|
||||||
pubkey_s /* public key */
|
pubkey_s /* public key */
|
||||||
);
|
);
|
||||||
SSH_STRING_FREE(pubkey_s);
|
SSH_STRING_FREE(pubkey_s);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -861,7 +858,6 @@ fail:
|
|||||||
enum ssh_agent_state_e {
|
enum ssh_agent_state_e {
|
||||||
SSH_AGENT_STATE_NONE = 0,
|
SSH_AGENT_STATE_NONE = 0,
|
||||||
SSH_AGENT_STATE_PUBKEY,
|
SSH_AGENT_STATE_PUBKEY,
|
||||||
SSH_AGENT_STATE_CERT,
|
|
||||||
SSH_AGENT_STATE_AUTH
|
SSH_AGENT_STATE_AUTH
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -909,12 +905,7 @@ int ssh_userauth_agent(ssh_session session,
|
|||||||
const char *username)
|
const char *username)
|
||||||
{
|
{
|
||||||
int rc = SSH_AUTH_ERROR;
|
int rc = SSH_AUTH_ERROR;
|
||||||
struct ssh_agent_state_struct *state = NULL;
|
struct ssh_agent_state_struct *state;
|
||||||
ssh_key *configKeys = NULL;
|
|
||||||
ssh_key *configCerts = NULL;
|
|
||||||
size_t configKeysCount = 0;
|
|
||||||
size_t configCertsCount = 0;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if (session == NULL) {
|
if (session == NULL) {
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
@@ -931,7 +922,7 @@ int ssh_userauth_agent(ssh_session session,
|
|||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
ZERO_STRUCTP(session->agent_state);
|
ZERO_STRUCTP(session->agent_state);
|
||||||
session->agent_state->state = SSH_AGENT_STATE_NONE;
|
session->agent_state->state=SSH_AGENT_STATE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
state = session->agent_state;
|
state = session->agent_state;
|
||||||
@@ -943,230 +934,62 @@ int ssh_userauth_agent(ssh_session session,
|
|||||||
return SSH_AUTH_DENIED;
|
return SSH_AUTH_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session->opts.identities_only) {
|
|
||||||
/*
|
|
||||||
* Read keys mentioned in the config, so we can check if key from agent
|
|
||||||
* is in there.
|
|
||||||
*/
|
|
||||||
size_t identityLen = ssh_list_count(session->opts.identity);
|
|
||||||
size_t certsLen = ssh_list_count(session->opts.certificate);
|
|
||||||
struct ssh_iterator *it = ssh_list_get_iterator(session->opts.identity);
|
|
||||||
|
|
||||||
configKeys = malloc(identityLen * sizeof(ssh_key));
|
|
||||||
configCerts = malloc((certsLen + identityLen) * sizeof(ssh_key));
|
|
||||||
if (configKeys == NULL || configCerts == NULL) {
|
|
||||||
free(configKeys);
|
|
||||||
free(configCerts);
|
|
||||||
ssh_set_error_oom(session);
|
|
||||||
return SSH_AUTH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (it != NULL && configKeysCount < identityLen) {
|
|
||||||
const char *privkeyFile = it->data;
|
|
||||||
size_t certPathLen;
|
|
||||||
char *certFile = NULL;
|
|
||||||
ssh_key pubkey = NULL;
|
|
||||||
ssh_key cert = NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read the private key file listed in the config, but we're only
|
|
||||||
* interested in the public key. Don't try to decrypt private key.
|
|
||||||
*/
|
|
||||||
rc = ssh_pki_import_pubkey_file(privkeyFile, &pubkey);
|
|
||||||
if (rc == SSH_OK) {
|
|
||||||
configKeys[configKeysCount++] = pubkey;
|
|
||||||
} else {
|
|
||||||
char *pubkeyFile = NULL;
|
|
||||||
size_t pubkeyPathLen = strlen(privkeyFile) + sizeof(".pub");
|
|
||||||
|
|
||||||
SSH_KEY_FREE(pubkey);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we couldn't get the public key from the private key file,
|
|
||||||
* try a .pub file instead.
|
|
||||||
*/
|
|
||||||
pubkeyFile = malloc(pubkeyPathLen);
|
|
||||||
if (!pubkeyFile) {
|
|
||||||
ssh_set_error_oom(session);
|
|
||||||
rc = SSH_AUTH_ERROR;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
snprintf(pubkeyFile, pubkeyPathLen, "%s.pub", privkeyFile);
|
|
||||||
rc = ssh_pki_import_pubkey_file(pubkeyFile, &pubkey);
|
|
||||||
free(pubkeyFile);
|
|
||||||
if (rc == SSH_OK) {
|
|
||||||
configKeys[configKeysCount++] = pubkey;
|
|
||||||
} else if (pubkey) {
|
|
||||||
SSH_KEY_FREE(pubkey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Now try to see if there is a certificate with default name
|
|
||||||
* do not merge it yet with the key as we need to try first the
|
|
||||||
* non-certified key */
|
|
||||||
certPathLen = strlen(privkeyFile) + sizeof("-cert.pub");
|
|
||||||
certFile = malloc(certPathLen);
|
|
||||||
if (!certFile) {
|
|
||||||
ssh_set_error_oom(session);
|
|
||||||
rc = SSH_AUTH_ERROR;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
snprintf(certFile, certPathLen, "%s-cert.pub", privkeyFile);
|
|
||||||
rc = ssh_pki_import_cert_file(certFile, &cert);
|
|
||||||
free(certFile);
|
|
||||||
if (rc == SSH_OK) {
|
|
||||||
configCerts[configCertsCount++] = cert;
|
|
||||||
} else if (cert) {
|
|
||||||
SSH_KEY_FREE(cert);
|
|
||||||
}
|
|
||||||
|
|
||||||
it = it->next;
|
|
||||||
}
|
|
||||||
/* And now load separately-listed certificates. */
|
|
||||||
it = ssh_list_get_iterator(session->opts.certificate);
|
|
||||||
while (it != NULL && configCertsCount < certsLen + identityLen) {
|
|
||||||
const char *certFile = it->data;
|
|
||||||
ssh_key cert = NULL;
|
|
||||||
|
|
||||||
rc = ssh_pki_import_cert_file(certFile, &cert);
|
|
||||||
if (rc == SSH_OK) {
|
|
||||||
configCerts[configCertsCount++] = cert;
|
|
||||||
} else if (cert) {
|
|
||||||
SSH_KEY_FREE(cert);
|
|
||||||
}
|
|
||||||
|
|
||||||
it = it->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (state->pubkey != NULL) {
|
while (state->pubkey != NULL) {
|
||||||
if (state->state == SSH_AGENT_STATE_NONE) {
|
if (state->state == SSH_AGENT_STATE_NONE) {
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_DEBUG,
|
||||||
"Trying identity %s",
|
"Trying identity %s", state->comment);
|
||||||
state->comment);
|
|
||||||
if (session->opts.identities_only) {
|
|
||||||
/* Check if this key is one of the keys listed in the config */
|
|
||||||
bool found_key = false;
|
|
||||||
for (i = 0; i < configKeysCount; i++) {
|
|
||||||
int cmp = ssh_key_cmp(state->pubkey,
|
|
||||||
configKeys[i],
|
|
||||||
SSH_KEY_CMP_PUBLIC);
|
|
||||||
if (cmp == 0) {
|
|
||||||
found_key = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* or in separate certificates */
|
|
||||||
for (i = 0; i < configCertsCount; i++) {
|
|
||||||
int cmp = ssh_key_cmp(state->pubkey,
|
|
||||||
configCerts[i],
|
|
||||||
SSH_KEY_CMP_PUBLIC);
|
|
||||||
if (cmp == 0) {
|
|
||||||
found_key = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found_key) {
|
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
|
||||||
"Identities only is enabled and identity %s was "
|
|
||||||
"not listed in config, skipping",
|
|
||||||
state->comment);
|
|
||||||
SSH_STRING_FREE_CHAR(state->comment);
|
|
||||||
state->comment = NULL;
|
|
||||||
SSH_KEY_FREE(state->pubkey);
|
|
||||||
state->pubkey = ssh_agent_get_next_ident(
|
|
||||||
session, &state->comment);
|
|
||||||
|
|
||||||
if (state->pubkey == NULL) {
|
|
||||||
rc = SSH_AUTH_DENIED;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (state->state == SSH_AGENT_STATE_NONE ||
|
if (state->state == SSH_AGENT_STATE_NONE ||
|
||||||
state->state == SSH_AGENT_STATE_PUBKEY ||
|
state->state == SSH_AGENT_STATE_PUBKEY) {
|
||||||
state->state == SSH_AGENT_STATE_CERT) {
|
|
||||||
rc = ssh_userauth_try_publickey(session, username, state->pubkey);
|
rc = ssh_userauth_try_publickey(session, username, state->pubkey);
|
||||||
if (rc == SSH_AUTH_ERROR) {
|
if (rc == SSH_AUTH_ERROR) {
|
||||||
ssh_agent_state_free(state);
|
ssh_agent_state_free (state);
|
||||||
session->agent_state = NULL;
|
session->agent_state = NULL;
|
||||||
goto done;
|
return rc;
|
||||||
} else if (rc == SSH_AUTH_AGAIN) {
|
} else if (rc == SSH_AUTH_AGAIN) {
|
||||||
state->state = (state->state == SSH_AGENT_STATE_NONE ?
|
state->state = SSH_AGENT_STATE_PUBKEY;
|
||||||
SSH_AGENT_STATE_PUBKEY : state->state);
|
return rc;
|
||||||
goto done;
|
|
||||||
} else if (rc != SSH_AUTH_SUCCESS) {
|
} else if (rc != SSH_AUTH_SUCCESS) {
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_DEBUG,
|
||||||
"Public key of %s refused by server",
|
"Public key of %s refused by server", state->comment);
|
||||||
state->comment);
|
|
||||||
if (state->state == SSH_AGENT_STATE_PUBKEY) {
|
|
||||||
for (i = 0; i < configCertsCount; i++) {
|
|
||||||
int cmp = ssh_key_cmp(state->pubkey,
|
|
||||||
configCerts[i],
|
|
||||||
SSH_KEY_CMP_PUBLIC);
|
|
||||||
if (cmp == 0) {
|
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
|
||||||
"Retry with matching certificate");
|
|
||||||
SSH_KEY_FREE(state->pubkey);
|
|
||||||
state->pubkey = ssh_key_dup(configCerts[i]);
|
|
||||||
state->state = SSH_AGENT_STATE_CERT;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SSH_STRING_FREE_CHAR(state->comment);
|
SSH_STRING_FREE_CHAR(state->comment);
|
||||||
state->comment = NULL;
|
state->comment = NULL;
|
||||||
SSH_KEY_FREE(state->pubkey);
|
ssh_key_free(state->pubkey);
|
||||||
state->pubkey = ssh_agent_get_next_ident(session,
|
state->pubkey = ssh_agent_get_next_ident(session, &state->comment);
|
||||||
&state->comment);
|
|
||||||
state->state = SSH_AGENT_STATE_NONE;
|
state->state = SSH_AGENT_STATE_NONE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_DEBUG,
|
||||||
"Public key of %s accepted by server",
|
"Public key of %s accepted by server", state->comment);
|
||||||
state->comment);
|
|
||||||
state->state = SSH_AGENT_STATE_AUTH;
|
state->state = SSH_AGENT_STATE_AUTH;
|
||||||
}
|
}
|
||||||
if (state->state == SSH_AGENT_STATE_AUTH) {
|
if (state->state == SSH_AGENT_STATE_AUTH) {
|
||||||
rc = ssh_userauth_agent_publickey(session, username, state->pubkey);
|
rc = ssh_userauth_agent_publickey(session, username, state->pubkey);
|
||||||
if (rc == SSH_AUTH_AGAIN) {
|
if (rc == SSH_AUTH_AGAIN)
|
||||||
goto done;
|
return rc;
|
||||||
}
|
|
||||||
SSH_STRING_FREE_CHAR(state->comment);
|
SSH_STRING_FREE_CHAR(state->comment);
|
||||||
state->comment = NULL;
|
state->comment = NULL;
|
||||||
if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_PARTIAL) {
|
if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_PARTIAL) {
|
||||||
ssh_agent_state_free(session->agent_state);
|
ssh_agent_state_free (session->agent_state);
|
||||||
session->agent_state = NULL;
|
session->agent_state = NULL;
|
||||||
goto done;
|
return rc;
|
||||||
} else if (rc != SSH_AUTH_SUCCESS) {
|
} else if (rc != SSH_AUTH_SUCCESS) {
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_INFO,
|
||||||
"Server accepted public key but refused the signature");
|
"Server accepted public key but refused the signature");
|
||||||
SSH_KEY_FREE(state->pubkey);
|
ssh_key_free(state->pubkey);
|
||||||
state->pubkey = ssh_agent_get_next_ident(session,
|
state->pubkey = ssh_agent_get_next_ident(session, &state->comment);
|
||||||
&state->comment);
|
|
||||||
state->state = SSH_AGENT_STATE_NONE;
|
state->state = SSH_AGENT_STATE_NONE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ssh_agent_state_free (session->agent_state);
|
ssh_agent_state_free (session->agent_state);
|
||||||
session->agent_state = NULL;
|
session->agent_state = NULL;
|
||||||
rc = SSH_AUTH_SUCCESS;
|
return SSH_AUTH_SUCCESS;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh_agent_state_free (session->agent_state);
|
ssh_agent_state_free (session->agent_state);
|
||||||
session->agent_state = NULL;
|
session->agent_state = NULL;
|
||||||
done:
|
|
||||||
for (i = 0; i < configKeysCount; i++) {
|
|
||||||
ssh_key_free(configKeys[i]);
|
|
||||||
}
|
|
||||||
free(configKeys);
|
|
||||||
for (i = 0; i < configCertsCount; i++) {
|
|
||||||
ssh_key_free(configCerts[i]);
|
|
||||||
}
|
|
||||||
free(configCerts);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1174,8 +997,6 @@ enum ssh_auth_auto_state_e {
|
|||||||
SSH_AUTH_AUTO_STATE_NONE = 0,
|
SSH_AUTH_AUTO_STATE_NONE = 0,
|
||||||
SSH_AUTH_AUTO_STATE_PUBKEY,
|
SSH_AUTH_AUTO_STATE_PUBKEY,
|
||||||
SSH_AUTH_AUTO_STATE_KEY_IMPORTED,
|
SSH_AUTH_AUTO_STATE_KEY_IMPORTED,
|
||||||
SSH_AUTH_AUTO_STATE_CERTIFICATE_FILE,
|
|
||||||
SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION,
|
|
||||||
SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED
|
SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1184,8 +1005,6 @@ struct ssh_auth_auto_state_struct {
|
|||||||
struct ssh_iterator *it;
|
struct ssh_iterator *it;
|
||||||
ssh_key privkey;
|
ssh_key privkey;
|
||||||
ssh_key pubkey;
|
ssh_key pubkey;
|
||||||
ssh_key cert;
|
|
||||||
struct ssh_iterator *cert_it;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1220,8 +1039,7 @@ int ssh_userauth_publickey_auto_get_current_identity(ssh_session session,
|
|||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session->auth.auto_state != NULL &&
|
if (session->auth.auto_state != NULL && session->auth.auto_state->it != NULL) {
|
||||||
session->auth.auto_state->it != NULL) {
|
|
||||||
id = session->auth.auto_state->it->data;
|
id = session->auth.auto_state->it->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1265,9 +1083,6 @@ int ssh_userauth_publickey_auto_get_current_identity(ssh_session session,
|
|||||||
* @note Most server implementations do not permit changing the username during
|
* @note Most server implementations do not permit changing the username during
|
||||||
* authentication. The username should only be set with ssh_options_set() only
|
* authentication. The username should only be set with ssh_options_set() only
|
||||||
* before you connect to the server.
|
* before you connect to the server.
|
||||||
*
|
|
||||||
* The OpenSSH iterates over the identities and first try the plain public key
|
|
||||||
* and then the certificate if it is in place.
|
|
||||||
*/
|
*/
|
||||||
int ssh_userauth_publickey_auto(ssh_session session,
|
int ssh_userauth_publickey_auto(ssh_session session,
|
||||||
const char *username,
|
const char *username,
|
||||||
@@ -1275,7 +1090,7 @@ int ssh_userauth_publickey_auto(ssh_session session,
|
|||||||
{
|
{
|
||||||
ssh_auth_callback auth_fn = NULL;
|
ssh_auth_callback auth_fn = NULL;
|
||||||
void *auth_data = NULL;
|
void *auth_data = NULL;
|
||||||
struct ssh_auth_auto_state_struct *state = NULL;
|
struct ssh_auth_auto_state_struct *state;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (session == NULL) {
|
if (session == NULL) {
|
||||||
@@ -1306,7 +1121,7 @@ int ssh_userauth_publickey_auto(ssh_session session,
|
|||||||
rc = ssh_userauth_agent(session, username);
|
rc = ssh_userauth_agent(session, username);
|
||||||
if (rc == SSH_AUTH_SUCCESS ||
|
if (rc == SSH_AUTH_SUCCESS ||
|
||||||
rc == SSH_AUTH_PARTIAL ||
|
rc == SSH_AUTH_PARTIAL ||
|
||||||
rc == SSH_AUTH_AGAIN) {
|
rc == SSH_AUTH_AGAIN ) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
|
state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
|
||||||
@@ -1321,9 +1136,7 @@ int ssh_userauth_publickey_auto(ssh_session session,
|
|||||||
|
|
||||||
if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY) {
|
if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY) {
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_DEBUG,
|
||||||
"Trying to authenticate with %s",
|
"Trying to authenticate with %s", privkey_file);
|
||||||
privkey_file);
|
|
||||||
state->cert = NULL;
|
|
||||||
state->privkey = NULL;
|
state->privkey = NULL;
|
||||||
state->pubkey = NULL;
|
state->pubkey = NULL;
|
||||||
|
|
||||||
@@ -1336,165 +1149,86 @@ int ssh_userauth_publickey_auto(ssh_session session,
|
|||||||
if (pub_uri_from_priv == NULL) {
|
if (pub_uri_from_priv == NULL) {
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
} else {
|
} else {
|
||||||
snprintf(pubkey_file,
|
snprintf(pubkey_file, sizeof(pubkey_file), "%s",
|
||||||
sizeof(pubkey_file),
|
|
||||||
"%s",
|
|
||||||
pub_uri_from_priv);
|
pub_uri_from_priv);
|
||||||
SAFE_FREE(pub_uri_from_priv);
|
SAFE_FREE(pub_uri_from_priv);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
#endif /* WITH_PKCS11_URI */
|
#endif /* WITH_PKCS11_URI */
|
||||||
{
|
{
|
||||||
snprintf(pubkey_file,
|
snprintf(pubkey_file, sizeof(pubkey_file), "%s.pub", privkey_file);
|
||||||
sizeof(pubkey_file),
|
|
||||||
"%s.pub",
|
|
||||||
privkey_file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = ssh_pki_import_pubkey_file(pubkey_file, &state->pubkey);
|
rc = ssh_pki_import_pubkey_file(pubkey_file, &state->pubkey);
|
||||||
if (rc == SSH_ERROR) {
|
if (rc == SSH_ERROR) {
|
||||||
ssh_set_error(session,
|
ssh_set_error(session,
|
||||||
SSH_FATAL,
|
SSH_FATAL,
|
||||||
"Failed to import public key: %s",
|
"Failed to import public key: %s",
|
||||||
pubkey_file);
|
pubkey_file);
|
||||||
SAFE_FREE(session->auth.auto_state);
|
SAFE_FREE(session->auth.auto_state);
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
} else if (rc == SSH_EOF) {
|
} else if (rc == SSH_EOF) {
|
||||||
/* Read the private key and save the public key to file */
|
/* Read the private key and save the public key to file */
|
||||||
rc = ssh_pki_import_privkey_file(privkey_file,
|
rc = ssh_pki_import_privkey_file(privkey_file,
|
||||||
passphrase,
|
passphrase,
|
||||||
auth_fn,
|
auth_fn,
|
||||||
auth_data,
|
auth_data,
|
||||||
&state->privkey);
|
&state->privkey);
|
||||||
if (rc == SSH_ERROR) {
|
if (rc == SSH_ERROR) {
|
||||||
ssh_set_error(session,
|
ssh_set_error(session,
|
||||||
SSH_FATAL,
|
SSH_FATAL,
|
||||||
"Failed to read private key: %s",
|
"Failed to read private key: %s",
|
||||||
privkey_file);
|
privkey_file);
|
||||||
state->it = state->it->next;
|
state->it=state->it->next;
|
||||||
continue;
|
continue;
|
||||||
} else if (rc == SSH_EOF) {
|
} else if (rc == SSH_EOF) {
|
||||||
/* If the file doesn't exist, continue */
|
/* If the file doesn't exist, continue */
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_DEBUG,
|
||||||
"Private key %s doesn't exist.",
|
"Private key %s doesn't exist.",
|
||||||
privkey_file);
|
privkey_file);
|
||||||
state->it = state->it->next;
|
state->it=state->it->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = ssh_pki_export_privkey_to_pubkey(state->privkey,
|
rc = ssh_pki_export_privkey_to_pubkey(state->privkey, &state->pubkey);
|
||||||
&state->pubkey);
|
|
||||||
if (rc == SSH_ERROR) {
|
if (rc == SSH_ERROR) {
|
||||||
SSH_KEY_FREE(state->privkey);
|
ssh_key_free(state->privkey);
|
||||||
SAFE_FREE(session->auth.auto_state);
|
SAFE_FREE(session->auth.auto_state);
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = ssh_pki_export_pubkey_file(state->pubkey, pubkey_file);
|
rc = ssh_pki_export_pubkey_file(state->pubkey, pubkey_file);
|
||||||
if (rc == SSH_ERROR) {
|
if (rc == SSH_ERROR) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"Could not write public key to file: %s",
|
"Could not write public key to file: %s",
|
||||||
pubkey_file);
|
pubkey_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state->state = SSH_AUTH_AUTO_STATE_KEY_IMPORTED;
|
state->state = SSH_AUTH_AUTO_STATE_KEY_IMPORTED;
|
||||||
}
|
}
|
||||||
if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED ||
|
if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED) {
|
||||||
state->state == SSH_AUTH_AUTO_STATE_CERTIFICATE_FILE ||
|
rc = ssh_userauth_try_publickey(session, username, state->pubkey);
|
||||||
state->state == SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION) {
|
|
||||||
ssh_key k = state->pubkey;
|
|
||||||
if (state->state != SSH_AUTH_AUTO_STATE_KEY_IMPORTED) {
|
|
||||||
k = state->cert;
|
|
||||||
}
|
|
||||||
rc = ssh_userauth_try_publickey(session, username, k);
|
|
||||||
if (rc == SSH_AUTH_ERROR) {
|
if (rc == SSH_AUTH_ERROR) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"Public key authentication error for %s",
|
"Public key authentication error for %s",
|
||||||
privkey_file);
|
privkey_file);
|
||||||
SSH_KEY_FREE(state->cert);
|
ssh_key_free(state->privkey);
|
||||||
SSH_KEY_FREE(state->privkey);
|
state->privkey = NULL;
|
||||||
SSH_KEY_FREE(state->pubkey);
|
ssh_key_free(state->pubkey);
|
||||||
|
state->pubkey = NULL;
|
||||||
SAFE_FREE(session->auth.auto_state);
|
SAFE_FREE(session->auth.auto_state);
|
||||||
return rc;
|
return rc;
|
||||||
} else if (rc == SSH_AUTH_AGAIN) {
|
} else if (rc == SSH_AUTH_AGAIN) {
|
||||||
return rc;
|
return rc;
|
||||||
} else if (rc != SSH_AUTH_SUCCESS) {
|
} else if (rc != SSH_AUTH_SUCCESS) {
|
||||||
int r; /* do not reuse `rc` as it is used to return from here */
|
|
||||||
SSH_KEY_FREE(state->cert);
|
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_DEBUG,
|
||||||
"Public key for %s%s refused by server",
|
"Public key for %s refused by server",
|
||||||
privkey_file,
|
privkey_file);
|
||||||
(state->state != SSH_AUTH_AUTO_STATE_KEY_IMPORTED
|
ssh_key_free(state->privkey);
|
||||||
? " (with certificate)" : ""));
|
state->privkey = NULL;
|
||||||
/* Try certificate file by appending -cert.pub (if present) */
|
ssh_key_free(state->pubkey);
|
||||||
if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED) {
|
state->pubkey = NULL;
|
||||||
char cert_file[PATH_MAX] = {0};
|
state->it=state->it->next;
|
||||||
ssh_key cert = NULL;
|
|
||||||
|
|
||||||
snprintf(cert_file,
|
|
||||||
sizeof(cert_file),
|
|
||||||
"%s-cert.pub",
|
|
||||||
privkey_file);
|
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
|
||||||
"Trying to load the certificate %s (default path)",
|
|
||||||
cert_file);
|
|
||||||
r = ssh_pki_import_cert_file(cert_file, &cert);
|
|
||||||
if (r == SSH_OK) {
|
|
||||||
/* TODO check the pubkey and certs match */
|
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
|
||||||
"Certificate loaded %s. Retry the authentication.",
|
|
||||||
cert_file);
|
|
||||||
state->state = SSH_AUTH_AUTO_STATE_CERTIFICATE_FILE;
|
|
||||||
SSH_KEY_FREE(state->cert);
|
|
||||||
state->cert = cert;
|
|
||||||
/* try to authenticate with this certificate */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* if the file does not exists, try configuration options */
|
|
||||||
state->state = SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION;
|
|
||||||
}
|
|
||||||
/* Try certificate files loaded through options */
|
|
||||||
if (state->state == SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION) {
|
|
||||||
SSH_KEY_FREE(state->cert);
|
|
||||||
if (state->cert_it == NULL) {
|
|
||||||
state->cert_it = ssh_list_get_iterator(session->opts.certificate);
|
|
||||||
}
|
|
||||||
while (state->cert_it != NULL) {
|
|
||||||
const char *cert_file = state->cert_it->data;
|
|
||||||
ssh_key cert = NULL;
|
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
|
||||||
"Trying to load the certificate %s (options)",
|
|
||||||
cert_file);
|
|
||||||
r = ssh_pki_import_cert_file(cert_file, &cert);
|
|
||||||
if (r == SSH_OK) {
|
|
||||||
int cmp = ssh_key_cmp(cert,
|
|
||||||
state->pubkey,
|
|
||||||
SSH_KEY_CMP_PUBLIC);
|
|
||||||
if (cmp != 0) {
|
|
||||||
state->cert_it = state->cert_it->next;
|
|
||||||
SSH_KEY_FREE(cert);
|
|
||||||
continue; /* with next cert */
|
|
||||||
}
|
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
|
||||||
"Found matching certificate %s in options. Retry the authentication.",
|
|
||||||
cert_file);
|
|
||||||
state->cert = cert;
|
|
||||||
cert = NULL;
|
|
||||||
state->state = SSH_AUTH_AUTO_STATE_CERTIFICATE_OPTION;
|
|
||||||
/* try to authenticate with this identity */
|
|
||||||
break; /* try this cert */
|
|
||||||
}
|
|
||||||
/* continue with next identity */
|
|
||||||
}
|
|
||||||
if (state->cert != NULL) {
|
|
||||||
continue; /* retry with the certificate */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SSH_KEY_FREE(state->cert);
|
|
||||||
SSH_KEY_FREE(state->privkey);
|
|
||||||
SSH_KEY_FREE(state->pubkey);
|
|
||||||
state->it = state->it->next;
|
|
||||||
state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
|
state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1504,25 +1238,25 @@ int ssh_userauth_publickey_auto(ssh_session session,
|
|||||||
/* Public key has been accepted by the server */
|
/* Public key has been accepted by the server */
|
||||||
if (state->privkey == NULL) {
|
if (state->privkey == NULL) {
|
||||||
rc = ssh_pki_import_privkey_file(privkey_file,
|
rc = ssh_pki_import_privkey_file(privkey_file,
|
||||||
passphrase,
|
passphrase,
|
||||||
auth_fn,
|
auth_fn,
|
||||||
auth_data,
|
auth_data,
|
||||||
&state->privkey);
|
&state->privkey);
|
||||||
if (rc == SSH_ERROR) {
|
if (rc == SSH_ERROR) {
|
||||||
SSH_KEY_FREE(state->cert);
|
ssh_key_free(state->pubkey);
|
||||||
SSH_KEY_FREE(state->pubkey);
|
state->pubkey=NULL;
|
||||||
ssh_set_error(session,
|
ssh_set_error(session,
|
||||||
SSH_FATAL,
|
SSH_FATAL,
|
||||||
"Failed to read private key: %s",
|
"Failed to read private key: %s",
|
||||||
privkey_file);
|
privkey_file);
|
||||||
state->it = state->it->next;
|
state->it=state->it->next;
|
||||||
state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
|
state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
|
||||||
continue;
|
continue;
|
||||||
} else if (rc == SSH_EOF) {
|
} else if (rc == SSH_EOF) {
|
||||||
/* If the file doesn't exist, continue */
|
/* If the file doesn't exist, continue */
|
||||||
SSH_KEY_FREE(state->cert);
|
ssh_key_free(state->pubkey);
|
||||||
SSH_KEY_FREE(state->pubkey);
|
state->pubkey = NULL;
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_INFO,
|
||||||
"Private key %s doesn't exist.",
|
"Private key %s doesn't exist.",
|
||||||
privkey_file);
|
privkey_file);
|
||||||
state->it = state->it->next;
|
state->it = state->it->next;
|
||||||
@@ -1530,33 +1264,16 @@ int ssh_userauth_publickey_auto(ssh_session session,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (state->cert != NULL && !is_cert_type(state->privkey->cert_type)) {
|
|
||||||
rc = ssh_pki_copy_cert_to_privkey(state->cert, state->privkey);
|
|
||||||
if (rc != SSH_OK) {
|
|
||||||
SSH_KEY_FREE(state->cert);
|
|
||||||
SSH_KEY_FREE(state->privkey);
|
|
||||||
SSH_KEY_FREE(state->pubkey);
|
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"Failed to copy cert to private key");
|
|
||||||
state->it = state->it->next;
|
|
||||||
state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ssh_userauth_publickey(session, username, state->privkey);
|
rc = ssh_userauth_publickey(session, username, state->privkey);
|
||||||
if (rc != SSH_AUTH_AGAIN && rc != SSH_AUTH_DENIED) {
|
if (rc != SSH_AUTH_AGAIN && rc != SSH_AUTH_DENIED) {
|
||||||
bool cert_used = (state->cert != NULL);
|
ssh_key_free(state->privkey);
|
||||||
SSH_KEY_FREE(state->cert);
|
ssh_key_free(state->pubkey);
|
||||||
SSH_KEY_FREE(state->privkey);
|
|
||||||
SSH_KEY_FREE(state->pubkey);
|
|
||||||
SAFE_FREE(session->auth.auto_state);
|
SAFE_FREE(session->auth.auto_state);
|
||||||
if (rc == SSH_AUTH_SUCCESS) {
|
if (rc == SSH_AUTH_SUCCESS) {
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_INFO,
|
||||||
"Successfully authenticated using %s%s",
|
"Successfully authenticated using %s",
|
||||||
privkey_file,
|
privkey_file);
|
||||||
(cert_used ? " and certificate" : ""));
|
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -1564,19 +1281,18 @@ int ssh_userauth_publickey_auto(ssh_session session,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSH_KEY_FREE(state->cert);
|
ssh_key_free(state->privkey);
|
||||||
SSH_KEY_FREE(state->privkey);
|
ssh_key_free(state->pubkey);
|
||||||
SSH_KEY_FREE(state->pubkey);
|
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"The server accepted the public key but refused the signature");
|
"The server accepted the public key but refused the signature");
|
||||||
state->it = state->it->next;
|
state->it = state->it->next;
|
||||||
state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
|
state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
|
||||||
/* continue */
|
/* continue */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SSH_LOG(SSH_LOG_WARN,
|
SSH_LOG(SSH_LOG_INFO,
|
||||||
"Access denied: Tried every public key, none matched");
|
"Tried every public key, none matched");
|
||||||
SAFE_FREE(session->auth.auto_state);
|
SAFE_FREE(session->auth.auto_state);
|
||||||
return SSH_AUTH_DENIED;
|
return SSH_AUTH_DENIED;
|
||||||
}
|
}
|
||||||
@@ -1693,23 +1409,21 @@ int ssh_userauth_agent_pubkey(ssh_session session,
|
|||||||
key->type = publickey->type;
|
key->type = publickey->type;
|
||||||
key->type_c = ssh_key_type_to_char(key->type);
|
key->type_c = ssh_key_type_to_char(key->type);
|
||||||
key->flags = SSH_KEY_FLAG_PUBLIC;
|
key->flags = SSH_KEY_FLAG_PUBLIC;
|
||||||
#if defined(HAVE_LIBMBEDCRYPTO)
|
#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
key->pk = publickey->rsa_pub;
|
key->dsa = publickey->dsa_pub;
|
||||||
#elif defined(HAVE_LIBCRYPTO)
|
|
||||||
key->key = publickey->key_pub;
|
|
||||||
#else
|
|
||||||
key->rsa = publickey->rsa_pub;
|
key->rsa = publickey->rsa_pub;
|
||||||
#endif /* HAVE_LIBCRYPTO */
|
#else
|
||||||
|
key->key = publickey->key_pub;
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
|
||||||
rc = ssh_userauth_agent_publickey(session, username, key);
|
rc = ssh_userauth_agent_publickey(session, username, key);
|
||||||
|
|
||||||
#if defined(HAVE_LIBMBEDCRYPTO)
|
#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
key->pk = NULL;
|
key->dsa = NULL;
|
||||||
#elif defined(HAVE_LIBCRYPTO)
|
|
||||||
key->key = NULL;
|
|
||||||
#else
|
|
||||||
key->rsa = NULL;
|
key->rsa = NULL;
|
||||||
#endif /* HAVE_LIBCRYPTO */
|
#else
|
||||||
|
key->key = NULL;
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
ssh_key_free(key);
|
ssh_key_free(key);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@@ -1966,10 +1680,10 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_DEBUG,
|
||||||
"%" PRIu32 " keyboard-interactive prompts", nprompts);
|
"%d keyboard-interactive prompts", nprompts);
|
||||||
if (nprompts > KBDINT_MAX_PROMPT) {
|
if (nprompts > KBDINT_MAX_PROMPT) {
|
||||||
ssh_set_error(session, SSH_FATAL,
|
ssh_set_error(session, SSH_FATAL,
|
||||||
"Too much prompts requested by the server: %" PRIu32 " (0x%.4" PRIx32 ")",
|
"Too much prompts requested by the server: %u (0x%.4x)",
|
||||||
nprompts, nprompts);
|
nprompts, nprompts);
|
||||||
ssh_kbdint_free(session->kbdint);
|
ssh_kbdint_free(session->kbdint);
|
||||||
session->kbdint = NULL;
|
session->kbdint = NULL;
|
||||||
@@ -2214,8 +1928,7 @@ int ssh_userauth_kbdint_getnanswers(ssh_session session)
|
|||||||
*
|
*
|
||||||
* @param[in] i index The number of the ith answer.
|
* @param[in] i index The number of the ith answer.
|
||||||
*
|
*
|
||||||
* @return The answer string, or NULL if the answer is not
|
* @return 0 on success, < 0 on error.
|
||||||
* available. Do not free the string.
|
|
||||||
*/
|
*/
|
||||||
const char *ssh_userauth_kbdint_getanswer(ssh_session session, unsigned int i)
|
const char *ssh_userauth_kbdint_getanswer(ssh_session session, unsigned int i)
|
||||||
{
|
{
|
||||||
@@ -2321,7 +2034,7 @@ int ssh_userauth_gssapi(ssh_session session)
|
|||||||
} else if (rc == SSH_ERROR) {
|
} else if (rc == SSH_ERROR) {
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "Authenticating with gssapi-with-mic");
|
SSH_LOG(SSH_LOG_PROTOCOL, "Authenticating with gssapi-with-mic");
|
||||||
|
|
||||||
session->auth.current_method = SSH_AUTH_METHOD_GSSAPI_MIC;
|
session->auth.current_method = SSH_AUTH_METHOD_GSSAPI_MIC;
|
||||||
session->auth.state = SSH_AUTH_STATE_NONE;
|
session->auth.state = SSH_AUTH_STATE_NONE;
|
||||||
|
|||||||
258
src/base64.c
258
src/base64.c
@@ -57,120 +57,119 @@ static int get_equals(char *string);
|
|||||||
* @returns A buffer containing the decoded string, NULL if something went
|
* @returns A buffer containing the decoded string, NULL if something went
|
||||||
* wrong (e.g. incorrect char).
|
* wrong (e.g. incorrect char).
|
||||||
*/
|
*/
|
||||||
ssh_buffer base64_to_bin(const char *source)
|
ssh_buffer base64_to_bin(const char *source) {
|
||||||
{
|
ssh_buffer buffer = NULL;
|
||||||
ssh_buffer buffer = NULL;
|
unsigned char block[3];
|
||||||
unsigned char block[3];
|
char *base64;
|
||||||
char *base64 = NULL;
|
char *ptr;
|
||||||
char *ptr = NULL;
|
size_t len;
|
||||||
size_t len;
|
int equals;
|
||||||
int equals;
|
|
||||||
|
|
||||||
base64 = strdup(source);
|
base64 = strdup(source);
|
||||||
if (base64 == NULL) {
|
if (base64 == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
ptr = base64;
|
||||||
|
|
||||||
|
/* Get the number of equals signs, which mirrors the padding */
|
||||||
|
equals = get_equals(ptr);
|
||||||
|
if (equals > 2) {
|
||||||
|
SAFE_FREE(base64);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = ssh_buffer_new();
|
||||||
|
if (buffer == NULL) {
|
||||||
|
SAFE_FREE(base64);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* The base64 buffer often contains sensitive data. Make sure we don't leak
|
||||||
|
* sensitive data
|
||||||
|
*/
|
||||||
|
ssh_buffer_set_secure(buffer);
|
||||||
|
|
||||||
|
len = strlen(ptr);
|
||||||
|
while (len > 4) {
|
||||||
|
if (_base64_to_bin(block, ptr, 3) < 0) {
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
ptr = base64;
|
if (ssh_buffer_add_data(buffer, block, 3) < 0) {
|
||||||
|
goto error;
|
||||||
/* Get the number of equals signs, which mirrors the padding */
|
|
||||||
equals = get_equals(ptr);
|
|
||||||
if (equals > 2) {
|
|
||||||
SAFE_FREE(base64);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
len -= 4;
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
|
|
||||||
buffer = ssh_buffer_new();
|
/*
|
||||||
if (buffer == NULL) {
|
* Depending on the number of bytes resting, there are 3 possibilities
|
||||||
SAFE_FREE(base64);
|
* from the RFC.
|
||||||
return NULL;
|
*/
|
||||||
}
|
switch (len) {
|
||||||
/*
|
|
||||||
* The base64 buffer often contains sensitive data. Make sure we don't leak
|
|
||||||
* sensitive data
|
|
||||||
*/
|
|
||||||
ssh_buffer_set_secure(buffer);
|
|
||||||
|
|
||||||
len = strlen(ptr);
|
|
||||||
while (len > 4) {
|
|
||||||
if (_base64_to_bin(block, ptr, 3) < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (ssh_buffer_add_data(buffer, block, 3) < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
len -= 4;
|
|
||||||
ptr += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Depending on the number of bytes resting, there are 3 possibilities
|
|
||||||
* from the RFC.
|
|
||||||
*/
|
|
||||||
switch (len) {
|
|
||||||
/*
|
/*
|
||||||
* (1) The final quantum of encoding input is an integral multiple of
|
* (1) The final quantum of encoding input is an integral multiple of
|
||||||
* 24 bits. Here, the final unit of encoded output will be an integral
|
* 24 bits. Here, the final unit of encoded output will be an integral
|
||||||
* multiple of 4 characters with no "=" padding
|
* multiple of 4 characters with no "=" padding
|
||||||
*/
|
*/
|
||||||
case 4:
|
case 4:
|
||||||
if (equals != 0) {
|
if (equals != 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (_base64_to_bin(block, ptr, 3) < 0) {
|
if (_base64_to_bin(block, ptr, 3) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (ssh_buffer_add_data(buffer, block, 3) < 0) {
|
if (ssh_buffer_add_data(buffer, block, 3) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
SAFE_FREE(base64);
|
SAFE_FREE(base64);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
/*
|
/*
|
||||||
* (2) The final quantum of encoding input is exactly 8 bits; here, the
|
* (2) The final quantum of encoding input is exactly 8 bits; here, the
|
||||||
* final unit of encoded output will be two characters followed by
|
* final unit of encoded output will be two characters followed by
|
||||||
* two "=" padding characters.
|
* two "=" padding characters.
|
||||||
*/
|
*/
|
||||||
case 2:
|
case 2:
|
||||||
if (equals != 2) {
|
if (equals != 2){
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_base64_to_bin(block, ptr, 1) < 0) {
|
if (_base64_to_bin(block, ptr, 1) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (ssh_buffer_add_data(buffer, block, 1) < 0) {
|
if (ssh_buffer_add_data(buffer, block, 1) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
SAFE_FREE(base64);
|
SAFE_FREE(base64);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
/*
|
/*
|
||||||
* The final quantum of encoding input is exactly 16 bits. Here, the final
|
* The final quantum of encoding input is exactly 16 bits. Here, the final
|
||||||
* unit of encoded output will be three characters followed by one "="
|
* unit of encoded output will be three characters followed by one "="
|
||||||
* padding character.
|
* padding character.
|
||||||
*/
|
*/
|
||||||
case 3:
|
case 3:
|
||||||
if (equals != 1) {
|
if (equals != 1) {
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (_base64_to_bin(block, ptr, 2) < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (ssh_buffer_add_data(buffer, block, 2) < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
SAFE_FREE(base64);
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
default:
|
|
||||||
/* 4,3,2 are the only padding size allowed */
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
if (_base64_to_bin(block, ptr, 2) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (ssh_buffer_add_data(buffer,block,2) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
SAFE_FREE(base64);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
default:
|
||||||
|
/* 4,3,2 are the only padding size allowed */
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
SAFE_FREE(base64);
|
SAFE_FREE(base64);
|
||||||
SSH_BUFFER_FREE(buffer);
|
SSH_BUFFER_FREE(buffer);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BLOCK(letter, n) do {ptr = strchr((const char *)alphabet, source[n]); \
|
#define BLOCK(letter, n) do {ptr = strchr((const char *)alphabet, source[n]); \
|
||||||
@@ -180,62 +179,59 @@ error:
|
|||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
/* Returns 0 if ok, -1 if not (ie invalid char into the stuff) */
|
/* Returns 0 if ok, -1 if not (ie invalid char into the stuff) */
|
||||||
static int to_block4(unsigned long *block, const char *source, int num)
|
static int to_block4(unsigned long *block, const char *source, int num) {
|
||||||
{
|
const char *ptr = NULL;
|
||||||
const char *ptr = NULL;
|
unsigned int i;
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
*block = 0;
|
|
||||||
if (num < 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BLOCK(A, 0); /* 6 bit */
|
|
||||||
BLOCK(B, 1); /* 12 bit */
|
|
||||||
|
|
||||||
if (num < 2) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BLOCK(C, 2); /* 18 bit */
|
|
||||||
|
|
||||||
if (num < 3) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BLOCK(D, 3); /* 24 bit */
|
|
||||||
|
|
||||||
|
*block = 0;
|
||||||
|
if (num < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLOCK(A, 0); /* 6 bit */
|
||||||
|
BLOCK(B,1); /* 12 bit */
|
||||||
|
|
||||||
|
if (num < 2) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLOCK(C, 2); /* 18 bit */
|
||||||
|
|
||||||
|
if (num < 3) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLOCK(D, 3); /* 24 bit */
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* num = numbers of final bytes to be decoded */
|
/* num = numbers of final bytes to be decoded */
|
||||||
static int _base64_to_bin(unsigned char dest[3], const char *source, int num)
|
static int _base64_to_bin(unsigned char dest[3], const char *source, int num) {
|
||||||
{
|
unsigned long block;
|
||||||
unsigned long block;
|
|
||||||
|
|
||||||
if (to_block4(&block, source, num) < 0) {
|
if (to_block4(&block, source, num) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
dest[0] = GET_A(block);
|
dest[0] = GET_A(block);
|
||||||
dest[1] = GET_B(block);
|
dest[1] = GET_B(block);
|
||||||
dest[2] = GET_C(block);
|
dest[2] = GET_C(block);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Count the number of "=" signs and replace them by zeroes */
|
/* Count the number of "=" signs and replace them by zeroes */
|
||||||
static int get_equals(char *string)
|
static int get_equals(char *string) {
|
||||||
{
|
char *ptr = string;
|
||||||
char *ptr = string;
|
int num = 0;
|
||||||
int num = 0;
|
|
||||||
|
|
||||||
while ((ptr = strchr(ptr, '=')) != NULL) {
|
while ((ptr=strchr(ptr,'=')) != NULL) {
|
||||||
num++;
|
num++;
|
||||||
*ptr = '\0';
|
*ptr = '\0';
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* thanks sysk for debugging my mess :) */
|
/* thanks sysk for debugging my mess :) */
|
||||||
@@ -287,7 +283,7 @@ uint8_t *bin_to_base64(const uint8_t *source, size_t len)
|
|||||||
}
|
}
|
||||||
ptr = base64;
|
ptr = base64;
|
||||||
|
|
||||||
while (len > 0) {
|
while(len > 0){
|
||||||
_bin_to_base64(ptr, source, len > 3 ? 3 : len);
|
_bin_to_base64(ptr, source, len > 3 ? 3 : len);
|
||||||
ptr += 4;
|
ptr += 4;
|
||||||
if (len < 3) {
|
if (len < 3) {
|
||||||
|
|||||||
10
src/bignum.c
10
src/bignum.c
@@ -70,7 +70,7 @@ bignum ssh_make_string_bn(ssh_string string)
|
|||||||
|
|
||||||
#ifdef DEBUG_CRYPTO
|
#ifdef DEBUG_CRYPTO
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_TRACE,
|
||||||
"Importing a %zu bits, %zu bytes object ...",
|
"Importing a %zu bits, %zu bytes object ...\n",
|
||||||
len * 8, len);
|
len * 8, len);
|
||||||
#endif /* DEBUG_CRYPTO */
|
#endif /* DEBUG_CRYPTO */
|
||||||
|
|
||||||
@@ -88,5 +88,11 @@ void ssh_print_bignum(const char *name, const_bignum num)
|
|||||||
}
|
}
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "%s value: %s", name,
|
SSH_LOG(SSH_LOG_DEBUG, "%s value: %s", name,
|
||||||
(hex == NULL) ? "(null)" : (char *)hex);
|
(hex == NULL) ? "(null)" : (char *)hex);
|
||||||
ssh_crypto_free(hex);
|
#ifdef HAVE_LIBGCRYPT
|
||||||
|
SAFE_FREE(hex);
|
||||||
|
#elif defined HAVE_LIBCRYPTO
|
||||||
|
OPENSSL_free(hex);
|
||||||
|
#elif defined HAVE_LIBMBEDCRYPTO
|
||||||
|
SAFE_FREE(hex);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
247
src/bind.c
247
src/bind.c
@@ -149,6 +149,15 @@ ssh_bind ssh_bind_new(void) {
|
|||||||
static int ssh_bind_import_keys(ssh_bind sshbind) {
|
static int ssh_bind_import_keys(ssh_bind sshbind) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
if (sshbind->ecdsakey == NULL &&
|
||||||
|
sshbind->dsakey == NULL &&
|
||||||
|
sshbind->rsakey == NULL &&
|
||||||
|
sshbind->ed25519key == NULL) {
|
||||||
|
ssh_set_error(sshbind, SSH_FATAL,
|
||||||
|
"ECDSA, ED25519, DSA, or RSA host key file must be set");
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_ECC
|
#ifdef HAVE_ECC
|
||||||
if (sshbind->ecdsa == NULL && sshbind->ecdsakey != NULL) {
|
if (sshbind->ecdsa == NULL && sshbind->ecdsakey != NULL) {
|
||||||
rc = ssh_pki_import_privkey_file(sshbind->ecdsakey,
|
rc = ssh_pki_import_privkey_file(sshbind->ecdsakey,
|
||||||
@@ -172,6 +181,30 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_DSA
|
||||||
|
if (sshbind->dsa == NULL && sshbind->dsakey != NULL) {
|
||||||
|
rc = ssh_pki_import_privkey_file(sshbind->dsakey,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&sshbind->dsa);
|
||||||
|
if (rc == SSH_ERROR || rc == SSH_EOF) {
|
||||||
|
ssh_set_error(sshbind, SSH_FATAL,
|
||||||
|
"Failed to import private DSA host key");
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssh_key_type(sshbind->dsa) != SSH_KEYTYPE_DSS) {
|
||||||
|
ssh_set_error(sshbind, SSH_FATAL,
|
||||||
|
"The DSA host key has the wrong type: %d",
|
||||||
|
ssh_key_type(sshbind->dsa));
|
||||||
|
ssh_key_free(sshbind->dsa);
|
||||||
|
sshbind->dsa = NULL;
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (sshbind->rsa == NULL && sshbind->rsakey != NULL) {
|
if (sshbind->rsa == NULL && sshbind->rsakey != NULL) {
|
||||||
rc = ssh_pki_import_privkey_file(sshbind->rsakey,
|
rc = ssh_pki_import_privkey_file(sshbind->rsakey,
|
||||||
NULL,
|
NULL,
|
||||||
@@ -218,120 +251,94 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ssh_bind_listen(ssh_bind sshbind) {
|
int ssh_bind_listen(ssh_bind sshbind) {
|
||||||
const char *host;
|
const char *host;
|
||||||
socket_t fd;
|
socket_t fd;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Apply global bind configurations, if it hasn't been applied before */
|
if (sshbind->rsa == NULL &&
|
||||||
rc = ssh_bind_options_parse_config(sshbind, NULL);
|
sshbind->dsa == NULL &&
|
||||||
if (rc != 0) {
|
sshbind->ecdsa == NULL &&
|
||||||
ssh_set_error(sshbind, SSH_FATAL,"Could not parse global config");
|
sshbind->ed25519 == NULL) {
|
||||||
return SSH_ERROR;
|
rc = ssh_bind_import_keys(sshbind);
|
||||||
}
|
if (rc != SSH_OK) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Set default hostkey paths if no hostkey was found before */
|
if (sshbind->bindfd == SSH_INVALID_SOCKET) {
|
||||||
if (sshbind->ecdsakey == NULL &&
|
host = sshbind->bindaddr;
|
||||||
sshbind->rsakey == NULL &&
|
if (host == NULL) {
|
||||||
sshbind->ed25519key == NULL) {
|
host = "0.0.0.0";
|
||||||
|
}
|
||||||
|
|
||||||
sshbind->ecdsakey = strdup("/etc/ssh/ssh_host_ecdsa_key");
|
fd = bind_socket(sshbind, host, sshbind->bindport);
|
||||||
sshbind->rsakey = strdup("/etc/ssh/ssh_host_rsa_key");
|
if (fd == SSH_INVALID_SOCKET) {
|
||||||
sshbind->ed25519key = strdup("/etc/ssh/ssh_host_ed25519_key");
|
ssh_key_free(sshbind->dsa);
|
||||||
}
|
sshbind->dsa = NULL;
|
||||||
|
ssh_key_free(sshbind->rsa);
|
||||||
|
sshbind->rsa = NULL;
|
||||||
|
/* XXX should this clear also other structures that were allocated */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Apply global bind configurations, if it hasn't been applied before */
|
if (listen(fd, 10) < 0) {
|
||||||
rc = ssh_bind_options_parse_config(sshbind, NULL);
|
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||||
if (rc != 0) {
|
ssh_set_error(sshbind, SSH_FATAL,
|
||||||
ssh_set_error(sshbind, SSH_FATAL, "Could not parse global config");
|
"Listening to socket %d: %s",
|
||||||
return SSH_ERROR;
|
fd, ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||||
}
|
CLOSE_SOCKET(fd);
|
||||||
|
ssh_key_free(sshbind->dsa);
|
||||||
|
sshbind->dsa = NULL;
|
||||||
|
ssh_key_free(sshbind->rsa);
|
||||||
|
sshbind->rsa = NULL;
|
||||||
|
/* XXX should this clear also other structures that were allocated */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set default hostkey paths if no hostkey was found before */
|
sshbind->bindfd = fd;
|
||||||
if (sshbind->ecdsakey == NULL &&
|
|
||||||
sshbind->rsakey == NULL &&
|
|
||||||
sshbind->ed25519key == NULL) {
|
|
||||||
|
|
||||||
sshbind->ecdsakey = strdup("/etc/ssh/ssh_host_ecdsa_key");
|
|
||||||
sshbind->rsakey = strdup("/etc/ssh/ssh_host_rsa_key");
|
|
||||||
sshbind->ed25519key = strdup("/etc/ssh/ssh_host_ed25519_key");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sshbind->rsa == NULL &&
|
|
||||||
sshbind->ecdsa == NULL &&
|
|
||||||
sshbind->ed25519 == NULL) {
|
|
||||||
rc = ssh_bind_import_keys(sshbind);
|
|
||||||
if (rc != SSH_OK) {
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sshbind->bindfd == SSH_INVALID_SOCKET) {
|
|
||||||
host = sshbind->bindaddr;
|
|
||||||
if (host == NULL) {
|
|
||||||
host = "0.0.0.0";
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = bind_socket(sshbind, host, sshbind->bindport);
|
|
||||||
if (fd == SSH_INVALID_SOCKET) {
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (listen(fd, 10) < 0) {
|
|
||||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
|
||||||
ssh_set_error(sshbind,
|
|
||||||
SSH_FATAL,
|
|
||||||
"Listening to socket %d: %s",
|
|
||||||
fd,
|
|
||||||
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
|
||||||
CLOSE_SOCKET(fd);
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
sshbind->bindfd = fd;
|
|
||||||
} else {
|
} else {
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "Using app-provided bind socket");
|
SSH_LOG(SSH_LOG_INFO, "Using app-provided bind socket");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssh_bind_set_callbacks(ssh_bind sshbind, ssh_bind_callbacks callbacks, void *userdata)
|
int ssh_bind_set_callbacks(ssh_bind sshbind, ssh_bind_callbacks callbacks,
|
||||||
{
|
void *userdata){
|
||||||
if (sshbind == NULL) {
|
if (sshbind == NULL) {
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
if (callbacks == NULL) {
|
if (callbacks == NULL) {
|
||||||
ssh_set_error_invalid(sshbind);
|
ssh_set_error_invalid(sshbind);
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
if (callbacks->size <= 0 || callbacks->size > 1024 * sizeof(void *)) {
|
if(callbacks->size <= 0 || callbacks->size > 1024 * sizeof(void *)){
|
||||||
ssh_set_error(sshbind,
|
ssh_set_error(sshbind,SSH_FATAL,
|
||||||
SSH_FATAL,
|
"Invalid callback passed in (badly initialized)");
|
||||||
"Invalid callback passed in (badly initialized)");
|
return SSH_ERROR;
|
||||||
return SSH_ERROR;
|
}
|
||||||
}
|
sshbind->bind_callbacks = callbacks;
|
||||||
sshbind->bind_callbacks = callbacks;
|
sshbind->bind_callbacks_userdata=userdata;
|
||||||
sshbind->bind_callbacks_userdata = userdata;
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal
|
/** @internal
|
||||||
* @brief callback being called by poll when an event happens
|
* @brief callback being called by poll when an event happens
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int ssh_bind_poll_callback(ssh_poll_handle sshpoll, socket_t fd, int revents, void *user)
|
static int ssh_bind_poll_callback(ssh_poll_handle sshpoll,
|
||||||
{
|
socket_t fd, int revents, void *user){
|
||||||
ssh_bind sshbind = (ssh_bind)user;
|
ssh_bind sshbind=(ssh_bind)user;
|
||||||
(void)sshpoll;
|
(void)sshpoll;
|
||||||
(void)fd;
|
(void)fd;
|
||||||
|
|
||||||
if (revents & POLLIN) {
|
if(revents & POLLIN){
|
||||||
/* new incoming connection */
|
/* new incoming connection */
|
||||||
if (ssh_callbacks_exists(sshbind->bind_callbacks, incoming_connection)) {
|
if(ssh_callbacks_exists(sshbind->bind_callbacks,incoming_connection)){
|
||||||
sshbind->bind_callbacks->incoming_connection(sshbind,
|
sshbind->bind_callbacks->incoming_connection(sshbind,
|
||||||
sshbind->bind_callbacks_userdata);
|
sshbind->bind_callbacks_userdata);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal
|
/** @internal
|
||||||
@@ -359,24 +366,20 @@ ssh_poll_handle ssh_bind_get_poll(ssh_bind sshbind)
|
|||||||
return sshbind->poll;
|
return sshbind->poll;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssh_bind_set_blocking(ssh_bind sshbind, int blocking)
|
void ssh_bind_set_blocking(ssh_bind sshbind, int blocking) {
|
||||||
{
|
sshbind->blocking = blocking ? 1 : 0;
|
||||||
sshbind->blocking = blocking ? 1 : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
socket_t ssh_bind_get_fd(ssh_bind sshbind)
|
socket_t ssh_bind_get_fd(ssh_bind sshbind) {
|
||||||
{
|
return sshbind->bindfd;
|
||||||
return sshbind->bindfd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssh_bind_set_fd(ssh_bind sshbind, socket_t fd)
|
void ssh_bind_set_fd(ssh_bind sshbind, socket_t fd) {
|
||||||
{
|
sshbind->bindfd = fd;
|
||||||
sshbind->bindfd = fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssh_bind_fd_toaccept(ssh_bind sshbind)
|
void ssh_bind_fd_toaccept(ssh_bind sshbind) {
|
||||||
{
|
sshbind->toaccept = 1;
|
||||||
sshbind->toaccept = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssh_bind_free(ssh_bind sshbind){
|
void ssh_bind_free(ssh_bind sshbind){
|
||||||
@@ -398,10 +401,13 @@ void ssh_bind_free(ssh_bind sshbind){
|
|||||||
SAFE_FREE(sshbind->config_dir);
|
SAFE_FREE(sshbind->config_dir);
|
||||||
SAFE_FREE(sshbind->pubkey_accepted_key_types);
|
SAFE_FREE(sshbind->pubkey_accepted_key_types);
|
||||||
|
|
||||||
|
SAFE_FREE(sshbind->dsakey);
|
||||||
SAFE_FREE(sshbind->rsakey);
|
SAFE_FREE(sshbind->rsakey);
|
||||||
SAFE_FREE(sshbind->ecdsakey);
|
SAFE_FREE(sshbind->ecdsakey);
|
||||||
SAFE_FREE(sshbind->ed25519key);
|
SAFE_FREE(sshbind->ed25519key);
|
||||||
|
|
||||||
|
ssh_key_free(sshbind->dsa);
|
||||||
|
sshbind->dsa = NULL;
|
||||||
ssh_key_free(sshbind->rsa);
|
ssh_key_free(sshbind->rsa);
|
||||||
sshbind->rsa = NULL;
|
sshbind->rsa = NULL;
|
||||||
ssh_key_free(sshbind->ecdsa);
|
ssh_key_free(sshbind->ecdsa);
|
||||||
@@ -432,6 +438,13 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd)
|
|||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Apply global bind configurations, if it hasn't been applied before */
|
||||||
|
rc = ssh_bind_options_parse_config(sshbind, NULL);
|
||||||
|
if (rc != 0) {
|
||||||
|
ssh_set_error(sshbind, SSH_FATAL,"Could not parse global config");
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
session->server = 1;
|
session->server = 1;
|
||||||
|
|
||||||
/* Copy options from bind to session */
|
/* Copy options from bind to session */
|
||||||
@@ -480,16 +493,16 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd)
|
|||||||
session->common.log_verbosity = sshbind->common.log_verbosity;
|
session->common.log_verbosity = sshbind->common.log_verbosity;
|
||||||
|
|
||||||
if (sshbind->banner != NULL) {
|
if (sshbind->banner != NULL) {
|
||||||
session->server_opts.custombanner = strdup(sshbind->banner);
|
session->opts.custombanner = strdup(sshbind->banner);
|
||||||
if (session->server_opts.custombanner == NULL) {
|
if (session->opts.custombanner == NULL) {
|
||||||
ssh_set_error_oom(sshbind);
|
ssh_set_error_oom(sshbind);
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sshbind->moduli_file != NULL) {
|
if (sshbind->moduli_file != NULL) {
|
||||||
session->server_opts.moduli_file = strdup(sshbind->moduli_file);
|
session->opts.moduli_file = strdup(sshbind->moduli_file);
|
||||||
if (session->server_opts.moduli_file == NULL) {
|
if (session->opts.moduli_file == NULL) {
|
||||||
ssh_set_error_oom(sshbind);
|
ssh_set_error_oom(sshbind);
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
@@ -518,6 +531,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd)
|
|||||||
* only using ssh_bind_accept_fd to manage sockets ourselves.
|
* only using ssh_bind_accept_fd to manage sockets ourselves.
|
||||||
*/
|
*/
|
||||||
if (sshbind->rsa == NULL &&
|
if (sshbind->rsa == NULL &&
|
||||||
|
sshbind->dsa == NULL &&
|
||||||
sshbind->ecdsa == NULL &&
|
sshbind->ecdsa == NULL &&
|
||||||
sshbind->ed25519 == NULL) {
|
sshbind->ed25519 == NULL) {
|
||||||
rc = ssh_bind_import_keys(sshbind);
|
rc = ssh_bind_import_keys(sshbind);
|
||||||
@@ -534,6 +548,15 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd)
|
|||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_DSA
|
||||||
|
if (sshbind->dsa) {
|
||||||
|
session->srv.dsa_key = ssh_key_dup(sshbind->dsa);
|
||||||
|
if (session->srv.dsa_key == NULL) {
|
||||||
|
ssh_set_error_oom(sshbind);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (sshbind->rsa) {
|
if (sshbind->rsa) {
|
||||||
session->srv.rsa_key = ssh_key_dup(sshbind->rsa);
|
session->srv.rsa_key = ssh_key_dup(sshbind->rsa);
|
||||||
|
|||||||
@@ -363,7 +363,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
|||||||
if (p && (*parser_flags & PARSING)) {
|
if (p && (*parser_flags & PARSING)) {
|
||||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HOSTKEY, p);
|
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HOSTKEY, p);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"line %d: Failed to set Hostkey value '%s'",
|
"line %d: Failed to set Hostkey value '%s'",
|
||||||
count, p);
|
count, p);
|
||||||
}
|
}
|
||||||
@@ -374,7 +374,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
|||||||
if (p && (*parser_flags & PARSING)) {
|
if (p && (*parser_flags & PARSING)) {
|
||||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDADDR, p);
|
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDADDR, p);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"line %d: Failed to set ListenAddress value '%s'",
|
"line %d: Failed to set ListenAddress value '%s'",
|
||||||
count, p);
|
count, p);
|
||||||
}
|
}
|
||||||
@@ -385,7 +385,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
|||||||
if (p && (*parser_flags & PARSING)) {
|
if (p && (*parser_flags & PARSING)) {
|
||||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDPORT_STR, p);
|
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDPORT_STR, p);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"line %d: Failed to set Port value '%s'",
|
"line %d: Failed to set Port value '%s'",
|
||||||
count, p);
|
count, p);
|
||||||
}
|
}
|
||||||
@@ -396,7 +396,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
|||||||
if (p && (*parser_flags & PARSING)) {
|
if (p && (*parser_flags & PARSING)) {
|
||||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_CIPHERS_C_S, p);
|
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_CIPHERS_C_S, p);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"line %d: Failed to set C->S Ciphers value '%s'",
|
"line %d: Failed to set C->S Ciphers value '%s'",
|
||||||
count, p);
|
count, p);
|
||||||
break;
|
break;
|
||||||
@@ -404,7 +404,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
|||||||
|
|
||||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_CIPHERS_S_C, p);
|
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_CIPHERS_S_C, p);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"line %d: Failed to set S->C Ciphers value '%s'",
|
"line %d: Failed to set S->C Ciphers value '%s'",
|
||||||
count, p);
|
count, p);
|
||||||
}
|
}
|
||||||
@@ -415,7 +415,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
|||||||
if (p && (*parser_flags & PARSING)) {
|
if (p && (*parser_flags & PARSING)) {
|
||||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HMAC_C_S, p);
|
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HMAC_C_S, p);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"line %d: Failed to set C->S MAC value '%s'",
|
"line %d: Failed to set C->S MAC value '%s'",
|
||||||
count, p);
|
count, p);
|
||||||
break;
|
break;
|
||||||
@@ -423,7 +423,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
|||||||
|
|
||||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HMAC_S_C, p);
|
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HMAC_S_C, p);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"line %d: Failed to set S->C MAC value '%s'",
|
"line %d: Failed to set S->C MAC value '%s'",
|
||||||
count, p);
|
count, p);
|
||||||
}
|
}
|
||||||
@@ -437,10 +437,10 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
|||||||
if (strcasecmp(p, "quiet") == 0) {
|
if (strcasecmp(p, "quiet") == 0) {
|
||||||
value = SSH_LOG_NONE;
|
value = SSH_LOG_NONE;
|
||||||
} else if (strcasecmp(p, "fatal") == 0 ||
|
} else if (strcasecmp(p, "fatal") == 0 ||
|
||||||
strcasecmp(p, "error")== 0) {
|
strcasecmp(p, "error")== 0 ||
|
||||||
value = SSH_LOG_WARN;
|
|
||||||
} else if (strcasecmp(p, "verbose") == 0 ||
|
|
||||||
strcasecmp(p, "info") == 0) {
|
strcasecmp(p, "info") == 0) {
|
||||||
|
value = SSH_LOG_WARN;
|
||||||
|
} else if (strcasecmp(p, "verbose") == 0) {
|
||||||
value = SSH_LOG_INFO;
|
value = SSH_LOG_INFO;
|
||||||
} else if (strcasecmp(p, "DEBUG") == 0 ||
|
} else if (strcasecmp(p, "DEBUG") == 0 ||
|
||||||
strcasecmp(p, "DEBUG1") == 0) {
|
strcasecmp(p, "DEBUG1") == 0) {
|
||||||
@@ -453,7 +453,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
|||||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_LOG_VERBOSITY,
|
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_LOG_VERBOSITY,
|
||||||
&value);
|
&value);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"line %d: Failed to set LogLevel value '%s'",
|
"line %d: Failed to set LogLevel value '%s'",
|
||||||
count, p);
|
count, p);
|
||||||
}
|
}
|
||||||
@@ -465,7 +465,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
|||||||
if (p && (*parser_flags & PARSING)) {
|
if (p && (*parser_flags & PARSING)) {
|
||||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_KEY_EXCHANGE, p);
|
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_KEY_EXCHANGE, p);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"line %d: Failed to set KexAlgorithms value '%s'",
|
"line %d: Failed to set KexAlgorithms value '%s'",
|
||||||
count, p);
|
count, p);
|
||||||
}
|
}
|
||||||
@@ -540,13 +540,13 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
|||||||
/* Skip one argument */
|
/* Skip one argument */
|
||||||
p = ssh_config_get_str_tok(&s, NULL);
|
p = ssh_config_get_str_tok(&s, NULL);
|
||||||
if (p == NULL || p[0] == '\0') {
|
if (p == NULL || p[0] == '\0') {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "line %d: Match keyword "
|
SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
|
||||||
"'%s' requires argument\n", count, p2);
|
"'%s' requires argument\n", count, p2);
|
||||||
SAFE_FREE(x);
|
SAFE_FREE(x);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
args++;
|
args++;
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"line %d: Unsupported Match keyword '%s', ignoring\n",
|
"line %d: Unsupported Match keyword '%s', ignoring\n",
|
||||||
count,
|
count,
|
||||||
p2);
|
p2);
|
||||||
@@ -576,7 +576,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
|||||||
rc = ssh_bind_options_set(bind,
|
rc = ssh_bind_options_set(bind,
|
||||||
SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES, p);
|
SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES, p);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"line %d: Failed to set PubKeyAcceptedKeyTypes value '%s'",
|
"line %d: Failed to set PubKeyAcceptedKeyTypes value '%s'",
|
||||||
count, p);
|
count, p);
|
||||||
}
|
}
|
||||||
@@ -588,26 +588,26 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
|||||||
rc = ssh_bind_options_set(bind,
|
rc = ssh_bind_options_set(bind,
|
||||||
SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, p);
|
SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, p);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"line %d: Failed to set HostkeyAlgorithms value '%s'",
|
"line %d: Failed to set HostkeyAlgorithms value '%s'",
|
||||||
count, p);
|
count, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BIND_CFG_NOT_ALLOWED_IN_MATCH:
|
case BIND_CFG_NOT_ALLOWED_IN_MATCH:
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "Option not allowed in Match block: %s, line: %d",
|
SSH_LOG(SSH_LOG_WARN, "Option not allowed in Match block: %s, line: %d",
|
||||||
keyword, count);
|
keyword, count);
|
||||||
break;
|
break;
|
||||||
case BIND_CFG_UNKNOWN:
|
case BIND_CFG_UNKNOWN:
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Unknown option: %s, line: %d",
|
SSH_LOG(SSH_LOG_WARN, "Unknown option: %s, line: %d",
|
||||||
keyword, count);
|
keyword, count);
|
||||||
break;
|
break;
|
||||||
case BIND_CFG_UNSUPPORTED:
|
case BIND_CFG_UNSUPPORTED:
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Unsupported option: %s, line: %d",
|
SSH_LOG(SSH_LOG_WARN, "Unsupported option: %s, line: %d",
|
||||||
keyword, count);
|
keyword, count);
|
||||||
break;
|
break;
|
||||||
case BIND_CFG_NA:
|
case BIND_CFG_NA:
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Option not applicable: %s, line: %d",
|
SSH_LOG(SSH_LOG_WARN, "Option not applicable: %s, line: %d",
|
||||||
keyword, count);
|
keyword, count);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
15
src/buffer.c
15
src/buffer.c
@@ -880,7 +880,7 @@ static int ssh_buffer_pack_allocate_va(struct ssh_buffer_struct *buffer,
|
|||||||
cstring = NULL;
|
cstring = NULL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Invalid buffer format %c", *p);
|
SSH_LOG(SSH_LOG_WARN, "Invalid buffer format %c", *p);
|
||||||
rc = SSH_ERROR;
|
rc = SSH_ERROR;
|
||||||
}
|
}
|
||||||
if (rc != SSH_OK){
|
if (rc != SSH_OK){
|
||||||
@@ -919,11 +919,10 @@ static int ssh_buffer_pack_allocate_va(struct ssh_buffer_struct *buffer,
|
|||||||
* SSH_ERROR on error
|
* SSH_ERROR on error
|
||||||
* @see ssh_buffer_add_format() for format list values.
|
* @see ssh_buffer_add_format() for format list values.
|
||||||
*/
|
*/
|
||||||
static int
|
int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||||
ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
const char *format,
|
||||||
const char *format,
|
size_t argc,
|
||||||
size_t argc,
|
va_list ap)
|
||||||
va_list ap)
|
|
||||||
{
|
{
|
||||||
int rc = SSH_ERROR;
|
int rc = SSH_ERROR;
|
||||||
const char *p;
|
const char *p;
|
||||||
@@ -1010,7 +1009,7 @@ ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
|||||||
cstring = NULL;
|
cstring = NULL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Invalid buffer format %c", *p);
|
SSH_LOG(SSH_LOG_WARN, "Invalid buffer format %c", *p);
|
||||||
rc = SSH_ERROR;
|
rc = SSH_ERROR;
|
||||||
}
|
}
|
||||||
if (rc != SSH_OK){
|
if (rc != SSH_OK){
|
||||||
@@ -1242,7 +1241,7 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
|||||||
rc = SSH_OK;
|
rc = SSH_OK;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Invalid buffer format %c", *p);
|
SSH_LOG(SSH_LOG_WARN, "Invalid buffer format %c", *p);
|
||||||
}
|
}
|
||||||
if (rc != SSH_OK) {
|
if (rc != SSH_OK) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -45,15 +45,6 @@ static void ssh_legacy_log_callback(int priority,
|
|||||||
log_fn(session, priority, buffer, log_data);
|
log_fn(session, priority, buffer, log_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
_ssh_remove_legacy_log_cb(void)
|
|
||||||
{
|
|
||||||
if (ssh_get_log_callback() == ssh_legacy_log_callback) {
|
|
||||||
_ssh_reset_log_cb();
|
|
||||||
ssh_set_log_userdata(NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int ssh_set_callbacks(ssh_session session, ssh_callbacks cb) {
|
int ssh_set_callbacks(ssh_session session, ssh_callbacks cb) {
|
||||||
if (session == NULL || cb == NULL) {
|
if (session == NULL || cb == NULL) {
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
|
|||||||
847
src/channels.c
847
src/channels.c
File diff suppressed because it is too large
Load Diff
88
src/client.c
88
src/client.c
@@ -47,12 +47,6 @@
|
|||||||
#include "libssh/pki.h"
|
#include "libssh/pki.h"
|
||||||
#include "libssh/kex.h"
|
#include "libssh/kex.h"
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#ifdef HAVE_PTHREAD
|
|
||||||
extern int proxy_disconnect;
|
|
||||||
#endif /* HAVE_PTHREAD */
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
#define set_status(session, status) do {\
|
#define set_status(session, status) do {\
|
||||||
if (session->common.callbacks && session->common.callbacks->connect_status_function) \
|
if (session->common.callbacks && session->common.callbacks->connect_status_function) \
|
||||||
session->common.callbacks->connect_status_function(session->common.callbacks->userdata, status); \
|
session->common.callbacks->connect_status_function(session->common.callbacks->userdata, status); \
|
||||||
@@ -79,7 +73,7 @@ static void socket_callback_connected(int code, int errno_code, void *user)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_TRACE,"Socket connection callback: %d (%d)",code, errno_code);
|
SSH_LOG(SSH_LOG_RARE,"Socket connection callback: %d (%d)",code, errno_code);
|
||||||
if(code == SSH_SOCKET_CONNECTED_OK)
|
if(code == SSH_SOCKET_CONNECTED_OK)
|
||||||
session->session_state=SSH_SESSION_STATE_SOCKET_CONNECTED;
|
session->session_state=SSH_SESSION_STATE_SOCKET_CONNECTED;
|
||||||
else {
|
else {
|
||||||
@@ -191,13 +185,13 @@ int ssh_send_banner(ssh_session session, int server)
|
|||||||
int rc = SSH_ERROR;
|
int rc = SSH_ERROR;
|
||||||
|
|
||||||
if (server == 1) {
|
if (server == 1) {
|
||||||
if (session->server_opts.custombanner == NULL) {
|
if (session->opts.custombanner == NULL){
|
||||||
session->serverbanner = strdup(banner);
|
session->serverbanner = strdup(banner);
|
||||||
if (session->serverbanner == NULL) {
|
if (session->serverbanner == NULL) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
len = strlen(session->server_opts.custombanner);
|
len = strlen(session->opts.custombanner);
|
||||||
session->serverbanner = malloc(len + 8 + 1);
|
session->serverbanner = malloc(len + 8 + 1);
|
||||||
if(session->serverbanner == NULL) {
|
if(session->serverbanner == NULL) {
|
||||||
goto end;
|
goto end;
|
||||||
@@ -205,7 +199,7 @@ int ssh_send_banner(ssh_session session, int server)
|
|||||||
snprintf(session->serverbanner,
|
snprintf(session->serverbanner,
|
||||||
len + 8 + 1,
|
len + 8 + 1,
|
||||||
"SSH-2.0-%s",
|
"SSH-2.0-%s",
|
||||||
session->server_opts.custombanner);
|
session->opts.custombanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(buffer,
|
snprintf(buffer,
|
||||||
@@ -416,7 +410,8 @@ static void ssh_client_connection_callback(ssh_session session)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
set_status(session, 0.4f);
|
set_status(session, 0.4f);
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "SSH server banner: %s", session->serverbanner);
|
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||||
|
"SSH server banner: %s", session->serverbanner);
|
||||||
|
|
||||||
/* Here we analyze the different protocols the server allows. */
|
/* Here we analyze the different protocols the server allows. */
|
||||||
rc = ssh_analyze_banner(session, 0);
|
rc = ssh_analyze_banner(session, 0);
|
||||||
@@ -474,11 +469,10 @@ static void ssh_client_connection_callback(ssh_session session)
|
|||||||
if (session->dh_handshake_state == DH_STATE_FINISHED) {
|
if (session->dh_handshake_state == DH_STATE_FINISHED) {
|
||||||
set_status(session, 1.0f);
|
set_status(session, 1.0f);
|
||||||
session->connected = 1;
|
session->connected = 1;
|
||||||
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) {
|
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
|
||||||
session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
|
session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
|
||||||
} else {
|
else
|
||||||
session->session_state = SSH_SESSION_STATE_AUTHENTICATING;
|
session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SSH_SESSION_STATE_AUTHENTICATING:
|
case SSH_SESSION_STATE_AUTHENTICATING:
|
||||||
@@ -492,8 +486,10 @@ static void ssh_client_connection_callback(ssh_session session)
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
error:
|
error:
|
||||||
ssh_session_socket_close(session);
|
ssh_socket_close(session->socket);
|
||||||
SSH_LOG(SSH_LOG_WARN, "%s", ssh_get_error(session));
|
session->alive = 0;
|
||||||
|
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal
|
/** @internal
|
||||||
@@ -578,7 +574,7 @@ int ssh_connect(ssh_session session)
|
|||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||||
"libssh %s, using threading %s",
|
"libssh %s, using threading %s",
|
||||||
ssh_copyright(),
|
ssh_copyright(),
|
||||||
ssh_threads_get_type());
|
ssh_threads_get_type());
|
||||||
@@ -596,22 +592,10 @@ int ssh_connect(ssh_session session)
|
|||||||
ssh_socket_set_fd(session->socket, session->opts.fd);
|
ssh_socket_set_fd(session->socket, session->opts.fd);
|
||||||
ret = SSH_OK;
|
ret = SSH_OK;
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#ifdef HAVE_PTHREAD
|
|
||||||
} else if (ssh_libssh_proxy_jumps() &&
|
|
||||||
ssh_list_count(session->opts.proxy_jumps) != 0) {
|
|
||||||
ret = ssh_socket_connect_proxyjump(session->socket);
|
|
||||||
#endif /* HAVE_PTHREAD */
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
} else if (session->opts.ProxyCommand != NULL) {
|
} else if (session->opts.ProxyCommand != NULL) {
|
||||||
#ifdef WITH_EXEC
|
|
||||||
ret = ssh_socket_connect_proxycommand(session->socket,
|
ret = ssh_socket_connect_proxycommand(session->socket,
|
||||||
session->opts.ProxyCommand);
|
session->opts.ProxyCommand);
|
||||||
#else
|
#endif
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"The libssh is built without support for proxy commands.");
|
|
||||||
ret = SSH_ERROR;
|
|
||||||
#endif /* WITH_EXEC */
|
|
||||||
} else {
|
} else {
|
||||||
ret = ssh_socket_connect(session->socket,
|
ret = ssh_socket_connect(session->socket,
|
||||||
session->opts.host,
|
session->opts.host,
|
||||||
@@ -625,7 +609,7 @@ int ssh_connect(ssh_session session)
|
|||||||
set_status(session, 0.2f);
|
set_status(session, 0.2f);
|
||||||
|
|
||||||
session->alive = 1;
|
session->alive = 1;
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||||
"Socket connecting, now waiting for the callbacks to work");
|
"Socket connecting, now waiting for the callbacks to work");
|
||||||
|
|
||||||
pending:
|
pending:
|
||||||
@@ -716,28 +700,6 @@ int ssh_get_openssh_version(ssh_session session)
|
|||||||
|
|
||||||
return session->openssh;
|
return session->openssh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Most SSH connections will only ever request a single session, but an
|
|
||||||
* attacker may abuse a running ssh client to surreptitiously open
|
|
||||||
* additional sessions under their control. OpenSSH provides a global
|
|
||||||
* request "no-more-sessions@openssh.com" to mitigate this attack.
|
|
||||||
*
|
|
||||||
* @param[in] session The SSH session to use.
|
|
||||||
*
|
|
||||||
* @returns SSH_OK on success, SSH_ERROR on error.
|
|
||||||
* @returns SSH_AGAIN, if the session is in nonblocking mode,
|
|
||||||
* and call must be done again.
|
|
||||||
*/
|
|
||||||
int ssh_request_no_more_sessions(ssh_session session)
|
|
||||||
{
|
|
||||||
if (session == NULL) {
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ssh_global_request(session, "no-more-sessions@openssh.com", NULL, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add disconnect message when ssh_session is disconnected
|
* @brief Add disconnect message when ssh_session is disconnected
|
||||||
* To add a disconnect message to give peer a better hint.
|
* To add a disconnect message to give peer a better hint.
|
||||||
@@ -771,6 +733,7 @@ ssh_session_set_disconnect_message(ssh_session session, const char *message)
|
|||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Disconnect from a session (client or server).
|
* @brief Disconnect from a session (client or server).
|
||||||
*
|
*
|
||||||
@@ -792,16 +755,6 @@ ssh_disconnect(ssh_session session)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#ifdef HAVE_PTHREAD
|
|
||||||
/* Only send the disconnect to all other threads when the root session calls
|
|
||||||
* ssh_disconnect() */
|
|
||||||
if (session->proxy_root) {
|
|
||||||
proxy_disconnect = 1;
|
|
||||||
}
|
|
||||||
#endif /* HAVE_PTHREAD */
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
if (session->disconnect_message == NULL) {
|
if (session->disconnect_message == NULL) {
|
||||||
session->disconnect_message = strdup("Bye Bye") ;
|
session->disconnect_message = strdup("Bye Bye") ;
|
||||||
if (session->disconnect_message == NULL) {
|
if (session->disconnect_message == NULL) {
|
||||||
@@ -823,7 +776,10 @@ ssh_disconnect(ssh_session session)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ssh_packet_send(session);
|
ssh_packet_send(session);
|
||||||
ssh_session_socket_close(session);
|
/* Do not close the socket, if the fd was set via options. */
|
||||||
|
if (session->opts.fd == SSH_INVALID_SOCKET) {
|
||||||
|
ssh_socket_close(session->socket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@@ -895,7 +851,7 @@ error:
|
|||||||
*/
|
*/
|
||||||
const char *ssh_copyright(void)
|
const char *ssh_copyright(void)
|
||||||
{
|
{
|
||||||
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2024 "
|
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2023 "
|
||||||
"Aris Adamantiadis, Andreas Schneider "
|
"Aris Adamantiadis, Andreas Schneider "
|
||||||
"and libssh contributors. "
|
"and libssh contributors. "
|
||||||
"Distributed under the LGPL, please refer to COPYING "
|
"Distributed under the LGPL, please refer to COPYING "
|
||||||
|
|||||||
397
src/config.c
397
src/config.c
@@ -39,11 +39,6 @@
|
|||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
# include <signal.h>
|
# include <signal.h>
|
||||||
# include <sys/wait.h>
|
# include <sys/wait.h>
|
||||||
# include <net/if.h>
|
|
||||||
# include <netinet/in.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_IFADDRS_H
|
|
||||||
#include <ifaddrs.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "libssh/config_parser.h"
|
#include "libssh/config_parser.h"
|
||||||
@@ -97,7 +92,7 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
|||||||
{ "canonicalizehostname", SOC_UNSUPPORTED},
|
{ "canonicalizehostname", SOC_UNSUPPORTED},
|
||||||
{ "canonicalizemaxdots", SOC_UNSUPPORTED},
|
{ "canonicalizemaxdots", SOC_UNSUPPORTED},
|
||||||
{ "canonicalizepermittedcnames", SOC_UNSUPPORTED},
|
{ "canonicalizepermittedcnames", SOC_UNSUPPORTED},
|
||||||
{ "certificatefile", SOC_CERTIFICATE},
|
{ "certificatefile", SOC_UNSUPPORTED},
|
||||||
{ "kbdinteractiveauthentication", SOC_UNSUPPORTED},
|
{ "kbdinteractiveauthentication", SOC_UNSUPPORTED},
|
||||||
{ "checkhostip", SOC_UNSUPPORTED},
|
{ "checkhostip", SOC_UNSUPPORTED},
|
||||||
{ "connectionattempts", SOC_UNSUPPORTED},
|
{ "connectionattempts", SOC_UNSUPPORTED},
|
||||||
@@ -108,7 +103,7 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
|||||||
{ "hostbasedauthentication", SOC_UNSUPPORTED},
|
{ "hostbasedauthentication", SOC_UNSUPPORTED},
|
||||||
{ "hostbasedacceptedalgorithms", SOC_UNSUPPORTED},
|
{ "hostbasedacceptedalgorithms", SOC_UNSUPPORTED},
|
||||||
{ "hostkeyalias", SOC_UNSUPPORTED},
|
{ "hostkeyalias", SOC_UNSUPPORTED},
|
||||||
{ "identitiesonly", SOC_IDENTITIESONLY},
|
{ "identitiesonly", SOC_UNSUPPORTED},
|
||||||
{ "identityagent", SOC_IDENTITYAGENT},
|
{ "identityagent", SOC_IDENTITYAGENT},
|
||||||
{ "ipqos", SOC_UNSUPPORTED},
|
{ "ipqos", SOC_UNSUPPORTED},
|
||||||
{ "kbdinteractivedevices", SOC_UNSUPPORTED},
|
{ "kbdinteractivedevices", SOC_UNSUPPORTED},
|
||||||
@@ -165,8 +160,7 @@ enum ssh_config_match_e {
|
|||||||
MATCH_HOST,
|
MATCH_HOST,
|
||||||
MATCH_ORIGINALHOST,
|
MATCH_ORIGINALHOST,
|
||||||
MATCH_USER,
|
MATCH_USER,
|
||||||
MATCH_LOCALUSER,
|
MATCH_LOCALUSER
|
||||||
MATCH_LOCALNETWORK
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ssh_config_match_keyword_table_s {
|
struct ssh_config_match_keyword_table_s {
|
||||||
@@ -174,18 +168,16 @@ struct ssh_config_match_keyword_table_s {
|
|||||||
enum ssh_config_match_e opcode;
|
enum ssh_config_match_e opcode;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ssh_config_match_keyword_table_s
|
static struct ssh_config_match_keyword_table_s ssh_config_match_keyword_table[] = {
|
||||||
ssh_config_match_keyword_table[] = {
|
{ "all", MATCH_ALL },
|
||||||
{"all", MATCH_ALL},
|
{ "canonical", MATCH_CANONICAL },
|
||||||
{"canonical", MATCH_CANONICAL},
|
{ "final", MATCH_FINAL },
|
||||||
{"final", MATCH_FINAL},
|
{ "exec", MATCH_EXEC },
|
||||||
{"exec", MATCH_EXEC},
|
{ "host", MATCH_HOST },
|
||||||
{"host", MATCH_HOST},
|
{ "originalhost", MATCH_ORIGINALHOST },
|
||||||
{"originalhost", MATCH_ORIGINALHOST},
|
{ "user", MATCH_USER },
|
||||||
{"user", MATCH_USER},
|
{ "localuser", MATCH_LOCALUSER },
|
||||||
{"localuser", MATCH_LOCALUSER},
|
{ NULL, MATCH_UNKNOWN },
|
||||||
{"localnetwork", MATCH_LOCALNETWORK},
|
|
||||||
{NULL, MATCH_UNKNOWN},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ssh_config_parse_line(ssh_session session, const char *line,
|
static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||||
@@ -307,8 +299,20 @@ ssh_config_match(char *value, const char *pattern, bool negate)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_EXEC
|
#ifdef _WIN32
|
||||||
/* FIXME reuse the ssh_execute_command() from socket.c */
|
static int
|
||||||
|
ssh_match_exec(ssh_session session, const char *command, bool negate)
|
||||||
|
{
|
||||||
|
(void) session;
|
||||||
|
(void) command;
|
||||||
|
(void) negate;
|
||||||
|
|
||||||
|
SSH_LOG(SSH_LOG_TRACE, "Unsupported 'exec' command on Windows '%s'",
|
||||||
|
command);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else /* _WIN32 */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ssh_exec_shell(char *cmd)
|
ssh_exec_shell(char *cmd)
|
||||||
{
|
{
|
||||||
@@ -421,33 +425,12 @@ ssh_match_exec(ssh_session session, const char *command, bool negate)
|
|||||||
free(cmd);
|
free(cmd);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#else
|
#endif /* _WIN32 */
|
||||||
static int
|
|
||||||
ssh_match_exec(ssh_session session, const char *command, bool negate)
|
|
||||||
{
|
|
||||||
(void)session;
|
|
||||||
(void)command;
|
|
||||||
(void)negate;
|
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
/* @brief: Parse the ProxyJump configuration line and if parsing,
|
||||||
"Unsupported 'exec' command on Windows '%s'",
|
|
||||||
command);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /* WITH_EXEC */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief: Parse the ProxyJump configuration line and if parsing,
|
|
||||||
* stores the result in the configuration option
|
* stores the result in the configuration option
|
||||||
*
|
|
||||||
* @param[in] session The ssh session
|
|
||||||
* @param[in] s The string to be parsed.
|
|
||||||
* @param[in] do_parsing Whether to parse or not.
|
|
||||||
*
|
|
||||||
* @returns SSH_OK if the provided string is formatted and parsed correctly
|
|
||||||
* SSH_ERROR on failure
|
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
|
ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
|
||||||
{
|
{
|
||||||
char *c = NULL, *cp = NULL, *endp = NULL;
|
char *c = NULL, *cp = NULL, *endp = NULL;
|
||||||
@@ -456,16 +439,12 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
|
|||||||
char *port = NULL;
|
char *port = NULL;
|
||||||
char *next = NULL;
|
char *next = NULL;
|
||||||
int cmp, rv = SSH_ERROR;
|
int cmp, rv = SSH_ERROR;
|
||||||
struct ssh_jump_info_struct *jump_host = NULL;
|
|
||||||
bool parse_entry = do_parsing;
|
bool parse_entry = do_parsing;
|
||||||
bool libssh_proxy_jump = ssh_libssh_proxy_jumps();
|
|
||||||
|
|
||||||
/* Special value none disables the proxy */
|
/* Special value none disables the proxy */
|
||||||
cmp = strcasecmp(s, "none");
|
cmp = strcasecmp(s, "none");
|
||||||
if (cmp == 0) {
|
if (cmp == 0 && do_parsing) {
|
||||||
if (!libssh_proxy_jump && do_parsing) {
|
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, s);
|
||||||
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, s);
|
|
||||||
}
|
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,65 +462,25 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
|
|||||||
/* Split out the token */
|
/* Split out the token */
|
||||||
*endp = '\0';
|
*endp = '\0';
|
||||||
}
|
}
|
||||||
if (parse_entry && libssh_proxy_jump) {
|
if (parse_entry) {
|
||||||
jump_host = calloc(1, sizeof(struct ssh_jump_info_struct));
|
|
||||||
if (jump_host == NULL) {
|
|
||||||
ssh_set_error_oom(session);
|
|
||||||
rv = SSH_ERROR;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = ssh_config_parse_uri(cp,
|
|
||||||
&jump_host->username,
|
|
||||||
&jump_host->hostname,
|
|
||||||
&port,
|
|
||||||
false);
|
|
||||||
if (rv != SSH_OK) {
|
|
||||||
ssh_set_error_invalid(session);
|
|
||||||
SAFE_FREE(jump_host);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (port == NULL) {
|
|
||||||
jump_host->port = 22;
|
|
||||||
} else {
|
|
||||||
jump_host->port = strtol(port, NULL, 10);
|
|
||||||
SAFE_FREE(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prepend because we will recursively proxy jump */
|
|
||||||
rv = ssh_list_prepend(session->opts.proxy_jumps, jump_host);
|
|
||||||
if (rv != SSH_OK) {
|
|
||||||
ssh_set_error_oom(session);
|
|
||||||
SAFE_FREE(jump_host);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else if (parse_entry) {
|
|
||||||
/* We actually care only about the first item */
|
/* We actually care only about the first item */
|
||||||
rv = ssh_config_parse_uri(cp, &username, &hostname, &port, false);
|
rv = ssh_config_parse_uri(cp, &username, &hostname, &port);
|
||||||
if (rv != SSH_OK) {
|
|
||||||
ssh_set_error_invalid(session);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
/* The rest of the list needs to be passed on */
|
/* The rest of the list needs to be passed on */
|
||||||
if (endp != NULL) {
|
if (endp != NULL) {
|
||||||
next = strdup(endp + 1);
|
next = strdup(endp + 1);
|
||||||
if (next == NULL) {
|
if (next == NULL) {
|
||||||
ssh_set_error_oom(session);
|
ssh_set_error_oom(session);
|
||||||
rv = SSH_ERROR;
|
rv = SSH_ERROR;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* The rest is just sanity-checked to avoid failures later */
|
/* The rest is just sanity-checked to avoid failures later */
|
||||||
rv = ssh_config_parse_uri(cp, NULL, NULL, NULL, false);
|
rv = ssh_config_parse_uri(cp, NULL, NULL, NULL);
|
||||||
if (rv != SSH_OK) {
|
|
||||||
ssh_set_error_invalid(session);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!libssh_proxy_jump) {
|
if (rv != SSH_OK) {
|
||||||
parse_entry = 0;
|
goto out;
|
||||||
}
|
}
|
||||||
|
parse_entry = 0;
|
||||||
if (endp != NULL) {
|
if (endp != NULL) {
|
||||||
cp = endp + 1;
|
cp = endp + 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -549,7 +488,7 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
|
|||||||
}
|
}
|
||||||
} while (cp != NULL);
|
} while (cp != NULL);
|
||||||
|
|
||||||
if (!libssh_proxy_jump && hostname != NULL && do_parsing) {
|
if (hostname != NULL && do_parsing) {
|
||||||
char com[512] = {0};
|
char com[512] = {0};
|
||||||
|
|
||||||
rv = snprintf(com, sizeof(com), "ssh%s%s%s%s%s%s -W '[%%h]:%%p' %s",
|
rv = snprintf(com, sizeof(com), "ssh%s%s%s%s%s%s -W '[%%h]:%%p' %s",
|
||||||
@@ -561,23 +500,15 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
|
|||||||
next ? next : "",
|
next ? next : "",
|
||||||
hostname);
|
hostname);
|
||||||
if (rv < 0 || rv >= (int)sizeof(com)) {
|
if (rv < 0 || rv >= (int)sizeof(com)) {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Too long ProxyJump configuration line");
|
SSH_LOG(SSH_LOG_WARN, "Too long ProxyJump configuration line");
|
||||||
rv = SSH_ERROR;
|
rv = SSH_ERROR;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
rv = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, com);
|
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, com);
|
||||||
if (rv != SSH_OK) {
|
|
||||||
ssh_set_error_oom(session);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = SSH_OK;
|
rv = SSH_OK;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (rv != SSH_OK) {
|
|
||||||
ssh_proxyjumps_free(session->opts.proxy_jumps);
|
|
||||||
}
|
|
||||||
SAFE_FREE(username);
|
SAFE_FREE(username);
|
||||||
SAFE_FREE(hostname);
|
SAFE_FREE(hostname);
|
||||||
SAFE_FREE(port);
|
SAFE_FREE(port);
|
||||||
@@ -641,99 +572,6 @@ ssh_config_make_absolute(ssh_session session,
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_IFADDRS_H
|
|
||||||
/**
|
|
||||||
* @brief Checks if host address matches the local network specified.
|
|
||||||
*
|
|
||||||
* Verify whether a local network interface address matches any of the CIDR
|
|
||||||
* patterns.
|
|
||||||
*
|
|
||||||
* @param addrlist The CIDR pattern-list to be checked, can contain both
|
|
||||||
* IPv4 and IPv6 addresses and has to be comma separated
|
|
||||||
* (',' only, space after comma not allowed).
|
|
||||||
*
|
|
||||||
* @param negate The negate condition. The return value is negated
|
|
||||||
* (returns 1 instead of 0 and vice versa).
|
|
||||||
*
|
|
||||||
* @return 1 if match found.
|
|
||||||
* @return 0 if no match found.
|
|
||||||
* @return -1 on errors.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
ssh_match_localnetwork(const char *addrlist, bool negate)
|
|
||||||
{
|
|
||||||
struct ifaddrs *ifa = NULL, *ifaddrs = NULL;
|
|
||||||
int r, found = 0;
|
|
||||||
char address[NI_MAXHOST], err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
|
||||||
socklen_t sa_len;
|
|
||||||
|
|
||||||
r = getifaddrs(&ifaddrs);
|
|
||||||
if (r != 0) {
|
|
||||||
SSH_LOG(SSH_LOG_WARN,
|
|
||||||
"Match localnetwork: getifaddrs() failed: %s",
|
|
||||||
ssh_strerror(r, err_msg, SSH_ERRNO_MSG_MAX));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
|
|
||||||
if (ifa->ifa_addr == NULL || (ifa->ifa_flags & IFF_UP) == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ifa->ifa_addr->sa_family) {
|
|
||||||
case AF_INET:
|
|
||||||
sa_len = sizeof(struct sockaddr_in);
|
|
||||||
break;
|
|
||||||
case AF_INET6:
|
|
||||||
sa_len = sizeof(struct sockaddr_in6);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
|
||||||
"Interface %s: unsupported address family %d",
|
|
||||||
ifa->ifa_name,
|
|
||||||
ifa->ifa_addr->sa_family);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = getnameinfo(ifa->ifa_addr,
|
|
||||||
sa_len,
|
|
||||||
address,
|
|
||||||
sizeof(address),
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
NI_NUMERICHOST);
|
|
||||||
if (r != 0) {
|
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
|
||||||
"Interface %s getnameinfo failed: %s",
|
|
||||||
ifa->ifa_name,
|
|
||||||
gai_strerror(r));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
|
||||||
"Interface %s address %s",
|
|
||||||
ifa->ifa_name,
|
|
||||||
address);
|
|
||||||
|
|
||||||
r = match_cidr_address_list(address,
|
|
||||||
addrlist,
|
|
||||||
ifa->ifa_addr->sa_family);
|
|
||||||
if (r == 1) {
|
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
|
||||||
"Matched interface %s: address %s in %s",
|
|
||||||
ifa->ifa_name,
|
|
||||||
address,
|
|
||||||
addrlist);
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
freeifaddrs(ifaddrs);
|
|
||||||
|
|
||||||
return (found == (negate ? 0 : 1));
|
|
||||||
}
|
|
||||||
#endif /* HAVE_IFADDRS_H */
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ssh_config_parse_line(ssh_session session,
|
ssh_config_parse_line(ssh_session session,
|
||||||
const char *line,
|
const char *line,
|
||||||
@@ -785,9 +623,7 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
opcode != SOC_MATCH &&
|
opcode != SOC_MATCH &&
|
||||||
opcode != SOC_INCLUDE &&
|
opcode != SOC_INCLUDE &&
|
||||||
opcode != SOC_IDENTITY &&
|
opcode != SOC_IDENTITY &&
|
||||||
opcode != SOC_CERTIFICATE &&
|
opcode > SOC_UNSUPPORTED) { /* Ignore all unknown types here */
|
||||||
opcode > SOC_UNSUPPORTED &&
|
|
||||||
opcode < SOC_MAX) { /* Ignore all unknown types here */
|
|
||||||
/* Skip all the options that were already applied */
|
/* Skip all the options that were already applied */
|
||||||
if (seen[opcode] != 0) {
|
if (seen[opcode] != 0) {
|
||||||
SAFE_FREE(x);
|
SAFE_FREE(x);
|
||||||
@@ -831,7 +667,7 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
args++;
|
args++;
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "line %d: Processing Match keyword '%s'",
|
SSH_LOG(SSH_LOG_TRACE, "line %d: Processing Match keyword '%s'",
|
||||||
count, p);
|
count, p);
|
||||||
|
|
||||||
/* If the option is prefixed with ! the result should be negated */
|
/* If the option is prefixed with ! the result should be negated */
|
||||||
@@ -863,7 +699,7 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
|
|
||||||
case MATCH_FINAL:
|
case MATCH_FINAL:
|
||||||
case MATCH_CANONICAL:
|
case MATCH_CANONICAL:
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_INFO,
|
||||||
"line %d: Unsupported Match keyword '%s', skipping",
|
"line %d: Unsupported Match keyword '%s', skipping",
|
||||||
count,
|
count,
|
||||||
p);
|
p);
|
||||||
@@ -875,13 +711,13 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
/* Skip one argument (including in quotes) */
|
/* Skip one argument (including in quotes) */
|
||||||
p = ssh_config_get_token(&s);
|
p = ssh_config_get_token(&s);
|
||||||
if (p == NULL || p[0] == '\0') {
|
if (p == NULL || p[0] == '\0') {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "line %d: Match keyword "
|
SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
|
||||||
"'%s' requires argument", count, p2);
|
"'%s' requires argument", count, p2);
|
||||||
SAFE_FREE(x);
|
SAFE_FREE(x);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (result != 1) {
|
if (result != 1) {
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "line %d: Skipped match exec "
|
SSH_LOG(SSH_LOG_INFO, "line %d: Skipped match exec "
|
||||||
"'%s' as previous conditions already failed.",
|
"'%s' as previous conditions already failed.",
|
||||||
count, p2);
|
count, p2);
|
||||||
continue;
|
continue;
|
||||||
@@ -902,7 +738,7 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
}
|
}
|
||||||
localuser = ssh_get_local_username();
|
localuser = ssh_get_local_username();
|
||||||
if (localuser == NULL) {
|
if (localuser == NULL) {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "line %d: Can not get local username "
|
SSH_LOG(SSH_LOG_WARN, "line %d: Can not get local username "
|
||||||
"for conditional matching.", count);
|
"for conditional matching.", count);
|
||||||
SAFE_FREE(x);
|
SAFE_FREE(x);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -916,13 +752,13 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
/* Skip one argument */
|
/* Skip one argument */
|
||||||
p = ssh_config_get_str_tok(&s, NULL);
|
p = ssh_config_get_str_tok(&s, NULL);
|
||||||
if (p == NULL || p[0] == '\0') {
|
if (p == NULL || p[0] == '\0') {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "line %d: Match keyword "
|
SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
|
||||||
"'%s' requires argument", count, p2);
|
"'%s' requires argument", count, p2);
|
||||||
SAFE_FREE(x);
|
SAFE_FREE(x);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
args++;
|
args++;
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_INFO,
|
||||||
"line %d: Unsupported Match keyword '%s', ignoring",
|
"line %d: Unsupported Match keyword '%s', ignoring",
|
||||||
count,
|
count,
|
||||||
p2);
|
p2);
|
||||||
@@ -957,55 +793,6 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
args++;
|
args++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MATCH_LOCALNETWORK:
|
|
||||||
/* Here we match only one argument */
|
|
||||||
p = ssh_config_get_str_tok(&s, NULL);
|
|
||||||
if (p == NULL || p[0] == '\0') {
|
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"line %d: ERROR - Match local network keyword"
|
|
||||||
"requires argument",
|
|
||||||
count);
|
|
||||||
SAFE_FREE(x);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#ifdef HAVE_IFADDRS_H
|
|
||||||
rv = match_cidr_address_list(NULL, p, -1);
|
|
||||||
if (rv == -1) {
|
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"line %d: ERROR - List invalid entry: %s",
|
|
||||||
count,
|
|
||||||
p);
|
|
||||||
SAFE_FREE(x);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
rv = ssh_match_localnetwork(p, negate);
|
|
||||||
if (rv == -1) {
|
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"line %d: ERROR - Error while retrieving "
|
|
||||||
"network interface information -"
|
|
||||||
" List entry: %s",
|
|
||||||
count,
|
|
||||||
p);
|
|
||||||
SAFE_FREE(x);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
result &= rv;
|
|
||||||
#else /* HAVE_IFADDRS_H */
|
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"line %d: ERROR - match localnetwork "
|
|
||||||
"not supported on this platform",
|
|
||||||
count);
|
|
||||||
SAFE_FREE(x);
|
|
||||||
return -1;
|
|
||||||
#endif /* HAVE_IFADDRS_H */
|
|
||||||
args++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MATCH_UNKNOWN:
|
case MATCH_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
ssh_set_error(session, SSH_FATAL,
|
ssh_set_error(session, SSH_FATAL,
|
||||||
@@ -1133,8 +920,7 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* We share the seen value with the ProxyCommand */
|
/* We share the seen value with the ProxyCommand */
|
||||||
rv = ssh_config_parse_proxy_jump(session,
|
rv = ssh_config_parse_proxy_jump(session, p,
|
||||||
p,
|
|
||||||
(*parsing && !seen[SOC_PROXYCOMMAND]));
|
(*parsing && !seen[SOC_PROXYCOMMAND]));
|
||||||
if (rv != SSH_OK) {
|
if (rv != SSH_OK) {
|
||||||
SAFE_FREE(x);
|
SAFE_FREE(x);
|
||||||
@@ -1179,10 +965,10 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
if (strcasecmp(p, "quiet") == 0) {
|
if (strcasecmp(p, "quiet") == 0) {
|
||||||
value = SSH_LOG_NONE;
|
value = SSH_LOG_NONE;
|
||||||
} else if (strcasecmp(p, "fatal") == 0 ||
|
} else if (strcasecmp(p, "fatal") == 0 ||
|
||||||
strcasecmp(p, "error")== 0) {
|
strcasecmp(p, "error")== 0 ||
|
||||||
value = SSH_LOG_WARN;
|
|
||||||
} else if (strcasecmp(p, "verbose") == 0 ||
|
|
||||||
strcasecmp(p, "info") == 0) {
|
strcasecmp(p, "info") == 0) {
|
||||||
|
value = SSH_LOG_WARN;
|
||||||
|
} else if (strcasecmp(p, "verbose") == 0) {
|
||||||
value = SSH_LOG_INFO;
|
value = SSH_LOG_INFO;
|
||||||
} else if (strcasecmp(p, "DEBUG") == 0 ||
|
} else if (strcasecmp(p, "DEBUG") == 0 ||
|
||||||
strcasecmp(p, "DEBUG1") == 0) {
|
strcasecmp(p, "DEBUG1") == 0) {
|
||||||
@@ -1227,13 +1013,13 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
ll = strtoll(p, &endp, 10);
|
ll = strtoll(p, &endp, 10);
|
||||||
if (p == endp || ll < 0) {
|
if (p == endp || ll < 0) {
|
||||||
/* No number or negative */
|
/* No number or negative */
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Invalid argument to rekey limit");
|
SSH_LOG(SSH_LOG_WARN, "Invalid argument to rekey limit");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (*endp) {
|
switch (*endp) {
|
||||||
case 'G':
|
case 'G':
|
||||||
if (ll > LLONG_MAX / 1024) {
|
if (ll > LLONG_MAX / 1024) {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit");
|
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||||
ll = -1;
|
ll = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1241,7 +1027,7 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
FALL_THROUGH;
|
FALL_THROUGH;
|
||||||
case 'M':
|
case 'M':
|
||||||
if (ll > LLONG_MAX / 1024) {
|
if (ll > LLONG_MAX / 1024) {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit");
|
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||||
ll = -1;
|
ll = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1249,7 +1035,7 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
FALL_THROUGH;
|
FALL_THROUGH;
|
||||||
case 'K':
|
case 'K':
|
||||||
if (ll > LLONG_MAX / 1024) {
|
if (ll > LLONG_MAX / 1024) {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit");
|
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||||
ll = -1;
|
ll = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1265,7 +1051,7 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (*endp != ' ' && *endp != '\0') {
|
if (*endp != ' ' && *endp != '\0') {
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"Invalid trailing characters after the rekey limit: %s",
|
"Invalid trailing characters after the rekey limit: %s",
|
||||||
endp);
|
endp);
|
||||||
break;
|
break;
|
||||||
@@ -1286,14 +1072,14 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
ll = strtoll(p, &endp, 10);
|
ll = strtoll(p, &endp, 10);
|
||||||
if (p == endp || ll < 0) {
|
if (p == endp || ll < 0) {
|
||||||
/* No number or negative */
|
/* No number or negative */
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Invalid argument to rekey limit");
|
SSH_LOG(SSH_LOG_WARN, "Invalid argument to rekey limit");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (*endp) {
|
switch (*endp) {
|
||||||
case 'w':
|
case 'w':
|
||||||
case 'W':
|
case 'W':
|
||||||
if (ll > LLONG_MAX / 7) {
|
if (ll > LLONG_MAX / 7) {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit");
|
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||||
ll = -1;
|
ll = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1302,7 +1088,7 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
case 'd':
|
case 'd':
|
||||||
case 'D':
|
case 'D':
|
||||||
if (ll > LLONG_MAX / 24) {
|
if (ll > LLONG_MAX / 24) {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit");
|
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||||
ll = -1;
|
ll = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1311,7 +1097,7 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
case 'h':
|
case 'h':
|
||||||
case 'H':
|
case 'H':
|
||||||
if (ll > LLONG_MAX / 60) {
|
if (ll > LLONG_MAX / 60) {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit");
|
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||||
ll = -1;
|
ll = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1320,7 +1106,7 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
case 'm':
|
case 'm':
|
||||||
case 'M':
|
case 'M':
|
||||||
if (ll > LLONG_MAX / 60) {
|
if (ll > LLONG_MAX / 60) {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit");
|
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||||
ll = -1;
|
ll = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1339,7 +1125,7 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (*endp != '\0') {
|
if (*endp != '\0') {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Invalid trailing characters after the"
|
SSH_LOG(SSH_LOG_WARN, "Invalid trailing characters after the"
|
||||||
" rekey limit: %s", endp);
|
" rekey limit: %s", endp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1375,15 +1161,15 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SOC_NA:
|
case SOC_NA:
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Unapplicable option: %s, line: %d",
|
SSH_LOG(SSH_LOG_INFO, "Unapplicable option: %s, line: %d",
|
||||||
keyword, count);
|
keyword, count);
|
||||||
break;
|
break;
|
||||||
case SOC_UNSUPPORTED:
|
case SOC_UNSUPPORTED:
|
||||||
SSH_LOG(SSH_LOG_RARE, "Unsupported option: %s, line: %d",
|
SSH_LOG(SSH_LOG_INFO, "Unsupported option: %s, line: %d",
|
||||||
keyword, count);
|
keyword, count);
|
||||||
break;
|
break;
|
||||||
case SOC_UNKNOWN:
|
case SOC_UNKNOWN:
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Unknown option: %s, line: %d",
|
SSH_LOG(SSH_LOG_INFO, "Unknown option: %s, line: %d",
|
||||||
keyword, count);
|
keyword, count);
|
||||||
break;
|
break;
|
||||||
case SOC_IDENTITYAGENT:
|
case SOC_IDENTITYAGENT:
|
||||||
@@ -1392,51 +1178,6 @@ ssh_config_parse_line(ssh_session session,
|
|||||||
ssh_options_set(session, SSH_OPTIONS_IDENTITY_AGENT, p);
|
ssh_options_set(session, SSH_OPTIONS_IDENTITY_AGENT, p);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SOC_IDENTITIESONLY:
|
|
||||||
i = ssh_config_get_yesno(&s, -1);
|
|
||||||
if (i >= 0 && *parsing) {
|
|
||||||
bool b = i;
|
|
||||||
ssh_options_set(session, SSH_OPTIONS_IDENTITIES_ONLY, &b);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SOC_CONTROLMASTER:
|
|
||||||
p = ssh_config_get_str_tok(&s, NULL);
|
|
||||||
if (p && *parsing) {
|
|
||||||
int value = -1;
|
|
||||||
|
|
||||||
if (strcasecmp(p, "auto") == 0) {
|
|
||||||
value = SSH_CONTROL_MASTER_AUTO;
|
|
||||||
} else if (strcasecmp(p, "yes") == 0) {
|
|
||||||
value = SSH_CONTROL_MASTER_YES;
|
|
||||||
} else if (strcasecmp(p, "no") == 0) {
|
|
||||||
value = SSH_CONTROL_MASTER_NO;
|
|
||||||
} else if (strcasecmp(p, "autoask") == 0) {
|
|
||||||
value = SSH_CONTROL_MASTER_AUTOASK;
|
|
||||||
} else if (strcasecmp(p, "ask") == 0) {
|
|
||||||
value = SSH_CONTROL_MASTER_ASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value != -1) {
|
|
||||||
ssh_options_set(session, SSH_OPTIONS_CONTROL_MASTER, &value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SOC_CONTROLPATH:
|
|
||||||
p = ssh_config_get_str_tok(&s, NULL);
|
|
||||||
if (p == NULL) {
|
|
||||||
SAFE_FREE(x);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (*parsing) {
|
|
||||||
ssh_options_set(session, SSH_OPTIONS_CONTROL_PATH, p);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SOC_CERTIFICATE:
|
|
||||||
p = ssh_config_get_str_tok(&s, NULL);
|
|
||||||
if (p && *parsing) {
|
|
||||||
ssh_options_set(session, SSH_OPTIONS_CERTIFICATE, p);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d",
|
ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d",
|
||||||
opcode);
|
opcode);
|
||||||
@@ -1519,12 +1260,12 @@ int ssh_config_parse_string(ssh_session session, const char *input)
|
|||||||
}
|
}
|
||||||
if (c == NULL) {
|
if (c == NULL) {
|
||||||
/* should not happen, would mean a string without trailing '\0' */
|
/* should not happen, would mean a string without trailing '\0' */
|
||||||
SSH_LOG(SSH_LOG_TRACE, "No trailing '\\0' in config string");
|
SSH_LOG(SSH_LOG_WARN, "No trailing '\\0' in config string");
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
line_len = c - line_start;
|
line_len = c - line_start;
|
||||||
if (line_len > MAX_LINE_SIZE - 1) {
|
if (line_len > MAX_LINE_SIZE - 1) {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Line %u too long: %u characters",
|
SSH_LOG(SSH_LOG_WARN, "Line %u too long: %u characters",
|
||||||
line_num, line_len);
|
line_num, line_len);
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,10 +162,9 @@ int ssh_config_get_yesno(char **str, int notfound)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ssh_config_parse_uri(const char *tok,
|
int ssh_config_parse_uri(const char *tok,
|
||||||
char **username,
|
char **username,
|
||||||
char **hostname,
|
char **hostname,
|
||||||
char **port,
|
char **port)
|
||||||
bool ignore_port)
|
|
||||||
{
|
{
|
||||||
char *endp = NULL;
|
char *endp = NULL;
|
||||||
long port_n;
|
long port_n;
|
||||||
@@ -194,10 +193,6 @@ int ssh_config_parse_uri(const char *tok,
|
|||||||
if (*username == NULL) {
|
if (*username == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
rc = ssh_check_username_syntax(*username);
|
|
||||||
if (rc != SSH_OK) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
tok = endp + 1;
|
tok = endp + 1;
|
||||||
/* If there is second @ character, this does not look like our URI */
|
/* If there is second @ character, this does not look like our URI */
|
||||||
@@ -215,17 +210,12 @@ int ssh_config_parse_uri(const char *tok,
|
|||||||
if (endp == NULL) {
|
if (endp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else if (!ignore_port) {
|
} else {
|
||||||
/* Hostnames or aliases expand to the last colon (if port is requested)
|
/* Hostnames or aliases expand to the last colon or to the end */
|
||||||
* or to the end */
|
|
||||||
endp = strrchr(tok, ':');
|
endp = strrchr(tok, ':');
|
||||||
if (endp == NULL) {
|
if (endp == NULL) {
|
||||||
endp = strchr(tok, '\0');
|
endp = strchr(tok, '\0');
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
/* If no port is requested, expand to the end of line
|
|
||||||
* (to accommodate the IPv6 addresses) */
|
|
||||||
endp = strchr(tok, '\0');
|
|
||||||
}
|
}
|
||||||
if (tok == endp) {
|
if (tok == endp) {
|
||||||
/* Zero-length hostnames are not valid */
|
/* Zero-length hostnames are not valid */
|
||||||
@@ -257,7 +247,7 @@ int ssh_config_parse_uri(const char *tok,
|
|||||||
/* Verify the port is valid positive number */
|
/* Verify the port is valid positive number */
|
||||||
port_n = strtol(endp + 1, &port_end, 10);
|
port_n = strtol(endp + 1, &port_end, 10);
|
||||||
if (port_n < 1 || *port_end != '\0') {
|
if (port_n < 1 || *port_end != '\0') {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Failed to parse port number."
|
SSH_LOG(SSH_LOG_WARN, "Failed to parse port number."
|
||||||
" The value '%ld' is invalid or there are some"
|
" The value '%ld' is invalid or there are some"
|
||||||
" trailing characters: '%s'", port_n, port_end);
|
" trailing characters: '%s'", port_n, port_end);
|
||||||
goto error;
|
goto error;
|
||||||
|
|||||||
@@ -54,6 +54,11 @@
|
|||||||
#define NTDDI_VERSION 0x05010000 /* NTDDI_WINXP */
|
#define NTDDI_VERSION 0x05010000 /* NTDDI_WINXP */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if _MSC_VER >= 1400
|
||||||
|
#include <io.h>
|
||||||
|
#undef close
|
||||||
|
#define close _close
|
||||||
|
#endif /* _MSC_VER */
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
@@ -163,7 +168,7 @@ static int set_tcp_nodelay(socket_t socket)
|
|||||||
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||||
const char *bind_addr, int port)
|
const char *bind_addr, int port)
|
||||||
{
|
{
|
||||||
socket_t s = -1, first = -1;
|
socket_t s = -1;
|
||||||
int rc;
|
int rc;
|
||||||
struct addrinfo *ai = NULL;
|
struct addrinfo *ai = NULL;
|
||||||
struct addrinfo *itr = NULL;
|
struct addrinfo *itr = NULL;
|
||||||
@@ -253,22 +258,12 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
|||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
|
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
|
||||||
if (rc == -1) {
|
if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
|
||||||
if ((errno != 0) && (errno != EINPROGRESS)) {
|
ssh_set_error(session, SSH_FATAL,
|
||||||
ssh_set_error(session, SSH_FATAL,
|
"Failed to connect: %s",
|
||||||
"Failed to connect: %s",
|
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||||
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
ssh_connect_socket_close(s);
|
||||||
ssh_connect_socket_close(s);
|
s = -1;
|
||||||
s = -1;
|
|
||||||
} else {
|
|
||||||
if (first == -1) {
|
|
||||||
first = s;
|
|
||||||
} else { /* errno == EINPROGRESS */
|
|
||||||
/* save only the first "working" socket */
|
|
||||||
ssh_connect_socket_close(s);
|
|
||||||
s = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,12 +272,6 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
|||||||
|
|
||||||
freeaddrinfo(ai);
|
freeaddrinfo(ai);
|
||||||
|
|
||||||
/* first let's go through all the addresses looking for immediate
|
|
||||||
* connection, otherwise return the first address without error or error */
|
|
||||||
if (s == -1) {
|
|
||||||
s = first;
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,19 @@
|
|||||||
#define CHUNKSIZE 4096
|
#define CHUNKSIZE 4096
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifdef _WIN32
|
||||||
|
# ifdef HAVE_IO_H
|
||||||
|
# include <io.h>
|
||||||
|
# undef open
|
||||||
|
# define open _open
|
||||||
|
# undef close
|
||||||
|
# define close _close
|
||||||
|
# undef read
|
||||||
|
# define read _read
|
||||||
|
# undef unlink
|
||||||
|
# define unlink _unlink
|
||||||
|
# endif /* HAVE_IO_H */
|
||||||
|
#else
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
# include <sys/socket.h>
|
# include <sys/socket.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -291,11 +303,9 @@ static void ssh_connector_fd_in_cb(ssh_connector connector)
|
|||||||
* Loop around write in case the write blocks even for CHUNKSIZE
|
* Loop around write in case the write blocks even for CHUNKSIZE
|
||||||
* bytes
|
* bytes
|
||||||
*/
|
*/
|
||||||
while (total < r) {
|
while (total != r) {
|
||||||
w = ssh_connector_fd_write(connector,
|
w = ssh_connector_fd_write(connector, buffer + total, r - total);
|
||||||
buffer + total,
|
if (w < 0){
|
||||||
r - total);
|
|
||||||
if (w < 0) {
|
|
||||||
ssh_connector_except(connector, connector->out_fd);
|
ssh_connector_except(connector, connector->out_fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
#include "libssh/pki.h"
|
#include "libssh/pki.h"
|
||||||
#include "libssh/bignum.h"
|
#include "libssh/bignum.h"
|
||||||
|
|
||||||
#ifdef HAVE_LIBCRYPTO
|
#if defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_X25519)
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ static struct ssh_packet_callbacks_struct ssh_curve25519_client_callbacks = {
|
|||||||
static int ssh_curve25519_init(ssh_session session)
|
static int ssh_curve25519_init(ssh_session session)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
#ifdef HAVE_LIBCRYPTO
|
#if defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_X25519)
|
||||||
EVP_PKEY_CTX *pctx = NULL;
|
EVP_PKEY_CTX *pctx = NULL;
|
||||||
EVP_PKEY *pkey = NULL;
|
EVP_PKEY *pkey = NULL;
|
||||||
size_t pubkey_len = CURVE25519_PUBKEY_SIZE;
|
size_t pubkey_len = CURVE25519_PUBKEY_SIZE;
|
||||||
@@ -136,7 +136,7 @@ static int ssh_curve25519_init(ssh_session session)
|
|||||||
crypto_scalarmult_base(session->next_crypto->curve25519_client_pubkey,
|
crypto_scalarmult_base(session->next_crypto->curve25519_client_pubkey,
|
||||||
session->next_crypto->curve25519_privkey);
|
session->next_crypto->curve25519_privkey);
|
||||||
}
|
}
|
||||||
#endif /* HAVE_LIBCRYPTO */
|
#endif /* defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_X25519) */
|
||||||
|
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
@@ -181,7 +181,7 @@ static int ssh_curve25519_build_k(ssh_session session)
|
|||||||
{
|
{
|
||||||
ssh_curve25519_pubkey k;
|
ssh_curve25519_pubkey k;
|
||||||
|
|
||||||
#ifdef HAVE_LIBCRYPTO
|
#if defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_X25519)
|
||||||
EVP_PKEY_CTX *pctx = NULL;
|
EVP_PKEY_CTX *pctx = NULL;
|
||||||
EVP_PKEY *pkey = NULL, *pubkey = NULL;
|
EVP_PKEY *pkey = NULL, *pubkey = NULL;
|
||||||
size_t shared_key_len = sizeof(k);
|
size_t shared_key_len = sizeof(k);
|
||||||
@@ -260,7 +260,7 @@ out:
|
|||||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||||
session->next_crypto->curve25519_server_pubkey);
|
session->next_crypto->curve25519_server_pubkey);
|
||||||
}
|
}
|
||||||
#endif /* HAVE_LIBCRYPTO */
|
#endif /* defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_X25519) */
|
||||||
|
|
||||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->shared_secret);
|
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->shared_secret);
|
||||||
if (session->next_crypto->shared_secret == NULL) {
|
if (session->next_crypto->shared_secret == NULL) {
|
||||||
@@ -380,7 +380,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
|
|||||||
ssh_string q_s_string = NULL;
|
ssh_string q_s_string = NULL;
|
||||||
ssh_string server_pubkey_blob = NULL;
|
ssh_string server_pubkey_blob = NULL;
|
||||||
|
|
||||||
/* SSH host keys (rsa, ed25519 and ecdsa) */
|
/* SSH host keys (rsa,dsa,ecdsa) */
|
||||||
ssh_key privkey = NULL;
|
ssh_key privkey = NULL;
|
||||||
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
|
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
|
||||||
ssh_string sig_blob = NULL;
|
ssh_string sig_blob = NULL;
|
||||||
@@ -490,7 +490,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_KEX_ECDH_REPLY sent");
|
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_ECDH_REPLY sent");
|
||||||
rc = ssh_packet_send(session);
|
rc = ssh_packet_send(session);
|
||||||
if (rc == SSH_ERROR) {
|
if (rc == SSH_ERROR) {
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
|
|||||||
27
src/dh-gex.c
27
src/dh-gex.c
@@ -116,7 +116,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group)
|
|||||||
(void) type;
|
(void) type;
|
||||||
(void) user;
|
(void) user;
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_KEX_DH_GEX_GROUP received");
|
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_DH_GEX_GROUP received");
|
||||||
|
|
||||||
if (bignum_ctx_invalid(ctx)) {
|
if (bignum_ctx_invalid(ctx)) {
|
||||||
goto error;
|
goto error;
|
||||||
@@ -261,7 +261,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply)
|
|||||||
bignum server_pubkey = NULL;
|
bignum server_pubkey = NULL;
|
||||||
(void)type;
|
(void)type;
|
||||||
(void)user;
|
(void)user;
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_KEX_DH_GEX_REPLY received");
|
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_DH_GEX_REPLY received");
|
||||||
|
|
||||||
ssh_client_dhgex_remove_callbacks(session);
|
ssh_client_dhgex_remove_callbacks(session);
|
||||||
rc = ssh_buffer_unpack(packet,
|
rc = ssh_buffer_unpack(packet,
|
||||||
@@ -435,7 +435,7 @@ static int ssh_retrieve_dhgroup_file(FILE *moduli,
|
|||||||
if (rc == EOF) {
|
if (rc == EOF) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "Invalid moduli entry line %zu", line);
|
SSH_LOG(SSH_LOG_INFO, "Invalid moduli entry line %zu", line);
|
||||||
do {
|
do {
|
||||||
firstbyte = getc(moduli);
|
firstbyte = getc(moduli);
|
||||||
} while(firstbyte != '\n' && firstbyte != EOF);
|
} while(firstbyte != '\n' && firstbyte != EOF);
|
||||||
@@ -450,9 +450,10 @@ static int ssh_retrieve_dhgroup_file(FILE *moduli,
|
|||||||
proposed_size = size + 1;
|
proposed_size = size + 1;
|
||||||
if (proposed_size != *best_size &&
|
if (proposed_size != *best_size &&
|
||||||
dhgroup_better_size(pmin, pn, pmax, *best_size, proposed_size)) {
|
dhgroup_better_size(pmin, pn, pmax, *best_size, proposed_size)) {
|
||||||
best_nlines = 1;
|
best_nlines = 0;
|
||||||
*best_size = proposed_size;
|
*best_size = proposed_size;
|
||||||
} else if (proposed_size == *best_size) {
|
}
|
||||||
|
if (proposed_size == *best_size) {
|
||||||
best_nlines++;
|
best_nlines++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,14 +473,14 @@ static int ssh_retrieve_dhgroup_file(FILE *moduli,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (*best_size != 0) {
|
if (*best_size != 0) {
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_INFO,
|
||||||
"Selected %zu bits modulus out of %zu candidates in %zu lines",
|
"Selected %zu bits modulus out of %zu candidates in %zu lines",
|
||||||
*best_size,
|
*best_size,
|
||||||
best_nlines - 1,
|
best_nlines - 1,
|
||||||
line);
|
line);
|
||||||
} else {
|
} else {
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_WARNING,
|
||||||
"No moduli found for [%" PRIu32 ":%" PRIu32 ":%" PRIu32 "]",
|
"No moduli found for [%u:%u:%u]",
|
||||||
pmin,
|
pmin,
|
||||||
pn,
|
pn,
|
||||||
pmax);
|
pmax);
|
||||||
@@ -525,7 +526,7 @@ static int ssh_retrieve_dhgroup(char *moduli_file,
|
|||||||
|
|
||||||
if (moduli == NULL) {
|
if (moduli == NULL) {
|
||||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||||
SSH_LOG(SSH_LOG_DEBUG,
|
SSH_LOG(SSH_LOG_WARNING,
|
||||||
"Unable to open moduli file: %s",
|
"Unable to open moduli file: %s",
|
||||||
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||||
return ssh_fallback_group(pmax, p, g);
|
return ssh_fallback_group(pmax, p, g);
|
||||||
@@ -620,12 +621,12 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_request)
|
|||||||
ssh_set_error_invalid(session);
|
ssh_set_error_invalid(session);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "dh-gex: DHGEX_REQUEST[%" PRIu32 ":%" PRIu32 ":%" PRIu32 "]", pmin, pn, pmax);
|
SSH_LOG(SSH_LOG_INFO, "dh-gex: DHGEX_REQUEST[%u:%u:%u]", pmin, pn, pmax);
|
||||||
|
|
||||||
if (pmin > pn || pn > pmax || pn > DH_PMAX || pmax < DH_PMIN) {
|
if (pmin > pn || pn > pmax || pn > DH_PMAX || pmax < DH_PMIN) {
|
||||||
ssh_set_error(session,
|
ssh_set_error(session,
|
||||||
SSH_FATAL,
|
SSH_FATAL,
|
||||||
"Invalid dh-gex arguments [%" PRIu32 ":%" PRIu32 ":%" PRIu32 "]",
|
"Invalid dh-gex arguments [%u:%u:%u]",
|
||||||
pmin,
|
pmin,
|
||||||
pn,
|
pn,
|
||||||
pmax);
|
pmax);
|
||||||
@@ -642,7 +643,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_request)
|
|||||||
pn = pmin;
|
pn = pmin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc = ssh_retrieve_dhgroup(session->server_opts.moduli_file,
|
rc = ssh_retrieve_dhgroup(session->opts.moduli_file,
|
||||||
pmin,
|
pmin,
|
||||||
pn,
|
pn,
|
||||||
pmax,
|
pmax,
|
||||||
@@ -652,7 +653,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_request)
|
|||||||
if (rc == SSH_ERROR) {
|
if (rc == SSH_ERROR) {
|
||||||
ssh_set_error(session,
|
ssh_set_error(session,
|
||||||
SSH_FATAL,
|
SSH_FATAL,
|
||||||
"Couldn't find DH group for [%" PRIu32 ":%" PRIu32 ":%" PRIu32 "]",
|
"Couldn't find DH group for [%u:%u:%u]",
|
||||||
pmin,
|
pmin,
|
||||||
pn,
|
pn,
|
||||||
pmax);
|
pmax);
|
||||||
|
|||||||
@@ -30,14 +30,16 @@
|
|||||||
|
|
||||||
#ifdef HAVE_ECDH
|
#ifdef HAVE_ECDH
|
||||||
#include <openssl/ecdh.h>
|
#include <openssl/ecdh.h>
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
#define NISTP256 NID_X9_62_prime256v1
|
#define NISTP256 NID_X9_62_prime256v1
|
||||||
#define NISTP384 NID_secp384r1
|
#define NISTP384 NID_secp384r1
|
||||||
#define NISTP521 NID_secp521r1
|
#define NISTP521 NID_secp521r1
|
||||||
#else
|
#else
|
||||||
#include <openssl/err.h>
|
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/param_build.h>
|
|
||||||
#include <openssl/params.h>
|
#include <openssl/params.h>
|
||||||
#include <openssl/core_names.h>
|
#include <openssl/core_names.h>
|
||||||
#include "libcrypto-compat.h"
|
#include "libcrypto-compat.h"
|
||||||
@@ -46,7 +48,11 @@
|
|||||||
/** @internal
|
/** @internal
|
||||||
* @brief Map the given key exchange enum value to its curve name.
|
* @brief Map the given key exchange enum value to its curve name.
|
||||||
*/
|
*/
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
static int ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
|
static int ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
|
||||||
#else
|
#else
|
||||||
static const char *ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
|
static const char *ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
|
||||||
@@ -58,185 +64,183 @@ static const char *ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
|
|||||||
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) {
|
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) {
|
||||||
return NISTP521;
|
return NISTP521;
|
||||||
}
|
}
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
#else
|
#else
|
||||||
return NULL;
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @internal
|
|
||||||
* @brief Generate ECDH key pair for ecdh key exchange and store it in the
|
|
||||||
* session->next_crypto structure
|
|
||||||
*/
|
|
||||||
static ssh_string ssh_ecdh_generate(ssh_session session)
|
|
||||||
{
|
|
||||||
ssh_string pubkey_string = NULL;
|
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
|
||||||
const EC_POINT *point = NULL;
|
|
||||||
const EC_GROUP *group = NULL;
|
|
||||||
EC_KEY *key = NULL;
|
|
||||||
int curve;
|
|
||||||
#else
|
|
||||||
EC_POINT *point = NULL;
|
|
||||||
EC_GROUP *group = NULL;
|
|
||||||
const char *curve = NULL;
|
|
||||||
EVP_PKEY *key = NULL;
|
|
||||||
OSSL_PARAM *out_params = NULL;
|
|
||||||
const OSSL_PARAM *pubkey_param = NULL;
|
|
||||||
const void *pubkey = NULL;
|
|
||||||
size_t pubkey_len;
|
|
||||||
int nid;
|
|
||||||
int rc;
|
|
||||||
#endif /* OPENSSL_VERSION_NUMBER */
|
|
||||||
|
|
||||||
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
|
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
|
||||||
if (curve == SSH_ERROR) {
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Failed to get curve name");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
key = EC_KEY_new_by_curve_name(curve);
|
|
||||||
#else
|
|
||||||
if (curve == NULL) {
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Failed to get curve name");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
key = EVP_EC_gen(curve);
|
|
||||||
#endif /* OPENSSL_VERSION_NUMBER */
|
|
||||||
if (key == NULL) {
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Failed to generate key");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
|
||||||
group = EC_KEY_get0_group(key);
|
|
||||||
|
|
||||||
EC_KEY_generate_key(key);
|
|
||||||
|
|
||||||
point = EC_KEY_get0_public_key(key);
|
|
||||||
|
|
||||||
pubkey_string = pki_key_make_ecpoint_string(group, point);
|
|
||||||
#else
|
|
||||||
rc = EVP_PKEY_todata(key, EVP_PKEY_PUBLIC_KEY, &out_params);
|
|
||||||
if (rc != 1) {
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Failed to export public key");
|
|
||||||
EVP_PKEY_free(key);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pubkey_param = OSSL_PARAM_locate_const(out_params, OSSL_PKEY_PARAM_PUB_KEY);
|
|
||||||
if (pubkey_param == NULL) {
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Failed to find public key");
|
|
||||||
EVP_PKEY_free(key);
|
|
||||||
OSSL_PARAM_free(out_params);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = OSSL_PARAM_get_octet_string_ptr(pubkey_param,
|
|
||||||
(const void**)&pubkey,
|
|
||||||
&pubkey_len);
|
|
||||||
if (rc != 1) {
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Failed to read public key");
|
|
||||||
OSSL_PARAM_free(out_params);
|
|
||||||
EVP_PKEY_free(key);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert the data to low-level representation */
|
|
||||||
nid = pki_key_ecgroup_name_to_nid(curve);
|
|
||||||
group = EC_GROUP_new_by_curve_name_ex(NULL, NULL, nid);
|
|
||||||
if (group == NULL) {
|
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"Could not create group: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
|
||||||
OSSL_PARAM_free(out_params);
|
|
||||||
EVP_PKEY_free(key);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
point = EC_POINT_new(group);
|
|
||||||
if (point == NULL) {
|
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"Could not create point: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
|
||||||
EC_GROUP_free(group);
|
|
||||||
OSSL_PARAM_free(out_params);
|
|
||||||
EVP_PKEY_free(key);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
rc = EC_POINT_oct2point(group, point, pubkey, pubkey_len, NULL);
|
|
||||||
OSSL_PARAM_free(out_params);
|
|
||||||
if (rc != 1) {
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Failed to export public key");
|
|
||||||
EC_GROUP_free(group);
|
|
||||||
EC_POINT_free(point);
|
|
||||||
EVP_PKEY_free(key);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pubkey_string = pki_key_make_ecpoint_string(group, point);
|
|
||||||
EC_GROUP_free(group);
|
|
||||||
EC_POINT_free(point);
|
|
||||||
#endif /* OPENSSL_VERSION_NUMBER */
|
|
||||||
if (pubkey_string == NULL) {
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Failed to convert public key");
|
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
|
||||||
EC_KEY_free(key);
|
|
||||||
#else
|
|
||||||
EVP_PKEY_free(key);
|
|
||||||
#endif /* OPENSSL_VERSION_NUMBER */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
session->next_crypto->ecdh_privkey = key;
|
|
||||||
return pubkey_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @internal
|
/** @internal
|
||||||
* @brief Starts ecdh-sha2-nistp256 key exchange
|
* @brief Starts ecdh-sha2-nistp256 key exchange
|
||||||
*/
|
*/
|
||||||
int ssh_client_ecdh_init(ssh_session session)
|
int ssh_client_ecdh_init(ssh_session session){
|
||||||
{
|
int rc;
|
||||||
ssh_string client_pubkey = NULL;
|
ssh_string client_pubkey;
|
||||||
int rc;
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
EC_KEY *key;
|
||||||
|
const EC_GROUP *group;
|
||||||
|
const EC_POINT *pubkey;
|
||||||
|
int curve;
|
||||||
|
int len;
|
||||||
|
bignum_CTX ctx = BN_CTX_new();
|
||||||
|
if (ctx == NULL) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
const char *curve = NULL;
|
||||||
|
EVP_PKEY *key = NULL;
|
||||||
|
OSSL_PARAM *out_params = NULL;
|
||||||
|
const OSSL_PARAM *pubkey_param = NULL;
|
||||||
|
const uint8_t *pubkey = NULL;
|
||||||
|
size_t pubkey_len;
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
|
||||||
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
|
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
return SSH_ERROR;
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
}
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
BN_CTX_free(ctx);
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
client_pubkey = ssh_ecdh_generate(session);
|
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
|
||||||
if (client_pubkey == NULL) {
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
return SSH_ERROR;
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
}
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
if (curve == SSH_ERROR) {
|
||||||
|
BN_CTX_free(ctx);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
rc = ssh_buffer_add_ssh_string(session->out_buffer, client_pubkey);
|
key = EC_KEY_new_by_curve_name(curve);
|
||||||
if (rc < 0) {
|
#else
|
||||||
ssh_string_free(client_pubkey);
|
if (curve == NULL) {
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
key = EVP_EC_gen(curve);
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
|
||||||
/* register the packet callbacks */
|
if (key == NULL) {
|
||||||
ssh_packet_set_callbacks(session, &ssh_ecdh_client_callbacks);
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
BN_CTX_free(ctx);
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
rc = ssh_packet_send(session);
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
group = EC_KEY_get0_group(key);
|
||||||
|
|
||||||
return rc;
|
EC_KEY_generate_key(key);
|
||||||
|
|
||||||
|
pubkey=EC_KEY_get0_public_key(key);
|
||||||
|
len = EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
|
||||||
|
NULL,0,ctx);
|
||||||
|
|
||||||
|
client_pubkey = ssh_string_new(len);
|
||||||
|
if (client_pubkey == NULL) {
|
||||||
|
BN_CTX_free(ctx);
|
||||||
|
EC_KEY_free(key);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
|
||||||
|
ssh_string_data(client_pubkey),len,ctx);
|
||||||
|
BN_CTX_free(ctx);
|
||||||
|
#else
|
||||||
|
rc = EVP_PKEY_todata(key, EVP_PKEY_PUBLIC_KEY, &out_params);
|
||||||
|
if (rc != 1) {
|
||||||
|
EVP_PKEY_free(key);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
pubkey_param = OSSL_PARAM_locate_const(out_params, OSSL_PKEY_PARAM_PUB_KEY);
|
||||||
|
if (pubkey_param == NULL) {
|
||||||
|
EVP_PKEY_free(key);
|
||||||
|
OSSL_PARAM_free(out_params);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = OSSL_PARAM_get_octet_string_ptr(pubkey_param,
|
||||||
|
(const void**)&pubkey,
|
||||||
|
&pubkey_len);
|
||||||
|
if (rc != 1) {
|
||||||
|
OSSL_PARAM_free(out_params);
|
||||||
|
EVP_PKEY_free(key);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
client_pubkey = ssh_string_new(pubkey_len);
|
||||||
|
if (client_pubkey == NULL) {
|
||||||
|
OSSL_PARAM_free(out_params);
|
||||||
|
EVP_PKEY_free(key);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ssh_string_data(client_pubkey), pubkey, pubkey_len);
|
||||||
|
OSSL_PARAM_free(out_params);
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
|
||||||
|
rc = ssh_buffer_add_ssh_string(session->out_buffer,client_pubkey);
|
||||||
|
if (rc < 0) {
|
||||||
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
EC_KEY_free(key);
|
||||||
|
#else
|
||||||
|
EVP_PKEY_free(key);
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
SSH_STRING_FREE(client_pubkey);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->next_crypto->ecdh_privkey = key;
|
||||||
|
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
||||||
|
|
||||||
|
/* register the packet callbacks */
|
||||||
|
ssh_packet_set_callbacks(session, &ssh_ecdh_client_callbacks);
|
||||||
|
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||||
|
|
||||||
|
rc = ssh_packet_send(session);
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ecdh_build_k(ssh_session session)
|
int ecdh_build_k(ssh_session session) {
|
||||||
{
|
|
||||||
struct ssh_crypto_struct *next_crypto = session->next_crypto;
|
struct ssh_crypto_struct *next_crypto = session->next_crypto;
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
const EC_GROUP *group = EC_KEY_get0_group(next_crypto->ecdh_privkey);
|
const EC_GROUP *group = EC_KEY_get0_group(next_crypto->ecdh_privkey);
|
||||||
EC_POINT *pubkey = NULL;
|
EC_POINT *pubkey;
|
||||||
void *buffer = NULL;
|
void *buffer;
|
||||||
int rc;
|
int rc;
|
||||||
int len = (EC_GROUP_get_degree(group) + 7) / 8;
|
int len = (EC_GROUP_get_degree(group) + 7) / 8;
|
||||||
bignum_CTX ctx = bignum_ctx_new();
|
bignum_CTX ctx = bignum_ctx_new();
|
||||||
@@ -288,86 +292,59 @@ int ecdh_build_k(ssh_session session)
|
|||||||
bignum_bin2bn(buffer, len, &next_crypto->shared_secret);
|
bignum_bin2bn(buffer, len, &next_crypto->shared_secret);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
#else
|
#else
|
||||||
const char *curve = NULL;
|
|
||||||
EVP_PKEY *pubkey = NULL;
|
EVP_PKEY *pubkey = NULL;
|
||||||
void *secret = NULL;
|
void *secret = NULL;
|
||||||
size_t secret_len;
|
size_t secret_len;
|
||||||
int rc;
|
int rc;
|
||||||
ssh_string peer_pubkey = NULL;
|
OSSL_PARAM params[2];
|
||||||
OSSL_PARAM_BLD *param_bld = OSSL_PARAM_BLD_new();
|
|
||||||
EVP_PKEY_CTX *dh_ctx = EVP_PKEY_CTX_new_from_pkey(NULL,
|
EVP_PKEY_CTX *dh_ctx = EVP_PKEY_CTX_new_from_pkey(NULL,
|
||||||
next_crypto->ecdh_privkey,
|
next_crypto->ecdh_privkey,
|
||||||
NULL);
|
NULL);
|
||||||
|
EVP_PKEY_CTX *pubkey_ctx = EVP_PKEY_CTX_new_from_pkey(NULL,
|
||||||
if (dh_ctx == NULL || param_bld == NULL) {
|
next_crypto->ecdh_privkey,
|
||||||
ssh_set_error_oom(session);
|
NULL);
|
||||||
|
if (dh_ctx == NULL || pubkey_ctx == NULL) {
|
||||||
EVP_PKEY_CTX_free(dh_ctx);
|
EVP_PKEY_CTX_free(dh_ctx);
|
||||||
OSSL_PARAM_BLD_free(param_bld);
|
EVP_PKEY_CTX_free(pubkey_ctx);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = EVP_PKEY_derive_init(dh_ctx);
|
rc = EVP_PKEY_derive_init(dh_ctx);
|
||||||
if (rc != 1) {
|
if (rc != 1) {
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"Could not init PKEY derive: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
|
||||||
EVP_PKEY_CTX_free(dh_ctx);
|
EVP_PKEY_CTX_free(dh_ctx);
|
||||||
OSSL_PARAM_BLD_free(param_bld);
|
EVP_PKEY_CTX_free(pubkey_ctx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = EVP_PKEY_fromdata_init(pubkey_ctx);
|
||||||
|
if (rc != 1) {
|
||||||
|
EVP_PKEY_CTX_free(dh_ctx);
|
||||||
|
EVP_PKEY_CTX_free(pubkey_ctx);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session->server) {
|
if (session->server) {
|
||||||
peer_pubkey = next_crypto->ecdh_client_pubkey;
|
params[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
|
||||||
|
ssh_string_data(next_crypto->ecdh_client_pubkey),
|
||||||
|
ssh_string_len(next_crypto->ecdh_client_pubkey));
|
||||||
} else {
|
} else {
|
||||||
peer_pubkey = next_crypto->ecdh_server_pubkey;
|
params[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
|
||||||
|
ssh_string_data(next_crypto->ecdh_server_pubkey),
|
||||||
|
ssh_string_len(next_crypto->ecdh_server_pubkey));
|
||||||
}
|
}
|
||||||
rc = OSSL_PARAM_BLD_push_octet_string(param_bld,
|
params[1] = OSSL_PARAM_construct_end();
|
||||||
OSSL_PKEY_PARAM_PUB_KEY,
|
|
||||||
ssh_string_data(peer_pubkey),
|
rc = EVP_PKEY_fromdata(pubkey_ctx, &pubkey, EVP_PKEY_PUBLIC_KEY, params);
|
||||||
ssh_string_len(peer_pubkey));
|
|
||||||
if (rc != 1) {
|
if (rc != 1) {
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"Could not push the pub key: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
|
||||||
EVP_PKEY_CTX_free(dh_ctx);
|
EVP_PKEY_CTX_free(dh_ctx);
|
||||||
OSSL_PARAM_BLD_free(param_bld);
|
EVP_PKEY_CTX_free(pubkey_ctx);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
curve = ecdh_kex_type_to_curve(next_crypto->kex_type);
|
|
||||||
rc = OSSL_PARAM_BLD_push_utf8_string(param_bld,
|
|
||||||
OSSL_PKEY_PARAM_GROUP_NAME,
|
|
||||||
(char *)curve,
|
|
||||||
strlen(curve));
|
|
||||||
if (rc != 1) {
|
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"Could not push the group name: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
|
||||||
EVP_PKEY_CTX_free(dh_ctx);
|
|
||||||
OSSL_PARAM_BLD_free(param_bld);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = evp_build_pkey("EC", param_bld, &pubkey, EVP_PKEY_PUBLIC_KEY);
|
EVP_PKEY_CTX_free(pubkey_ctx);
|
||||||
OSSL_PARAM_BLD_free(param_bld);
|
|
||||||
if (rc != SSH_OK) {
|
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"Could not build the pkey: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
|
||||||
EVP_PKEY_CTX_free(dh_ctx);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = EVP_PKEY_derive_set_peer(dh_ctx, pubkey);
|
rc = EVP_PKEY_derive_set_peer(dh_ctx, pubkey);
|
||||||
EVP_PKEY_free(pubkey);
|
|
||||||
if (rc != 1) {
|
if (rc != 1) {
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"Could not set peer pubkey: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
|
||||||
EVP_PKEY_CTX_free(dh_ctx);
|
EVP_PKEY_CTX_free(dh_ctx);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -375,29 +352,19 @@ int ecdh_build_k(ssh_session session)
|
|||||||
/* get the max length of the secret */
|
/* get the max length of the secret */
|
||||||
rc = EVP_PKEY_derive(dh_ctx, NULL, &secret_len);
|
rc = EVP_PKEY_derive(dh_ctx, NULL, &secret_len);
|
||||||
if (rc != 1) {
|
if (rc != 1) {
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"Could not set peer pubkey: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
|
||||||
EVP_PKEY_CTX_free(dh_ctx);
|
EVP_PKEY_CTX_free(dh_ctx);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
secret = malloc(secret_len);
|
secret = malloc(secret_len);
|
||||||
if (secret == NULL) {
|
if (secret == NULL) {
|
||||||
ssh_set_error_oom(session);
|
|
||||||
EVP_PKEY_CTX_free(dh_ctx);
|
EVP_PKEY_CTX_free(dh_ctx);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = EVP_PKEY_derive(dh_ctx, secret, &secret_len);
|
rc = EVP_PKEY_derive(dh_ctx, secret, &secret_len);
|
||||||
if (rc != 1) {
|
if (rc != 1) {
|
||||||
ssh_set_error(session,
|
|
||||||
SSH_FATAL,
|
|
||||||
"Could not derive shared key: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
|
||||||
EVP_PKEY_CTX_free(dh_ctx);
|
EVP_PKEY_CTX_free(dh_ctx);
|
||||||
free(secret);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,7 +374,11 @@ int ecdh_build_k(ssh_session session)
|
|||||||
free(secret);
|
free(secret);
|
||||||
#endif /* OPENSSL_VERSION_NUMBER */
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
if (next_crypto->shared_secret == NULL) {
|
if (next_crypto->shared_secret == NULL) {
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
EC_KEY_free(next_crypto->ecdh_privkey);
|
EC_KEY_free(next_crypto->ecdh_privkey);
|
||||||
#else
|
#else
|
||||||
EVP_PKEY_free(next_crypto->ecdh_privkey);
|
EVP_PKEY_free(next_crypto->ecdh_privkey);
|
||||||
@@ -415,7 +386,11 @@ int ecdh_build_k(ssh_session session)
|
|||||||
next_crypto->ecdh_privkey = NULL;
|
next_crypto->ecdh_privkey = NULL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
EC_KEY_free(next_crypto->ecdh_privkey);
|
EC_KEY_free(next_crypto->ecdh_privkey);
|
||||||
#else
|
#else
|
||||||
EVP_PKEY_free(next_crypto->ecdh_privkey);
|
EVP_PKEY_free(next_crypto->ecdh_privkey);
|
||||||
@@ -438,12 +413,30 @@ int ecdh_build_k(ssh_session session)
|
|||||||
/** @brief Handle a SSH_MSG_KEXDH_INIT packet (server) and send a
|
/** @brief Handle a SSH_MSG_KEXDH_INIT packet (server) and send a
|
||||||
* SSH_MSG_KEXDH_REPLY
|
* SSH_MSG_KEXDH_REPLY
|
||||||
*/
|
*/
|
||||||
SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init)
|
SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||||
{
|
|
||||||
/* ECDH keys */
|
/* ECDH keys */
|
||||||
ssh_string q_c_string = NULL;
|
ssh_string q_c_string;
|
||||||
ssh_string q_s_string = NULL;
|
ssh_string q_s_string;
|
||||||
/* SSH host keys (rsa, ed25519 and ecdsa) */
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
EC_KEY *ecdh_key;
|
||||||
|
const EC_GROUP *group;
|
||||||
|
const EC_POINT *ecdh_pubkey;
|
||||||
|
bignum_CTX ctx;
|
||||||
|
int curve;
|
||||||
|
int len;
|
||||||
|
#else
|
||||||
|
EVP_PKEY *ecdh_key = NULL;
|
||||||
|
const void *pubkey_ptr = NULL;
|
||||||
|
size_t len;
|
||||||
|
OSSL_PARAM *params = NULL;
|
||||||
|
const OSSL_PARAM *pubkey = NULL;
|
||||||
|
const char *curve = NULL;
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
/* SSH host keys (rsa,dsa,ecdsa) */
|
||||||
ssh_key privkey;
|
ssh_key privkey;
|
||||||
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
|
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
|
||||||
ssh_string sig_blob = NULL;
|
ssh_string sig_blob = NULL;
|
||||||
@@ -452,22 +445,125 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init)
|
|||||||
(void)type;
|
(void)type;
|
||||||
(void)user;
|
(void)user;
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Processing SSH_MSG_KEXDH_INIT");
|
|
||||||
|
|
||||||
ssh_packet_remove_callbacks(session, &ssh_ecdh_server_callbacks);
|
ssh_packet_remove_callbacks(session, &ssh_ecdh_server_callbacks);
|
||||||
/* Extract the client pubkey from the init packet */
|
/* Extract the client pubkey from the init packet */
|
||||||
q_c_string = ssh_buffer_get_ssh_string(packet);
|
q_c_string = ssh_buffer_get_ssh_string(packet);
|
||||||
if (q_c_string == NULL) {
|
if (q_c_string == NULL) {
|
||||||
ssh_set_error(session, SSH_FATAL, "No Q_C ECC point in packet");
|
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
session->next_crypto->ecdh_client_pubkey = q_c_string;
|
session->next_crypto->ecdh_client_pubkey = q_c_string;
|
||||||
|
|
||||||
q_s_string = ssh_ecdh_generate(session);
|
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
|
||||||
if (q_s_string == NULL) {
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
if (curve == SSH_ERROR) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (curve == NULL) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
|
||||||
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
ecdh_key = EC_KEY_new_by_curve_name(curve);
|
||||||
|
#else
|
||||||
|
ecdh_key = EVP_EC_gen(curve);
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
if (ecdh_key == NULL) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
/* Build server's keypair */
|
||||||
|
ctx = BN_CTX_new();
|
||||||
|
if (ctx == NULL) {
|
||||||
|
EC_KEY_free(ecdh_key);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
group = EC_KEY_get0_group(ecdh_key);
|
||||||
|
EC_KEY_generate_key(ecdh_key);
|
||||||
|
|
||||||
|
ecdh_pubkey = EC_KEY_get0_public_key(ecdh_key);
|
||||||
|
len = EC_POINT_point2oct(group,
|
||||||
|
ecdh_pubkey,
|
||||||
|
POINT_CONVERSION_UNCOMPRESSED,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
ctx);
|
||||||
|
#else
|
||||||
|
rc = EVP_PKEY_todata(ecdh_key, EVP_PKEY_PUBLIC_KEY, ¶ms);
|
||||||
|
if (rc != 1) {
|
||||||
|
EVP_PKEY_free(ecdh_key);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
pubkey = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
|
||||||
|
if (pubkey == NULL) {
|
||||||
|
OSSL_PARAM_free(params);
|
||||||
|
EVP_PKEY_free(ecdh_key);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = OSSL_PARAM_get_octet_string_ptr(pubkey, &pubkey_ptr, &len);
|
||||||
|
if (rc != 1) {
|
||||||
|
OSSL_PARAM_free(params);
|
||||||
|
EVP_PKEY_free(ecdh_key);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
q_s_string = ssh_string_new(len);
|
||||||
|
if (q_s_string == NULL) {
|
||||||
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
EC_KEY_free(ecdh_key);
|
||||||
|
BN_CTX_free(ctx);
|
||||||
|
#else
|
||||||
|
EVP_PKEY_free(ecdh_key);
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO Change to new API when the OpenSSL will support export of uncompressed EC keys
|
||||||
|
* https://github.com/openssl/openssl/pull/16624
|
||||||
|
* #if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
EC_POINT_point2oct(group,
|
||||||
|
ecdh_pubkey,
|
||||||
|
POINT_CONVERSION_UNCOMPRESSED,
|
||||||
|
ssh_string_data(q_s_string),
|
||||||
|
len,
|
||||||
|
ctx);
|
||||||
|
BN_CTX_free(ctx);
|
||||||
|
#else
|
||||||
|
if (memcpy(ssh_string_data(q_s_string), pubkey_ptr, len)) {
|
||||||
|
OSSL_PARAM_free(params);
|
||||||
|
EVP_PKEY_free(ecdh_key);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSSL_PARAM_free(params);
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
|
||||||
|
session->next_crypto->ecdh_privkey = ecdh_key;
|
||||||
session->next_crypto->ecdh_server_pubkey = q_s_string;
|
session->next_crypto->ecdh_server_pubkey = q_s_string;
|
||||||
|
|
||||||
/* build k and session_id */
|
/* build k and session_id */
|
||||||
@@ -517,7 +613,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_KEXDH_REPLY sent");
|
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent");
|
||||||
rc = ssh_packet_send(session);
|
rc = ssh_packet_send(session);
|
||||||
if (rc == SSH_ERROR) {
|
if (rc == SSH_ERROR) {
|
||||||
goto error;
|
goto error;
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
|||||||
ssh_string q_s_string;
|
ssh_string q_s_string;
|
||||||
gcry_sexp_t param = NULL;
|
gcry_sexp_t param = NULL;
|
||||||
gcry_sexp_t key = NULL;
|
gcry_sexp_t key = NULL;
|
||||||
/* SSH host keys (rsa, ed25519 and ecdsa) */
|
/* SSH host keys (rsa,dsa,ecdsa) */
|
||||||
ssh_key privkey;
|
ssh_key privkey;
|
||||||
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
|
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
|
||||||
ssh_string sig_blob = NULL;
|
ssh_string sig_blob = NULL;
|
||||||
@@ -366,7 +366,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_KEXDH_REPLY sent");
|
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent");
|
||||||
rc = ssh_packet_send(session);
|
rc = ssh_packet_send(session);
|
||||||
if (rc != SSH_OK) {
|
if (rc != SSH_OK) {
|
||||||
goto out;
|
goto out;
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_KEXDH_REPLY sent");
|
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent");
|
||||||
rc = ssh_packet_send(session);
|
rc = ssh_packet_send(session);
|
||||||
if (rc != SSH_OK) {
|
if (rc != SSH_OK) {
|
||||||
rc = SSH_ERROR;
|
rc = SSH_ERROR;
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ void _ssh_set_error(void *error,
|
|||||||
va_end(va);
|
va_end(va);
|
||||||
|
|
||||||
err->error.error_code = code;
|
err->error.error_code = code;
|
||||||
if (ssh_get_log_level() == SSH_LOG_TRACE) {
|
if (ssh_get_log_level() >= SSH_LOG_WARN) {
|
||||||
ssh_log_function(SSH_LOG_TRACE,
|
ssh_log_function(SSH_LOG_WARN,
|
||||||
function,
|
function,
|
||||||
err->error.error_buffer);
|
err->error.error_buffer);
|
||||||
}
|
}
|
||||||
|
|||||||
7
src/external/blowfish.c
vendored
7
src/external/blowfish.c
vendored
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: blowfish.c,v 1.20 2021/11/29 01:04:45 djm Exp $ */
|
/* $OpenBSD: blowfish.c,v 1.18 2004/11/02 17:23:26 hshoexer Exp $ */
|
||||||
/*
|
/*
|
||||||
* Blowfish block cipher for OpenBSD
|
* Blowfish block cipher for OpenBSD
|
||||||
* Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
|
* Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
|
||||||
@@ -14,7 +14,10 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Niels Provos.
|
||||||
|
* 4. The name of the author may not be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ char *ssh_gcry_bn2dec(bignum bn) {
|
|||||||
size = gcry_mpi_get_nbits(bn) * 3;
|
size = gcry_mpi_get_nbits(bn) * 3;
|
||||||
rsize = size / 10 + size / 1000 + 2;
|
rsize = size / 10 + size / 1000 + 2;
|
||||||
|
|
||||||
ret = gcry_malloc(rsize + 1);
|
ret = malloc(rsize + 1);
|
||||||
if (ret == NULL) {
|
if (ret == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
231
src/gssapi.c
231
src/gssapi.c
@@ -38,19 +38,46 @@
|
|||||||
#include <libssh/string.h>
|
#include <libssh/string.h>
|
||||||
#include <libssh/server.h>
|
#include <libssh/server.h>
|
||||||
|
|
||||||
|
/** current state of an GSSAPI authentication */
|
||||||
|
enum ssh_gssapi_state_e {
|
||||||
|
SSH_GSSAPI_STATE_NONE, /* no status */
|
||||||
|
SSH_GSSAPI_STATE_RCV_TOKEN, /* Expecting a token */
|
||||||
|
SSH_GSSAPI_STATE_RCV_MIC, /* Expecting a MIC */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ssh_gssapi_struct{
|
||||||
|
enum ssh_gssapi_state_e state; /* current state */
|
||||||
|
struct gss_OID_desc_struct mech; /* mechanism being elected for auth */
|
||||||
|
gss_cred_id_t server_creds; /* credentials of server */
|
||||||
|
gss_cred_id_t client_creds; /* creds delegated by the client */
|
||||||
|
gss_ctx_id_t ctx; /* the authentication context */
|
||||||
|
gss_name_t client_name; /* Identity of the client */
|
||||||
|
char *user; /* username of client */
|
||||||
|
char *canonic_user; /* canonic form of the client's username */
|
||||||
|
char *service; /* name of the service */
|
||||||
|
struct {
|
||||||
|
gss_name_t server_name; /* identity of server */
|
||||||
|
OM_uint32 flags; /* flags used for init context */
|
||||||
|
gss_OID oid; /* mech being used for authentication */
|
||||||
|
gss_cred_id_t creds; /* creds used to initialize context */
|
||||||
|
gss_cred_id_t client_deleg_creds; /* delegated creds (const, not freeable) */
|
||||||
|
} client;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** @internal
|
/** @internal
|
||||||
* @initializes a gssapi context for authentication
|
* @initializes a gssapi context for authentication
|
||||||
*/
|
*/
|
||||||
int
|
static int ssh_gssapi_init(ssh_session session)
|
||||||
ssh_gssapi_init(ssh_session session)
|
|
||||||
{
|
{
|
||||||
if (session->gssapi != NULL)
|
if (session->gssapi != NULL)
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
session->gssapi = calloc(1, sizeof(struct ssh_gssapi_struct));
|
session->gssapi = malloc(sizeof(struct ssh_gssapi_struct));
|
||||||
if (session->gssapi == NULL) {
|
if(!session->gssapi){
|
||||||
ssh_set_error_oom(session);
|
ssh_set_error_oom(session);
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
ZERO_STRUCTP(session->gssapi);
|
||||||
session->gssapi->server_creds = GSS_C_NO_CREDENTIAL;
|
session->gssapi->server_creds = GSS_C_NO_CREDENTIAL;
|
||||||
session->gssapi->client_creds = GSS_C_NO_CREDENTIAL;
|
session->gssapi->client_creds = GSS_C_NO_CREDENTIAL;
|
||||||
session->gssapi->ctx = GSS_C_NO_CONTEXT;
|
session->gssapi->ctx = GSS_C_NO_CONTEXT;
|
||||||
@@ -58,60 +85,21 @@ ssh_gssapi_init(ssh_session session)
|
|||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ssh_gssapi_log_error(int verb, const char *msg_a, int maj_stat, int min_stat)
|
|
||||||
{
|
|
||||||
gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
|
|
||||||
OM_uint32 dummy_min;
|
|
||||||
OM_uint32 message_context = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
gss_display_status(&dummy_min,
|
|
||||||
maj_stat,
|
|
||||||
GSS_C_GSS_CODE,
|
|
||||||
GSS_C_NO_OID,
|
|
||||||
&message_context,
|
|
||||||
&msg);
|
|
||||||
SSH_LOG(verb, "GSSAPI(%s): %s", msg_a, (const char *)msg.value);
|
|
||||||
gss_release_buffer(&dummy_min, &msg);
|
|
||||||
|
|
||||||
} while (message_context != 0);
|
|
||||||
|
|
||||||
do {
|
|
||||||
gss_display_status(&dummy_min,
|
|
||||||
min_stat,
|
|
||||||
GSS_C_MECH_CODE,
|
|
||||||
GSS_C_NO_OID,
|
|
||||||
&message_context,
|
|
||||||
&msg);
|
|
||||||
SSH_LOG(verb, "GSSAPI(%s): %s", msg_a, (const char *)msg.value);
|
|
||||||
gss_release_buffer(&dummy_min, &msg);
|
|
||||||
|
|
||||||
} while (message_context != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @internal
|
/** @internal
|
||||||
* @frees a gssapi context
|
* @frees a gssapi context
|
||||||
*/
|
*/
|
||||||
void
|
static void ssh_gssapi_free(ssh_session session)
|
||||||
ssh_gssapi_free(ssh_session session)
|
|
||||||
{
|
{
|
||||||
OM_uint32 min;
|
OM_uint32 min;
|
||||||
if (session->gssapi == NULL)
|
if (session->gssapi == NULL)
|
||||||
return;
|
return;
|
||||||
SAFE_FREE(session->gssapi->user);
|
SAFE_FREE(session->gssapi->user);
|
||||||
|
SAFE_FREE(session->gssapi->mech.elements);
|
||||||
gss_release_name(&min, &session->gssapi->client.server_name);
|
|
||||||
gss_release_cred(&min,&session->gssapi->server_creds);
|
gss_release_cred(&min,&session->gssapi->server_creds);
|
||||||
if (session->gssapi->client.creds !=
|
if (session->gssapi->client.creds !=
|
||||||
session->gssapi->client.client_deleg_creds) {
|
session->gssapi->client.client_deleg_creds) {
|
||||||
gss_release_cred(&min, &session->gssapi->client.creds);
|
gss_release_cred(&min, &session->gssapi->client.creds);
|
||||||
}
|
}
|
||||||
gss_release_oid(&min, &session->gssapi->client.oid);
|
|
||||||
gss_delete_sec_context(&min, &session->gssapi->ctx, GSS_C_NO_BUFFER);
|
|
||||||
|
|
||||||
SAFE_FREE(session->gssapi->mech.elements);
|
|
||||||
SAFE_FREE(session->gssapi->canonic_user);
|
|
||||||
SAFE_FREE(session->gssapi);
|
SAFE_FREE(session->gssapi);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,6 +133,55 @@ static int ssh_gssapi_send_response(ssh_session session, ssh_string oid)
|
|||||||
|
|
||||||
#endif /* WITH_SERVER */
|
#endif /* WITH_SERVER */
|
||||||
|
|
||||||
|
static void ssh_gssapi_log_error(int verb,
|
||||||
|
const char *msg,
|
||||||
|
int maj_stat,
|
||||||
|
int min_stat)
|
||||||
|
{
|
||||||
|
gss_buffer_desc msg_maj = {
|
||||||
|
.length = 0,
|
||||||
|
};
|
||||||
|
gss_buffer_desc msg_min = {
|
||||||
|
.length = 0,
|
||||||
|
};
|
||||||
|
OM_uint32 dummy_maj, dummy_min;
|
||||||
|
OM_uint32 message_context = 0;
|
||||||
|
|
||||||
|
dummy_maj = gss_display_status(&dummy_min,
|
||||||
|
maj_stat,
|
||||||
|
GSS_C_GSS_CODE,
|
||||||
|
GSS_C_NO_OID,
|
||||||
|
&message_context,
|
||||||
|
&msg_maj);
|
||||||
|
if (dummy_maj != 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
dummy_maj = gss_display_status(&dummy_min,
|
||||||
|
min_stat,
|
||||||
|
GSS_C_MECH_CODE,
|
||||||
|
GSS_C_NO_OID,
|
||||||
|
&message_context,
|
||||||
|
&msg_min);
|
||||||
|
if (dummy_maj != 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
SSH_LOG(verb,
|
||||||
|
"GSSAPI(%s): %s - %s",
|
||||||
|
msg,
|
||||||
|
(const char *)msg_maj.value,
|
||||||
|
(const char *)msg_min.value);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (msg_maj.value) {
|
||||||
|
gss_release_buffer(&dummy_min, &msg_maj);
|
||||||
|
}
|
||||||
|
if (msg_min.value) {
|
||||||
|
gss_release_buffer(&dummy_min, &msg_min);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WITH_SERVER
|
#ifdef WITH_SERVER
|
||||||
|
|
||||||
/** @internal
|
/** @internal
|
||||||
@@ -168,39 +205,27 @@ ssh_gssapi_handle_userauth(ssh_session session, const char *user,
|
|||||||
struct gss_OID_desc_struct oid;
|
struct gss_OID_desc_struct oid;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Destroy earlier GSSAPI context if any */
|
if (ssh_callbacks_exists(session->server_callbacks, gssapi_select_oid_function)){
|
||||||
ssh_gssapi_free(session);
|
ssh_string oid_s = session->server_callbacks->gssapi_select_oid_function(session,
|
||||||
rc = ssh_gssapi_init(session);
|
user, n_oid, oids,
|
||||||
if (rc == SSH_ERROR)
|
session->server_callbacks->userdata);
|
||||||
return rc;
|
if (oid_s != NULL){
|
||||||
|
if (ssh_gssapi_init(session) == SSH_ERROR)
|
||||||
/* Callback should select oid and acquire credential */
|
return SSH_ERROR;
|
||||||
if (ssh_callbacks_exists(session->server_callbacks,
|
session->gssapi->state = SSH_GSSAPI_STATE_RCV_TOKEN;
|
||||||
gssapi_select_oid_function)) {
|
|
||||||
ssh_string oid_s = NULL;
|
|
||||||
session->gssapi->state = SSH_GSSAPI_STATE_RCV_TOKEN;
|
|
||||||
SAFE_FREE(session->gssapi->user);
|
|
||||||
session->gssapi->user = strdup(user);
|
|
||||||
oid_s = session->server_callbacks->gssapi_select_oid_function(
|
|
||||||
session,
|
|
||||||
user,
|
|
||||||
n_oid,
|
|
||||||
oids,
|
|
||||||
session->server_callbacks->userdata);
|
|
||||||
if (oid_s != NULL) {
|
|
||||||
rc = ssh_gssapi_send_response(session, oid_s);
|
rc = ssh_gssapi_send_response(session, oid_s);
|
||||||
|
SSH_STRING_FREE(oid_s);
|
||||||
return rc;
|
return rc;
|
||||||
} else {
|
} else {
|
||||||
return ssh_auth_reply_default(session, 0);
|
return ssh_auth_reply_default(session,0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Default implementation for selecting oid and acquiring credential */
|
|
||||||
gss_create_empty_oid_set(&min_stat, &both_supported);
|
gss_create_empty_oid_set(&min_stat, &both_supported);
|
||||||
|
|
||||||
maj_stat = gss_indicate_mechs(&min_stat, &supported);
|
maj_stat = gss_indicate_mechs(&min_stat, &supported);
|
||||||
if (maj_stat != GSS_S_COMPLETE) {
|
if (maj_stat != GSS_S_COMPLETE) {
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "indicate mechs %d, %d", maj_stat, min_stat);
|
SSH_LOG(SSH_LOG_WARNING, "indicate mecks %d, %d", maj_stat, min_stat);
|
||||||
ssh_gssapi_log_error(SSH_LOG_DEBUG,
|
ssh_gssapi_log_error(SSH_LOG_WARNING,
|
||||||
"indicate mechs",
|
"indicate mechs",
|
||||||
maj_stat,
|
maj_stat,
|
||||||
min_stat);
|
min_stat);
|
||||||
@@ -222,7 +247,7 @@ ssh_gssapi_handle_userauth(ssh_session session, const char *user,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){
|
if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){
|
||||||
SSH_LOG(SSH_LOG_TRACE,"GSSAPI: received invalid OID");
|
SSH_LOG(SSH_LOG_WARNING,"GSSAPI: received invalid OID");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
oid.elements = &oid_s[2];
|
oid.elements = &oid_s[2];
|
||||||
@@ -235,19 +260,24 @@ ssh_gssapi_handle_userauth(ssh_session session, const char *user,
|
|||||||
}
|
}
|
||||||
gss_release_oid_set(&min_stat, &supported);
|
gss_release_oid_set(&min_stat, &supported);
|
||||||
if (oid_count == 0){
|
if (oid_count == 0){
|
||||||
SSH_LOG(SSH_LOG_DEBUG,"GSSAPI: no OID match");
|
SSH_LOG(SSH_LOG_PROTOCOL,"GSSAPI: no OID match");
|
||||||
ssh_auth_reply_default(session, 0);
|
ssh_auth_reply_default(session, 0);
|
||||||
gss_release_oid_set(&min_stat, &both_supported);
|
gss_release_oid_set(&min_stat, &both_supported);
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
/* from now we have room for context */
|
||||||
|
if (ssh_gssapi_init(session) == SSH_ERROR) {
|
||||||
|
gss_release_oid_set(&min_stat, &both_supported);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
name_buf.value = service_name;
|
name_buf.value = service_name;
|
||||||
name_buf.length = strlen(name_buf.value) + 1;
|
name_buf.length = strlen(name_buf.value) + 1;
|
||||||
maj_stat = gss_import_name(&min_stat, &name_buf,
|
maj_stat = gss_import_name(&min_stat, &name_buf,
|
||||||
(gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &server_name);
|
(gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &server_name);
|
||||||
if (maj_stat != GSS_S_COMPLETE) {
|
if (maj_stat != GSS_S_COMPLETE) {
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "importing name %d, %d", maj_stat, min_stat);
|
SSH_LOG(SSH_LOG_WARNING, "importing name %d, %d", maj_stat, min_stat);
|
||||||
ssh_gssapi_log_error(SSH_LOG_DEBUG,
|
ssh_gssapi_log_error(SSH_LOG_WARNING,
|
||||||
"importing name",
|
"importing name",
|
||||||
maj_stat,
|
maj_stat,
|
||||||
min_stat);
|
min_stat);
|
||||||
@@ -262,8 +292,8 @@ ssh_gssapi_handle_userauth(ssh_session session, const char *user,
|
|||||||
gss_release_oid_set(&min_stat, &both_supported);
|
gss_release_oid_set(&min_stat, &both_supported);
|
||||||
|
|
||||||
if (maj_stat != GSS_S_COMPLETE) {
|
if (maj_stat != GSS_S_COMPLETE) {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "error acquiring credentials %d, %d", maj_stat, min_stat);
|
SSH_LOG(SSH_LOG_WARNING, "error acquiring credentials %d, %d", maj_stat, min_stat);
|
||||||
ssh_gssapi_log_error(SSH_LOG_TRACE,
|
ssh_gssapi_log_error(SSH_LOG_WARNING,
|
||||||
"acquiring creds",
|
"acquiring creds",
|
||||||
maj_stat,
|
maj_stat,
|
||||||
min_stat);
|
min_stat);
|
||||||
@@ -271,7 +301,7 @@ ssh_gssapi_handle_userauth(ssh_session session, const char *user,
|
|||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "acquiring credentials %d, %d", maj_stat, min_stat);
|
SSH_LOG(SSH_LOG_PROTOCOL, "acquiring credentials %d, %d", maj_stat, min_stat);
|
||||||
|
|
||||||
/* finding which OID from client we selected */
|
/* finding which OID from client we selected */
|
||||||
for (i=0 ; i< n_oid ; ++i){
|
for (i=0 ; i< n_oid ; ++i){
|
||||||
@@ -282,7 +312,7 @@ ssh_gssapi_handle_userauth(ssh_session session, const char *user,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){
|
if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){
|
||||||
SSH_LOG(SSH_LOG_TRACE,"GSSAPI: received invalid OID");
|
SSH_LOG(SSH_LOG_WARNING,"GSSAPI: received invalid OID");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
oid.elements = &oid_s[2];
|
oid.elements = &oid_s[2];
|
||||||
@@ -297,7 +327,6 @@ ssh_gssapi_handle_userauth(ssh_session session, const char *user,
|
|||||||
session->gssapi->mech.elements = malloc(oid.length);
|
session->gssapi->mech.elements = malloc(oid.length);
|
||||||
if (session->gssapi->mech.elements == NULL){
|
if (session->gssapi->mech.elements == NULL){
|
||||||
ssh_set_error_oom(session);
|
ssh_set_error_oom(session);
|
||||||
gss_release_oid_set(&min_stat, &selected);
|
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
memcpy(session->gssapi->mech.elements, oid.elements, oid.length);
|
memcpy(session->gssapi->mech.elements, oid.elements, oid.length);
|
||||||
@@ -308,14 +337,13 @@ ssh_gssapi_handle_userauth(ssh_session session, const char *user,
|
|||||||
return ssh_gssapi_send_response(session, oids[i]);
|
return ssh_gssapi_send_response(session, oids[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
static char *ssh_gssapi_name_to_char(gss_name_t name)
|
||||||
ssh_gssapi_name_to_char(gss_name_t name)
|
|
||||||
{
|
{
|
||||||
gss_buffer_desc buffer;
|
gss_buffer_desc buffer;
|
||||||
OM_uint32 maj_stat, min_stat;
|
OM_uint32 maj_stat, min_stat;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
maj_stat = gss_display_name(&min_stat, name, &buffer, NULL);
|
maj_stat = gss_display_name(&min_stat, name, &buffer, NULL);
|
||||||
ssh_gssapi_log_error(SSH_LOG_DEBUG,
|
ssh_gssapi_log_error(SSH_LOG_WARNING,
|
||||||
"converting name",
|
"converting name",
|
||||||
maj_stat,
|
maj_stat,
|
||||||
min_stat);
|
min_stat);
|
||||||
@@ -362,6 +390,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){
|
|||||||
token, &out_token, session->server_callbacks->userdata);
|
token, &out_token, session->server_callbacks->userdata);
|
||||||
if (rc == SSH_ERROR){
|
if (rc == SSH_ERROR){
|
||||||
ssh_auth_reply_default(session, 0);
|
ssh_auth_reply_default(session, 0);
|
||||||
|
ssh_gssapi_free(session);
|
||||||
|
session->gssapi=NULL;
|
||||||
return SSH_PACKET_USED;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
if (ssh_string_len(out_token) != 0){
|
if (ssh_string_len(out_token) != 0){
|
||||||
@@ -375,8 +405,9 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){
|
|||||||
}
|
}
|
||||||
ssh_packet_send(session);
|
ssh_packet_send(session);
|
||||||
SSH_STRING_FREE(out_token);
|
SSH_STRING_FREE(out_token);
|
||||||
|
} else {
|
||||||
|
session->gssapi->state = SSH_GSSAPI_STATE_RCV_MIC;
|
||||||
}
|
}
|
||||||
session->gssapi->state = SSH_GSSAPI_STATE_RCV_MIC;
|
|
||||||
return SSH_PACKET_USED;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
hexa = ssh_get_hexa(ssh_string_data(token),ssh_string_len(token));
|
hexa = ssh_get_hexa(ssh_string_data(token),ssh_string_len(token));
|
||||||
@@ -388,7 +419,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){
|
|||||||
maj_stat = gss_accept_sec_context(&min_stat, &session->gssapi->ctx, session->gssapi->server_creds,
|
maj_stat = gss_accept_sec_context(&min_stat, &session->gssapi->ctx, session->gssapi->server_creds,
|
||||||
&input_token, input_bindings, &client_name, NULL /*mech_oid*/, &output_token, &ret_flags,
|
&input_token, input_bindings, &client_name, NULL /*mech_oid*/, &output_token, &ret_flags,
|
||||||
NULL /*time*/, &session->gssapi->client_creds);
|
NULL /*time*/, &session->gssapi->client_creds);
|
||||||
ssh_gssapi_log_error(SSH_LOG_DEBUG,
|
ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
|
||||||
"accepting token",
|
"accepting token",
|
||||||
maj_stat,
|
maj_stat,
|
||||||
min_stat);
|
min_stat);
|
||||||
@@ -398,12 +429,14 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){
|
|||||||
session->gssapi->canonic_user = ssh_gssapi_name_to_char(client_name);
|
session->gssapi->canonic_user = ssh_gssapi_name_to_char(client_name);
|
||||||
}
|
}
|
||||||
if (GSS_ERROR(maj_stat)){
|
if (GSS_ERROR(maj_stat)){
|
||||||
ssh_gssapi_log_error(SSH_LOG_DEBUG,
|
ssh_gssapi_log_error(SSH_LOG_WARNING,
|
||||||
"Gssapi error",
|
"Gssapi error",
|
||||||
maj_stat,
|
maj_stat,
|
||||||
min_stat);
|
min_stat);
|
||||||
gss_release_buffer(&min_stat, &output_token);
|
gss_release_buffer(&min_stat, &output_token);
|
||||||
ssh_auth_reply_default(session,0);
|
ssh_auth_reply_default(session,0);
|
||||||
|
ssh_gssapi_free(session);
|
||||||
|
session->gssapi=NULL;
|
||||||
return SSH_PACKET_USED;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,13 +452,14 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){
|
|||||||
if (rc != SSH_OK) {
|
if (rc != SSH_OK) {
|
||||||
ssh_set_error_oom(session);
|
ssh_set_error_oom(session);
|
||||||
ssh_auth_reply_default(session, 0);
|
ssh_auth_reply_default(session, 0);
|
||||||
|
ssh_gssapi_free(session);
|
||||||
|
session->gssapi = NULL;
|
||||||
return SSH_PACKET_USED;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
ssh_packet_send(session);
|
ssh_packet_send(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
gss_release_buffer(&min_stat, &output_token);
|
gss_release_buffer(&min_stat, &output_token);
|
||||||
gss_release_name(&min_stat, &client_name);
|
|
||||||
|
|
||||||
if(maj_stat == GSS_S_COMPLETE){
|
if(maj_stat == GSS_S_COMPLETE){
|
||||||
session->gssapi->state = SSH_GSSAPI_STATE_RCV_MIC;
|
session->gssapi->state = SSH_GSSAPI_STATE_RCV_MIC;
|
||||||
@@ -513,7 +547,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_mic)
|
|||||||
mic_token_buf.value = ssh_string_data(mic_token);
|
mic_token_buf.value = ssh_string_data(mic_token);
|
||||||
|
|
||||||
maj_stat = gss_verify_mic(&min_stat, session->gssapi->ctx, &mic_buf, &mic_token_buf, NULL);
|
maj_stat = gss_verify_mic(&min_stat, session->gssapi->ctx, &mic_buf, &mic_token_buf, NULL);
|
||||||
ssh_gssapi_log_error(SSH_LOG_DEBUG,
|
ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
|
||||||
"verifying MIC",
|
"verifying MIC",
|
||||||
maj_stat,
|
maj_stat,
|
||||||
min_stat);
|
min_stat);
|
||||||
@@ -544,6 +578,7 @@ error:
|
|||||||
ssh_auth_reply_default(session,0);
|
ssh_auth_reply_default(session,0);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
ssh_gssapi_free(session);
|
||||||
if (mic_buffer != NULL) {
|
if (mic_buffer != NULL) {
|
||||||
SSH_BUFFER_FREE(mic_buffer);
|
SSH_BUFFER_FREE(mic_buffer);
|
||||||
}
|
}
|
||||||
@@ -656,10 +691,6 @@ static int ssh_gssapi_match(ssh_session session, gss_OID_set *valid_oids)
|
|||||||
&session->gssapi->client.creds,
|
&session->gssapi->client.creds,
|
||||||
&actual_mechs, NULL);
|
&actual_mechs, NULL);
|
||||||
if (GSS_ERROR(maj_stat)) {
|
if (GSS_ERROR(maj_stat)) {
|
||||||
ssh_gssapi_log_error(SSH_LOG_WARN,
|
|
||||||
"acquiring credential",
|
|
||||||
maj_stat,
|
|
||||||
min_stat);
|
|
||||||
ret = SSH_ERROR;
|
ret = SSH_ERROR;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@@ -720,8 +751,6 @@ int ssh_gssapi_auth_mic(ssh_session session)
|
|||||||
gss_buffer_desc hostname;
|
gss_buffer_desc hostname;
|
||||||
const char *gss_host = session->opts.host;
|
const char *gss_host = session->opts.host;
|
||||||
|
|
||||||
/* Destroy earlier GSSAPI context if any */
|
|
||||||
ssh_gssapi_free(session);
|
|
||||||
rc = ssh_gssapi_init(session);
|
rc = ssh_gssapi_init(session);
|
||||||
if (rc == SSH_ERROR) {
|
if (rc == SSH_ERROR) {
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
@@ -739,8 +768,8 @@ int ssh_gssapi_auth_mic(ssh_session session)
|
|||||||
(gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
|
(gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
|
||||||
&session->gssapi->client.server_name);
|
&session->gssapi->client.server_name);
|
||||||
if (maj_stat != GSS_S_COMPLETE) {
|
if (maj_stat != GSS_S_COMPLETE) {
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "importing name %d, %d", maj_stat, min_stat);
|
SSH_LOG(SSH_LOG_WARNING, "importing name %d, %d", maj_stat, min_stat);
|
||||||
ssh_gssapi_log_error(SSH_LOG_DEBUG,
|
ssh_gssapi_log_error(SSH_LOG_WARNING,
|
||||||
"importing name",
|
"importing name",
|
||||||
maj_stat,
|
maj_stat,
|
||||||
min_stat);
|
min_stat);
|
||||||
@@ -754,7 +783,7 @@ int ssh_gssapi_auth_mic(ssh_session session)
|
|||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "Authenticating with gssapi to host %s with user %s",
|
SSH_LOG(SSH_LOG_PROTOCOL, "Authenticating with gssapi to host %s with user %s",
|
||||||
session->opts.host, session->gssapi->user);
|
session->opts.host, session->gssapi->user);
|
||||||
rc = ssh_gssapi_match(session, &selected);
|
rc = ssh_gssapi_match(session, &selected);
|
||||||
if (rc == SSH_ERROR) {
|
if (rc == SSH_ERROR) {
|
||||||
@@ -762,7 +791,7 @@ int ssh_gssapi_auth_mic(ssh_session session)
|
|||||||
}
|
}
|
||||||
|
|
||||||
n_oids = selected->count;
|
n_oids = selected->count;
|
||||||
SSH_LOG(SSH_LOG_DEBUG, "Sending %zu oids", n_oids);
|
SSH_LOG(SSH_LOG_PROTOCOL, "Sending %zu oids", n_oids);
|
||||||
|
|
||||||
oids = calloc(n_oids, sizeof(ssh_string));
|
oids = calloc(n_oids, sizeof(ssh_string));
|
||||||
if (oids == NULL) {
|
if (oids == NULL) {
|
||||||
@@ -878,7 +907,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){
|
|||||||
0, NULL, &input_token, NULL,
|
0, NULL, &input_token, NULL,
|
||||||
&output_token, NULL, NULL);
|
&output_token, NULL, NULL);
|
||||||
if(GSS_ERROR(maj_stat)){
|
if(GSS_ERROR(maj_stat)){
|
||||||
ssh_gssapi_log_error(SSH_LOG_DEBUG,
|
ssh_gssapi_log_error(SSH_LOG_WARNING,
|
||||||
"Initializing gssapi context",
|
"Initializing gssapi context",
|
||||||
maj_stat,
|
maj_stat,
|
||||||
min_stat);
|
min_stat);
|
||||||
@@ -906,6 +935,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){
|
|||||||
|
|
||||||
error:
|
error:
|
||||||
session->auth.state = SSH_AUTH_STATE_ERROR;
|
session->auth.state = SSH_AUTH_STATE_ERROR;
|
||||||
|
ssh_gssapi_free(session);
|
||||||
|
session->gssapi = NULL;
|
||||||
return SSH_PACKET_USED;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -993,13 +1024,13 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
|
|||||||
0, NULL, &input_token, NULL,
|
0, NULL, &input_token, NULL,
|
||||||
&output_token, NULL, NULL);
|
&output_token, NULL, NULL);
|
||||||
|
|
||||||
ssh_gssapi_log_error(SSH_LOG_DEBUG,
|
ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
|
||||||
"accepting token",
|
"accepting token",
|
||||||
maj_stat,
|
maj_stat,
|
||||||
min_stat);
|
min_stat);
|
||||||
SSH_STRING_FREE(token);
|
SSH_STRING_FREE(token);
|
||||||
if (GSS_ERROR(maj_stat)){
|
if (GSS_ERROR(maj_stat)){
|
||||||
ssh_gssapi_log_error(SSH_LOG_DEBUG,
|
ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
|
||||||
"Gssapi error",
|
"Gssapi error",
|
||||||
maj_stat,
|
maj_stat,
|
||||||
min_stat);
|
min_stat);
|
||||||
@@ -1033,5 +1064,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
|
|||||||
|
|
||||||
error:
|
error:
|
||||||
session->auth.state = SSH_AUTH_STATE_ERROR;
|
session->auth.state = SSH_AUTH_STATE_ERROR;
|
||||||
|
ssh_gssapi_free(session);
|
||||||
|
session->gssapi = NULL;
|
||||||
return SSH_PACKET_USED;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user