mirror of
https://github.com/clearml/dropbear
synced 2025-06-26 18:17:32 +00:00
Compare commits
264 Commits
DROPBEAR_2
...
DROPBEAR_2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e4e562cfb | ||
|
|
92ec446cb9 | ||
|
|
9097da0284 | ||
|
|
eedeb009ec | ||
|
|
d8bc6abcf0 | ||
|
|
2293e3d105 | ||
|
|
550b3056fd | ||
|
|
1ba5e8052e | ||
|
|
6f5abeff2e | ||
|
|
7cbf6b131b | ||
|
|
a461298109 | ||
|
|
90c3a74b2a | ||
|
|
87373be960 | ||
|
|
85d9672e47 | ||
|
|
e0ae527190 | ||
|
|
7fb1bec84a | ||
|
|
1f308fb2b4 | ||
|
|
e2d36d493f | ||
|
|
7c43594075 | ||
|
|
e4827025be | ||
|
|
00798ca8cc | ||
|
|
e84cb3c3c2 | ||
|
|
78b9cecb52 | ||
|
|
93c54fe6f6 | ||
|
|
5f97d0fbbc | ||
|
|
dc01a8edd4 | ||
|
|
23cc2bfb8c | ||
|
|
9e379835c4 | ||
|
|
8ccbd216c6 | ||
|
|
90f4da29d7 | ||
|
|
54dbd5bbc8 | ||
|
|
849b8ec469 | ||
|
|
84e18f72ae | ||
|
|
633b98ef28 | ||
|
|
2a34a72bff | ||
|
|
24bae46e42 | ||
|
|
7585d4606e | ||
|
|
94bff1df66 | ||
|
|
2e60d20a76 | ||
|
|
ce59260ee9 | ||
|
|
387ebccf36 | ||
|
|
2f618af086 | ||
|
|
0ac33d22f7 | ||
|
|
c7bd5ac77d | ||
|
|
941c067765 | ||
|
|
839e023ed8 | ||
|
|
2e05a2b8c4 | ||
|
|
fc2c67e61c | ||
|
|
9c3e9fcdad | ||
|
|
1a4db21fe4 | ||
|
|
d96a52541f | ||
|
|
e7ac4c1ab3 | ||
|
|
ecd8505218 | ||
|
|
1fa1c3f9db | ||
|
|
91df741926 | ||
|
|
2a431cab03 | ||
|
|
9fdab3ced8 | ||
|
|
6e15e75391 | ||
|
|
1c2a1838fc | ||
|
|
bfd730aa4c | ||
|
|
e3c6a86b1e | ||
|
|
bbaeb917ff | ||
|
|
20f1e49b73 | ||
|
|
292656d899 | ||
|
|
05b36b484e | ||
|
|
be3016b8d5 | ||
|
|
5cf43d76bf | ||
|
|
6f05e810d9 | ||
|
|
947d2697cf | ||
|
|
449ddae628 | ||
|
|
6b90885d4f | ||
|
|
bd6c37adb6 | ||
|
|
59235276ac | ||
|
|
e5ce3fc51b | ||
|
|
9f97511356 | ||
|
|
ef0aac432c | ||
|
|
7928d83b02 | ||
|
|
3e91ec07e4 | ||
|
|
d680a9e3fb | ||
|
|
6086851fc1 | ||
|
|
61726df20c | ||
|
|
1601a657d4 | ||
|
|
50b14f696c | ||
|
|
c239baf801 | ||
|
|
18638859e6 | ||
|
|
224b16b247 | ||
|
|
d9d97969a3 | ||
|
|
897da4ee36 | ||
|
|
90f9f43335 | ||
|
|
0e1dee828a | ||
|
|
cbdc1f0753 | ||
|
|
7e306336d0 | ||
|
|
e7def4c211 | ||
|
|
19e1afbd1c | ||
|
|
fee32054e6 | ||
|
|
9754fdd995 | ||
|
|
ef20b9ff7a | ||
|
|
275611fbaa | ||
|
|
a070159cc5 | ||
|
|
20f9683ae0 | ||
|
|
dce384668b | ||
|
|
fdcd21e74b | ||
|
|
67b4fa313e | ||
|
|
5dff74109e | ||
|
|
20d970a0e2 | ||
|
|
94734ad377 | ||
|
|
14ad6a5972 | ||
|
|
9e66b5a9b1 | ||
|
|
f782cf375a | ||
|
|
3317916111 | ||
|
|
f367273549 | ||
|
|
91ef9b2fa9 | ||
|
|
579463933b | ||
|
|
989c5c1436 | ||
|
|
3113932151 | ||
|
|
125a970d71 | ||
|
|
89c0b2a6d8 | ||
|
|
31e379c300 | ||
|
|
843953379c | ||
|
|
2a90c1ca7e | ||
|
|
59bb1777be | ||
|
|
c5f3c550a6 | ||
|
|
1809f741cb | ||
|
|
9adfff5c1a | ||
|
|
8008b595d3 | ||
|
|
21bed0d21a | ||
|
|
4b1f5ec7c2 | ||
|
|
ab9439519a | ||
|
|
abeb9d64a3 | ||
|
|
fdb7ffa864 | ||
|
|
46845fd3e8 | ||
|
|
c53ca6ebc0 | ||
|
|
f04a3a2cfa | ||
|
|
364a53577e | ||
|
|
1b1997bf2d | ||
|
|
34f9adb1c9 | ||
|
|
2e7d468b90 | ||
|
|
86a717c80c | ||
|
|
76a3eb393c | ||
|
|
5f0cc969a0 | ||
|
|
755c1458f0 | ||
|
|
8795d733ec | ||
|
|
28f61c8b3a | ||
|
|
9abcc7b909 | ||
|
|
2c35f1c8fd | ||
|
|
136188259e | ||
|
|
02179b1218 | ||
|
|
1e350de136 | ||
|
|
9aeda4c5bd | ||
|
|
8eb30c353a | ||
|
|
c44a78a2e6 | ||
|
|
b6685bf806 | ||
|
|
269d690e71 | ||
|
|
4df268f10e | ||
|
|
19b3f01477 | ||
|
|
86811f4765 | ||
|
|
dd0352d93b | ||
|
|
30ec18d938 | ||
|
|
9d495ab2b5 | ||
|
|
9174de47a9 | ||
|
|
d857faf18e | ||
|
|
d5c8ba1690 | ||
|
|
9bb9b4829d | ||
|
|
e25c297c3c | ||
|
|
4de876f259 | ||
|
|
b9073961f7 | ||
|
|
a7a79d569a | ||
|
|
6165f53fcd | ||
|
|
4122cac66b | ||
|
|
a1dcebe4f4 | ||
|
|
6cbb23a819 | ||
|
|
5c57a31184 | ||
|
|
7b2c42aa75 | ||
|
|
1ed8d3938e | ||
|
|
b24984deb3 | ||
|
|
eabd9f5e60 | ||
|
|
d4609682af | ||
|
|
634415f79e | ||
|
|
4ba830fc31 | ||
|
|
3022a46039 | ||
|
|
d9a868ff60 | ||
|
|
c890a0c133 | ||
|
|
9ec934a94a | ||
|
|
5e606a964b | ||
|
|
d88034434c | ||
|
|
776d908703 | ||
|
|
444b15889f | ||
|
|
957450582f | ||
|
|
6d2d3669f3 | ||
|
|
1387654cc8 | ||
|
|
10eb218fb0 | ||
|
|
bfb2b30de6 | ||
|
|
426d4d72c6 | ||
|
|
cce29ba38c | ||
|
|
ed2e276b3a | ||
|
|
12a020aa62 | ||
|
|
b969101b33 | ||
|
|
86a742f635 | ||
|
|
9468f7f6d6 | ||
|
|
628a3f5cca | ||
|
|
e815e97440 | ||
|
|
0e7409c7ff | ||
|
|
393ca2a290 | ||
|
|
ad1d48e07b | ||
|
|
ac98aae160 | ||
|
|
c1267398a2 | ||
|
|
8c3a2bb63e | ||
|
|
923fc9087c | ||
|
|
83511fecc0 | ||
|
|
ed0552f214 | ||
|
|
5cf83a7212 | ||
|
|
7808eff0a9 | ||
|
|
da57dd13c5 | ||
|
|
f1826ea389 | ||
|
|
c884e5000e | ||
|
|
1ccac01cee | ||
|
|
50a5d3756f | ||
|
|
ca86726f9f | ||
|
|
6b5317e7cc | ||
|
|
2a1d28ea3a | ||
|
|
0e0ff51582 | ||
|
|
cd700aaf6e | ||
|
|
188ec1e258 | ||
|
|
d01fb265d6 | ||
|
|
db688e3ec1 | ||
|
|
e767bbb41f | ||
|
|
2b599df57a | ||
|
|
5baa10a6b6 | ||
|
|
3e1a389629 | ||
|
|
37e6207396 | ||
|
|
927a2dc849 | ||
|
|
ce9f9594da | ||
|
|
f0bf37b6cb | ||
|
|
2f0b35a105 | ||
|
|
7a9ed81f5f | ||
|
|
12e7d570a2 | ||
|
|
bb7934bf04 | ||
|
|
fb3c718963 | ||
|
|
231fc607f9 | ||
|
|
9594a3aa45 | ||
|
|
162fcab347 | ||
|
|
0c8bdfd7cd | ||
|
|
5e4dc71907 | ||
|
|
3e4433f715 | ||
|
|
29062e629f | ||
|
|
47f7272ba1 | ||
|
|
bf6f3f613d | ||
|
|
0c9a643216 | ||
|
|
fa2d843403 | ||
|
|
1dc5312f00 | ||
|
|
73444f2957 | ||
|
|
a18a6b8db8 | ||
|
|
bf56591fb8 | ||
|
|
5ea428a30d | ||
|
|
af524c4d65 | ||
|
|
2bc9f35052 | ||
|
|
55a0c5068f | ||
|
|
8128b15e41 | ||
|
|
8081b0e033 | ||
|
|
61cecbb337 | ||
|
|
aee1309c91 | ||
|
|
710c1df413 | ||
|
|
0f165a95a8 | ||
|
|
581f04c80b |
8
.hgsigs
8
.hgsigs
@@ -8,3 +8,11 @@ deb211f75ca194e2fcf0d2e5f71c60474e42ec95 0 iEYEABECAAYFAlJO01cACgkQjPn4sExkf7yDq
|
||||
025237c9f0a1a60a616f984d82fb2a9270d3b0ea 0 iEYEABECAAYFAlJeqDYACgkQjPn4sExkf7y5nQCfW6t+TJySBTTo+gCfDUBPRVxvNe8AoIn/15aWfqH/A2G9uikfoVtWK3pd
|
||||
a50a1dc743317fad9b3737bc68fbca640659bb6d 0 iEYEABECAAYFAlJeqL0ACgkQjPn4sExkf7yVqACg6IP0fU29+Feh/TDeemDA+2XAzrIAoIdZfMDvVYlDoWotZD8ACFnf5H1P
|
||||
9ec083a21adfcb099f21eb03704b66d14a4ba800 0 iEYEABECAAYFAlKE4JoACgkQjPn4sExkf7wLDgCghkVGwMjI138bEv+ORVzN7zIH7cEAoLckaxZc1k1aXlmlSCRlP8cuKH3o
|
||||
3d1d7d151c0ce3a79da62e86463f5632fa2b144a 0 iEYEABECAAYFAlKd5AEACgkQjPn4sExkf7wzWgCfdvPEEIdlMPqcbOQMJ7b+eAyy164An2ip1lPh1eS5g26/gSfruvWBVym4
|
||||
277429102f1337bd10c89107d3e01de509cc1a7e 0 iEYEABECAAYFAlMEvF4ACgkQjPn4sExkf7xeVQCgtbxJ4G3hsFwUOM0K1WGr1J2vsbEAoMM8dEyr1mdrbgO1tzNLfD1nxbyn
|
||||
96584b934d04ebab443f603e78d38fe692d36313 0 iEYEABECAAYFAlPVFrQACgkQjPn4sExkf7xr6ACglRiLE21vRrS1rJ809o2yMADIKtwAn1f5SyZUngSde8eE55JxCMwtMC5m
|
||||
caac692b366c153cea0e9cd59aa2d79a7d843d4e 0 iEYEABECAAYFAlPk1mcACgkQjPn4sExkf7wLpgCeOqMYqpkf4lYUuyrn9VYThNpc7PkAn3JOSNgIqkKUcmSy6FstrI8jwJzq
|
||||
2d421bc0545d1be6d59a4ebfe61606d94b124b0c 0 iEYEABECAAYFAlRJDCQACgkQjPn4sExkf7xUYACcCwVJkYWXJn5x/D5A+qMupy778lEAn0rg1oNiq96YU/4jOPsS5IMItihu
|
||||
1d2d81b1b7c1b100e9c369e40b9fa5b2d491eea9 0 iEYEABECAAYFAlTKOKUACgkQjPn4sExkf7xWMACfYFozyHiRk5GaocTa5z6Ws1uyB4kAoLubxoxcnM3E7AA9mHAzc3OB5M0Y
|
||||
a687f835236c7025b5cb2968fe9c4ebc4a49f0ea 0 iQIcBAABCgAGBQJVxg62AAoJEPSYMBLCC7qsC+EQAKw8YWogrVHhIFct2fx/nqybSPVrhFyKFKHhq7K/lZeVm0MGIWdSyVcQgP+Hs2jWNBWzG4AJ1BtifHWQH6IDh7W5RuwOXu5KobgPW9BsN3EVE9KIR+xe9jCAmFl9rIw0tNpy1q6R0TpYXx/sWlMilxecyEGyr2Ias2Sm19aY2mOEv8PLfh9BLfrJEKtt2NxL7TX8ScPwJXJMmVIQjN9WK4Ptx3tjcGNRivEVR/dftP5sJx2DBJx9avyDqrfloMW7Q7sPgJ88MPruCDxedOkbzH7JdHe3Humr2G4LsI0KPU7pNN6EBDjhJ+SVXuOyAgu5j/C0R+0ggGfjSrjDu8WjHyclFlwwu2MSGuHf111I1qkLtaRY3H1FZO5Y2gbLwBLQ82svA4klcBIxtP5jKAZDTh1jQMYsfKotvZdawOWrPDkNmKoUg2JXLHAtj9Dd0uGIhqfspZY3qlpzxw9uCkljWclUBD097ygotwAb2XdLoAWZ3KdvoPM+k448vIAQ7Q/aqcnm/dLQJr3Le029gpkOKoWKaQTlk0itrRGpgETHAhE2LnmWxYSKp6NYSKMgEONbfDiVNLyDTOlvpPiEb20RsOP64xA4wVDGmPenCURmMYoepQK6oJdtkNtCdth2S49KxPQAC+Dem4YZ7b+5b+cXrK5Nz7elBxZzRQWdjmZ4JDQK
|
||||
ef4b26364b0cdda1084751d7de3d76c589e2d9cb 0 iQIcBAABCgAGBQJVxg7BAAoJEESTFJTynGdz9Q4P/A0Kq4H52rQqxq42PoEMFbVQIUfkFzyWjAz8eEGLmP5x5/sdpyxZDEyBSUG55uyNvOPTHE+Sd3t2h2Iieq749qwYgqggXC0P+C0zGzW3hB5Rv6dTUrKN1yCyaWE2tY488RsyVlcAs4vrp1Cum5Gv8/BUVKjzZmkZ1iq/3RyrvbLEiLoMrcLnQ+sUdaYHvfEwxDbzpOEvepg8iDJBitTrfG9xHp9otX6ucahwn1EumFvC5mvUxbiQ9jv76t4FJztjMoB24hPCH9T1FjB8uNsoM+j2Z67r81eJrGgNpJzjX0S3lY/AADZGhfGnfybTM9gFuQayIJuCJqduQibVwYkAAnPi17NmbdwPu0Rdz55oU+ft09XLVm/qkQcD1EP5bxYWnLIEMkkZQnFx7WdMpjKK9oGxZHeFYAKEgPgePCkk4TQ4PxNa+3854H19AUssQlaueGcbDLyPIRiSyqhleXawGfaJi+1jBt0DM7CNbAHAUWUE07VhQzNGWjabdEk4eXKTmDL+mZJFdHGBhyCve8sPmZBYJvM2PRgcXe8fwFh+R7gVj6kFbZJvgM9kG7EeF+4ZMEXG4yKpV/SKfMMeEPBCZjFxZhlJJ0fsZbB1Y/iLw8LXnJ0fa/5xFYv6k+iytfom/rqS4iUD7NWTjcEYHjd4EO4QlPD2Ef/AWOO8YBUBv8kA
|
||||
|
||||
7
.hgtags
7
.hgtags
@@ -41,3 +41,10 @@ e76614145aea67f66e4a4257685c771efba21aa1 DROPBEAR_2013.58
|
||||
7b68e581985fd4ea50869f8608ab95cda5d17876 DROPBEAR_2013.59
|
||||
a50a1dc743317fad9b3737bc68fbca640659bb6d DROPBEAR_2013.60
|
||||
e894dbc015ba7ff4c3bf897ee20e28ca90c55a16 DROPBEAR_2013.61test
|
||||
3d1d7d151c0ce3a79da62e86463f5632fa2b144a DROPBEAR_2013.62
|
||||
2351b2da8e0d08dcc6e64fcc328b53b9630bda68 DROPBEAR_2014.63
|
||||
0d2d39957c029adb7f4327d37fe6b4900f0736d9 DROPBEAR_2014.64
|
||||
e9579816f20ea85affc6135e87f8477992808948 DROPBEAR_2014.65
|
||||
735511a4c761141416ad0e6728989d2dafa55bc2 DROPBEAR_2014.66
|
||||
cbd674d63cd4f3781464a8d4056a5506c8ae926f DROPBEAR_2015.67
|
||||
809feaa9408f036734129c77f2b3c7e779d4f099 DROPBEAR_2015.68
|
||||
|
||||
23
.travis.yml
Normal file
23
.travis.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
language: c
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
script:
|
||||
- autoconf && autoheader && ./configure $BUNDLEDLIBTOM CFLAGS="-O2 -Wall -Wno-pointer-sign $WEXTRAFLAGS" --prefix=$HOME/inst
|
||||
- test "$NOWRITEV" && sed -i s/HAVE_WRITEV/DONT_HAVE_WRITEV/ config.h || true
|
||||
- make install
|
||||
- ~/inst/bin/dropbearkey -t rsa -f testrsa
|
||||
- ~/inst/bin/dropbearkey -t dss -f testdss
|
||||
- ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
|
||||
- ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384
|
||||
- ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq libz-dev libtomcrypt-dev libtommath-dev
|
||||
|
||||
env:
|
||||
- BUNDLEDLIBTOM=--disable-bundled-libtom WEXTRAFLAGS=-Werror
|
||||
- BUNDLEDLIBTOM=--enable-bundled-libtom
|
||||
- MULTI=1
|
||||
- NOWRITEV=1
|
||||
199
CHANGES
199
CHANGES
@@ -1,3 +1,202 @@
|
||||
2015.69 - 25 November 2015
|
||||
|
||||
- Fix crash when forwarded TCP connections fail to connect (bug introduced in 2015.68)
|
||||
|
||||
- Avoid hang on session close when multiple sessions are started, affects Qt Creator
|
||||
Patch from Andrzej Szombierski
|
||||
|
||||
- Reduce per-channel memory consumption in common case, increase default
|
||||
channel limit from 100 to 1000 which should improve SOCKS forwarding for modern
|
||||
webpages
|
||||
|
||||
- Handle multiple command line arguments in a single flag, thanks to Guilhem Moulin
|
||||
|
||||
- Manpage improvements from Guilhem Moulin
|
||||
|
||||
- Build fixes for Android from Mike Frysinger
|
||||
|
||||
- Don't display the MOTD when an explicit command is run from Guilhem Moulin
|
||||
|
||||
- Check curve25519 shared secret isn't zero
|
||||
|
||||
2015.68 - Saturday 8 August 2015
|
||||
|
||||
- Reduce local data copying for improved efficiency. Measured 30%
|
||||
increase in throughput for connections to localhost
|
||||
|
||||
- Forwarded TCP ports connect asynchronously and try all available addresses
|
||||
(IPv4, IPv6, round robin DNS)
|
||||
|
||||
- Fix all compile warnings, many patches from Gaël Portay
|
||||
Note that configure with -Werror may not be successful on some platforms (OS X)
|
||||
and some configuration options may still result in unused variable
|
||||
warnings.
|
||||
|
||||
- Use TCP Fast Open on Linux if available. Saves a round trip at connection
|
||||
to hosts that have previously been connected.
|
||||
Needs a recent Linux kernel and possibly "sysctl -w net.ipv4.tcp_fastopen=3"
|
||||
Client side is disabled by default pending further compatibility testing
|
||||
with networks and systems.
|
||||
|
||||
- Increase maximum command length to 9000 bytes
|
||||
|
||||
- Free memory before exiting, patch from Thorsten Horstmann. Useful for
|
||||
Dropbear ports to embedded systems and for checking memory leaks
|
||||
with valgrind. Only partially implemented for dbclient.
|
||||
This is disabled by default, enable with DROPBEAR_CLEANUP in sysoptions.h
|
||||
|
||||
- DROPBEAR_DEFAULT_CLI_AUTHKEY setting now always prepends home directory unless
|
||||
there is a leading slash (~ isn't treated specially)
|
||||
|
||||
- Fix small ECC memory leaks
|
||||
|
||||
- Tighten validation of Diffie-Hellman parameters, from Florent Daigniere of
|
||||
Matta Consulting. Odds of bad values are around 2**-512 -- improbable.
|
||||
|
||||
- Twofish-ctr cipher is supported though disabled by default
|
||||
|
||||
- Fix pre-authentication timeout when waiting for client SSH-2.0 banner, thanks
|
||||
to CL Ouyang
|
||||
|
||||
- Fix null pointer crash with restrictions in authorized_keys without a command, patch from
|
||||
Guilhem Moulin
|
||||
|
||||
- Ensure authentication timeout is handled while reading the initial banner,
|
||||
thanks to CL Ouyang for finding it.
|
||||
|
||||
- Fix null pointer crash when handling bad ECC keys. Found by afl-fuzz
|
||||
|
||||
2015.67 - Wednesday 28 January 2015
|
||||
|
||||
- Call fsync() after generating private keys to ensure they aren't lost if a
|
||||
reboot occurs. Thanks to Peter Korsgaard
|
||||
|
||||
- Disable non-delayed zlib compression by default on the server. Can be
|
||||
enabled if required for old clients with DROPBEAR_SERVER_DELAY_ZLIB
|
||||
|
||||
- Default client key path ~/.ssh/id_dropbear
|
||||
|
||||
- Prefer stronger algorithms by default, from Fedor Brunner.
|
||||
AES256 over 3DES
|
||||
Diffie-hellman group14 over group1
|
||||
|
||||
- Add option to disable CBC ciphers.
|
||||
|
||||
- Disable twofish in default options.h
|
||||
|
||||
- Enable sha2 HMAC algorithms by default, the code was already required
|
||||
for ECC key exchange. sha1 is the first preference still for performance.
|
||||
|
||||
- Fix installing dropbear.8 in a separate build directory, from Like Ma
|
||||
|
||||
- Allow configure to succeed if libtomcrypt/libtommath are missing, from Elan Ruusamäe
|
||||
|
||||
- Don't crash if ssh-agent provides an unknown type of key. From Catalin Patulea
|
||||
|
||||
- Minor bug fixes, a few issues found by Coverity scan
|
||||
|
||||
2014.66 - Thursday 23 October 2014
|
||||
|
||||
- Use the same keepalive handling behaviour as OpenSSH. This will work better
|
||||
with some SSH implementations that have different behaviour with unknown
|
||||
message types.
|
||||
|
||||
- Don't reply with SSH_MSG_UNIMPLEMENTED when we receive a reply to our own
|
||||
keepalive message
|
||||
|
||||
- Set $SSH_CLIENT to keep bash happy, patch from Ryan Cleere
|
||||
|
||||
- Fix wtmp which broke since 2013.62, patch from Whoopie
|
||||
|
||||
2014.65 - Friday 8 August 2014
|
||||
|
||||
- Fix 2014.64 regression, server session hang on exit with scp (and probably
|
||||
others), thanks to NiLuJe for tracking it down
|
||||
|
||||
- Fix 2014.64 regression, clock_gettime() error handling which broke on older
|
||||
Linux kernels, reported by NiLuJe
|
||||
|
||||
- Fix 2014.64 regression, writev() could occassionally fail with EAGAIN which
|
||||
wasn't caught
|
||||
|
||||
- Avoid error message when trying to set QoS on proxycommand or multihop pipes
|
||||
|
||||
- Use /usr/bin/xauth, thanks to Mike Frysinger
|
||||
|
||||
- Don't exit the client if the local user entry can't be found, thanks to iquaba
|
||||
|
||||
2014.64 - Sunday 27 July 2014
|
||||
|
||||
- Fix compiling with ECDSA and DSS disabled
|
||||
|
||||
- Don't exit abruptly if too many outgoing packets are queued for writev(). Patch
|
||||
thanks to Ronny Meeus
|
||||
|
||||
- The -K keepalive option now behaves more like OpenSSH's "ServerAliveInterval".
|
||||
If no response is received after 3 keepalives then the session is terminated. This
|
||||
will close connections faster than waiting for a TCP timeout.
|
||||
|
||||
- Rework TCP priority setting. New settings are
|
||||
if (connecting || ptys || x11) tos = LOWDELAY
|
||||
else if (tcp_forwards) tos = 0
|
||||
else tos = BULK
|
||||
Thanks to Catalin Patulea for the suggestion.
|
||||
|
||||
- Improve handling of many concurrent new TCP forwarded connections, should now
|
||||
be able to handle as many as MAX_CHANNELS. Thanks to Eduardo Silva for reporting
|
||||
and investigating it.
|
||||
|
||||
- Make sure that exit messages from the client are printed, regression in 2013.57
|
||||
|
||||
- Use monotonic clock where available, timeouts won't be affected by system time
|
||||
changes
|
||||
|
||||
- Add -V for version
|
||||
|
||||
2014.63 - Wednesday 19 February 2014
|
||||
|
||||
- Fix ~. to terminate a client interactive session after waking a laptop
|
||||
from sleep.
|
||||
|
||||
- Changed port separator syntax again, now using host^port. This is because
|
||||
IPv6 link-local addresses use %. Reported by Gui Iribarren
|
||||
|
||||
- Avoid constantly relinking dropbearmulti target, fix "make install"
|
||||
for multi target, thanks to Mike Frysinger
|
||||
|
||||
- Avoid getting stuck in a loop writing huge key files, reported by Bruno
|
||||
Thomsen
|
||||
|
||||
- Don't link dropbearkey or dropbearconvert to libz or libutil,
|
||||
thanks to Nicolas Boos
|
||||
|
||||
- Fix linking -lcrypt on systems without /usr/lib, thanks to Nicolas Boos
|
||||
|
||||
- Avoid crash on exit due to cleaned up keys before last packets are sent,
|
||||
debugged by Ronald Wahl
|
||||
|
||||
- Fix a race condition in rekeying where Dropbear would exit if it received a
|
||||
still-in-flight packet after initiating rekeying. Reported by Oliver Metz.
|
||||
This is a longstanding bug but is triggered more easily since 2013.57
|
||||
|
||||
- Fix README for ecdsa keys, from Catalin Patulea
|
||||
|
||||
- Ensure that generated RSA keys are always exactly the length
|
||||
requested. Previously Dropbear always generated N+16 or N+15 bit keys.
|
||||
Thanks to Unit 193
|
||||
|
||||
- Fix DROPBEAR_CLI_IMMEDIATE_AUTH mode which saves a network round trip if the
|
||||
first public key succeeds. Still not enabled by default, needs more
|
||||
compatibility testing with other implementations.
|
||||
|
||||
- Fix for port 0 forwarding in the client and port forwarding with Apache MINA SSHD. Thanks to
|
||||
|
||||
- Fix for bad system linux/pkt-sched.h header file with older Linux
|
||||
kernels, from Steve Dover
|
||||
|
||||
- Fix signal handlers so that errno is saved, thanks to Erik Ahlén for a patch
|
||||
and Mark Wickham for independently spotting the same problem.
|
||||
|
||||
2013.62 - Tuesday 3 December 2013
|
||||
|
||||
- Disable "interactive" QoS connection options when a connection doesn't
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -8,7 +8,7 @@ The majority of code is written by Matt Johnston, under the license below.
|
||||
Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the
|
||||
same license:
|
||||
|
||||
Copyright (c) 2002-2013 Matt Johnston
|
||||
Copyright (c) 2002-2015 Matt Johnston
|
||||
Portions copyright (c) 2004 Mihnea Stoenescu
|
||||
All rights reserved.
|
||||
|
||||
|
||||
48
Makefile.in
48
Makefile.in
@@ -13,13 +13,15 @@ ifndef PROGRAMS
|
||||
PROGRAMS=dropbear dbclient dropbearkey dropbearconvert
|
||||
endif
|
||||
|
||||
LTC=libtomcrypt/libtomcrypt.a
|
||||
LTM=libtommath/libtommath.a
|
||||
STATIC_LTC=libtomcrypt/libtomcrypt.a
|
||||
STATIC_LTM=libtommath/libtommath.a
|
||||
|
||||
LIBTOM_LIBS=@LIBTOM_LIBS@
|
||||
|
||||
ifeq (@BUNDLED_LIBTOM@, 1)
|
||||
LIBTOM_DEPS=$(LTC) $(LTM)
|
||||
LIBTOM_DEPS=$(STATIC_LTC) $(STATIC_LTM)
|
||||
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
|
||||
LIBS+=$(LTC) $(LTM)
|
||||
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
|
||||
endif
|
||||
|
||||
COMMONOBJS=dbutil.o buffer.o \
|
||||
@@ -38,12 +40,12 @@ SVROBJS=svr-kex.o svr-auth.o sshpty.o \
|
||||
CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
|
||||
cli-session.o cli-runopts.o cli-chansession.o \
|
||||
cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o \
|
||||
cli-agentfwd.o list.o
|
||||
cli-agentfwd.o
|
||||
|
||||
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
|
||||
common-channel.o common-chansession.o termcodes.o loginrec.o \
|
||||
tcp-accept.o listener.o process-packet.o \
|
||||
common-runopts.o circbuffer.o curve25519-donna.o
|
||||
common-runopts.o circbuffer.o curve25519-donna.o list.o netio.o
|
||||
|
||||
KEYOBJS=dropbearkey.o
|
||||
|
||||
@@ -58,7 +60,7 @@ HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \
|
||||
loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \
|
||||
listener.h fake-rfc2553.h ecc.h ecdsa.h
|
||||
|
||||
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) @CRYPTLIB@
|
||||
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
|
||||
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
|
||||
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
|
||||
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
|
||||
@@ -129,23 +131,23 @@ insmultidropbear: dropbearmulti
|
||||
-rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
|
||||
$(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
|
||||
$(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
|
||||
|
||||
insmulti%: dropbearmulti
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
-rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
|
||||
$(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1
|
||||
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
|
||||
# dropbear should go in sbin, so it needs a seperate rule
|
||||
# dropbear should go in sbin, so it needs a separate rule
|
||||
inst_dropbear: dropbear
|
||||
$(INSTALL) -d $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
|
||||
$(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
|
||||
$(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
|
||||
|
||||
inst_%: $*
|
||||
inst_%: %
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
$(INSTALL) $*$(EXEEXT) $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
|
||||
@@ -160,8 +162,14 @@ dbclient: $(dbclientobjs)
|
||||
dropbearkey: $(dropbearkeyobjs)
|
||||
dropbearconvert: $(dropbearconvertobjs)
|
||||
|
||||
dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBS)
|
||||
dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
|
||||
|
||||
dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
|
||||
|
||||
dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS)
|
||||
|
||||
# scp doesn't use the libs so is special.
|
||||
scp: $(SCPOBJS) $(HEADERS) Makefile
|
||||
@@ -171,14 +179,14 @@ scp: $(SCPOBJS) $(HEADERS) Makefile
|
||||
# multi-binary compilation.
|
||||
MULTIOBJS=
|
||||
ifeq ($(MULTI),1)
|
||||
MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs))) @CRYPTLIB@
|
||||
MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs)))
|
||||
CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
|
||||
endif
|
||||
|
||||
dropbearmulti: multilink
|
||||
dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@ $(MULTIOBJS) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
|
||||
|
||||
multibinary: $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS)
|
||||
multibinary: dropbearmulti$(EXEEXT)
|
||||
|
||||
multilink: multibinary $(addprefix link, $(PROGRAMS))
|
||||
|
||||
@@ -186,10 +194,10 @@ link%:
|
||||
-rm -f $*$(EXEEXT)
|
||||
-ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT)
|
||||
|
||||
$(LTC): options.h
|
||||
$(STATIC_LTC): options.h
|
||||
cd libtomcrypt && $(MAKE)
|
||||
|
||||
$(LTM): options.h
|
||||
$(STATIC_LTM): options.h
|
||||
cd libtommath && $(MAKE)
|
||||
|
||||
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean
|
||||
|
||||
2
README
2
README
@@ -54,7 +54,7 @@ dropbearkey's '-y' option.
|
||||
To run the server, you need to server keys, this is one-off:
|
||||
./dropbearkey -t rsa -f dropbear_rsa_host_key
|
||||
./dropbearkey -t dss -f dropbear_dss_host_key
|
||||
./dropbearkey -t ecdsa -f dropbear_dss_host_key
|
||||
./dropbearkey -t ecdsa -f dropbear_ecdsa_host_key
|
||||
|
||||
or alternatively convert OpenSSH keys to Dropbear:
|
||||
./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
#ifndef _AGENTFWD_H_
|
||||
#define _AGENTFWD_H_
|
||||
#ifndef DROPBEAR_AGENTFWD_H_
|
||||
#define DROPBEAR_AGENTFWD_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "chansession.h"
|
||||
@@ -60,4 +60,4 @@ void svr_agentset(struct ChanSess *chansess);
|
||||
|
||||
#endif /* ENABLE_SVR_AGENTFWD */
|
||||
|
||||
#endif /* _AGENTFWD_H_ */
|
||||
#endif /* DROPBEAR_AGENTFWD_H_ */
|
||||
|
||||
9
algo.h
9
algo.h
@@ -22,9 +22,9 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _ALGO_H_
|
||||
#ifndef DROPBEAR_ALGO_H_
|
||||
|
||||
#define _ALGO_H_
|
||||
#define DROPBEAR_ALGO_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
struct Algo_Type {
|
||||
|
||||
const unsigned char *name; /* identifying name */
|
||||
const char *name; /* identifying name */
|
||||
char val; /* a value for this cipher, or -1 for invalid */
|
||||
const void *data; /* algorithm specific data */
|
||||
char usable; /* whether we can use this algorithm */
|
||||
@@ -51,6 +51,7 @@ extern algo_type sshhostkey[];
|
||||
extern algo_type sshciphers[];
|
||||
extern algo_type sshhashes[];
|
||||
extern algo_type ssh_compress[];
|
||||
extern algo_type ssh_delaycompress[];
|
||||
extern algo_type ssh_nocompress[];
|
||||
|
||||
extern const struct dropbear_cipher dropbear_nocipher;
|
||||
@@ -133,4 +134,4 @@ enum {
|
||||
DROPBEAR_COMP_ZLIB_DELAY,
|
||||
};
|
||||
|
||||
#endif /* _ALGO_H_ */
|
||||
#endif /* DROPBEAR_ALGO_H_ */
|
||||
|
||||
10
auth.h
10
auth.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _AUTH_H_
|
||||
#define _AUTH_H_
|
||||
#ifndef DROPBEAR_AUTH_H_
|
||||
#define DROPBEAR_AUTH_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
@@ -106,7 +106,7 @@ struct AuthState {
|
||||
valid */
|
||||
unsigned int failcount; /* Number of (failed) authentication attempts.*/
|
||||
unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have. Applies for
|
||||
client and server (though has differing [obvious]
|
||||
client and server (though has differing
|
||||
meanings). */
|
||||
unsigned perm_warn : 1; /* Server only, set if bad permissions on
|
||||
~/.ssh/authorized_keys have already been
|
||||
@@ -133,8 +133,8 @@ struct PubKeyOptions {
|
||||
int no_x11_forwarding_flag;
|
||||
int no_pty_flag;
|
||||
/* "command=" option. */
|
||||
unsigned char * forced_command;
|
||||
char * forced_command;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* _AUTH_H_ */
|
||||
#endif /* DROPBEAR_AUTH_H_ */
|
||||
|
||||
6
bignum.h
6
bignum.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _BIGNUM_H_
|
||||
#define _BIGNUM_H_
|
||||
#ifndef DROPBEAR_BIGNUM_H_
|
||||
#define DROPBEAR_BIGNUM_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
@@ -35,4 +35,4 @@ void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
|
||||
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
|
||||
hash_state *hs, mp_int *mp);
|
||||
|
||||
#endif /* _BIGNUM_H_ */
|
||||
#endif /* DROPBEAR_BIGNUM_H_ */
|
||||
|
||||
48
buffer.c
48
buffer.c
@@ -46,17 +46,15 @@ buffer* buf_new(unsigned int size) {
|
||||
dropbear_exit("buf->size too big");
|
||||
}
|
||||
|
||||
buf = (buffer*)m_malloc(sizeof(buffer));
|
||||
buf = (buffer*)m_malloc(sizeof(buffer)+size);
|
||||
|
||||
if (size > 0) {
|
||||
buf->data = (unsigned char*)m_malloc(size);
|
||||
buf->data = (unsigned char*)buf + sizeof(buffer);
|
||||
} else {
|
||||
buf->data = NULL;
|
||||
}
|
||||
|
||||
buf->size = size;
|
||||
buf->pos = 0;
|
||||
buf->len = 0;
|
||||
|
||||
return buf;
|
||||
|
||||
@@ -65,7 +63,6 @@ buffer* buf_new(unsigned int size) {
|
||||
/* free the buffer's data and the buffer itself */
|
||||
void buf_free(buffer* buf) {
|
||||
|
||||
m_free(buf->data)
|
||||
m_free(buf);
|
||||
}
|
||||
|
||||
@@ -78,17 +75,18 @@ void buf_burn(buffer* buf) {
|
||||
|
||||
/* resize a buffer, pos and len will be repositioned if required when
|
||||
* downsizing */
|
||||
void buf_resize(buffer *buf, unsigned int newsize) {
|
||||
buffer* buf_resize(buffer *buf, unsigned int newsize) {
|
||||
|
||||
if (newsize > BUF_MAX_SIZE) {
|
||||
dropbear_exit("buf->size too big");
|
||||
}
|
||||
|
||||
buf->data = m_realloc(buf->data, newsize);
|
||||
buf = m_realloc(buf, sizeof(buffer)+newsize);
|
||||
buf->data = (unsigned char*)buf + sizeof(buffer);
|
||||
buf->size = newsize;
|
||||
buf->len = MIN(newsize, buf->len);
|
||||
buf->pos = MIN(newsize, buf->pos);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Create a copy of buf, allocating required memory etc. */
|
||||
@@ -99,7 +97,9 @@ buffer* buf_newcopy(buffer* buf) {
|
||||
|
||||
ret = buf_new(buf->len);
|
||||
ret->len = buf->len;
|
||||
memcpy(ret->data, buf->data, buf->len);
|
||||
if (buf->len > 0) {
|
||||
memcpy(ret->data, buf->data, buf->len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ void buf_setpos(buffer* buf, unsigned int pos) {
|
||||
buf->pos = pos;
|
||||
}
|
||||
|
||||
/* increment the postion by incr, increasing the buffer length if required */
|
||||
/* increment the position by incr, increasing the buffer length if required */
|
||||
void buf_incrwritepos(buffer* buf, unsigned int incr) {
|
||||
if (incr > BUF_MAX_INCR || buf->pos + incr > buf->size) {
|
||||
dropbear_exit("Bad buf_incrwritepos");
|
||||
@@ -203,10 +203,10 @@ unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) {
|
||||
/* Return a null-terminated string, it is malloced, so must be free()ed
|
||||
* Note that the string isn't checked for null bytes, hence the retlen
|
||||
* may be longer than what is returned by strlen */
|
||||
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
|
||||
unsigned int len;
|
||||
unsigned char* ret;
|
||||
char* ret;
|
||||
len = buf_getint(buf);
|
||||
if (len > MAX_STRING_LEN) {
|
||||
dropbear_exit("String too long");
|
||||
@@ -225,15 +225,15 @@ unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
|
||||
/* Return a string as a newly allocated buffer */
|
||||
buffer * buf_getstringbuf(buffer *buf) {
|
||||
buffer *ret;
|
||||
unsigned char* str;
|
||||
unsigned int len;
|
||||
str = buf_getstring(buf, &len);
|
||||
ret = m_malloc(sizeof(*ret));
|
||||
ret->data = str;
|
||||
ret->len = len;
|
||||
ret->size = len;
|
||||
ret->pos = 0;
|
||||
buffer *ret = NULL;
|
||||
unsigned int len = buf_getint(buf);
|
||||
if (len > MAX_STRING_LEN) {
|
||||
dropbear_exit("String too long");
|
||||
}
|
||||
ret = buf_new(len);
|
||||
memcpy(buf_getwriteptr(ret, len), buf_getptr(buf, len), len);
|
||||
buf_incrpos(buf, len);
|
||||
buf_incrlen(ret, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -262,16 +262,16 @@ void buf_putint(buffer* buf, int unsigned val) {
|
||||
}
|
||||
|
||||
/* put a SSH style string into the buffer, increasing buffer len if required */
|
||||
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len) {
|
||||
void buf_putstring(buffer* buf, const char* str, unsigned int len) {
|
||||
|
||||
buf_putint(buf, len);
|
||||
buf_putbytes(buf, str, len);
|
||||
buf_putbytes(buf, (const unsigned char*)str, len);
|
||||
|
||||
}
|
||||
|
||||
/* puts an entire buffer as a SSH string. ignore pos of buf_str. */
|
||||
void buf_putbufstring(buffer *buf, const buffer* buf_str) {
|
||||
buf_putstring(buf, buf_str->data, buf_str->len);
|
||||
buf_putstring(buf, (const char*)buf_str->data, buf_str->len);
|
||||
}
|
||||
|
||||
/* put the set of len bytes into the buffer, incrementing the pos, increasing
|
||||
|
||||
16
buffer.h
16
buffer.h
@@ -22,14 +22,15 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _BUFFER_H_
|
||||
#ifndef DROPBEAR_BUFFER_H_
|
||||
|
||||
#define _BUFFER_H_
|
||||
#define DROPBEAR_BUFFER_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
struct buf {
|
||||
|
||||
/* don't manipulate data member outside of buffer.c - it
|
||||
is a pointer into the malloc holding buffer itself */
|
||||
unsigned char * data;
|
||||
unsigned int len; /* the used size */
|
||||
unsigned int pos;
|
||||
@@ -40,7 +41,8 @@ struct buf {
|
||||
typedef struct buf buffer;
|
||||
|
||||
buffer * buf_new(unsigned int size);
|
||||
void buf_resize(buffer *buf, unsigned int newsize);
|
||||
/* Possibly returns a new buffer*, like realloc() */
|
||||
buffer * buf_resize(buffer *buf, unsigned int newsize);
|
||||
void buf_free(buffer* buf);
|
||||
void buf_burn(buffer* buf);
|
||||
buffer* buf_newcopy(buffer* buf);
|
||||
@@ -54,15 +56,15 @@ unsigned char buf_getbool(buffer* buf);
|
||||
void buf_putbyte(buffer* buf, unsigned char val);
|
||||
unsigned char* buf_getptr(buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen);
|
||||
char* buf_getstring(buffer* buf, unsigned int *retlen);
|
||||
buffer * buf_getstringbuf(buffer *buf);
|
||||
void buf_eatstring(buffer *buf);
|
||||
void buf_putint(buffer* buf, unsigned int val);
|
||||
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len);
|
||||
void buf_putstring(buffer* buf, const char* str, unsigned int len);
|
||||
void buf_putbufstring(buffer *buf, const buffer* buf_str);
|
||||
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
|
||||
void buf_putmpint(buffer* buf, mp_int * mp);
|
||||
int buf_getmpint(buffer* buf, mp_int* mp);
|
||||
unsigned int buf_getint(buffer* buf);
|
||||
|
||||
#endif /* _BUFFER_H_ */
|
||||
#endif /* DROPBEAR_BUFFER_H_ */
|
||||
|
||||
40
channel.h
40
channel.h
@@ -22,21 +22,13 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _CHANNEL_H_
|
||||
#define _CHANNEL_H_
|
||||
#ifndef DROPBEAR_CHANNEL_H_
|
||||
#define DROPBEAR_CHANNEL_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "circbuffer.h"
|
||||
|
||||
/* channel->type values */
|
||||
#define CHANNEL_ID_NONE 0
|
||||
#define CHANNEL_ID_SESSION 1
|
||||
#define CHANNEL_ID_X11 2
|
||||
#define CHANNEL_ID_AGENT 3
|
||||
#define CHANNEL_ID_TCPDIRECT 4
|
||||
#define CHANNEL_ID_TCPFORWARDED 5
|
||||
|
||||
#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1
|
||||
#define SSH_OPEN_CONNECT_FAILED 2
|
||||
#define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3
|
||||
@@ -49,6 +41,13 @@
|
||||
|
||||
struct ChanType;
|
||||
|
||||
enum dropbear_channel_prio {
|
||||
DROPBEAR_CHANNEL_PRIO_INTERACTIVE, /* pty shell, x11 */
|
||||
DROPBEAR_CHANNEL_PRIO_UNKNOWABLE, /* tcp - can't know what's being forwarded */
|
||||
DROPBEAR_CHANNEL_PRIO_BULK, /* the rest - probably scp or something */
|
||||
DROPBEAR_CHANNEL_PRIO_EARLY, /* channel is still being set up */
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
|
||||
unsigned int index; /* the local channel index */
|
||||
@@ -74,6 +73,7 @@ struct Channel {
|
||||
* to ensure we don't run it twice (nor type->checkclose()). */
|
||||
int close_handler_done;
|
||||
|
||||
struct dropbear_progress_connection *conn_pending;
|
||||
int initconn; /* used for TCP forwarding, whether the channel has been
|
||||
fully initialised */
|
||||
|
||||
@@ -87,24 +87,31 @@ struct Channel {
|
||||
void (*read_mangler)(struct Channel*, unsigned char* bytes, int *len);
|
||||
|
||||
const struct ChanType* type;
|
||||
|
||||
enum dropbear_channel_prio prio;
|
||||
};
|
||||
|
||||
struct ChanType {
|
||||
|
||||
int sepfds; /* Whether this channel has seperate pipes for in/out or not */
|
||||
int sepfds; /* Whether this channel has separate pipes for in/out or not */
|
||||
char *name;
|
||||
int (*inithandler)(struct Channel*);
|
||||
int (*check_close)(struct Channel*);
|
||||
void (*reqhandler)(struct Channel*);
|
||||
void (*closehandler)(struct Channel*);
|
||||
|
||||
};
|
||||
|
||||
/* Callback for connect_remote */
|
||||
void channel_connect_done(int result, int sock, void* user_data, const char* errstring);
|
||||
|
||||
void chaninitialise(const struct ChanType *chantypes[]);
|
||||
void chancleanup();
|
||||
void setchannelfds(fd_set *readfd, fd_set *writefd);
|
||||
void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads);
|
||||
void channelio(fd_set *readfd, fd_set *writefd);
|
||||
struct Channel* getchannel();
|
||||
/* Returns an arbitrary channel that is in a ready state - not
|
||||
being initialised and no EOF in either direction. NULL if none. */
|
||||
struct Channel* get_any_ready_channel();
|
||||
|
||||
void recv_msg_channel_open();
|
||||
void recv_msg_channel_request();
|
||||
@@ -128,5 +135,10 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type);
|
||||
void recv_msg_channel_open_confirmation();
|
||||
void recv_msg_channel_open_failure();
|
||||
#endif
|
||||
void start_send_channel_request(struct Channel *channel, char *type);
|
||||
|
||||
#endif /* _CHANNEL_H_ */
|
||||
void send_msg_request_success();
|
||||
void send_msg_request_failure();
|
||||
|
||||
|
||||
#endif /* DROPBEAR_CHANNEL_H_ */
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _CHANSESSION_H_
|
||||
#define _CHANSESSION_H_
|
||||
#ifndef DROPBEAR_CHANSESSION_H_
|
||||
#define DROPBEAR_CHANSESSION_H_
|
||||
|
||||
#include "loginrec.h"
|
||||
#include "channel.h"
|
||||
@@ -39,21 +39,24 @@ struct exitinfo {
|
||||
|
||||
struct ChanSess {
|
||||
|
||||
unsigned char * cmd; /* command to exec */
|
||||
char * cmd; /* command to exec */
|
||||
pid_t pid; /* child process pid */
|
||||
|
||||
/* pty details */
|
||||
int master; /* the master terminal fd*/
|
||||
int slave;
|
||||
unsigned char * tty;
|
||||
unsigned char * term;
|
||||
char * tty;
|
||||
char * term;
|
||||
|
||||
/* exit details */
|
||||
struct exitinfo exit;
|
||||
|
||||
/* Used to set $SSH_CONNECTION in the child session.
|
||||
Is only set temporarily before forking */
|
||||
|
||||
/* These are only set temporarily before forking */
|
||||
/* Used to set $SSH_CONNECTION in the child session. */
|
||||
char *connection_string;
|
||||
/* Used to set $SSH_CLIENT in the child session. */
|
||||
char *client_string;
|
||||
|
||||
#ifndef DISABLE_X11FWD
|
||||
struct Listener * x11listener;
|
||||
@@ -89,7 +92,6 @@ void cli_chansess_winchange();
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
void cli_send_netcat_request();
|
||||
#endif
|
||||
void cli_start_send_channel_request(struct Channel *channel, unsigned char *type);
|
||||
|
||||
void svr_chansessinitialise();
|
||||
extern const struct ChanType svrchansess;
|
||||
@@ -101,4 +103,4 @@ struct SigMap {
|
||||
|
||||
extern const struct SigMap signames[];
|
||||
|
||||
#endif /* _CHANSESSION_H_ */
|
||||
#endif /* DROPBEAR_CHANSESSION_H_ */
|
||||
|
||||
54
circbuffer.c
54
circbuffer.c
@@ -37,9 +37,8 @@ circbuffer * cbuf_new(unsigned int size) {
|
||||
}
|
||||
|
||||
cbuf = (circbuffer*)m_malloc(sizeof(circbuffer));
|
||||
if (size > 0) {
|
||||
cbuf->data = (unsigned char*)m_malloc(size);
|
||||
}
|
||||
/* data is malloced on first write */
|
||||
cbuf->data = NULL;
|
||||
cbuf->used = 0;
|
||||
cbuf->readpos = 0;
|
||||
cbuf->writepos = 0;
|
||||
@@ -50,8 +49,10 @@ circbuffer * cbuf_new(unsigned int size) {
|
||||
|
||||
void cbuf_free(circbuffer * cbuf) {
|
||||
|
||||
m_burn(cbuf->data, cbuf->size);
|
||||
m_free(cbuf->data);
|
||||
if (cbuf->data) {
|
||||
m_burn(cbuf->data, cbuf->size);
|
||||
m_free(cbuf->data);
|
||||
}
|
||||
m_free(cbuf);
|
||||
}
|
||||
|
||||
@@ -67,23 +68,6 @@ unsigned int cbuf_getavail(circbuffer * cbuf) {
|
||||
|
||||
}
|
||||
|
||||
unsigned int cbuf_readlen(circbuffer *cbuf) {
|
||||
|
||||
dropbear_assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
|
||||
dropbear_assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
|
||||
|
||||
if (cbuf->used == 0) {
|
||||
TRACE(("cbuf_readlen: unused buffer"))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cbuf->readpos < cbuf->writepos) {
|
||||
return cbuf->writepos - cbuf->readpos;
|
||||
}
|
||||
|
||||
return cbuf->size - cbuf->readpos;
|
||||
}
|
||||
|
||||
unsigned int cbuf_writelen(circbuffer *cbuf) {
|
||||
|
||||
dropbear_assert(cbuf->used <= cbuf->size);
|
||||
@@ -102,12 +86,19 @@ unsigned int cbuf_writelen(circbuffer *cbuf) {
|
||||
return cbuf->size - cbuf->writepos;
|
||||
}
|
||||
|
||||
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
|
||||
if (len > cbuf_readlen(cbuf)) {
|
||||
dropbear_exit("Bad cbuf read");
|
||||
}
|
||||
void cbuf_readptrs(circbuffer *cbuf,
|
||||
unsigned char **p1, unsigned int *len1,
|
||||
unsigned char **p2, unsigned int *len2) {
|
||||
*p1 = &cbuf->data[cbuf->readpos];
|
||||
*len1 = MIN(cbuf->used, cbuf->size - cbuf->readpos);
|
||||
|
||||
return &cbuf->data[cbuf->readpos];
|
||||
if (*len1 < cbuf->used) {
|
||||
*p2 = cbuf->data;
|
||||
*len2 = cbuf->used - *len1;
|
||||
} else {
|
||||
*p2 = NULL;
|
||||
*len2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
|
||||
@@ -116,6 +107,11 @@ unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
|
||||
dropbear_exit("Bad cbuf write");
|
||||
}
|
||||
|
||||
if (!cbuf->data) {
|
||||
/* lazy allocation */
|
||||
cbuf->data = (unsigned char*)m_malloc(cbuf->size);
|
||||
}
|
||||
|
||||
return &cbuf->data[cbuf->writepos];
|
||||
}
|
||||
|
||||
@@ -131,10 +127,6 @@ void cbuf_incrwrite(circbuffer *cbuf, unsigned int len) {
|
||||
|
||||
|
||||
void cbuf_incrread(circbuffer *cbuf, unsigned int len) {
|
||||
if (len > cbuf_readlen(cbuf)) {
|
||||
dropbear_exit("Bad cbuf read");
|
||||
}
|
||||
|
||||
dropbear_assert(cbuf->used >= len);
|
||||
cbuf->used -= len;
|
||||
cbuf->readpos = (cbuf->readpos + len) % cbuf->size;
|
||||
|
||||
10
circbuffer.h
10
circbuffer.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _CIRCBUFFER_H_
|
||||
#define _CIRCBUFFER_H_
|
||||
#ifndef DROPBEAR_CIRCBUFFER_H_
|
||||
#define DROPBEAR_CIRCBUFFER_H_
|
||||
struct circbuf {
|
||||
|
||||
unsigned int size;
|
||||
@@ -40,10 +40,12 @@ void cbuf_free(circbuffer * cbuf);
|
||||
|
||||
unsigned int cbuf_getused(circbuffer * cbuf); /* how much data stored */
|
||||
unsigned int cbuf_getavail(circbuffer * cbuf); /* how much we can write */
|
||||
unsigned int cbuf_readlen(circbuffer *cbuf); /* max linear read len */
|
||||
unsigned int cbuf_writelen(circbuffer *cbuf); /* max linear write len */
|
||||
|
||||
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len);
|
||||
/* returns pointers to the two portions of the circular buffer that can be read */
|
||||
void cbuf_readptrs(circbuffer *cbuf,
|
||||
unsigned char **p1, unsigned int *len1,
|
||||
unsigned char **p2, unsigned int *len2);
|
||||
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len);
|
||||
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len);
|
||||
void cbuf_incrread(circbuffer *cbuf, unsigned int len);
|
||||
|
||||
@@ -155,7 +155,7 @@ static buffer * agent_request(unsigned char type, buffer *data) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf_resize(inbuf, readlen);
|
||||
inbuf = buf_resize(inbuf, readlen);
|
||||
buf_setpos(inbuf, 0);
|
||||
ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
|
||||
if ((size_t)ret != readlen) {
|
||||
@@ -210,13 +210,14 @@ static void agent_get_key_list(m_list * ret_list)
|
||||
ret = buf_get_pub_key(key_buf, pubkey, &key_type);
|
||||
buf_free(key_buf);
|
||||
if (ret != DROPBEAR_SUCCESS) {
|
||||
/* This is slack, properly would cleanup vars etc */
|
||||
dropbear_exit("Bad pubkey received from agent");
|
||||
}
|
||||
pubkey->type = key_type;
|
||||
pubkey->source = SIGNKEY_SOURCE_AGENT;
|
||||
TRACE(("Skipping bad/unknown type pubkey from agent"));
|
||||
sign_key_free(pubkey);
|
||||
} else {
|
||||
pubkey->type = key_type;
|
||||
pubkey->source = SIGNKEY_SOURCE_AGENT;
|
||||
|
||||
list_append(ret_list, pubkey);
|
||||
list_append(ret_list, pubkey);
|
||||
}
|
||||
|
||||
/* We'll ignore the comment for now. might want it later.*/
|
||||
buf_eatstring(inbuf);
|
||||
@@ -234,7 +235,7 @@ void cli_setup_agent(struct Channel *channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
cli_start_send_channel_request(channel, "auth-agent-req@openssh.com");
|
||||
start_send_channel_request(channel, "auth-agent-req@openssh.com");
|
||||
/* Don't want replies */
|
||||
buf_putbyte(ses.writepayload, 0);
|
||||
encrypt_packet();
|
||||
|
||||
92
cli-auth.c
92
cli-auth.c
@@ -41,31 +41,41 @@ void cli_authinitialise() {
|
||||
/* Send a "none" auth request to get available methods */
|
||||
void cli_auth_getmethods() {
|
||||
TRACE(("enter cli_auth_getmethods"))
|
||||
#ifdef CLI_IMMEDIATE_AUTH
|
||||
ses.authstate.authtypes = AUTH_TYPE_PUBKEY;
|
||||
if (getenv(DROPBEAR_PASSWORD_ENV)) {
|
||||
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT;
|
||||
}
|
||||
if (cli_auth_try() == DROPBEAR_SUCCESS) {
|
||||
TRACE(("skipped initial none auth query"))
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
strlen(cli_opts.username));
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
SSH_SERVICE_CONNECTION_LEN);
|
||||
buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
|
||||
|
||||
encrypt_packet();
|
||||
|
||||
#ifdef DROPBEAR_CLI_IMMEDIATE_AUTH
|
||||
/* We can't haven't two auth requests in-flight with delayed zlib mode
|
||||
since if the first one succeeds then the remote side will
|
||||
expect the second one to be compressed.
|
||||
Race described at
|
||||
http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/zlib-openssh.html
|
||||
*/
|
||||
if (ses.keys->trans.algo_comp != DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.authstate.authtypes = AUTH_TYPE_PUBKEY;
|
||||
if (getenv(DROPBEAR_PASSWORD_ENV)) {
|
||||
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT;
|
||||
}
|
||||
if (cli_auth_try() == DROPBEAR_SUCCESS) {
|
||||
TRACE(("skipped initial none auth query"))
|
||||
/* Note that there will be two auth responses in-flight */
|
||||
cli_ses.ignore_next_auth_response = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
TRACE(("leave cli_auth_getmethods"))
|
||||
}
|
||||
|
||||
void recv_msg_userauth_banner() {
|
||||
|
||||
unsigned char* banner = NULL;
|
||||
char* banner = NULL;
|
||||
unsigned int bannerlen;
|
||||
unsigned int i, linecount;
|
||||
|
||||
@@ -141,8 +151,8 @@ void recv_msg_userauth_specific_60() {
|
||||
|
||||
void recv_msg_userauth_failure() {
|
||||
|
||||
unsigned char * methods = NULL;
|
||||
unsigned char * tok = NULL;
|
||||
char * methods = NULL;
|
||||
char * tok = NULL;
|
||||
unsigned int methlen = 0;
|
||||
unsigned int partial = 0;
|
||||
unsigned int i = 0;
|
||||
@@ -150,31 +160,46 @@ void recv_msg_userauth_failure() {
|
||||
TRACE(("<- MSG_USERAUTH_FAILURE"))
|
||||
TRACE(("enter recv_msg_userauth_failure"))
|
||||
|
||||
if (ses.authstate.authdone) {
|
||||
TRACE(("leave recv_msg_userauth_failure, already authdone."))
|
||||
return;
|
||||
}
|
||||
|
||||
if (cli_ses.state != USERAUTH_REQ_SENT) {
|
||||
/* Perhaps we should be more fatal? */
|
||||
dropbear_exit("Unexpected userauth failure");
|
||||
}
|
||||
|
||||
/* When DROPBEAR_CLI_IMMEDIATE_AUTH is set there will be an initial response for
|
||||
the "none" auth request, and then a response to the immediate auth request.
|
||||
We need to be careful handling them. */
|
||||
if (cli_ses.ignore_next_auth_response) {
|
||||
cli_ses.state = USERAUTH_REQ_SENT;
|
||||
cli_ses.ignore_next_auth_response = 0;
|
||||
TRACE(("leave recv_msg_userauth_failure, ignored response, state set to USERAUTH_REQ_SENT"));
|
||||
return;
|
||||
} else {
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
/* If it was a pubkey auth request, we should cross that key
|
||||
* off the list. */
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
|
||||
cli_pubkeyfail();
|
||||
}
|
||||
/* If it was a pubkey auth request, we should cross that key
|
||||
* off the list. */
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
|
||||
cli_pubkeyfail();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_INTERACT_AUTH
|
||||
/* If we get a failure message for keyboard interactive without
|
||||
* receiving any request info packet, then we don't bother trying
|
||||
* keyboard interactive again */
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT
|
||||
&& !cli_ses.interact_request_received) {
|
||||
TRACE(("setting auth_interact_failed = 1"))
|
||||
cli_ses.auth_interact_failed = 1;
|
||||
}
|
||||
/* If we get a failure message for keyboard interactive without
|
||||
* receiving any request info packet, then we don't bother trying
|
||||
* keyboard interactive again */
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT
|
||||
&& !cli_ses.interact_request_received) {
|
||||
TRACE(("setting auth_interact_failed = 1"))
|
||||
cli_ses.auth_interact_failed = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
cli_ses.lastauthtype = AUTH_TYPE_NONE;
|
||||
cli_ses.state = USERAUTH_FAIL_RCVD;
|
||||
cli_ses.lastauthtype = AUTH_TYPE_NONE;
|
||||
}
|
||||
|
||||
methods = buf_getstring(ses.payload, &methlen);
|
||||
|
||||
@@ -227,13 +252,14 @@ void recv_msg_userauth_failure() {
|
||||
}
|
||||
|
||||
m_free(methods);
|
||||
|
||||
cli_ses.state = USERAUTH_FAIL_RCVD;
|
||||
|
||||
TRACE(("leave recv_msg_userauth_failure"))
|
||||
}
|
||||
|
||||
void recv_msg_userauth_success() {
|
||||
/* This function can validly get called multiple times
|
||||
if DROPBEAR_CLI_IMMEDIATE_AUTH is set */
|
||||
|
||||
TRACE(("received msg_userauth_success"))
|
||||
/* Note: in delayed-zlib mode, setting authdone here
|
||||
* will enable compression in the transport layer */
|
||||
@@ -298,6 +324,7 @@ int cli_auth_try() {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_CLI_PASSWORD_AUTH) || defined(ENABLE_CLI_INTERACT_AUTH)
|
||||
/* A helper for getpass() that exits if the user cancels. The returned
|
||||
* password is statically allocated by getpass() */
|
||||
char* getpass_or_cancel(char* prompt)
|
||||
@@ -321,3 +348,4 @@ char* getpass_or_cancel(char* prompt)
|
||||
}
|
||||
return password;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -31,10 +31,10 @@
|
||||
|
||||
#ifdef ENABLE_CLI_INTERACT_AUTH
|
||||
|
||||
static unsigned char* get_response(unsigned char* prompt)
|
||||
static char* get_response(char* prompt)
|
||||
{
|
||||
FILE* tty = NULL;
|
||||
unsigned char* response = NULL;
|
||||
char* response = NULL;
|
||||
/* not a password, but a reasonable limit */
|
||||
char buf[DROPBEAR_MAX_CLI_PASS];
|
||||
char* ret = NULL;
|
||||
@@ -50,13 +50,13 @@ static unsigned char* get_response(unsigned char* prompt)
|
||||
}
|
||||
|
||||
if (ret == NULL) {
|
||||
response = (unsigned char*)m_strdup("");
|
||||
response = m_strdup("");
|
||||
} else {
|
||||
unsigned int buflen = strlen(buf);
|
||||
/* fgets includes newlines */
|
||||
if (buflen > 0 && buf[buflen-1] == '\n')
|
||||
buf[buflen-1] = '\0';
|
||||
response = (unsigned char*)m_strdup(buf);
|
||||
response = m_strdup(buf);
|
||||
}
|
||||
|
||||
m_burn(buf, sizeof(buf));
|
||||
@@ -66,14 +66,14 @@ static unsigned char* get_response(unsigned char* prompt)
|
||||
|
||||
void recv_msg_userauth_info_request() {
|
||||
|
||||
unsigned char *name = NULL;
|
||||
unsigned char *instruction = NULL;
|
||||
char *name = NULL;
|
||||
char *instruction = NULL;
|
||||
unsigned int num_prompts = 0;
|
||||
unsigned int i;
|
||||
|
||||
unsigned char *prompt = NULL;
|
||||
char *prompt = NULL;
|
||||
unsigned int echo = 0;
|
||||
unsigned char *response = NULL;
|
||||
char *response = NULL;
|
||||
|
||||
TRACE(("enter recv_msg_recv_userauth_info_request"))
|
||||
|
||||
@@ -121,7 +121,7 @@ void recv_msg_userauth_info_request() {
|
||||
echo = buf_getbool(ses.payload);
|
||||
|
||||
if (!echo) {
|
||||
unsigned char* p = getpass_or_cancel(prompt);
|
||||
char* p = getpass_or_cancel(prompt);
|
||||
response = m_strdup(p);
|
||||
m_burn(p, strlen(p));
|
||||
} else {
|
||||
@@ -153,7 +153,7 @@ void cli_auth_interactive() {
|
||||
strlen(cli_opts.username));
|
||||
|
||||
/* service name */
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
SSH_SERVICE_CONNECTION_LEN);
|
||||
|
||||
/* method */
|
||||
|
||||
@@ -143,10 +143,10 @@ void cli_auth_password() {
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
strlen(cli_opts.username));
|
||||
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
SSH_SERVICE_CONNECTION_LEN);
|
||||
|
||||
buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD,
|
||||
buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD,
|
||||
AUTH_METHOD_PASSWORD_LEN);
|
||||
|
||||
buf_putbyte(ses.writepayload, 0); /* FALSE - so says the spec */
|
||||
|
||||
@@ -58,7 +58,7 @@ void recv_msg_userauth_pk_ok() {
|
||||
buffer* keybuf = NULL;
|
||||
char* algotype = NULL;
|
||||
unsigned int algolen;
|
||||
int keytype;
|
||||
enum signkey_type keytype;
|
||||
unsigned int remotelen;
|
||||
|
||||
TRACE(("enter recv_msg_userauth_pk_ok"))
|
||||
@@ -141,7 +141,7 @@ void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
|
||||
const char *algoname = NULL;
|
||||
int algolen;
|
||||
unsigned int algolen;
|
||||
buffer* sigbuf = NULL;
|
||||
|
||||
TRACE(("enter send_msg_userauth_pubkey"))
|
||||
@@ -152,10 +152,10 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
strlen(cli_opts.username));
|
||||
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
SSH_SERVICE_CONNECTION_LEN);
|
||||
|
||||
buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
|
||||
buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
|
||||
AUTH_METHOD_PUBKEY_LEN);
|
||||
|
||||
buf_putbyte(ses.writepayload, realsign);
|
||||
|
||||
@@ -41,7 +41,7 @@ static void cli_chansessreq(struct Channel *channel);
|
||||
static void send_chansess_pty_req(struct Channel *channel);
|
||||
static void send_chansess_shell_req(struct Channel *channel);
|
||||
static void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len);
|
||||
|
||||
static int cli_init_netcat(struct Channel *channel);
|
||||
|
||||
static void cli_tty_setup();
|
||||
|
||||
@@ -56,7 +56,7 @@ const struct ChanType clichansess = {
|
||||
|
||||
static void cli_chansessreq(struct Channel *channel) {
|
||||
|
||||
unsigned char* type = NULL;
|
||||
char* type = NULL;
|
||||
int wantreply;
|
||||
|
||||
TRACE(("enter cli_chansessreq"))
|
||||
@@ -92,17 +92,6 @@ static void cli_closechansess(struct Channel *UNUSED(channel)) {
|
||||
}
|
||||
}
|
||||
|
||||
void cli_start_send_channel_request(struct Channel *channel,
|
||||
unsigned char *type) {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
|
||||
buf_putint(ses.writepayload, channel->remotechan);
|
||||
|
||||
buf_putstring(ses.writepayload, type, strlen(type));
|
||||
|
||||
}
|
||||
|
||||
/* Taken from OpenSSH's sshtty.c:
|
||||
* RCSID("OpenBSD: sshtty.c,v 1.5 2003/09/19 17:43:35 markus Exp "); */
|
||||
static void cli_tty_setup() {
|
||||
@@ -283,11 +272,11 @@ void cli_chansess_winchange() {
|
||||
|
||||
static void send_chansess_pty_req(struct Channel *channel) {
|
||||
|
||||
unsigned char* term = NULL;
|
||||
char* term = NULL;
|
||||
|
||||
TRACE(("enter send_chansess_pty_req"))
|
||||
|
||||
cli_start_send_channel_request(channel, "pty-req");
|
||||
start_send_channel_request(channel, "pty-req");
|
||||
|
||||
/* Don't want replies */
|
||||
buf_putbyte(ses.writepayload, 0);
|
||||
@@ -316,7 +305,7 @@ static void send_chansess_pty_req(struct Channel *channel) {
|
||||
|
||||
static void send_chansess_shell_req(struct Channel *channel) {
|
||||
|
||||
unsigned char* reqtype = NULL;
|
||||
char* reqtype = NULL;
|
||||
|
||||
TRACE(("enter send_chansess_shell_req"))
|
||||
|
||||
@@ -330,7 +319,7 @@ static void send_chansess_shell_req(struct Channel *channel) {
|
||||
reqtype = "shell";
|
||||
}
|
||||
|
||||
cli_start_send_channel_request(channel, reqtype);
|
||||
start_send_channel_request(channel, reqtype);
|
||||
|
||||
/* XXX TODO */
|
||||
buf_putbyte(ses.writepayload, 0); /* Don't want replies */
|
||||
@@ -357,6 +346,11 @@ static int cli_init_stdpipe_sess(struct Channel *channel) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cli_init_netcat(struct Channel *channel) {
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
|
||||
return cli_init_stdpipe_sess(channel);
|
||||
}
|
||||
|
||||
static int cli_initchansess(struct Channel *channel) {
|
||||
|
||||
cli_init_stdpipe_sess(channel);
|
||||
@@ -369,8 +363,9 @@ static int cli_initchansess(struct Channel *channel) {
|
||||
|
||||
if (cli_opts.wantpty) {
|
||||
send_chansess_pty_req(channel);
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE;
|
||||
} else {
|
||||
set_sock_priority(ses.sock_out, DROPBEAR_PRIO_BULK);
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
|
||||
}
|
||||
|
||||
send_chansess_shell_req(channel);
|
||||
@@ -389,7 +384,7 @@ static int cli_initchansess(struct Channel *channel) {
|
||||
static const struct ChanType cli_chan_netcat = {
|
||||
0, /* sepfds */
|
||||
"direct-tcpip",
|
||||
cli_init_stdpipe_sess, /* inithandler */
|
||||
cli_init_netcat, /* inithandler */
|
||||
NULL,
|
||||
NULL,
|
||||
cli_closechansess
|
||||
@@ -397,7 +392,7 @@ static const struct ChanType cli_chan_netcat = {
|
||||
|
||||
void cli_send_netcat_request() {
|
||||
|
||||
const unsigned char* source_host = "127.0.0.1";
|
||||
const char* source_host = "127.0.0.1";
|
||||
const int source_port = 22;
|
||||
|
||||
TRACE(("enter cli_send_netcat_request"))
|
||||
@@ -408,7 +403,7 @@ void cli_send_netcat_request() {
|
||||
dropbear_exit("Couldn't open initial channel");
|
||||
}
|
||||
|
||||
buf_putstring(ses.writepayload, cli_opts.netcat_host,
|
||||
buf_putstring(ses.writepayload, cli_opts.netcat_host,
|
||||
strlen(cli_opts.netcat_host));
|
||||
buf_putint(ses.writepayload, cli_opts.netcat_port);
|
||||
|
||||
|
||||
17
cli-kex.c
17
cli-kex.c
@@ -79,15 +79,13 @@ void send_msg_kexdh_init() {
|
||||
}
|
||||
cli_ses.curve25519_param = gen_kexcurve25519_param();
|
||||
}
|
||||
buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
|
||||
buf_putstring(ses.writepayload, (const char*)cli_ses.curve25519_param->pub, CURVE25519_LEN);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
cli_ses.param_kex_algo = ses.newkeys->algo_kex;
|
||||
encrypt_packet();
|
||||
ses.requirenext[0] = SSH_MSG_KEXDH_REPLY;
|
||||
ses.requirenext[1] = SSH_MSG_KEXINIT;
|
||||
}
|
||||
|
||||
/* Handle a diffie-hellman key exchange reply. */
|
||||
@@ -179,8 +177,7 @@ void recv_msg_kexdh_reply() {
|
||||
hostkey = NULL;
|
||||
|
||||
send_msg_newkeys();
|
||||
ses.requirenext[0] = SSH_MSG_NEWKEYS;
|
||||
ses.requirenext[1] = 0;
|
||||
ses.requirenext = SSH_MSG_NEWKEYS;
|
||||
TRACE(("leave recv_msg_kexdh_init"))
|
||||
}
|
||||
|
||||
@@ -325,7 +322,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
}
|
||||
|
||||
/* Compare hostnames */
|
||||
if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
|
||||
if (strncmp(cli_opts.remotehost, (const char *) buf_getptr(line, hostlen),
|
||||
hostlen) != 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -337,7 +334,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) {
|
||||
if (strncmp((const char *) buf_getptr(line, algolen), algoname, algolen) != 0) {
|
||||
TRACE(("algo doesn't match"))
|
||||
continue;
|
||||
}
|
||||
@@ -349,7 +346,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
}
|
||||
|
||||
/* Now we're at the interesting hostkey */
|
||||
ret = cmp_base64_key(keyblob, keybloblen, algoname, algolen,
|
||||
ret = cmp_base64_key(keyblob, keybloblen, (const unsigned char *) algoname, algolen,
|
||||
line, &fingerprint);
|
||||
|
||||
if (ret == DROPBEAR_SUCCESS) {
|
||||
@@ -385,9 +382,9 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */
|
||||
buf_setpos(line, 0);
|
||||
buf_setlen(line, 0);
|
||||
buf_putbytes(line, cli_opts.remotehost, hostlen);
|
||||
buf_putbytes(line, (const unsigned char *) cli_opts.remotehost, hostlen);
|
||||
buf_putbyte(line, ' ');
|
||||
buf_putbytes(line, algoname, algolen);
|
||||
buf_putbytes(line, (const unsigned char *) algoname, algolen);
|
||||
buf_putbyte(line, ' ');
|
||||
len = line->size - line->pos;
|
||||
/* The only failure with base64 is buffer_overflow, but buf_getwriteptr
|
||||
|
||||
28
cli-main.c
28
cli-main.c
@@ -30,6 +30,7 @@
|
||||
#include "session.h"
|
||||
#include "dbrandom.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "netio.h"
|
||||
|
||||
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
|
||||
static void cli_dropbear_log(int priority, const char* format, va_list param);
|
||||
@@ -46,7 +47,7 @@ int main(int argc, char ** argv) {
|
||||
#endif
|
||||
|
||||
int sock_in, sock_out;
|
||||
char* error = NULL;
|
||||
struct dropbear_progress_connection *progress = NULL;
|
||||
|
||||
_dropbear_exit = cli_dropbear_exit;
|
||||
_dropbear_log = cli_dropbear_log;
|
||||
@@ -72,19 +73,11 @@ int main(int argc, char ** argv) {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
int sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
|
||||
0, &error);
|
||||
sock_in = sock_out = sock;
|
||||
if (cli_opts.wantpty) {
|
||||
set_sock_priority(sock, DROPBEAR_PRIO_LOWDELAY);
|
||||
}
|
||||
progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport, cli_connected, &ses);
|
||||
sock_in = sock_out = -1;
|
||||
}
|
||||
|
||||
if (sock_in < 0) {
|
||||
dropbear_exit("%s", error);
|
||||
}
|
||||
|
||||
cli_session(sock_in, sock_out);
|
||||
cli_session(sock_in, sock_out, progress);
|
||||
|
||||
/* not reached */
|
||||
return -1;
|
||||
@@ -94,6 +87,7 @@ int main(int argc, char ** argv) {
|
||||
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
|
||||
|
||||
char fmtbuf[300];
|
||||
char exitmsg[500];
|
||||
|
||||
if (!sessinitdone) {
|
||||
snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s",
|
||||
@@ -105,11 +99,15 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
|
||||
cli_opts.remoteport, format);
|
||||
}
|
||||
|
||||
/* Arguments to the exit printout may be unsafe to use after session_cleanup() */
|
||||
vsnprintf(exitmsg, sizeof(exitmsg), fmtbuf, param);
|
||||
|
||||
/* Do the cleanup first, since then the terminal will be reset */
|
||||
session_cleanup();
|
||||
/* Avoid printing onwards from terminal cruft */
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
_dropbear_log(LOG_INFO, fmtbuf, param);
|
||||
|
||||
dropbear_log(LOG_INFO, "%s", exitmsg);;
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
@@ -121,7 +119,7 @@ static void cli_dropbear_log(int UNUSED(priority),
|
||||
vsnprintf(printbuf, sizeof(printbuf), format, param);
|
||||
|
||||
fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf);
|
||||
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
static void exec_proxy_cmd(void *user_data_cmd) {
|
||||
|
||||
256
cli-runopts.c
256
cli-runopts.c
@@ -38,7 +38,7 @@ static void parse_hostname(const char* orighostarg);
|
||||
static void parse_multihop_hostname(const char* orighostarg, const char* argv0);
|
||||
static void fill_own_user();
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
static void loadidentityfile(const char* filename);
|
||||
static void loadidentityfile(const char* filename, int warnfail);
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
static void addforward(const char* str, m_list *fwdlist);
|
||||
@@ -65,7 +65,7 @@ static void printhelp() {
|
||||
"-y -y Don't perform any remote host key checking (caution)\n"
|
||||
"-s Request a subsystem (use by external sftp)\n"
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
"-i <identityfile> (multiple allowed)\n"
|
||||
"-i <identityfile> (multiple allowed, default %s)\n"
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
"-A Enable agent auth forwarding\n"
|
||||
@@ -90,10 +90,14 @@ static void printhelp() {
|
||||
"-c <cipher list> Specify preferred ciphers ('-c help' to list options)\n"
|
||||
"-m <MAC list> Specify preferred MACs for packet verification (or '-m help')\n"
|
||||
#endif
|
||||
"-V Version\n"
|
||||
#ifdef DEBUG_TRACE
|
||||
"-v verbose (compiled with DEBUG_TRACE)\n"
|
||||
#endif
|
||||
,DROPBEAR_VERSION, cli_opts.progname,
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
DROPBEAR_DEFAULT_CLI_AUTHKEY,
|
||||
#endif
|
||||
DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
|
||||
|
||||
}
|
||||
@@ -101,25 +105,30 @@ static void printhelp() {
|
||||
void cli_getopts(int argc, char ** argv) {
|
||||
unsigned int i, j;
|
||||
char ** next = 0;
|
||||
unsigned int cmdlen;
|
||||
enum {
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
int nextiskey = 0; /* A flag if the next argument is a keyfile */
|
||||
OPT_AUTHKEY,
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
int nextislocal = 0;
|
||||
OPT_LOCALTCPFWD,
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
int nextisremote = 0;
|
||||
OPT_REMOTETCPFWD,
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
int nextisnetcat = 0;
|
||||
OPT_NETCAT,
|
||||
#endif
|
||||
/* a flag (no arg) if 'next' is NULL, a string-valued option otherwise */
|
||||
OPT_OTHER
|
||||
} opt;
|
||||
unsigned int cmdlen;
|
||||
char* dummy = NULL; /* Not used for anything real */
|
||||
|
||||
char* recv_window_arg = NULL;
|
||||
char* keepalive_arg = NULL;
|
||||
char* idle_timeout_arg = NULL;
|
||||
char *host_arg = NULL;
|
||||
char c;
|
||||
|
||||
/* see printhelp() for options */
|
||||
cli_opts.progname = argv[0];
|
||||
@@ -152,7 +161,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
cli_opts.proxycmd = NULL;
|
||||
#endif
|
||||
#ifndef DISABLE_ZLIB
|
||||
opts.enable_compress = 1;
|
||||
opts.compress_mode = DROPBEAR_COMPRESS_ON;
|
||||
#endif
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
opts.cipher_list = NULL;
|
||||
@@ -163,57 +172,28 @@ void cli_getopts(int argc, char ** argv) {
|
||||
opts.ipv6 = 1;
|
||||
*/
|
||||
opts.recv_window = DEFAULT_RECV_WINDOW;
|
||||
opts.keepalive_secs = DEFAULT_KEEPALIVE;
|
||||
opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT;
|
||||
|
||||
fill_own_user();
|
||||
|
||||
/* Iterate all the arguments */
|
||||
for (i = 1; i < (unsigned int)argc; i++) {
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
if (nextiskey) {
|
||||
/* Load a hostkey since the previous argument was "-i" */
|
||||
loadidentityfile(argv[i]);
|
||||
nextiskey = 0;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
if (nextisremote) {
|
||||
TRACE(("nextisremote true"))
|
||||
addforward(argv[i], cli_opts.remotefwds);
|
||||
nextisremote = 0;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
if (nextislocal) {
|
||||
TRACE(("nextislocal true"))
|
||||
addforward(argv[i], cli_opts.localfwds);
|
||||
nextislocal = 0;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
if (nextisnetcat) {
|
||||
TRACE(("nextisnetcat true"))
|
||||
add_netcat(argv[i]);
|
||||
nextisnetcat = 0;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (next) {
|
||||
/* The previous flag set a value to assign */
|
||||
*next = argv[i];
|
||||
if (*next == NULL) {
|
||||
dropbear_exit("Invalid null argument");
|
||||
/* Handle non-flag arguments such as hostname or commands for the remote host */
|
||||
if (argv[i][0] != '-')
|
||||
{
|
||||
if (host_arg == NULL) {
|
||||
host_arg = argv[i];
|
||||
continue;
|
||||
}
|
||||
next = NULL;
|
||||
continue;
|
||||
/* Commands to pass to the remote host. No more flag handling,
|
||||
commands are consumed below */
|
||||
break;
|
||||
}
|
||||
|
||||
if (argv[i][0] == '-') {
|
||||
/* A flag *waves* */
|
||||
|
||||
switch (argv[i][1]) {
|
||||
/* Begins with '-' */
|
||||
opt = OPT_OTHER;
|
||||
for (j = 1; (c = argv[i][j]) != '\0' && !next && opt == OPT_OTHER; j++) {
|
||||
switch (c) {
|
||||
case 'y': /* always accept the remote hostkey */
|
||||
if (cli_opts.always_accept_key) {
|
||||
/* twice means no checking at all */
|
||||
@@ -226,12 +206,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
break;
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
case 'i': /* an identityfile */
|
||||
/* Keep scp happy when it changes "-i file" to "-ifile" */
|
||||
if (strlen(argv[i]) > 2) {
|
||||
loadidentityfile(&argv[i][2]);
|
||||
} else {
|
||||
nextiskey = 1;
|
||||
}
|
||||
opt = OPT_AUTHKEY;
|
||||
break;
|
||||
#endif
|
||||
case 't': /* we want a pty */
|
||||
@@ -251,7 +226,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
break;
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
case 'L':
|
||||
nextislocal = 1;
|
||||
opt = OPT_LOCALTCPFWD;
|
||||
break;
|
||||
case 'g':
|
||||
opts.listen_fwd_all = 1;
|
||||
@@ -259,12 +234,12 @@ void cli_getopts(int argc, char ** argv) {
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
case 'R':
|
||||
nextisremote = 1;
|
||||
opt = OPT_REMOTETCPFWD;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
case 'B':
|
||||
nextisnetcat = 1;
|
||||
opt = OPT_NETCAT;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
@@ -322,54 +297,93 @@ void cli_getopts(int argc, char ** argv) {
|
||||
#ifndef ENABLE_CLI_LOCALTCPFWD
|
||||
case 'L':
|
||||
#endif
|
||||
case 'V':
|
||||
print_version();
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
case 'o':
|
||||
case 'b':
|
||||
next = &dummy;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"WARNING: Ignoring unknown argument '%s'\n", argv[i]);
|
||||
fprintf(stderr,
|
||||
"WARNING: Ignoring unknown option -%c\n", c);
|
||||
break;
|
||||
} /* Switch */
|
||||
|
||||
/* Now we handle args where they might be "-luser" (no spaces)*/
|
||||
if (next && strlen(argv[i]) > 2) {
|
||||
*next = &argv[i][2];
|
||||
next = NULL;
|
||||
}
|
||||
|
||||
continue; /* next argument */
|
||||
|
||||
} else {
|
||||
TRACE(("non-flag arg: '%s'", argv[i]))
|
||||
|
||||
/* Either the hostname or commands */
|
||||
|
||||
if (host_arg == NULL) {
|
||||
host_arg = argv[i];
|
||||
} else {
|
||||
|
||||
/* this is part of the commands to send - after this we
|
||||
* don't parse any more options, and flags are sent as the
|
||||
* command */
|
||||
cmdlen = 0;
|
||||
for (j = i; j < (unsigned int)argc; j++) {
|
||||
cmdlen += strlen(argv[j]) + 1; /* +1 for spaces */
|
||||
}
|
||||
/* Allocate the space */
|
||||
cli_opts.cmd = (char*)m_malloc(cmdlen);
|
||||
cli_opts.cmd[0] = '\0';
|
||||
|
||||
/* Append all the bits */
|
||||
for (j = i; j < (unsigned int)argc; j++) {
|
||||
strlcat(cli_opts.cmd, argv[j], cmdlen);
|
||||
strlcat(cli_opts.cmd, " ", cmdlen);
|
||||
}
|
||||
/* It'll be null-terminated here */
|
||||
|
||||
/* We've eaten all the options and flags */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!next && opt == OPT_OTHER) /* got a flag */
|
||||
continue;
|
||||
|
||||
if (c == '\0') {
|
||||
i++;
|
||||
j = 0;
|
||||
if (!argv[i])
|
||||
dropbear_exit("Missing argument");
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
if (opt == OPT_AUTHKEY) {
|
||||
TRACE(("opt authkey"))
|
||||
loadidentityfile(&argv[i][j], 1);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
if (opt == OPT_REMOTETCPFWD) {
|
||||
TRACE(("opt remotetcpfwd"))
|
||||
addforward(&argv[i][j], cli_opts.remotefwds);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
if (opt == OPT_LOCALTCPFWD) {
|
||||
TRACE(("opt localtcpfwd"))
|
||||
addforward(&argv[i][j], cli_opts.localfwds);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
if (opt == OPT_NETCAT) {
|
||||
TRACE(("opt netcat"))
|
||||
add_netcat(&argv[i][j]);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (next) {
|
||||
/* The previous flag set a value to assign */
|
||||
*next = &argv[i][j];
|
||||
if (*next == NULL)
|
||||
dropbear_exit("Invalid null argument");
|
||||
next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Done with options/flags; now handle the hostname (which may not
|
||||
* start with a hyphen) and optional command */
|
||||
|
||||
if (host_arg == NULL) { /* missing hostname */
|
||||
printhelp();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
TRACE(("host is: %s", host_arg))
|
||||
|
||||
if (i < (unsigned int)argc) {
|
||||
/* Build the command to send */
|
||||
cmdlen = 0;
|
||||
for (j = i; j < (unsigned int)argc; j++)
|
||||
cmdlen += strlen(argv[j]) + 1; /* +1 for spaces */
|
||||
|
||||
/* Allocate the space */
|
||||
cli_opts.cmd = (char*)m_malloc(cmdlen);
|
||||
cli_opts.cmd[0] = '\0';
|
||||
|
||||
/* Append all the bits */
|
||||
for (j = i; j < (unsigned int)argc; j++) {
|
||||
strlcat(cli_opts.cmd, argv[j], cmdlen);
|
||||
strlcat(cli_opts.cmd, " ", cmdlen);
|
||||
}
|
||||
/* It'll be null-terminated here */
|
||||
TRACE(("cmd is: %s", cli_opts.cmd))
|
||||
}
|
||||
|
||||
/* And now a few sanity checks and setup */
|
||||
@@ -378,11 +392,6 @@ void cli_getopts(int argc, char ** argv) {
|
||||
parse_ciphers_macs();
|
||||
#endif
|
||||
|
||||
if (host_arg == NULL) {
|
||||
printhelp();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
if (cli_opts.proxycmd) {
|
||||
/* To match the common path of m_freeing it */
|
||||
@@ -437,6 +446,14 @@ void cli_getopts(int argc, char ** argv) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DROPBEAR_DEFAULT_CLI_AUTHKEY) && defined(ENABLE_CLI_PUBKEY_AUTH)
|
||||
{
|
||||
char *expand_path = expand_homedir_path(DROPBEAR_DEFAULT_CLI_AUTHKEY);
|
||||
loadidentityfile(expand_path, 0);
|
||||
m_free(expand_path);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The hostname gets set up last, since
|
||||
* in multi-hop mode it will require knowledge
|
||||
* of other flags such as -i */
|
||||
@@ -448,14 +465,18 @@ void cli_getopts(int argc, char ** argv) {
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
static void loadidentityfile(const char* filename) {
|
||||
static void loadidentityfile(const char* filename, int warnfail) {
|
||||
sign_key *key;
|
||||
enum signkey_type keytype;
|
||||
|
||||
TRACE(("loadidentityfile %s", filename))
|
||||
|
||||
key = new_sign_key();
|
||||
keytype = DROPBEAR_SIGNKEY_ANY;
|
||||
if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
|
||||
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
|
||||
if (warnfail) {
|
||||
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
|
||||
}
|
||||
sign_key_free(key);
|
||||
} else {
|
||||
key->type = keytype;
|
||||
@@ -476,11 +497,14 @@ multihop_passthrough_args() {
|
||||
m_list_elem *iter;
|
||||
/* Fill out -i, -y, -W options that make sense for all
|
||||
* the intermediate processes */
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
|
||||
{
|
||||
sign_key * key = (sign_key*)iter->item;
|
||||
len += 3 + strlen(key->filename);
|
||||
}
|
||||
#endif /* ENABLE_CLI_PUBKEY_AUTH */
|
||||
|
||||
len += 30; /* space for -W <size>, terminator. */
|
||||
ret = m_malloc(len);
|
||||
total = 0;
|
||||
@@ -502,6 +526,7 @@ multihop_passthrough_args() {
|
||||
total += written;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
|
||||
{
|
||||
sign_key * key = (sign_key*)iter->item;
|
||||
@@ -510,6 +535,7 @@ multihop_passthrough_args() {
|
||||
dropbear_assert((unsigned int)written < size);
|
||||
total += written;
|
||||
}
|
||||
#endif /* ENABLE_CLI_PUBKEY_AUTH */
|
||||
|
||||
/* if args were passed, total will be not zero, and it will have a space at the end, so remove that */
|
||||
if (total > 0)
|
||||
@@ -587,7 +613,7 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
|
||||
passthrough_args, remainder);
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* The stream will be incompressible since it's encrypted. */
|
||||
opts.enable_compress = 0;
|
||||
opts.compress_mode = DROPBEAR_COMPRESS_OFF;
|
||||
#endif
|
||||
m_free(passthrough_args);
|
||||
}
|
||||
@@ -617,7 +643,7 @@ static void parse_hostname(const char* orighostarg) {
|
||||
cli_opts.username = m_strdup(cli_opts.own_user);
|
||||
}
|
||||
|
||||
port = strchr(cli_opts.remotehost, '%');
|
||||
port = strchr(cli_opts.remotehost, '^');
|
||||
if (!port) {
|
||||
/* legacy separator */
|
||||
port = strchr(cli_opts.remotehost, '/');
|
||||
@@ -676,11 +702,13 @@ static void fill_own_user() {
|
||||
uid = getuid();
|
||||
|
||||
pw = getpwuid(uid);
|
||||
if (pw == NULL || pw->pw_name == NULL) {
|
||||
dropbear_exit("Unknown own user");
|
||||
if (pw && pw->pw_name != NULL) {
|
||||
cli_opts.own_user = m_strdup(pw->pw_name);
|
||||
} else {
|
||||
dropbear_log(LOG_INFO, "Warning: failed to identify current user. Trying anyway.");
|
||||
cli_opts.own_user = m_strdup("unknown");
|
||||
}
|
||||
|
||||
cli_opts.own_user = m_strdup(pw->pw_name);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
|
||||
@@ -37,13 +37,15 @@
|
||||
#include "chansession.h"
|
||||
#include "agentfwd.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "netio.h"
|
||||
|
||||
static void cli_remoteclosed();
|
||||
static void cli_remoteclosed() ATTRIB_NORETURN;
|
||||
static void cli_sessionloop();
|
||||
static void cli_session_init();
|
||||
static void cli_finished();
|
||||
static void cli_finished() ATTRIB_NORETURN;
|
||||
static void recv_msg_service_accept(void);
|
||||
static void cli_session_cleanup(void);
|
||||
static void recv_msg_global_request_cli(void);
|
||||
|
||||
struct clientsession cli_ses; /* GLOBAL */
|
||||
|
||||
@@ -68,9 +70,16 @@ static const packettype cli_packettypes[] = {
|
||||
{SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure},
|
||||
{SSH_MSG_USERAUTH_BANNER, recv_msg_userauth_banner}, /* client */
|
||||
{SSH_MSG_USERAUTH_SPECIFIC_60, recv_msg_userauth_specific_60}, /* client */
|
||||
{SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_cli},
|
||||
{SSH_MSG_CHANNEL_SUCCESS, ignore_recv_response},
|
||||
{SSH_MSG_CHANNEL_FAILURE, ignore_recv_response},
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
{SSH_MSG_REQUEST_SUCCESS, cli_recv_msg_request_success}, /* client */
|
||||
{SSH_MSG_REQUEST_FAILURE, cli_recv_msg_request_failure}, /* client */
|
||||
#else
|
||||
/* For keepalive */
|
||||
{SSH_MSG_REQUEST_SUCCESS, ignore_recv_response},
|
||||
{SSH_MSG_REQUEST_FAILURE, ignore_recv_response},
|
||||
#endif
|
||||
{0, 0} /* End */
|
||||
};
|
||||
@@ -85,21 +94,38 @@ static const struct ChanType *cli_chantypes[] = {
|
||||
NULL /* Null termination */
|
||||
};
|
||||
|
||||
void cli_session(int sock_in, int sock_out) {
|
||||
void cli_connected(int result, int sock, void* userdata, const char *errstring)
|
||||
{
|
||||
struct sshsession *myses = userdata;
|
||||
if (result == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Connect failed: %s", errstring);
|
||||
}
|
||||
myses->sock_in = myses->sock_out = sock;
|
||||
update_channel_prio();
|
||||
}
|
||||
|
||||
void cli_session(int sock_in, int sock_out, struct dropbear_progress_connection *progress) {
|
||||
|
||||
common_session_init(sock_in, sock_out);
|
||||
|
||||
if (progress) {
|
||||
connect_set_writequeue(progress, &ses.writequeue);
|
||||
}
|
||||
|
||||
chaninitialise(cli_chantypes);
|
||||
|
||||
/* Set up cli_ses vars */
|
||||
cli_session_init();
|
||||
|
||||
|
||||
/* Ready to go */
|
||||
sessinitdone = 1;
|
||||
|
||||
/* Exchange identification */
|
||||
send_session_identification();
|
||||
|
||||
kexfirstinitialise(); /* initialise the kex state */
|
||||
|
||||
send_msg_kexinit();
|
||||
|
||||
session_loop(cli_sessionloop);
|
||||
@@ -228,6 +254,10 @@ static void cli_sessionloop() {
|
||||
cli_ses.state = USERAUTH_REQ_SENT;
|
||||
TRACE(("leave cli_sessionloop: sent userauth methods req"))
|
||||
return;
|
||||
|
||||
case USERAUTH_REQ_SENT:
|
||||
TRACE(("leave cli_sessionloop: waiting, req_sent"))
|
||||
return;
|
||||
|
||||
case USERAUTH_FAIL_RCVD:
|
||||
if (cli_auth_try() == DROPBEAR_FAILURE) {
|
||||
@@ -344,10 +374,10 @@ static void cli_remoteclosed() {
|
||||
/* Operates in-place turning dirty (untrusted potentially containing control
|
||||
* characters) text into clean text.
|
||||
* Note: this is safe only with ascii - other charsets could have problems. */
|
||||
void cleantext(unsigned char* dirtytext) {
|
||||
void cleantext(char* dirtytext) {
|
||||
|
||||
unsigned int i, j;
|
||||
unsigned char c;
|
||||
char c;
|
||||
|
||||
j = 0;
|
||||
for (i = 0; dirtytext[i] != '\0'; i++) {
|
||||
@@ -362,3 +392,9 @@ void cleantext(unsigned char* dirtytext) {
|
||||
/* Null terminate */
|
||||
dirtytext[j] = '\0';
|
||||
}
|
||||
|
||||
static void recv_msg_global_request_cli(void) {
|
||||
TRACE(("recv_msg_global_request_cli"))
|
||||
/* Send a proper rejection */
|
||||
send_msg_request_failure();
|
||||
}
|
||||
|
||||
42
cli-tcpfwd.c
42
cli-tcpfwd.c
@@ -30,6 +30,7 @@
|
||||
#include "runopts.h"
|
||||
#include "session.h"
|
||||
#include "ssh.h"
|
||||
#include "netio.h"
|
||||
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
static int newtcpforwarded(struct Channel * channel);
|
||||
@@ -52,7 +53,7 @@ static int cli_localtcp(const char* listenaddr,
|
||||
static const struct ChanType cli_chan_tcplocal = {
|
||||
1, /* sepfds */
|
||||
"direct-tcpip",
|
||||
NULL,
|
||||
tcp_prio_inithandler,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
@@ -161,9 +162,10 @@ void cli_recv_msg_request_success() {
|
||||
if (!fwd->have_reply) {
|
||||
fwd->have_reply = 1;
|
||||
if (fwd->listenport == 0) {
|
||||
/* The server should let us know which port was allocated if we requestd port 0 */
|
||||
/* The server should let us know which port was allocated if we requested port 0 */
|
||||
int allocport = buf_getint(ses.payload);
|
||||
if (allocport > 0) {
|
||||
fwd->listenport = allocport;
|
||||
dropbear_log(LOG_INFO, "Allocated port %d for remote forward to %s:%d",
|
||||
allocport, fwd->connectaddr, fwd->connectport);
|
||||
}
|
||||
@@ -214,43 +216,47 @@ static int newtcpforwarded(struct Channel * channel) {
|
||||
m_list_elem * iter = NULL;
|
||||
struct TCPFwdEntry *fwd;
|
||||
char portstring[NI_MAXSERV];
|
||||
int sock;
|
||||
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
|
||||
|
||||
origaddr = buf_getstring(ses.payload, NULL);
|
||||
origport = buf_getint(ses.payload);
|
||||
|
||||
/* Find which port corresponds */
|
||||
/* Find which port corresponds. First try and match address as well as port,
|
||||
in case they want to forward different ports separately ... */
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (origport == fwd->listenport
|
||||
&& (strcmp(origaddr, fwd->listenaddr) == 0)) {
|
||||
&& strcmp(origaddr, fwd->listenaddr) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iter)
|
||||
{
|
||||
/* ... otherwise try to generically match the only forwarded port
|
||||
without address (also handles ::1 vs 127.0.0.1 vs localhost case).
|
||||
rfc4254 is vague about the definition of "address that was connected" */
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (origport == fwd->listenport) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (iter == NULL) {
|
||||
/* We didn't request forwarding on that port */
|
||||
cleantext(origaddr);
|
||||
cleantext(origaddr);
|
||||
dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"",
|
||||
origaddr, origport);
|
||||
goto out;
|
||||
}
|
||||
|
||||
snprintf(portstring, sizeof(portstring), "%d", fwd->connectport);
|
||||
sock = connect_remote(fwd->connectaddr, portstring, 1, NULL);
|
||||
if (sock < 0) {
|
||||
TRACE(("leave newtcpdirect: sock failed"))
|
||||
err = SSH_OPEN_CONNECT_FAILED;
|
||||
goto out;
|
||||
}
|
||||
channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel);
|
||||
|
||||
ses.maxfd = MAX(ses.maxfd, sock);
|
||||
|
||||
/* We don't set readfd, that will get set after the connection's
|
||||
* progress succeeds */
|
||||
channel->writefd = sock;
|
||||
channel->initconn = 1;
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
|
||||
|
||||
err = SSH_OPEN_IN_PROGRESS;
|
||||
|
||||
|
||||
@@ -84,10 +84,14 @@ const struct dropbear_cipher dropbear_nocipher =
|
||||
|
||||
/* A few void* s are required to silence warnings
|
||||
* about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
|
||||
#ifdef DROPBEAR_ENABLE_CBC_MODE
|
||||
const struct dropbear_cipher_mode dropbear_mode_cbc =
|
||||
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
|
||||
const struct dropbear_cipher_mode dropbear_mode_none =
|
||||
{void_start, void_cipher, void_cipher};
|
||||
|
||||
#ifdef DROPBEAR_ENABLE_CTR_MODE
|
||||
/* a wrapper to make ctr_start and cbc_start look the same */
|
||||
static int dropbear_big_endian_ctr_start(int cipher,
|
||||
@@ -98,7 +102,7 @@ static int dropbear_big_endian_ctr_start(int cipher,
|
||||
}
|
||||
const struct dropbear_cipher_mode dropbear_mode_ctr =
|
||||
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
|
||||
#endif
|
||||
#endif /* DROPBEAR_ENABLE_CTR_MODE */
|
||||
|
||||
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
|
||||
{&hash_desc, keysize, hashsize} */
|
||||
@@ -137,21 +141,24 @@ algo_type sshciphers[] = {
|
||||
#ifdef DROPBEAR_AES128
|
||||
{"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_AES256
|
||||
{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH_CTR
|
||||
/* twofish ctr is conditional as it hasn't been tested for interoperability, see options.h */
|
||||
#ifdef DROPBEAR_TWOFISH256
|
||||
{"twofish256-ctr", 0, &dropbear_twofish256, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH128
|
||||
{"twofish128-ctr", 0, &dropbear_twofish128, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#endif /* DROPBEAR_TWOFISH_CTR */
|
||||
#endif /* DROPBEAR_ENABLE_CTR_MODE */
|
||||
|
||||
/* CBC modes are always enabled */
|
||||
#ifdef DROPBEAR_ENABLE_CBC_MODE
|
||||
#ifdef DROPBEAR_AES128
|
||||
{"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_AES256
|
||||
{"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
@@ -162,9 +169,16 @@ algo_type sshciphers[] = {
|
||||
#ifdef DROPBEAR_TWOFISH128
|
||||
{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH
|
||||
{"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
#ifdef DROPBEAR_NONE_CIPHER
|
||||
{"none", 0, (void*)&dropbear_nocipher, 1, &dropbear_mode_none},
|
||||
#endif
|
||||
@@ -172,18 +186,18 @@ algo_type sshciphers[] = {
|
||||
};
|
||||
|
||||
algo_type sshhashes[] = {
|
||||
#ifdef DROPBEAR_SHA2_256_HMAC
|
||||
{"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_512_HMAC
|
||||
{"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA1_96_HMAC
|
||||
{"hmac-sha1-96", 0, &dropbear_sha1_96, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA1_HMAC
|
||||
{"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_256_HMAC
|
||||
{"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_512_HMAC
|
||||
{"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
{"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL},
|
||||
#endif
|
||||
@@ -195,7 +209,13 @@ algo_type sshhashes[] = {
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
algo_type ssh_compress[] = {
|
||||
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
|
||||
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
algo_type ssh_delaycompress[] = {
|
||||
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
@@ -265,8 +285,8 @@ algo_type sshkex[] = {
|
||||
{"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
{"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL},
|
||||
{"diffie-hellman-group14-sha1", 0, &kex_dh_group14, 1, NULL},
|
||||
{"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL},
|
||||
#ifdef USE_KEXGUESS2
|
||||
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
|
||||
#endif
|
||||
@@ -305,10 +325,10 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
|
||||
buf_putbyte(algolist, ',');
|
||||
donefirst = 1;
|
||||
len = strlen(localalgos[i].name);
|
||||
buf_putbytes(algolist, localalgos[i].name, len);
|
||||
buf_putbytes(algolist, (const unsigned char *) localalgos[i].name, len);
|
||||
}
|
||||
}
|
||||
buf_putstring(buf, algolist->data, algolist->len);
|
||||
buf_putstring(buf, (const char*)algolist->data, algolist->len);
|
||||
buf_free(algolist);
|
||||
}
|
||||
|
||||
@@ -321,12 +341,12 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
enum kexguess2_used *kexguess2, int *goodguess)
|
||||
{
|
||||
|
||||
unsigned char * algolist = NULL;
|
||||
const unsigned char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
|
||||
char * algolist = NULL;
|
||||
const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
unsigned int remotecount, localcount, clicount, servcount, i, j;
|
||||
algo_type * ret = NULL;
|
||||
const unsigned char **clinames, **servnames;
|
||||
const char **clinames, **servnames;
|
||||
|
||||
if (goodguess) {
|
||||
*goodguess = 0;
|
||||
@@ -471,7 +491,7 @@ algolist_string(algo_type algos[])
|
||||
buf_setpos(b, b->len);
|
||||
buf_putbyte(b, '\0');
|
||||
buf_setpos(b, 4);
|
||||
ret_list = m_strdup(buf_getptr(b, b->len - b->pos));
|
||||
ret_list = m_strdup((const char *) buf_getptr(b, b->len - b->pos));
|
||||
buf_free(b);
|
||||
return ret_list;
|
||||
}
|
||||
|
||||
383
common-channel.c
383
common-channel.c
@@ -35,20 +35,21 @@
|
||||
#include "ssh.h"
|
||||
#include "listener.h"
|
||||
#include "runopts.h"
|
||||
#include "netio.h"
|
||||
|
||||
static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
|
||||
const unsigned char *text, const unsigned char *lang);
|
||||
const char *text, const char *lang);
|
||||
static void send_msg_channel_open_confirmation(struct Channel* channel,
|
||||
unsigned int recvwindow,
|
||||
unsigned int recvmaxpacket);
|
||||
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf);
|
||||
static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
|
||||
const unsigned char *moredata, unsigned int *morelen);
|
||||
static void send_msg_channel_window_adjust(struct Channel *channel,
|
||||
unsigned int incr);
|
||||
static void send_msg_channel_data(struct Channel *channel, int isextended);
|
||||
static void send_msg_channel_eof(struct Channel *channel);
|
||||
static void send_msg_channel_close(struct Channel *channel);
|
||||
static void remove_channel(struct Channel *channel);
|
||||
static void check_in_progress(struct Channel *channel);
|
||||
static unsigned int write_pending(struct Channel * channel);
|
||||
static void check_close(struct Channel *channel);
|
||||
static void close_chan_fd(struct Channel *channel, int fd, int how);
|
||||
@@ -59,6 +60,13 @@ static void close_chan_fd(struct Channel *channel, int fd, int how);
|
||||
#define ERRFD_IS_READ(channel) ((channel)->extrabuf == NULL)
|
||||
#define ERRFD_IS_WRITE(channel) (!ERRFD_IS_READ(channel))
|
||||
|
||||
/* allow space for:
|
||||
* 1 byte byte SSH_MSG_CHANNEL_DATA
|
||||
* 4 bytes uint32 recipient channel
|
||||
* 4 bytes string data
|
||||
*/
|
||||
#define RECV_MAX_CHANNEL_DATA_LEN (RECV_MAX_PAYLOAD_LEN-(1+4+4))
|
||||
|
||||
/* Initialise all the channels */
|
||||
void chaninitialise(const struct ChanType *chantypes[]) {
|
||||
|
||||
@@ -92,15 +100,6 @@ void chancleanup() {
|
||||
TRACE(("leave chancleanup"))
|
||||
}
|
||||
|
||||
static void
|
||||
chan_initwritebuf(struct Channel *channel)
|
||||
{
|
||||
dropbear_assert(channel->writebuf->size == 0 && channel->recvwindow == 0);
|
||||
cbuf_free(channel->writebuf);
|
||||
channel->writebuf = cbuf_new(opts.recv_window);
|
||||
channel->recvwindow = opts.recv_window;
|
||||
}
|
||||
|
||||
/* Create a new channel entry, send a reply confirm or failure */
|
||||
/* If remotechan, transwindow and transmaxpacket are not know (for a new
|
||||
* outgoing connection, with them to be filled on confirmation), they should
|
||||
@@ -156,16 +155,17 @@ static struct Channel* newchannel(unsigned int remotechan,
|
||||
newchan->writefd = FD_UNINIT;
|
||||
newchan->readfd = FD_UNINIT;
|
||||
newchan->errfd = FD_CLOSED; /* this isn't always set to start with */
|
||||
newchan->initconn = 0;
|
||||
newchan->await_open = 0;
|
||||
newchan->flushing = 0;
|
||||
|
||||
newchan->writebuf = cbuf_new(0); /* resized later by chan_initwritebuf */
|
||||
newchan->recvwindow = 0;
|
||||
newchan->writebuf = cbuf_new(opts.recv_window);
|
||||
newchan->recvwindow = opts.recv_window;
|
||||
|
||||
newchan->extrabuf = NULL; /* The user code can set it up */
|
||||
newchan->recvdonelen = 0;
|
||||
newchan->recvmaxpacket = RECV_MAX_PAYLOAD_LEN;
|
||||
newchan->recvmaxpacket = RECV_MAX_CHANNEL_DATA_LEN;
|
||||
|
||||
newchan->prio = DROPBEAR_CHANNEL_PRIO_EARLY; /* inithandler sets it */
|
||||
|
||||
ses.channels[i] = newchan;
|
||||
ses.chancount++;
|
||||
@@ -201,11 +201,14 @@ struct Channel* getchannel() {
|
||||
/* Iterate through the channels, performing IO if available */
|
||||
void channelio(fd_set *readfds, fd_set *writefds) {
|
||||
|
||||
/* Listeners such as TCP, X11, agent-auth */
|
||||
struct Channel *channel;
|
||||
unsigned int i;
|
||||
|
||||
/* foreach channel */
|
||||
for (i = 0; i < ses.chansize; i++) {
|
||||
/* Close checking only needs to occur for channels that had IO events */
|
||||
int do_check_close = 0;
|
||||
|
||||
channel = ses.channels[i];
|
||||
if (channel == NULL) {
|
||||
@@ -217,6 +220,7 @@ void channelio(fd_set *readfds, fd_set *writefds) {
|
||||
if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) {
|
||||
TRACE(("send normal readfd"))
|
||||
send_msg_channel_data(channel, 0);
|
||||
do_check_close = 1;
|
||||
}
|
||||
|
||||
/* read stderr data and send it over the wire */
|
||||
@@ -224,31 +228,35 @@ void channelio(fd_set *readfds, fd_set *writefds) {
|
||||
&& FD_ISSET(channel->errfd, readfds)) {
|
||||
TRACE(("send normal errfd"))
|
||||
send_msg_channel_data(channel, 1);
|
||||
do_check_close = 1;
|
||||
}
|
||||
|
||||
/* write to program/pipe stdin */
|
||||
if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) {
|
||||
if (channel->initconn) {
|
||||
/* XXX should this go somewhere cleaner? */
|
||||
check_in_progress(channel);
|
||||
continue; /* Important not to use the channel after
|
||||
check_in_progress(), as it may be NULL */
|
||||
}
|
||||
writechannel(channel, channel->writefd, channel->writebuf);
|
||||
writechannel(channel, channel->writefd, channel->writebuf, NULL, NULL);
|
||||
do_check_close = 1;
|
||||
}
|
||||
|
||||
/* stderr for client mode */
|
||||
if (ERRFD_IS_WRITE(channel)
|
||||
&& channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) {
|
||||
writechannel(channel, channel->errfd, channel->extrabuf);
|
||||
writechannel(channel, channel->errfd, channel->extrabuf, NULL, NULL);
|
||||
do_check_close = 1;
|
||||
}
|
||||
|
||||
if (ses.channel_signal_pending) {
|
||||
/* SIGCHLD can change channel state for server sessions */
|
||||
do_check_close = 1;
|
||||
}
|
||||
|
||||
/* handle any channel closing etc */
|
||||
check_close(channel);
|
||||
|
||||
if (do_check_close) {
|
||||
check_close(channel);
|
||||
}
|
||||
}
|
||||
|
||||
/* Listeners such as TCP, X11, agent-auth */
|
||||
ses.channel_signal_pending = 0;
|
||||
|
||||
#ifdef USING_LISTENERS
|
||||
handle_listeners(readfds);
|
||||
#endif
|
||||
@@ -352,27 +360,26 @@ static void check_close(struct Channel *channel) {
|
||||
* if so, set up the channel properly. Otherwise, the channel is cleaned up, so
|
||||
* it is important that the channel reference isn't used after a call to this
|
||||
* function */
|
||||
static void check_in_progress(struct Channel *channel) {
|
||||
void channel_connect_done(int result, int sock, void* user_data, const char* UNUSED(errstring)) {
|
||||
|
||||
int val;
|
||||
socklen_t vallen = sizeof(val);
|
||||
struct Channel *channel = user_data;
|
||||
|
||||
TRACE(("enter check_in_progress"))
|
||||
TRACE(("enter channel_connect_done"))
|
||||
|
||||
if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen)
|
||||
|| val != 0) {
|
||||
send_msg_channel_open_failure(channel->remotechan,
|
||||
SSH_OPEN_CONNECT_FAILED, "", "");
|
||||
close(channel->writefd);
|
||||
remove_channel(channel);
|
||||
TRACE(("leave check_in_progress: fail"))
|
||||
} else {
|
||||
chan_initwritebuf(channel);
|
||||
if (result == DROPBEAR_SUCCESS)
|
||||
{
|
||||
channel->readfd = channel->writefd = sock;
|
||||
channel->conn_pending = NULL;
|
||||
send_msg_channel_open_confirmation(channel, channel->recvwindow,
|
||||
channel->recvmaxpacket);
|
||||
channel->readfd = channel->writefd;
|
||||
channel->initconn = 0;
|
||||
TRACE(("leave check_in_progress: success"))
|
||||
TRACE(("leave channel_connect_done: success"))
|
||||
}
|
||||
else
|
||||
{
|
||||
send_msg_channel_open_failure(channel->remotechan,
|
||||
SSH_OPEN_CONNECT_FAILED, "", "");
|
||||
remove_channel(channel);
|
||||
TRACE(("leave check_in_progress: fail"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,7 +387,7 @@ static void check_in_progress(struct Channel *channel) {
|
||||
/* Send the close message and set the channel as closed */
|
||||
static void send_msg_channel_close(struct Channel *channel) {
|
||||
|
||||
TRACE(("enter send_msg_channel_close %p", channel))
|
||||
TRACE(("enter send_msg_channel_close %p", (void*)channel))
|
||||
if (channel->type->closehandler
|
||||
&& !channel->close_handler_done) {
|
||||
channel->type->closehandler(channel);
|
||||
@@ -418,35 +425,119 @@ static void send_msg_channel_eof(struct Channel *channel) {
|
||||
TRACE(("leave send_msg_channel_eof"))
|
||||
}
|
||||
|
||||
/* Called to write data out to the local side of the channel.
|
||||
* Only called when we know we can write to a channel, writes as much as
|
||||
* possible */
|
||||
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
|
||||
#ifndef HAVE_WRITEV
|
||||
static int writechannel_fallback(struct Channel* channel, int fd, circbuffer *cbuf,
|
||||
const unsigned char *UNUSED(moredata), unsigned int *morelen) {
|
||||
|
||||
int len, maxlen;
|
||||
unsigned char *circ_p1, *circ_p2;
|
||||
unsigned int circ_len1, circ_len2;
|
||||
ssize_t written;
|
||||
|
||||
TRACE(("enter writechannel fd %d", fd))
|
||||
|
||||
maxlen = cbuf_readlen(cbuf);
|
||||
|
||||
/* Write the data out */
|
||||
len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
|
||||
if (len <= 0) {
|
||||
TRACE(("errno %d len %d", errno, len))
|
||||
if (len < 0 && errno != EINTR) {
|
||||
close_chan_fd(channel, fd, SHUT_WR);
|
||||
}
|
||||
TRACE(("leave writechannel: len <= 0"))
|
||||
return;
|
||||
if (morelen) {
|
||||
/* fallback doesn't consume moredata */
|
||||
*morelen = 0;
|
||||
}
|
||||
TRACE(("writechannel wrote %d", len))
|
||||
|
||||
cbuf_incrread(cbuf, len);
|
||||
channel->recvdonelen += len;
|
||||
/* Write the first portion of the circular buffer */
|
||||
cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2);
|
||||
written = write(fd, circ_p1, circ_len1);
|
||||
if (written < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
TRACE(("channel IO write error fd %d %s", fd, strerror(errno)))
|
||||
close_chan_fd(channel, fd, SHUT_WR);
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
}
|
||||
cbuf_incrread(cbuf, written);
|
||||
channel->recvdonelen += written;
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
#endif /* !HAVE_WRITEV */
|
||||
|
||||
#ifdef HAVE_WRITEV
|
||||
static int writechannel_writev(struct Channel* channel, int fd, circbuffer *cbuf,
|
||||
const unsigned char *moredata, unsigned int *morelen) {
|
||||
|
||||
struct iovec iov[3];
|
||||
unsigned char *circ_p1, *circ_p2;
|
||||
unsigned int circ_len1, circ_len2;
|
||||
int io_count = 0;
|
||||
int cbuf_written;
|
||||
ssize_t written;
|
||||
|
||||
cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2);
|
||||
|
||||
if (circ_len1 > 0) {
|
||||
TRACE(("circ1 %d", circ_len1))
|
||||
iov[io_count].iov_base = circ_p1;
|
||||
iov[io_count].iov_len = circ_len1;
|
||||
io_count++;
|
||||
}
|
||||
|
||||
if (circ_len2 > 0) {
|
||||
TRACE(("circ2 %d", circ_len2))
|
||||
iov[io_count].iov_base = circ_p2;
|
||||
iov[io_count].iov_len = circ_len2;
|
||||
io_count++;
|
||||
}
|
||||
|
||||
if (morelen) {
|
||||
assert(moredata);
|
||||
TRACE(("more %d", *morelen))
|
||||
iov[io_count].iov_base = (void*)moredata;
|
||||
iov[io_count].iov_len = *morelen;
|
||||
io_count++;
|
||||
}
|
||||
|
||||
if (io_count == 0) {
|
||||
/* writechannel may sometimes be called twice in a main loop iteration.
|
||||
From common_recv_msg_channel_data() then channelio().
|
||||
The second call may not have any data to write, so we just return. */
|
||||
TRACE(("leave writechannel, no data"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
if (morelen) {
|
||||
/* Default return value, none consumed */
|
||||
*morelen = 0;
|
||||
}
|
||||
|
||||
written = writev(fd, iov, io_count);
|
||||
|
||||
if (written < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
TRACE(("channel IO write error fd %d %s", fd, strerror(errno)))
|
||||
close_chan_fd(channel, fd, SHUT_WR);
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
cbuf_written = MIN(circ_len1+circ_len2, (unsigned int)written);
|
||||
cbuf_incrread(cbuf, cbuf_written);
|
||||
if (morelen) {
|
||||
*morelen = written - cbuf_written;
|
||||
}
|
||||
channel->recvdonelen += written;
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
#endif /* HAVE_WRITEV */
|
||||
|
||||
/* Called to write data out to the local side of the channel.
|
||||
Writes the circular buffer contents and also the "moredata" buffer
|
||||
if not null. Will ignore EAGAIN.
|
||||
Returns DROPBEAR_FAILURE if writing to fd had an error and the channel is being closed, DROPBEAR_SUCCESS otherwise */
|
||||
static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
|
||||
const unsigned char *moredata, unsigned int *morelen) {
|
||||
int ret = DROPBEAR_SUCCESS;
|
||||
TRACE(("enter writechannel fd %d", fd))
|
||||
#ifdef HAVE_WRITEV
|
||||
ret = writechannel_writev(channel, fd, cbuf, moredata, morelen);
|
||||
#else
|
||||
ret = writechannel_fallback(channel, fd, cbuf, moredata, morelen);
|
||||
#endif
|
||||
|
||||
/* Window adjust handling */
|
||||
if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
|
||||
/* Set it back to max window */
|
||||
send_msg_channel_window_adjust(channel, channel->recvdonelen);
|
||||
channel->recvwindow += channel->recvdonelen;
|
||||
channel->recvdonelen = 0;
|
||||
@@ -458,11 +549,13 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
|
||||
channel->recvwindow <= cbuf_getavail(channel->extrabuf));
|
||||
|
||||
TRACE(("leave writechannel"))
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Set the file descriptors for the main select in session.c
|
||||
* This avoid channels which don't have any window available, are closed, etc*/
|
||||
void setchannelfds(fd_set *readfds, fd_set *writefds) {
|
||||
void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads) {
|
||||
|
||||
unsigned int i;
|
||||
struct Channel * channel;
|
||||
@@ -474,8 +567,13 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Stuff to put over the wire */
|
||||
if (channel->transwindow > 0) {
|
||||
/* Stuff to put over the wire.
|
||||
Avoid queueing data to send if we're in the middle of a
|
||||
key re-exchange (!dataallowed), but still read from the
|
||||
FD if there's the possibility of "~."" to kill an
|
||||
interactive session (the read_mangler) */
|
||||
if (channel->transwindow > 0
|
||||
&& ((ses.dataallowed && allow_reads) || channel->read_mangler)) {
|
||||
|
||||
if (channel->readfd >= 0) {
|
||||
FD_SET(channel->readfd, readfds);
|
||||
@@ -487,8 +585,7 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
|
||||
}
|
||||
|
||||
/* Stuff from the wire */
|
||||
if (channel->initconn
|
||||
||(channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0)) {
|
||||
if (channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0) {
|
||||
FD_SET(channel->writefd, writefds);
|
||||
}
|
||||
|
||||
@@ -555,14 +652,16 @@ static void remove_channel(struct Channel * channel) {
|
||||
}
|
||||
|
||||
|
||||
/* close the FDs in case they haven't been done
|
||||
* yet (they might have been shutdown etc) */
|
||||
TRACE(("CLOSE writefd %d", channel->writefd))
|
||||
close(channel->writefd);
|
||||
TRACE(("CLOSE readfd %d", channel->readfd))
|
||||
close(channel->readfd);
|
||||
TRACE(("CLOSE errfd %d", channel->errfd))
|
||||
close(channel->errfd);
|
||||
if (IS_DROPBEAR_SERVER || (channel->writefd != STDOUT_FILENO)) {
|
||||
/* close the FDs in case they haven't been done
|
||||
* yet (they might have been shutdown etc) */
|
||||
TRACE(("CLOSE writefd %d", channel->writefd))
|
||||
m_close(channel->writefd);
|
||||
TRACE(("CLOSE readfd %d", channel->readfd))
|
||||
m_close(channel->readfd);
|
||||
TRACE(("CLOSE errfd %d", channel->errfd))
|
||||
m_close(channel->errfd);
|
||||
}
|
||||
|
||||
if (!channel->close_handler_done
|
||||
&& channel->type->closehandler) {
|
||||
@@ -570,10 +669,16 @@ static void remove_channel(struct Channel * channel) {
|
||||
channel->close_handler_done = 1;
|
||||
}
|
||||
|
||||
if (channel->conn_pending) {
|
||||
cancel_connect(channel->conn_pending);
|
||||
}
|
||||
|
||||
ses.channels[channel->index] = NULL;
|
||||
m_free(channel);
|
||||
ses.chancount--;
|
||||
|
||||
update_channel_prio();
|
||||
|
||||
TRACE(("leave remove_channel"))
|
||||
}
|
||||
|
||||
@@ -585,7 +690,7 @@ void recv_msg_channel_request() {
|
||||
|
||||
channel = getchannel();
|
||||
|
||||
TRACE(("enter recv_msg_channel_request %p", channel))
|
||||
TRACE(("enter recv_msg_channel_request %p", (void*)channel))
|
||||
|
||||
if (channel->sent_close) {
|
||||
TRACE(("leave recv_msg_channel_request: already closed channel"))
|
||||
@@ -596,7 +701,12 @@ void recv_msg_channel_request() {
|
||||
&& !channel->close_handler_done) {
|
||||
channel->type->reqhandler(channel);
|
||||
} else {
|
||||
send_msg_channel_failure(channel);
|
||||
int wantreply;
|
||||
buf_eatstring(ses.payload);
|
||||
wantreply = buf_getbool(ses.payload);
|
||||
if (wantreply) {
|
||||
send_msg_channel_failure(channel);
|
||||
}
|
||||
}
|
||||
|
||||
TRACE(("leave recv_msg_channel_request"))
|
||||
@@ -713,6 +823,8 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
|
||||
unsigned int maxdata;
|
||||
unsigned int buflen;
|
||||
unsigned int len;
|
||||
unsigned int consumed;
|
||||
int res;
|
||||
|
||||
TRACE(("enter recv_msg_channel_data"))
|
||||
|
||||
@@ -739,25 +851,36 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
|
||||
dropbear_exit("Oversized packet");
|
||||
}
|
||||
|
||||
/* We may have to run throught twice, if the buffer wraps around. Can't
|
||||
* just "leave it for next time" like with writechannel, since this
|
||||
* is payload data */
|
||||
len = datalen;
|
||||
while (len > 0) {
|
||||
buflen = cbuf_writelen(cbuf);
|
||||
buflen = MIN(buflen, len);
|
||||
|
||||
memcpy(cbuf_writeptr(cbuf, buflen),
|
||||
buf_getptr(ses.payload, buflen), buflen);
|
||||
cbuf_incrwrite(cbuf, buflen);
|
||||
buf_incrpos(ses.payload, buflen);
|
||||
len -= buflen;
|
||||
}
|
||||
|
||||
dropbear_assert(channel->recvwindow >= datalen);
|
||||
channel->recvwindow -= datalen;
|
||||
dropbear_assert(channel->recvwindow <= opts.recv_window);
|
||||
|
||||
/* Attempt to write the data immediately without having to put it in the circular buffer */
|
||||
consumed = datalen;
|
||||
res = writechannel(channel, fd, cbuf, buf_getptr(ses.payload, datalen), &consumed);
|
||||
|
||||
datalen -= consumed;
|
||||
buf_incrpos(ses.payload, consumed);
|
||||
|
||||
|
||||
/* We may have to run throught twice, if the buffer wraps around. Can't
|
||||
* just "leave it for next time" like with writechannel, since this
|
||||
* is payload data.
|
||||
* If the writechannel() failed then remaining data is discarded */
|
||||
if (res == DROPBEAR_SUCCESS) {
|
||||
len = datalen;
|
||||
while (len > 0) {
|
||||
buflen = cbuf_writelen(cbuf);
|
||||
buflen = MIN(buflen, len);
|
||||
|
||||
memcpy(cbuf_writeptr(cbuf, buflen),
|
||||
buf_getptr(ses.payload, buflen), buflen);
|
||||
cbuf_incrwrite(cbuf, buflen);
|
||||
buf_incrpos(ses.payload, buflen);
|
||||
len -= buflen;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE(("leave recv_msg_channel_data"))
|
||||
}
|
||||
|
||||
@@ -798,7 +921,7 @@ static void send_msg_channel_window_adjust(struct Channel* channel,
|
||||
/* Handle a new channel request, performing any channel-type-specific setup */
|
||||
void recv_msg_channel_open() {
|
||||
|
||||
unsigned char *type;
|
||||
char *type;
|
||||
unsigned int typelen;
|
||||
unsigned int remotechan, transwindow, transmaxpacket;
|
||||
struct Channel *channel;
|
||||
@@ -847,6 +970,7 @@ void recv_msg_channel_open() {
|
||||
|
||||
if (channel == NULL) {
|
||||
TRACE(("newchannel returned NULL"))
|
||||
errtype = SSH_OPEN_RESOURCE_SHORTAGE;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
@@ -864,7 +988,9 @@ void recv_msg_channel_open() {
|
||||
}
|
||||
}
|
||||
|
||||
chan_initwritebuf(channel);
|
||||
if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
|
||||
}
|
||||
|
||||
/* success */
|
||||
send_msg_channel_open_confirmation(channel, channel->recvwindow,
|
||||
@@ -877,6 +1003,8 @@ failure:
|
||||
|
||||
cleanup:
|
||||
m_free(type);
|
||||
|
||||
update_channel_prio();
|
||||
|
||||
TRACE(("leave recv_msg_channel_open"))
|
||||
}
|
||||
@@ -910,7 +1038,7 @@ void send_msg_channel_success(struct Channel *channel) {
|
||||
/* Send a channel open failure message, with a corresponding reason
|
||||
* code (usually resource shortage or unknown chan type) */
|
||||
static void send_msg_channel_open_failure(unsigned int remotechan,
|
||||
int reason, const unsigned char *text, const unsigned char *lang) {
|
||||
int reason, const char *text, const char *lang) {
|
||||
|
||||
TRACE(("enter send_msg_channel_open_failure"))
|
||||
CHECKCLEARTOWRITE();
|
||||
@@ -918,8 +1046,8 @@ static void send_msg_channel_open_failure(unsigned int remotechan,
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN_FAILURE);
|
||||
buf_putint(ses.writepayload, remotechan);
|
||||
buf_putint(ses.writepayload, reason);
|
||||
buf_putstring(ses.writepayload, text, strlen((char*)text));
|
||||
buf_putstring(ses.writepayload, lang, strlen((char*)lang));
|
||||
buf_putstring(ses.writepayload, text, strlen(text));
|
||||
buf_putstring(ses.writepayload, lang, strlen(lang));
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave send_msg_channel_open_failure"))
|
||||
@@ -959,7 +1087,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
|
||||
}
|
||||
} else {
|
||||
TRACE(("CLOSE some fd %d", fd))
|
||||
close(fd);
|
||||
m_close(fd);
|
||||
closein = closeout = 1;
|
||||
}
|
||||
|
||||
@@ -982,7 +1110,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
|
||||
if (channel->type->sepfds && channel->readfd == FD_CLOSED
|
||||
&& channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {
|
||||
TRACE(("CLOSE (finally) of %d", fd))
|
||||
close(fd);
|
||||
m_close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -992,7 +1120,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
|
||||
* for X11, agent, tcp forwarding, and should be filled with channel-specific
|
||||
* options, with the calling function calling encrypt_packet() after
|
||||
* completion. It is mandatory for the caller to encrypt_packet() if
|
||||
* DROPBEAR_SUCCESS is returned */
|
||||
* a channel is returned. NULL is returned on failure. */
|
||||
int send_msg_channel_open_init(int fd, const struct ChanType *type) {
|
||||
|
||||
struct Channel* chan;
|
||||
@@ -1006,7 +1134,6 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
|
||||
|
||||
/* Outbound opened channels don't make use of in-progress connections,
|
||||
* we can set it up straight away */
|
||||
chan_initwritebuf(chan);
|
||||
|
||||
/* set fd non-blocking */
|
||||
setnonblocking(fd);
|
||||
@@ -1023,7 +1150,7 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
|
||||
buf_putstring(ses.writepayload, type->name, strlen(type->name));
|
||||
buf_putint(ses.writepayload, chan->index);
|
||||
buf_putint(ses.writepayload, opts.recv_window);
|
||||
buf_putint(ses.writepayload, RECV_MAX_PAYLOAD_LEN);
|
||||
buf_putint(ses.writepayload, RECV_MAX_CHANNEL_DATA_LEN);
|
||||
|
||||
TRACE(("leave send_msg_channel_open_init()"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
@@ -1058,9 +1185,14 @@ void recv_msg_channel_open_confirmation() {
|
||||
if (ret > 0) {
|
||||
remove_channel(channel);
|
||||
TRACE(("inithandler returned failure %d", ret))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
|
||||
}
|
||||
update_channel_prio();
|
||||
|
||||
TRACE(("leave recv_msg_channel_open_confirmation"))
|
||||
}
|
||||
@@ -1080,3 +1212,42 @@ void recv_msg_channel_open_failure() {
|
||||
remove_channel(channel);
|
||||
}
|
||||
#endif /* USING_LISTENERS */
|
||||
|
||||
void send_msg_request_success() {
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS);
|
||||
encrypt_packet();
|
||||
}
|
||||
|
||||
void send_msg_request_failure() {
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE);
|
||||
encrypt_packet();
|
||||
}
|
||||
|
||||
struct Channel* get_any_ready_channel() {
|
||||
size_t i;
|
||||
if (ses.chancount == 0) {
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < ses.chansize; i++) {
|
||||
struct Channel *chan = ses.channels[i];
|
||||
if (chan
|
||||
&& !(chan->sent_eof || chan->recv_eof)
|
||||
&& !(chan->await_open)) {
|
||||
return chan;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void start_send_channel_request(struct Channel *channel,
|
||||
char *type) {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
|
||||
buf_putint(ses.writepayload, channel->remotechan);
|
||||
|
||||
buf_putstring(ses.writepayload, type, strlen(type));
|
||||
|
||||
}
|
||||
|
||||
98
common-kex.c
98
common-kex.c
@@ -238,14 +238,24 @@ void recv_msg_newkeys() {
|
||||
void kexfirstinitialise() {
|
||||
ses.kexstate.donefirstkex = 0;
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
if (opts.enable_compress) {
|
||||
ses.compress_algos = ssh_compress;
|
||||
} else
|
||||
#endif
|
||||
#ifdef DISABLE_ZLIB
|
||||
ses.compress_algos = ssh_nocompress;
|
||||
#else
|
||||
switch (opts.compress_mode)
|
||||
{
|
||||
ses.compress_algos = ssh_nocompress;
|
||||
case DROPBEAR_COMPRESS_DELAYED:
|
||||
ses.compress_algos = ssh_delaycompress;
|
||||
break;
|
||||
|
||||
case DROPBEAR_COMPRESS_ON:
|
||||
ses.compress_algos = ssh_compress;
|
||||
break;
|
||||
|
||||
case DROPBEAR_COMPRESS_OFF:
|
||||
ses.compress_algos = ssh_nocompress;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
kexinitialise();
|
||||
}
|
||||
|
||||
@@ -270,7 +280,7 @@ static void kexinitialise() {
|
||||
|
||||
ses.kexstate.our_first_follows_matches = 0;
|
||||
|
||||
ses.kexstate.lastkextime = time(NULL);
|
||||
ses.kexstate.lastkextime = monotonic_now();
|
||||
|
||||
}
|
||||
|
||||
@@ -303,7 +313,7 @@ static void hashkeys(unsigned char *out, unsigned int outlen,
|
||||
hash_desc->done(&hs2, tmpout);
|
||||
memcpy(&out[offset], tmpout, MIN(outlen - offset, hash_desc->hashsize));
|
||||
}
|
||||
|
||||
m_burn(&hs2, sizeof(hash_state));
|
||||
}
|
||||
|
||||
/* Generate the actual encryption/integrity keys, using the results of the
|
||||
@@ -403,6 +413,7 @@ static void gen_new_keys() {
|
||||
m_burn(C2S_key, sizeof(C2S_key));
|
||||
m_burn(S2C_IV, sizeof(S2C_IV));
|
||||
m_burn(S2C_key, sizeof(S2C_key));
|
||||
m_burn(&hs, sizeof(hash_state));
|
||||
|
||||
TRACE(("leave gen_new_keys"))
|
||||
}
|
||||
@@ -483,9 +494,6 @@ static void gen_new_zstream_trans() {
|
||||
* and we calculate the first portion of the key-exchange-hash for used
|
||||
* later in the key exchange. No response is sent, as the client should
|
||||
* initiate the diffie-hellman key exchange */
|
||||
|
||||
/* Originally from kex.c, generalized for cli/svr mode --mihnea */
|
||||
/* Belongs in common_kex.c where it should be moved after review */
|
||||
void recv_msg_kexinit() {
|
||||
|
||||
unsigned int kexhashbuf_len = 0;
|
||||
@@ -503,7 +511,7 @@ void recv_msg_kexinit() {
|
||||
|
||||
/* start the kex hash */
|
||||
local_ident_len = strlen(LOCAL_IDENT);
|
||||
remote_ident_len = strlen((char*)ses.remoteident);
|
||||
remote_ident_len = strlen(ses.remoteident);
|
||||
|
||||
kexhashbuf_len = local_ident_len + remote_ident_len
|
||||
+ ses.transkexinit->len + ses.payload->len
|
||||
@@ -517,18 +525,19 @@ void recv_msg_kexinit() {
|
||||
read_kex_algos();
|
||||
|
||||
/* V_C, the client's version string (CR and NL excluded) */
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
(unsigned char*)LOCAL_IDENT, local_ident_len);
|
||||
buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len);
|
||||
/* V_S, the server's version string (CR and NL excluded) */
|
||||
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
|
||||
|
||||
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
ses.transkexinit->data, ses.transkexinit->len);
|
||||
(const char*)ses.transkexinit->data, ses.transkexinit->len);
|
||||
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
|
||||
buf_setpos(ses.payload, 0);
|
||||
buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);
|
||||
|
||||
buf_setpos(ses.payload, ses.payload_beginning);
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
(const char*)buf_getptr(ses.payload, ses.payload->len-ses.payload->pos),
|
||||
ses.payload->len-ses.payload->pos);
|
||||
ses.requirenext = SSH_MSG_KEXDH_REPLY;
|
||||
} else {
|
||||
/* SERVER */
|
||||
|
||||
@@ -537,18 +546,19 @@ void recv_msg_kexinit() {
|
||||
/* V_C, the client's version string (CR and NL excluded) */
|
||||
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
|
||||
/* V_S, the server's version string (CR and NL excluded) */
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
(unsigned char*)LOCAL_IDENT, local_ident_len);
|
||||
buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len);
|
||||
|
||||
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
|
||||
buf_setpos(ses.payload, 0);
|
||||
buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);
|
||||
buf_setpos(ses.payload, ses.payload_beginning);
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
(const char*)buf_getptr(ses.payload, ses.payload->len-ses.payload->pos),
|
||||
ses.payload->len-ses.payload->pos);
|
||||
|
||||
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
ses.transkexinit->data, ses.transkexinit->len);
|
||||
(const char*)ses.transkexinit->data, ses.transkexinit->len);
|
||||
|
||||
ses.requirenext[0] = SSH_MSG_KEXDH_INIT;
|
||||
ses.requirenext = SSH_MSG_KEXDH_INIT;
|
||||
}
|
||||
|
||||
buf_free(ses.transkexinit);
|
||||
@@ -621,16 +631,20 @@ void free_kexdh_param(struct kex_dh_param *param)
|
||||
void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
|
||||
sign_key *hostkey) {
|
||||
|
||||
mp_int dh_p;
|
||||
DEF_MP_INT(dh_p);
|
||||
DEF_MP_INT(dh_p_min1);
|
||||
mp_int *dh_e = NULL, *dh_f = NULL;
|
||||
|
||||
/* read the prime and generator*/
|
||||
m_mp_init(&dh_p);
|
||||
m_mp_init_multi(&dh_p, &dh_p_min1, NULL);
|
||||
load_dh_p(&dh_p);
|
||||
|
||||
/* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */
|
||||
if (mp_cmp(dh_pub_them, &dh_p) != MP_LT
|
||||
|| mp_cmp_d(dh_pub_them, 0) != MP_GT) {
|
||||
if (mp_sub_d(&dh_p, 1, &dh_p_min1) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
|
||||
/* Check that dh_pub_them (dh_e or dh_f) is in the range [2, p-2] */
|
||||
if (mp_cmp(dh_pub_them, &dh_p_min1) != MP_LT
|
||||
|| mp_cmp_d(dh_pub_them, 1) != MP_GT) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
|
||||
@@ -641,7 +655,7 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
|
||||
}
|
||||
|
||||
/* clear no longer needed vars */
|
||||
mp_clear_multi(&dh_p, NULL);
|
||||
mp_clear_multi(&dh_p, &dh_p_min1, NULL);
|
||||
|
||||
/* From here on, the code needs to work with the _same_ vars on each side,
|
||||
* not vice-versaing for client/server */
|
||||
@@ -689,6 +703,9 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
|
||||
ecc_key *Q_C, *Q_S, *Q_them;
|
||||
|
||||
Q_them = buf_get_ecc_raw_pubkey(pub_them, algo_kex->ecc_curve);
|
||||
if (Q_them == NULL) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
|
||||
ses.dh_K = dropbear_ecc_shared_secret(Q_them, ¶m->key);
|
||||
|
||||
@@ -743,6 +760,7 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
|
||||
unsigned char out[CURVE25519_LEN];
|
||||
const unsigned char* Q_C = NULL;
|
||||
const unsigned char* Q_S = NULL;
|
||||
char zeroes[CURVE25519_LEN] = {0};
|
||||
|
||||
if (buf_pub_them->len != CURVE25519_LEN)
|
||||
{
|
||||
@@ -750,6 +768,11 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
|
||||
}
|
||||
|
||||
curve25519_donna(out, param->priv, buf_pub_them->data);
|
||||
|
||||
if (constant_time_memcmp(zeroes, out, CURVE25519_LEN) == 0) {
|
||||
dropbear_exit("Bad curve25519");
|
||||
}
|
||||
|
||||
m_mp_alloc_init_multi(&ses.dh_K, NULL);
|
||||
bytes_to_mp(ses.dh_K, out, CURVE25519_LEN);
|
||||
m_burn(out, sizeof(out));
|
||||
@@ -767,9 +790,9 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
|
||||
/* K_S, the host key */
|
||||
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
|
||||
/* Q_C, client's ephemeral public key octet string */
|
||||
buf_putstring(ses.kexhashbuf, Q_C, CURVE25519_LEN);
|
||||
buf_putstring(ses.kexhashbuf, (const char*)Q_C, CURVE25519_LEN);
|
||||
/* Q_S, server's ephemeral public key octet string */
|
||||
buf_putstring(ses.kexhashbuf, Q_S, CURVE25519_LEN);
|
||||
buf_putstring(ses.kexhashbuf, (const char*)Q_S, CURVE25519_LEN);
|
||||
/* K, the shared secret */
|
||||
buf_putmpint(ses.kexhashbuf, ses.dh_K);
|
||||
|
||||
@@ -792,8 +815,16 @@ static void finish_kexhashbuf(void) {
|
||||
hash_desc->done(&hs, buf_getwriteptr(ses.hash, hash_desc->hashsize));
|
||||
buf_setlen(ses.hash, hash_desc->hashsize);
|
||||
|
||||
#if defined(DEBUG_KEXHASH) && defined(DEBUG_TRACE)
|
||||
if (!debug_trace) {
|
||||
printhex("kexhashbuf", ses.kexhashbuf->data, ses.kexhashbuf->len);
|
||||
printhex("kexhash", ses.hash->data, ses.hash->len);
|
||||
}
|
||||
#endif
|
||||
|
||||
buf_burn(ses.kexhashbuf);
|
||||
buf_free(ses.kexhashbuf);
|
||||
m_burn(&hs, sizeof(hash_state));
|
||||
ses.kexhashbuf = NULL;
|
||||
|
||||
/* first time around, we set the session_id to H */
|
||||
@@ -801,7 +832,6 @@ static void finish_kexhashbuf(void) {
|
||||
/* create the session_id, this never needs freeing */
|
||||
ses.session_id = buf_newcopy(ses.hash);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* read the other side's algo list. buf_match_algo is a callback to match
|
||||
|
||||
@@ -106,3 +106,8 @@ parse_ciphers_macs()
|
||||
}
|
||||
#endif
|
||||
|
||||
void print_version() {
|
||||
fprintf(stderr, "Dropbear v%s\n", DROPBEAR_VERSION);
|
||||
}
|
||||
|
||||
|
||||
|
||||
306
common-session.c
306
common-session.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "kex.h"
|
||||
#include "channel.h"
|
||||
#include "runopts.h"
|
||||
#include "netio.h"
|
||||
|
||||
static void checktimeouts();
|
||||
static long select_timeout();
|
||||
@@ -51,6 +52,11 @@ int exitflag = 0; /* GLOBAL */
|
||||
|
||||
/* called only at the start of a session, set up initial state */
|
||||
void common_session_init(int sock_in, int sock_out) {
|
||||
time_t now;
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
debug_start_net();
|
||||
#endif
|
||||
|
||||
TRACE(("enter session_init"))
|
||||
|
||||
@@ -58,9 +64,23 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
ses.sock_out = sock_out;
|
||||
ses.maxfd = MAX(sock_in, sock_out);
|
||||
|
||||
ses.connect_time = 0;
|
||||
ses.last_trx_packet_time = 0;
|
||||
ses.last_packet_time = 0;
|
||||
if (sock_in >= 0) {
|
||||
setnonblocking(sock_in);
|
||||
}
|
||||
if (sock_out >= 0) {
|
||||
setnonblocking(sock_out);
|
||||
}
|
||||
|
||||
ses.socket_prio = DROPBEAR_PRIO_DEFAULT;
|
||||
/* Sets it to lowdelay */
|
||||
update_channel_prio();
|
||||
|
||||
now = monotonic_now();
|
||||
ses.connect_time = now;
|
||||
ses.last_packet_time_keepalive_recv = now;
|
||||
ses.last_packet_time_idle = now;
|
||||
ses.last_packet_time_any_sent = 0;
|
||||
ses.last_packet_time_keepalive_sent = 0;
|
||||
|
||||
if (pipe(ses.signal_pipe) < 0) {
|
||||
dropbear_exit("Signal pipe failed");
|
||||
@@ -71,8 +91,6 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
|
||||
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
|
||||
|
||||
kexfirstinitialise(); /* initialise the kex state */
|
||||
|
||||
ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN);
|
||||
ses.transseq = 0;
|
||||
|
||||
@@ -82,7 +100,7 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
|
||||
initqueue(&ses.writequeue);
|
||||
|
||||
ses.requirenext[0] = SSH_MSG_KEXINIT;
|
||||
ses.requirenext = SSH_MSG_KEXINIT;
|
||||
ses.dataallowed = 1; /* we can send data until we actually
|
||||
send the SSH_MSG_KEXINIT */
|
||||
ses.ignorenext = 0;
|
||||
@@ -133,6 +151,7 @@ void session_loop(void(*loophandler)()) {
|
||||
|
||||
/* main loop, select()s for all sockets in use */
|
||||
for(;;) {
|
||||
const int writequeue_has_space = (ses.writequeue_len <= 2*TRANS_MAX_PAYLOAD_LEN);
|
||||
|
||||
timeout.tv_sec = select_timeout();
|
||||
timeout.tv_usec = 0;
|
||||
@@ -140,23 +159,34 @@ void session_loop(void(*loophandler)()) {
|
||||
FD_ZERO(&readfd);
|
||||
dropbear_assert(ses.payload == NULL);
|
||||
|
||||
/* during initial setup we flush out the KEXINIT packet before
|
||||
* attempting to read the remote version string, which might block */
|
||||
if (ses.sock_in != -1 && (ses.remoteident || isempty(&ses.writequeue))) {
|
||||
FD_SET(ses.sock_in, &readfd);
|
||||
}
|
||||
if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
|
||||
FD_SET(ses.sock_out, &writefd);
|
||||
}
|
||||
|
||||
/* We get woken up when signal handlers write to this pipe.
|
||||
SIGCHLD in svr-chansession is the only one currently. */
|
||||
FD_SET(ses.signal_pipe[0], &readfd);
|
||||
|
||||
/* set up for channels which require reading/writing */
|
||||
if (ses.dataallowed) {
|
||||
setchannelfds(&readfd, &writefd);
|
||||
/* set up for channels which can be read/written */
|
||||
setchannelfds(&readfd, &writefd, writequeue_has_space);
|
||||
|
||||
/* Pending connections to test */
|
||||
set_connect_fds(&writefd);
|
||||
|
||||
/* We delay reading from the input socket during initial setup until
|
||||
after we have written out our initial KEXINIT packet (empty writequeue).
|
||||
This means our initial packet can be in-flight while we're doing a blocking
|
||||
read for the remote ident.
|
||||
We also avoid reading from the socket if the writequeue is full, that avoids
|
||||
replies backing up */
|
||||
if (ses.sock_in != -1
|
||||
&& (ses.remoteident || isempty(&ses.writequeue))
|
||||
&& writequeue_has_space) {
|
||||
FD_SET(ses.sock_in, &readfd);
|
||||
}
|
||||
|
||||
/* Ordering is important, this test must occur after any other function
|
||||
might have queued packets (such as connection handlers) */
|
||||
if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
|
||||
FD_SET(ses.sock_out, &writefd);
|
||||
}
|
||||
|
||||
val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
|
||||
|
||||
if (exitflag) {
|
||||
@@ -187,13 +217,7 @@ void session_loop(void(*loophandler)()) {
|
||||
/* check for auth timeout, rekeying required etc */
|
||||
checktimeouts();
|
||||
|
||||
/* process session socket's incoming/outgoing data */
|
||||
if (ses.sock_out != -1) {
|
||||
if (FD_ISSET(ses.sock_out, &writefd) && !isempty(&ses.writequeue)) {
|
||||
write_packet();
|
||||
}
|
||||
}
|
||||
|
||||
/* process session socket's incoming data */
|
||||
if (ses.sock_in != -1) {
|
||||
if (FD_ISSET(ses.sock_in, &readfd)) {
|
||||
if (!ses.remoteident) {
|
||||
@@ -210,17 +234,25 @@ void session_loop(void(*loophandler)()) {
|
||||
process_packet();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* if required, flush out any queued reply packets that
|
||||
were being held up during a KEX */
|
||||
maybe_flush_reply_queue();
|
||||
|
||||
handle_connect_fds(&writefd);
|
||||
|
||||
/* process pipes etc for the channels, ses.dataallowed == 0
|
||||
* during rekeying ) */
|
||||
if (ses.dataallowed) {
|
||||
channelio(&readfd, &writefd);
|
||||
channelio(&readfd, &writefd);
|
||||
|
||||
/* process session socket's outgoing data */
|
||||
if (ses.sock_out != -1) {
|
||||
if (!isempty(&ses.writequeue)) {
|
||||
write_packet();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (loophandler) {
|
||||
loophandler();
|
||||
}
|
||||
@@ -230,6 +262,15 @@ void session_loop(void(*loophandler)()) {
|
||||
/* Not reached */
|
||||
}
|
||||
|
||||
static void cleanup_buf(buffer **buf) {
|
||||
if (!*buf) {
|
||||
return;
|
||||
}
|
||||
buf_burn(*buf);
|
||||
buf_free(*buf);
|
||||
*buf = NULL;
|
||||
}
|
||||
|
||||
/* clean up a session on exit */
|
||||
void session_cleanup() {
|
||||
|
||||
@@ -241,34 +282,57 @@ void session_cleanup() {
|
||||
return;
|
||||
}
|
||||
|
||||
/* BEWARE of changing order of functions here. */
|
||||
|
||||
/* Must be before extra_session_cleanup() */
|
||||
chancleanup();
|
||||
|
||||
if (ses.extra_session_cleanup) {
|
||||
ses.extra_session_cleanup();
|
||||
}
|
||||
|
||||
if (ses.session_id) {
|
||||
buf_burn(ses.session_id);
|
||||
buf_free(ses.session_id);
|
||||
ses.session_id = NULL;
|
||||
|
||||
/* After these are freed most functions will fail */
|
||||
#ifdef DROPBEAR_CLEANUP
|
||||
/* listeners call cleanup functions, this should occur before
|
||||
other session state is freed. */
|
||||
remove_all_listeners();
|
||||
|
||||
remove_connect_pending();
|
||||
|
||||
while (!isempty(&ses.writequeue)) {
|
||||
buf_free(dequeue(&ses.writequeue));
|
||||
}
|
||||
if (ses.hash) {
|
||||
buf_burn(ses.hash);
|
||||
buf_free(ses.hash);
|
||||
ses.hash = NULL;
|
||||
|
||||
m_free(ses.remoteident);
|
||||
m_free(ses.authstate.pw_dir);
|
||||
m_free(ses.authstate.pw_name);
|
||||
m_free(ses.authstate.pw_shell);
|
||||
m_free(ses.authstate.pw_passwd);
|
||||
m_free(ses.authstate.username);
|
||||
#endif
|
||||
|
||||
cleanup_buf(&ses.session_id);
|
||||
cleanup_buf(&ses.hash);
|
||||
cleanup_buf(&ses.payload);
|
||||
cleanup_buf(&ses.readbuf);
|
||||
cleanup_buf(&ses.writepayload);
|
||||
cleanup_buf(&ses.kexhashbuf);
|
||||
cleanup_buf(&ses.transkexinit);
|
||||
if (ses.dh_K) {
|
||||
mp_clear(ses.dh_K);
|
||||
}
|
||||
m_free(ses.dh_K);
|
||||
|
||||
m_burn(ses.keys, sizeof(struct key_context));
|
||||
m_free(ses.keys);
|
||||
|
||||
chancleanup();
|
||||
|
||||
TRACE(("leave session_cleanup"))
|
||||
}
|
||||
|
||||
void send_session_identification() {
|
||||
buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
|
||||
buf_putbytes(writebuf, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
|
||||
buf_putbyte(writebuf, 0x0); /* packet type */
|
||||
buf_setpos(writebuf, 0);
|
||||
enqueue(&ses.writequeue, writebuf);
|
||||
buf_putbytes(writebuf, (const unsigned char *) LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
|
||||
writebuf_enqueue(writebuf, 0);
|
||||
}
|
||||
|
||||
static void read_session_identification() {
|
||||
@@ -386,11 +450,37 @@ static int ident_readln(int fd, char* buf, int count) {
|
||||
return pos+1;
|
||||
}
|
||||
|
||||
void send_msg_ignore() {
|
||||
void ignore_recv_response() {
|
||||
/* Do nothing */
|
||||
TRACE(("Ignored msg_request_response"))
|
||||
}
|
||||
|
||||
static void send_msg_keepalive() {
|
||||
time_t old_time_idle = ses.last_packet_time_idle;
|
||||
struct Channel *chan = get_any_ready_channel();
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_IGNORE);
|
||||
buf_putstring(ses.writepayload, "", 0);
|
||||
|
||||
if (chan) {
|
||||
/* Channel requests are preferable, more implementations
|
||||
handle them than SSH_MSG_GLOBAL_REQUEST */
|
||||
TRACE(("keepalive channel request %d", chan->index))
|
||||
start_send_channel_request(chan, DROPBEAR_KEEPALIVE_STRING);
|
||||
} else {
|
||||
TRACE(("keepalive global request"))
|
||||
/* Some peers will reply with SSH_MSG_REQUEST_FAILURE,
|
||||
some will reply with SSH_MSG_UNIMPLEMENTED, some will exit. */
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
|
||||
buf_putstring(ses.writepayload, DROPBEAR_KEEPALIVE_STRING,
|
||||
strlen(DROPBEAR_KEEPALIVE_STRING));
|
||||
}
|
||||
buf_putbyte(ses.writepayload, 1); /* want_reply */
|
||||
encrypt_packet();
|
||||
|
||||
ses.last_packet_time_keepalive_sent = monotonic_now();
|
||||
|
||||
/* keepalives shouldn't update idle timeout, reset it back */
|
||||
ses.last_packet_time_idle = old_time_idle;
|
||||
}
|
||||
|
||||
/* Check all timeouts which are required. Currently these are the time for
|
||||
@@ -398,10 +488,10 @@ void send_msg_ignore() {
|
||||
static void checktimeouts() {
|
||||
|
||||
time_t now;
|
||||
|
||||
now = time(NULL);
|
||||
now = monotonic_now();
|
||||
|
||||
if (ses.connect_time != 0 && now - ses.connect_time >= AUTH_TIMEOUT) {
|
||||
if (IS_DROPBEAR_SERVER && ses.connect_time != 0
|
||||
&& now - ses.connect_time >= AUTH_TIMEOUT) {
|
||||
dropbear_close("Timeout before auth");
|
||||
}
|
||||
|
||||
@@ -417,30 +507,67 @@ static void checktimeouts() {
|
||||
send_msg_kexinit();
|
||||
}
|
||||
|
||||
if (opts.keepalive_secs > 0
|
||||
&& now - ses.last_trx_packet_time >= opts.keepalive_secs) {
|
||||
send_msg_ignore();
|
||||
if (opts.keepalive_secs > 0 && ses.authstate.authdone) {
|
||||
/* Avoid sending keepalives prior to auth - those are
|
||||
not valid pre-auth packet types */
|
||||
|
||||
/* Send keepalives if we've been idle */
|
||||
if (now - ses.last_packet_time_any_sent >= opts.keepalive_secs) {
|
||||
send_msg_keepalive();
|
||||
}
|
||||
|
||||
/* Also send an explicit keepalive message to trigger a response
|
||||
if the remote end hasn't sent us anything */
|
||||
if (now - ses.last_packet_time_keepalive_recv >= opts.keepalive_secs
|
||||
&& now - ses.last_packet_time_keepalive_sent >= opts.keepalive_secs) {
|
||||
send_msg_keepalive();
|
||||
}
|
||||
|
||||
if (now - ses.last_packet_time_keepalive_recv
|
||||
>= opts.keepalive_secs * DEFAULT_KEEPALIVE_LIMIT) {
|
||||
dropbear_exit("Keepalive timeout");
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.idle_timeout_secs > 0 && ses.last_packet_time > 0
|
||||
&& now - ses.last_packet_time >= opts.idle_timeout_secs) {
|
||||
if (opts.idle_timeout_secs > 0
|
||||
&& now - ses.last_packet_time_idle >= opts.idle_timeout_secs) {
|
||||
dropbear_close("Idle timeout");
|
||||
}
|
||||
}
|
||||
|
||||
static void update_timeout(long limit, long now, long last_event, long * timeout) {
|
||||
TRACE2(("update_timeout limit %ld, now %ld, last %ld, timeout %ld",
|
||||
limit, now, last_event, *timeout))
|
||||
if (last_event > 0 && limit > 0) {
|
||||
*timeout = MIN(*timeout, last_event+limit-now);
|
||||
TRACE2(("new timeout %ld", *timeout))
|
||||
}
|
||||
}
|
||||
|
||||
static long select_timeout() {
|
||||
/* determine the minimum timeout that might be required, so
|
||||
as to avoid waking when unneccessary */
|
||||
long ret = LONG_MAX;
|
||||
if (KEX_REKEY_TIMEOUT > 0)
|
||||
ret = MIN(KEX_REKEY_TIMEOUT, ret);
|
||||
if (AUTH_TIMEOUT > 0)
|
||||
ret = MIN(AUTH_TIMEOUT, ret);
|
||||
if (opts.keepalive_secs > 0)
|
||||
ret = MIN(opts.keepalive_secs, ret);
|
||||
if (opts.idle_timeout_secs > 0)
|
||||
ret = MIN(opts.idle_timeout_secs, ret);
|
||||
return ret;
|
||||
long timeout = LONG_MAX;
|
||||
long now = monotonic_now();
|
||||
|
||||
update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
|
||||
|
||||
if (ses.authstate.authdone != 1 && IS_DROPBEAR_SERVER) {
|
||||
/* AUTH_TIMEOUT is only relevant before authdone */
|
||||
update_timeout(AUTH_TIMEOUT, now, ses.connect_time, &timeout);
|
||||
}
|
||||
|
||||
if (ses.authstate.authdone) {
|
||||
update_timeout(opts.keepalive_secs, now,
|
||||
MAX(ses.last_packet_time_keepalive_recv, ses.last_packet_time_keepalive_sent),
|
||||
&timeout);
|
||||
}
|
||||
|
||||
update_timeout(opts.idle_timeout_secs, now, ses.last_packet_time_idle,
|
||||
&timeout);
|
||||
|
||||
/* clamp negative timeouts to zero - event has already triggered */
|
||||
return MAX(timeout, 0);
|
||||
}
|
||||
|
||||
const char* get_user_shell() {
|
||||
@@ -488,3 +615,52 @@ void fill_passwd(const char* username) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Called when channels are modified */
|
||||
void update_channel_prio() {
|
||||
enum dropbear_prio new_prio;
|
||||
int any = 0;
|
||||
unsigned int i;
|
||||
|
||||
TRACE(("update_channel_prio"))
|
||||
|
||||
if (ses.sock_out < 0) {
|
||||
TRACE(("leave update_channel_prio: no socket"))
|
||||
return;
|
||||
}
|
||||
|
||||
new_prio = DROPBEAR_PRIO_BULK;
|
||||
for (i = 0; i < ses.chansize; i++) {
|
||||
struct Channel *channel = ses.channels[i];
|
||||
if (!channel || channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
|
||||
if (channel && channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
|
||||
TRACE(("update_channel_prio: early %d", channel->index))
|
||||
}
|
||||
continue;
|
||||
}
|
||||
any = 1;
|
||||
if (channel->prio == DROPBEAR_CHANNEL_PRIO_INTERACTIVE)
|
||||
{
|
||||
TRACE(("update_channel_prio: lowdelay %d", channel->index))
|
||||
new_prio = DROPBEAR_PRIO_LOWDELAY;
|
||||
break;
|
||||
} else if (channel->prio == DROPBEAR_CHANNEL_PRIO_UNKNOWABLE
|
||||
&& new_prio == DROPBEAR_PRIO_BULK)
|
||||
{
|
||||
TRACE(("update_channel_prio: unknowable %d", channel->index))
|
||||
new_prio = DROPBEAR_PRIO_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
if (any == 0) {
|
||||
/* lowdelay during setup */
|
||||
TRACE(("update_channel_prio: not any"))
|
||||
new_prio = DROPBEAR_PRIO_LOWDELAY;
|
||||
}
|
||||
|
||||
if (new_prio != ses.socket_prio) {
|
||||
TRACE(("Dropbear priority transitioning %d -> %d", ses.socket_prio, new_prio))
|
||||
set_sock_priority(ses.sock_out, new_prio);
|
||||
ses.socket_prio = new_prio;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
compat.h
10
compat.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _COMPAT_H_
|
||||
#define _COMPAT_H_
|
||||
#ifndef DROPBEAR_COMPAT_H_
|
||||
#define DROPBEAR_COMPAT_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
@@ -49,8 +49,8 @@ void setusershell();
|
||||
void endusershell();
|
||||
#endif
|
||||
|
||||
#ifndef _PATH_DEVNULL
|
||||
#define _PATH_DEVNULL "/dev/null"
|
||||
#ifndef DROPBEAR_PATH_DEVNULL
|
||||
#define DROPBEAR_PATH_DEVNULL "/dev/null"
|
||||
#endif
|
||||
|
||||
#endif /* _COMPAT_H_ */
|
||||
#endif /* DROPBEAR_COMPAT_H_ */
|
||||
|
||||
47
configure.ac
47
configure.ac
@@ -265,7 +265,7 @@ AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
]],
|
||||
[[ struct sockaddr_storage s; ]])],
|
||||
[[ if (sizeof(struct sockaddr_storage)) return 0 ]])],
|
||||
[ ac_cv_have_struct_sockaddr_storage="yes" ],
|
||||
[ ac_cv_have_struct_sockaddr_storage="no" ]
|
||||
)
|
||||
@@ -279,7 +279,7 @@ AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
]],
|
||||
[[ struct sockaddr_in6 s; s.sin6_family = 0; ]])],
|
||||
[[ if (sizeof(struct sockaddr_in6)) return 0 ]])],
|
||||
[ ac_cv_have_struct_sockaddr_in6="yes" ],
|
||||
[ ac_cv_have_struct_sockaddr_in6="no" ]
|
||||
)
|
||||
@@ -293,7 +293,7 @@ AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
]],
|
||||
[[ struct in6_addr s; s.s6_addr[0] = 0; ]])],
|
||||
[[ if (sizeof(struct in6_addr)) return 0 ]])],
|
||||
[ ac_cv_have_struct_in6_addr="yes" ],
|
||||
[ ac_cv_have_struct_in6_addr="no" ]
|
||||
)
|
||||
@@ -308,7 +308,7 @@ AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
]],
|
||||
[[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ]])],
|
||||
[[ if (sizeof(struct addrinfo)) return 0 ]])],
|
||||
[ ac_cv_have_struct_addrinfo="yes" ],
|
||||
[ ac_cv_have_struct_addrinfo="no" ]
|
||||
)
|
||||
@@ -361,6 +361,10 @@ AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
|
||||
AC_CHECK_FUNCS(setutxent utmpxname)
|
||||
AC_CHECK_FUNCS(logout updwtmp logwtmp)
|
||||
|
||||
# OS X monotonic time
|
||||
AC_CHECK_HEADERS([mach/mach_time.h])
|
||||
AC_CHECK_FUNCS(mach_absolute_time)
|
||||
|
||||
AC_ARG_ENABLE(bundled-libtom,
|
||||
[ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists.
|
||||
--disable-bundled-libtom Force using system libtomcrypt/libtommath, fail if it does not exist.
|
||||
@@ -371,16 +375,16 @@ AC_ARG_ENABLE(bundled-libtom,
|
||||
AC_MSG_NOTICE(Forcing bundled libtom*)
|
||||
else
|
||||
BUNDLED_LIBTOM=0
|
||||
AC_CHECK_LIB(tommath, mp_exptmod, ,
|
||||
[AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] )
|
||||
AC_CHECK_LIB(tomcrypt, register_cipher, ,
|
||||
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="$LIBTOM_LIBS -ltommath",
|
||||
[AC_MSG_ERROR([Missing system libtommath and --disable-bundled-libtom was specified])] )
|
||||
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="$LIBTOM_LIBS -ltomcrypt",
|
||||
[AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] )
|
||||
fi
|
||||
],
|
||||
[
|
||||
BUNDLED_LIBTOM=0
|
||||
AC_CHECK_LIB(tommath, mp_exptmod, , BUNDLED_LIBTOM=1)
|
||||
AC_CHECK_LIB(tomcrypt, register_cipher, , BUNDLED_LIBTOM=1)
|
||||
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="$LIBTOM_LIBS -ltommath", BUNDLED_LIBTOM=1)
|
||||
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="$LIBTOM_LIBS -ltomcrypt", BUNDLED_LIBTOM=1)
|
||||
]
|
||||
)
|
||||
|
||||
@@ -388,6 +392,7 @@ if test $BUNDLED_LIBTOM = 1 ; then
|
||||
AC_DEFINE(BUNDLED_LIBTOM,,Use bundled libtom)
|
||||
fi
|
||||
|
||||
AC_SUBST(LIBTOM_LIBS)
|
||||
AC_SUBST(BUNDLED_LIBTOM)
|
||||
|
||||
dnl Added from OpenSSH 3.6.1p2's configure.ac
|
||||
@@ -627,7 +632,7 @@ fi
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_FUNC_MEMCMP
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev])
|
||||
AC_CHECK_FUNCS([dup2 getpass getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev crypt])
|
||||
|
||||
AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
|
||||
|
||||
@@ -655,6 +660,7 @@ fi
|
||||
AC_EXEEXT
|
||||
|
||||
# XXX there must be a nicer way to do this
|
||||
if test $BUNDLED_LIBTOM = 1 ; then
|
||||
AS_MKDIR_P(libtomcrypt/src/ciphers/aes)
|
||||
AS_MKDIR_P(libtomcrypt/src/ciphers/safer)
|
||||
AS_MKDIR_P(libtomcrypt/src/ciphers/twofish)
|
||||
@@ -705,16 +711,29 @@ AS_MKDIR_P(libtomcrypt/src/pk/katja)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/pkcs1)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/rsa)
|
||||
AS_MKDIR_P(libtomcrypt/src/prngs)
|
||||
LIBTOM_FILES="libtomcrypt/Makefile libtommath/Makefile"
|
||||
fi
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_CONFIG_FILES(Makefile libtomcrypt/Makefile libtommath/Makefile)
|
||||
AC_CONFIG_FILES(Makefile $LIBTOM_FILES)
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_NOTICE()
|
||||
if test $BUNDLED_LIBTOM = 1 ; then
|
||||
AC_MSG_NOTICE(Using bundled libtomcrypt and libtommath)
|
||||
AC_MSG_NOTICE([Using bundled libtomcrypt and libtommath])
|
||||
else
|
||||
AC_MSG_NOTICE(Using system libtomcrypt and libtommath)
|
||||
AC_MSG_NOTICE([Using system libtomcrypt and libtommath])
|
||||
fi
|
||||
|
||||
|
||||
if test "x$ac_cv_func_getpass" != xyes; then
|
||||
AC_MSG_NOTICE()
|
||||
AC_MSG_NOTICE([getpass() not available, dbclient will only have public-key authentication])
|
||||
fi
|
||||
|
||||
if test "x$ac_cv_func_crypt" != xyes; then
|
||||
AC_MSG_NOTICE()
|
||||
AC_MSG_NOTICE([crypt() not available, dropbear server will not have password authentication])
|
||||
fi
|
||||
|
||||
AC_MSG_NOTICE()
|
||||
AC_MSG_NOTICE(Now edit options.h to choose features.)
|
||||
AC_MSG_NOTICE([Now edit options.h to choose features.])
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef _CRYPTO_DESC_H
|
||||
#define _CRYPTO_DESC_H
|
||||
#ifndef DROPBEAR_CRYPTO_DESC_H
|
||||
#define DROPBEAR_CRYPTO_DESC_H
|
||||
|
||||
void crypto_init();
|
||||
|
||||
extern int dropbear_ltc_prng;
|
||||
|
||||
#endif /* _CRYPTO_DESC_H */
|
||||
#endif /* DROPBEAR_CRYPTO_DESC_H */
|
||||
|
||||
|
||||
@@ -527,7 +527,7 @@ static void fmonty(limb *x2, limb *z2, /* output 2Q */
|
||||
|
||||
memcpy(origx, x, 10 * sizeof(limb));
|
||||
fsum(x, z);
|
||||
fdifference(z, origx); // does x - z
|
||||
fdifference(z, origx); /* does x - z */
|
||||
|
||||
memcpy(origxprime, xprime, sizeof(limb) * 10);
|
||||
fsum(xprime, zprime);
|
||||
@@ -554,7 +554,7 @@ static void fmonty(limb *x2, limb *z2, /* output 2Q */
|
||||
fproduct(x2, xx, zz);
|
||||
freduce_degree(x2);
|
||||
freduce_coefficients(x2);
|
||||
fdifference(zz, xx); // does zz = xx - zz
|
||||
fdifference(zz, xx); /* does zz = xx - zz */
|
||||
memset(zzz + 10, 0, sizeof(limb) * 9);
|
||||
fscalar_product(zzz, zz, 121665);
|
||||
/* No need to call freduce_degree here:
|
||||
@@ -641,9 +641,9 @@ cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
|
||||
memcpy(resultz, nqz, sizeof(limb) * 10);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Shamelessly copied from djb's code
|
||||
// -----------------------------------------------------------------------------
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Shamelessly copied from djb's code
|
||||
* ----------------------------------------------------------------------------- */
|
||||
static void
|
||||
crecip(limb *out, const limb *z) {
|
||||
limb z2[10];
|
||||
|
||||
47
dbclient.1
47
dbclient.1
@@ -3,30 +3,36 @@
|
||||
dbclient \- lightweight SSH client
|
||||
.SH SYNOPSIS
|
||||
.B dbclient
|
||||
[\-Tt] [\-p
|
||||
[\fIflag arguments\fR] [\-p
|
||||
.I port\fR] [\-i
|
||||
.I id\fR] [\-L
|
||||
.I l\fR:\fIh\fR:\fIr\fR] [\-R
|
||||
.I l\fR:\fIh\fR:\fIr\fR] [\-l
|
||||
.I l\fR:\fIh\fR:\fIp\fR] [\-R
|
||||
.I l\fR:\fIh\fR:\fIp\fR] [\-l
|
||||
.IR user ]
|
||||
.I host
|
||||
.RI [ \fImore\ flags\fR ]
|
||||
.RI [ command ]
|
||||
|
||||
.B dbclient
|
||||
[
|
||||
.I args ]
|
||||
.I [user1]@host1[%port1],[user2]@host2[%port2],...
|
||||
[\fIargs\fR]
|
||||
[\fIuser1\fR]@\fIhost1\fR[^\fIport1\fR],[\fIuser2\fR]@\fIhost2\fR[^\fIport2\fR],...
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B dbclient
|
||||
is a SSH client designed to be small enough to be used in small memory
|
||||
environments, while still being functional and secure enough for general use.
|
||||
is a small SSH client
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.TP
|
||||
.B command
|
||||
A command to run on the remote host. This will normally be run by the remote host
|
||||
using the user's shell. The command begins at the first hyphen argument after the
|
||||
host argument. If no command is specified an interactive terminal will be opened
|
||||
(see -t and -T).
|
||||
.TP
|
||||
.B \-p \fIport
|
||||
Connect to
|
||||
.I port
|
||||
on the remote host. Alternatively a port can be specified as hostname%port.
|
||||
on the remote host. Alternatively a port can be specified as hostname^port.
|
||||
Default is 22.
|
||||
.TP
|
||||
.B \-i \fIidfile
|
||||
@@ -34,9 +40,9 @@ Identity file.
|
||||
Read the identity key from file
|
||||
.I idfile
|
||||
(multiple allowed). This file is created with dropbearkey(1) or converted
|
||||
from OpenSSH with dropbearconvert(1).
|
||||
from OpenSSH with dropbearconvert(1). The default path ~/.ssh/id_dropbear is used
|
||||
.TP
|
||||
.B \-L [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
|
||||
.B \-L\fR [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
|
||||
Local port forwarding.
|
||||
Forward the port
|
||||
.I listenport
|
||||
@@ -45,7 +51,7 @@ on the local host through the SSH connection to port
|
||||
on the host
|
||||
.IR host .
|
||||
.TP
|
||||
.B \-R [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
|
||||
.B \-R\fR [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
|
||||
Remote port forwarding.
|
||||
Forward the port
|
||||
.I listenport
|
||||
@@ -61,10 +67,12 @@ Login as
|
||||
on the remote host.
|
||||
.TP
|
||||
.B \-t
|
||||
Allocate a PTY.
|
||||
Allocate a PTY. This is the default when no command is given, it gives a full
|
||||
interactive remote session. The main effect is that keystrokes are sent remotely
|
||||
immediately as opposed to local line-based editing.
|
||||
.TP
|
||||
.B \-T
|
||||
Don't allocate a PTY.
|
||||
Don't allocate a PTY. This is the default a command is given. See -t.
|
||||
.TP
|
||||
.B \-N
|
||||
Don't request a remote shell or run any commands. Any command arguments are ignored.
|
||||
@@ -98,7 +106,7 @@ Ensure that traffic is transmitted at a certain interval in seconds. This is
|
||||
useful for working around firewalls or routers that drop connections after
|
||||
a certain period of inactivity. The trade-off is that a session may be
|
||||
closed if there is a temporary lapse of network connectivity. A setting
|
||||
if 0 disables keepalives.
|
||||
if 0 disables keepalives. If no response is received for 3 consecutive keepalives the connection will be closed.
|
||||
.TP
|
||||
.B \-I \fIidle_timeout
|
||||
Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
|
||||
@@ -121,13 +129,16 @@ Specify a comma separated list of authentication MACs to enable. Use \fI-m help\
|
||||
.TP
|
||||
.B \-s
|
||||
The specified command will be requested as a subsystem, used for sftp. Dropbear doesn't implement sftp itself but the OpenSSH sftp client can be used eg \fIsftp -S dbclient user@host\fR
|
||||
.TP
|
||||
.B \-V
|
||||
Print the version
|
||||
|
||||
.SH MULTI-HOP
|
||||
Dropbear will also allow multiple "hops" to be specified, separated by commas. In
|
||||
this case a connection will be made to the first host, then a TCP forwarded
|
||||
connection will be made through that to the second host, and so on. Hosts other than
|
||||
the final destination will not see anything other than the encrypted SSH stream.
|
||||
A port for a host can be specified with a hash (eg matt@martello%44 ).
|
||||
A port for a host can be specified with a caret (eg matt@martello^44 ).
|
||||
This syntax can also be used with scp or rsync (specifying dbclient as the
|
||||
ssh/rsh command). A file can be "bounced" through multiple SSH hops, eg
|
||||
|
||||
@@ -155,6 +166,10 @@ SSH_ASKPASS should be set to the path of a program that will return a password
|
||||
on standard output. This program will only be used if either DISPLAY is set and
|
||||
standard input is not a TTY, or the environment variable SSH_ASKPASS_ALWAYS is
|
||||
set.
|
||||
.SH NOTES
|
||||
If compiled with zlib support and if the server supports it, dbclient will
|
||||
always use compression.
|
||||
|
||||
.SH AUTHOR
|
||||
Matt Johnston (matt@ucc.asn.au).
|
||||
.br
|
||||
|
||||
@@ -141,7 +141,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void addrandom(char * buf, unsigned int len)
|
||||
void addrandom(unsigned char * buf, unsigned int len)
|
||||
{
|
||||
hash_state hs;
|
||||
|
||||
@@ -306,7 +306,7 @@ void gen_random_mpint(mp_int *max, mp_int *rand) {
|
||||
|
||||
/* keep regenerating until we get one satisfying
|
||||
* 0 < rand < max */
|
||||
} while (mp_cmp(rand, max) != MP_LT);
|
||||
} while (!(mp_cmp(rand, max) == MP_LT && mp_cmp_d(rand, 0) == MP_GT));
|
||||
m_burn(randbuf, len);
|
||||
m_free(randbuf);
|
||||
}
|
||||
|
||||
@@ -22,14 +22,14 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _RANDOM_H_
|
||||
#define _RANDOM_H_
|
||||
#ifndef DROPBEAR_RANDOM_H_
|
||||
#define DROPBEAR_RANDOM_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
void seedrandom();
|
||||
void genrandom(unsigned char* buf, unsigned int len);
|
||||
void addrandom(char * buf, unsigned int len);
|
||||
void addrandom(unsigned char * buf, unsigned int len);
|
||||
void gen_random_mpint(mp_int *max, mp_int *rand);
|
||||
|
||||
#endif /* _RANDOM_H_ */
|
||||
#endif /* DROPBEAR_RANDOM_H_ */
|
||||
|
||||
473
dbutil.c
473
dbutil.c
@@ -48,6 +48,19 @@
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#define _GNU_SOURCE
|
||||
/* To call clock_gettime() directly */
|
||||
#include <sys/syscall.h>
|
||||
#endif /* __linux */
|
||||
|
||||
#ifdef HAVE_MACH_MACH_TIME_H
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "buffer.h"
|
||||
@@ -137,18 +150,44 @@ void dropbear_log(int priority, const char* format, ...) {
|
||||
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
|
||||
static double debug_start_time = -1;
|
||||
|
||||
void debug_start_net()
|
||||
{
|
||||
if (getenv("DROPBEAR_DEBUG_NET_TIMESTAMP"))
|
||||
{
|
||||
/* Timestamps start from first network activity */
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
debug_start_time = tv.tv_sec + (tv.tv_usec / 1000000.0);
|
||||
TRACE(("Resetting Dropbear TRACE timestamps"))
|
||||
}
|
||||
}
|
||||
|
||||
static double time_since_start()
|
||||
{
|
||||
double nowf;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
nowf = tv.tv_sec + (tv.tv_usec / 1000000.0);
|
||||
if (debug_start_time < 0)
|
||||
{
|
||||
debug_start_time = nowf;
|
||||
return 0;
|
||||
}
|
||||
return nowf - debug_start_time;
|
||||
}
|
||||
|
||||
void dropbear_trace(const char* format, ...) {
|
||||
va_list param;
|
||||
struct timeval tv;
|
||||
|
||||
if (!debug_trace) {
|
||||
return;
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
va_start(param, format);
|
||||
fprintf(stderr, "TRACE (%d) %d.%d: ", getpid(), tv.tv_sec, tv.tv_usec);
|
||||
fprintf(stderr, "TRACE (%d) %f: ", getpid(), time_since_start());
|
||||
vfprintf(stderr, format, param);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(param);
|
||||
@@ -157,7 +196,6 @@ void dropbear_trace(const char* format, ...) {
|
||||
void dropbear_trace2(const char* format, ...) {
|
||||
static int trace_env = -1;
|
||||
va_list param;
|
||||
struct timeval tv;
|
||||
|
||||
if (trace_env == -1) {
|
||||
trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0;
|
||||
@@ -167,190 +205,14 @@ void dropbear_trace2(const char* format, ...) {
|
||||
return;
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
va_start(param, format);
|
||||
fprintf(stderr, "TRACE2 (%d) %d.%d: ", getpid(), tv.tv_sec, tv.tv_usec);
|
||||
fprintf(stderr, "TRACE2 (%d) %f: ", getpid(), time_since_start());
|
||||
vfprintf(stderr, format, param);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(param);
|
||||
}
|
||||
#endif /* DEBUG_TRACE */
|
||||
|
||||
void set_sock_nodelay(int sock) {
|
||||
int val;
|
||||
|
||||
/* disable nagle */
|
||||
val = 1;
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
|
||||
}
|
||||
|
||||
void set_sock_priority(int sock, enum dropbear_prio prio) {
|
||||
|
||||
int iptos_val = 0, so_prio_val = 0, rc;
|
||||
|
||||
/* set the TOS bit for either ipv4 or ipv6 */
|
||||
#ifdef IPTOS_LOWDELAY
|
||||
if (prio == DROPBEAR_PRIO_LOWDELAY) {
|
||||
iptos_val = IPTOS_LOWDELAY;
|
||||
} else if (prio == DROPBEAR_PRIO_BULK) {
|
||||
iptos_val = IPTOS_THROUGHPUT;
|
||||
}
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
|
||||
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
|
||||
if (rc < 0) {
|
||||
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
|
||||
}
|
||||
#endif
|
||||
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
|
||||
if (rc < 0) {
|
||||
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SO_PRIORITY
|
||||
if (prio == DROPBEAR_PRIO_LOWDELAY) {
|
||||
so_prio_val = TC_PRIO_INTERACTIVE;
|
||||
} else if (prio == DROPBEAR_PRIO_BULK) {
|
||||
so_prio_val = TC_PRIO_BULK;
|
||||
}
|
||||
/* linux specific, sets QoS class. see tc-prio(8) */
|
||||
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val));
|
||||
if (rc < 0)
|
||||
dropbear_log(LOG_WARNING, "Couldn't set SO_PRIORITY (%s)",
|
||||
strerror(errno));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* Listen on address:port.
|
||||
* Special cases are address of "" listening on everything,
|
||||
* and address of NULL listening on localhost only.
|
||||
* Returns the number of sockets bound on success, or -1 on failure. On
|
||||
* failure, if errstring wasn't NULL, it'll be a newly malloced error
|
||||
* string.*/
|
||||
int dropbear_listen(const char* address, const char* port,
|
||||
int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
|
||||
|
||||
struct addrinfo hints, *res = NULL, *res0 = NULL;
|
||||
int err;
|
||||
unsigned int nsock;
|
||||
struct linger linger;
|
||||
int val;
|
||||
int sock;
|
||||
|
||||
TRACE(("enter dropbear_listen"))
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
/* for calling getaddrinfo:
|
||||
address == NULL and !AI_PASSIVE: local loopback
|
||||
address == NULL and AI_PASSIVE: all interfaces
|
||||
address != NULL: whatever the address says */
|
||||
if (!address) {
|
||||
TRACE(("dropbear_listen: local loopback"))
|
||||
} else {
|
||||
if (address[0] == '\0') {
|
||||
TRACE(("dropbear_listen: all interfaces"))
|
||||
address = NULL;
|
||||
}
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
}
|
||||
err = getaddrinfo(address, port, &hints, &res0);
|
||||
|
||||
if (err) {
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
int len;
|
||||
len = 20 + strlen(gai_strerror(err));
|
||||
*errstring = (char*)m_malloc(len);
|
||||
snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
|
||||
}
|
||||
if (res0) {
|
||||
freeaddrinfo(res0);
|
||||
res0 = NULL;
|
||||
}
|
||||
TRACE(("leave dropbear_listen: failed resolving"))
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
nsock = 0;
|
||||
for (res = res0; res != NULL && nsock < sockcount;
|
||||
res = res->ai_next) {
|
||||
|
||||
/* Get a socket */
|
||||
socks[nsock] = socket(res->ai_family, res->ai_socktype,
|
||||
res->ai_protocol);
|
||||
|
||||
sock = socks[nsock]; /* For clarity */
|
||||
|
||||
if (sock < 0) {
|
||||
err = errno;
|
||||
TRACE(("socket() failed"))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Various useful socket options */
|
||||
val = 1;
|
||||
/* set to reuse, quick timeout */
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
|
||||
linger.l_onoff = 1;
|
||||
linger.l_linger = 5;
|
||||
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
|
||||
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
|
||||
if (res->ai_family == AF_INET6) {
|
||||
int on = 1;
|
||||
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
&on, sizeof(on)) == -1) {
|
||||
dropbear_log(LOG_WARNING, "Couldn't set IPV6_V6ONLY");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
set_sock_nodelay(sock);
|
||||
|
||||
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
err = errno;
|
||||
close(sock);
|
||||
TRACE(("bind(%s) failed", port))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (listen(sock, 20) < 0) {
|
||||
err = errno;
|
||||
close(sock);
|
||||
TRACE(("listen() failed"))
|
||||
continue;
|
||||
}
|
||||
|
||||
*maxfd = MAX(*maxfd, sock);
|
||||
|
||||
nsock++;
|
||||
}
|
||||
|
||||
if (res0) {
|
||||
freeaddrinfo(res0);
|
||||
res0 = NULL;
|
||||
}
|
||||
|
||||
if (nsock == 0) {
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
int len;
|
||||
len = 20 + strlen(strerror(err));
|
||||
*errstring = (char*)m_malloc(len);
|
||||
snprintf(*errstring, len, "Error listening: %s", strerror(err));
|
||||
}
|
||||
TRACE(("leave dropbear_listen: failure, %s", strerror(err)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
TRACE(("leave dropbear_listen: success, %d socks bound", nsock))
|
||||
return nsock;
|
||||
}
|
||||
|
||||
/* Connect to a given unix socket. The socket is blocking */
|
||||
#ifdef ENABLE_CONNECT_UNIX
|
||||
int connect_unix(const char* path) {
|
||||
@@ -374,93 +236,6 @@ int connect_unix(const char* path) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Connect via TCP to a host. Connection will try ipv4 or ipv6, will
|
||||
* return immediately if nonblocking is set. On failure, if errstring
|
||||
* wasn't null, it will be a newly malloced error message */
|
||||
|
||||
/* TODO: maxfd */
|
||||
int connect_remote(const char* remotehost, const char* remoteport,
|
||||
int nonblocking, char ** errstring) {
|
||||
|
||||
struct addrinfo *res0 = NULL, *res = NULL, hints;
|
||||
int sock;
|
||||
int err;
|
||||
|
||||
TRACE(("enter connect_remote"))
|
||||
|
||||
if (errstring != NULL) {
|
||||
*errstring = NULL;
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
|
||||
err = getaddrinfo(remotehost, remoteport, &hints, &res0);
|
||||
if (err) {
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
int len;
|
||||
len = 100 + strlen(gai_strerror(err));
|
||||
*errstring = (char*)m_malloc(len);
|
||||
snprintf(*errstring, len, "Error resolving '%s' port '%s'. %s",
|
||||
remotehost, remoteport, gai_strerror(err));
|
||||
}
|
||||
TRACE(("Error resolving: %s", gai_strerror(err)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
sock = -1;
|
||||
err = EADDRNOTAVAIL;
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
|
||||
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if (sock < 0) {
|
||||
err = errno;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nonblocking) {
|
||||
setnonblocking(sock);
|
||||
}
|
||||
|
||||
if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
if (errno == EINPROGRESS && nonblocking) {
|
||||
TRACE(("Connect in progress"))
|
||||
break;
|
||||
} else {
|
||||
err = errno;
|
||||
close(sock);
|
||||
sock = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
break; /* Success */
|
||||
}
|
||||
|
||||
if (sock < 0 && !(errno == EINPROGRESS && nonblocking)) {
|
||||
/* Failed */
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
int len;
|
||||
len = 20 + strlen(strerror(err));
|
||||
*errstring = (char*)m_malloc(len);
|
||||
snprintf(*errstring, len, "Error connecting: %s", strerror(err));
|
||||
}
|
||||
TRACE(("Error connecting: %s", strerror(err)))
|
||||
} else {
|
||||
/* Success */
|
||||
set_sock_nodelay(sock);
|
||||
}
|
||||
|
||||
freeaddrinfo(res0);
|
||||
if (sock > 0 && errstring != NULL && *errstring != NULL) {
|
||||
m_free(*errstring);
|
||||
}
|
||||
|
||||
TRACE(("leave connect_remote: sock %d\n", sock))
|
||||
return sock;
|
||||
}
|
||||
|
||||
/* Sets up a pipe for a, returning three non-blocking file descriptors
|
||||
* and the pid. exec_fn is the function that will actually execute the child process,
|
||||
* it will be run after the child has fork()ed, and is passed exec_data.
|
||||
@@ -596,88 +371,6 @@ void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) {
|
||||
execv(usershell, argv);
|
||||
}
|
||||
|
||||
void get_socket_address(int fd, char **local_host, char **local_port,
|
||||
char **remote_host, char **remote_port, int host_lookup)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
|
||||
if (local_host || local_port) {
|
||||
addrlen = sizeof(addr);
|
||||
if (getsockname(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
|
||||
dropbear_exit("Failed socket address: %s", strerror(errno));
|
||||
}
|
||||
getaddrstring(&addr, local_host, local_port, host_lookup);
|
||||
}
|
||||
if (remote_host || remote_port) {
|
||||
addrlen = sizeof(addr);
|
||||
if (getpeername(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
|
||||
dropbear_exit("Failed socket address: %s", strerror(errno));
|
||||
}
|
||||
getaddrstring(&addr, remote_host, remote_port, host_lookup);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return a string representation of the socket address passed. The return
|
||||
* value is allocated with malloc() */
|
||||
void getaddrstring(struct sockaddr_storage* addr,
|
||||
char **ret_host, char **ret_port,
|
||||
int host_lookup) {
|
||||
|
||||
char host[NI_MAXHOST+1], serv[NI_MAXSERV+1];
|
||||
unsigned int len;
|
||||
int ret;
|
||||
|
||||
int flags = NI_NUMERICSERV | NI_NUMERICHOST;
|
||||
|
||||
#ifndef DO_HOST_LOOKUP
|
||||
host_lookup = 0;
|
||||
#endif
|
||||
|
||||
if (host_lookup) {
|
||||
flags = NI_NUMERICSERV;
|
||||
}
|
||||
|
||||
len = sizeof(struct sockaddr_storage);
|
||||
/* Some platforms such as Solaris 8 require that len is the length
|
||||
* of the specific structure. Some older linux systems (glibc 2.1.3
|
||||
* such as debian potato) have sockaddr_storage.__ss_family instead
|
||||
* but we'll ignore them */
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
|
||||
if (addr->ss_family == AF_INET) {
|
||||
len = sizeof(struct sockaddr_in);
|
||||
}
|
||||
#ifdef AF_INET6
|
||||
if (addr->ss_family == AF_INET6) {
|
||||
len = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
|
||||
serv, sizeof(serv)-1, flags);
|
||||
|
||||
if (ret != 0) {
|
||||
if (host_lookup) {
|
||||
/* On some systems (Darwin does it) we get EINTR from getnameinfo
|
||||
* somehow. Eew. So we'll just return the IP, since that doesn't seem
|
||||
* to exhibit that behaviour. */
|
||||
getaddrstring(addr, ret_host, ret_port, 0);
|
||||
return;
|
||||
} else {
|
||||
/* if we can't do a numeric lookup, something's gone terribly wrong */
|
||||
dropbear_exit("Failed lookup: %s", gai_strerror(ret));
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_host) {
|
||||
*ret_host = m_strdup(host);
|
||||
}
|
||||
if (ret_port) {
|
||||
*ret_port = m_strdup(serv);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
void printhex(const char * label, const unsigned char * buf, int len) {
|
||||
|
||||
@@ -811,8 +504,12 @@ out:
|
||||
|
||||
/* make sure that the socket closes */
|
||||
void m_close(int fd) {
|
||||
|
||||
int val;
|
||||
|
||||
if (fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
val = close(fd);
|
||||
} while (val < 0 && errno == EINTR);
|
||||
@@ -916,6 +613,24 @@ int m_str_to_uint(const char* str, unsigned int *val) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns malloced path. inpath beginning with '/' is returned as-is,
|
||||
otherwise home directory is prepended */
|
||||
char * expand_homedir_path(const char *inpath) {
|
||||
struct passwd *pw = NULL;
|
||||
if (inpath[0] != '/') {
|
||||
pw = getpwuid(getuid());
|
||||
if (pw && pw->pw_dir) {
|
||||
int len = strlen(inpath) + strlen(pw->pw_dir) + 2;
|
||||
char *buf = m_malloc(len);
|
||||
snprintf(buf, len, "%s/%s", pw->pw_dir, inpath);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback */
|
||||
return m_strdup(inpath);
|
||||
}
|
||||
|
||||
int constant_time_memcmp(const void* a, const void *b, size_t n)
|
||||
{
|
||||
const char *xa = a, *xb = b;
|
||||
@@ -928,3 +643,57 @@ int constant_time_memcmp(const void* a, const void *b, size_t n)
|
||||
return c;
|
||||
}
|
||||
|
||||
#if defined(__linux__) && defined(SYS_clock_gettime)
|
||||
/* CLOCK_MONOTONIC_COARSE was added in Linux 2.6.32 but took a while to
|
||||
reach userspace include headers */
|
||||
#ifndef CLOCK_MONOTONIC_COARSE
|
||||
#define CLOCK_MONOTONIC_COARSE 6
|
||||
#endif
|
||||
static clockid_t get_linux_clock_source() {
|
||||
struct timespec ts;
|
||||
if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC_COARSE, &ts) == 0) {
|
||||
return CLOCK_MONOTONIC_COARSE;
|
||||
}
|
||||
|
||||
if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts) == 0) {
|
||||
return CLOCK_MONOTONIC;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
time_t monotonic_now() {
|
||||
#if defined(__linux__) && defined(SYS_clock_gettime)
|
||||
static clockid_t clock_source = -2;
|
||||
|
||||
if (clock_source == -2) {
|
||||
/* First run, find out which one works.
|
||||
-1 will fall back to time() */
|
||||
clock_source = get_linux_clock_source();
|
||||
}
|
||||
|
||||
if (clock_source >= 0) {
|
||||
struct timespec ts;
|
||||
if (syscall(SYS_clock_gettime, clock_source, &ts) != 0) {
|
||||
/* Intermittent clock failures should not happen */
|
||||
dropbear_exit("Clock broke");
|
||||
}
|
||||
return ts.tv_sec;
|
||||
}
|
||||
#endif /* linux clock_gettime */
|
||||
|
||||
#if defined(HAVE_MACH_ABSOLUTE_TIME)
|
||||
/* OS X, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
|
||||
static mach_timebase_info_data_t timebase_info;
|
||||
if (timebase_info.denom == 0) {
|
||||
mach_timebase_info(&timebase_info);
|
||||
}
|
||||
return mach_absolute_time() * timebase_info.numer / timebase_info.denom
|
||||
/ 1e9;
|
||||
#endif /* osx mach_absolute_time */
|
||||
|
||||
/* Fallback for everything else - this will sometimes go backwards */
|
||||
return time(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
33
dbutil.h
33
dbutil.h
@@ -22,12 +22,13 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _DBUTIL_H_
|
||||
#ifndef DROPBEAR_DBUTIL_H_
|
||||
|
||||
#define _DBUTIL_H_
|
||||
#define DROPBEAR_DBUTIL_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "queue.h"
|
||||
|
||||
#ifndef DISABLE_SYSLOG
|
||||
void startsyslog();
|
||||
@@ -58,32 +59,18 @@ void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
|
||||
void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2);
|
||||
void printhex(const char * label, const unsigned char * buf, int len);
|
||||
void printmpint(const char *label, mp_int *mp);
|
||||
void debug_start_net();
|
||||
extern int debug_trace;
|
||||
#endif
|
||||
|
||||
enum dropbear_prio {
|
||||
DROPBEAR_PRIO_DEFAULT,
|
||||
DROPBEAR_PRIO_LOWDELAY,
|
||||
DROPBEAR_PRIO_BULK,
|
||||
};
|
||||
|
||||
char * stripcontrol(const char * text);
|
||||
void get_socket_address(int fd, char **local_host, char **local_port,
|
||||
char **remote_host, char **remote_port, int host_lookup);
|
||||
void getaddrstring(struct sockaddr_storage* addr,
|
||||
char **ret_host, char **ret_port, int host_lookup);
|
||||
void set_sock_nodelay(int sock);
|
||||
void set_sock_priority(int sock, enum dropbear_prio prio);
|
||||
int dropbear_listen(const char* address, const char* port,
|
||||
int *socks, unsigned int sockcount, char **errstring, int *maxfd);
|
||||
|
||||
int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
|
||||
int *writefd, int *readfd, int *errfd, pid_t *pid);
|
||||
void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell);
|
||||
#ifdef ENABLE_CONNECT_UNIX
|
||||
int connect_unix(const char* addr);
|
||||
#endif
|
||||
int connect_remote(const char* remotehost, const char* remoteport,
|
||||
int nonblocking, char ** errstring);
|
||||
int buf_readfile(buffer* buf, const char* filename);
|
||||
int buf_getline(buffer * line, FILE * authfile);
|
||||
|
||||
@@ -91,7 +78,7 @@ void m_close(int fd);
|
||||
void * m_malloc(size_t size);
|
||||
void * m_strdup(const char * str);
|
||||
void * m_realloc(void* ptr, size_t size);
|
||||
#define m_free(X) free(X); (X) = NULL;
|
||||
#define m_free(X) do {free(X); (X) = NULL;} while (0)
|
||||
void m_burn(void* data, unsigned int len);
|
||||
void setnonblocking(int fd);
|
||||
void disallow_core();
|
||||
@@ -106,4 +93,10 @@ int m_str_to_uint(const char* str, unsigned int *val);
|
||||
/* Returns 0 if a and b have the same contents */
|
||||
int constant_time_memcmp(const void* a, const void *b, size_t n);
|
||||
|
||||
#endif /* _DBUTIL_H_ */
|
||||
/* Returns a time in seconds that doesn't go backwards - does not correspond to
|
||||
a real-world clock */
|
||||
time_t monotonic_now();
|
||||
|
||||
char * expand_homedir_path(const char *inpath);
|
||||
|
||||
#endif /* DROPBEAR_DBUTIL_H_ */
|
||||
|
||||
42
debian/changelog
vendored
42
debian/changelog
vendored
@@ -1,3 +1,45 @@
|
||||
dropbear (2015.69-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 25 Nov 2015 22:52:58 +0800
|
||||
|
||||
dropbear (2015.68-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Sat, 8 Aug 2015 22:52:58 +0800
|
||||
|
||||
dropbear (2015.67-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 28 Jan 2015 22:53:59 +0800
|
||||
|
||||
dropbear (2014.66-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 23 Oct 2014 22:54:00 +0800
|
||||
|
||||
dropbear (2014.65-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Fri, 8 Aug 2014 22:54:00 +0800
|
||||
|
||||
dropbear (2014.64-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Sun, 27 Jul 2014 22:54:00 +0800
|
||||
|
||||
dropbear (2014.63-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 19 Feb 2014 22:54:00 +0800
|
||||
|
||||
dropbear (2013.62) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
6
debug.h
6
debug.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
#ifndef DROPBEAR_DEBUG_H_
|
||||
#define DROPBEAR_DEBUG_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
|
||||
* since the printing may not sanitise strings etc. This will add a reasonable
|
||||
* amount to your executable size. */
|
||||
/* #define DEBUG_TRACE */
|
||||
/*#define DEBUG_TRACE*/
|
||||
|
||||
/* All functions writing to the cleartext payload buffer call
|
||||
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
|
||||
|
||||
23
dropbear.8
23
dropbear.8
@@ -3,15 +3,13 @@
|
||||
dropbear \- lightweight SSH server
|
||||
.SH SYNOPSIS
|
||||
.B dropbear
|
||||
[\-RFEmwsgjki] [\-b
|
||||
[\fIflag arguments\fR] [\-b
|
||||
.I banner\fR]
|
||||
[\-r
|
||||
.I hostkeyfile\fR] [\-p
|
||||
.IR [address:]port ]
|
||||
.I hostkeyfile\fR] [\-p [\fIaddress\fR:]\fIport\fR]
|
||||
.SH DESCRIPTION
|
||||
.B dropbear
|
||||
is a SSH server designed to be small enough to be used in small memory
|
||||
environments, while still being functional and secure enough for general use.
|
||||
is a small SSH server
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-b \fIbanner
|
||||
@@ -55,7 +53,7 @@ Disable local port forwarding.
|
||||
.B \-k
|
||||
Disable remote port forwarding.
|
||||
.TP
|
||||
.B \-p \fI[address:]port
|
||||
.B \-p\fR [\fIaddress\fR:]\fIport
|
||||
Listen on specified
|
||||
.I address
|
||||
and TCP
|
||||
@@ -88,16 +86,21 @@ Ensure that traffic is transmitted at a certain interval in seconds. This is
|
||||
useful for working around firewalls or routers that drop connections after
|
||||
a certain period of inactivity. The trade-off is that a session may be
|
||||
closed if there is a temporary lapse of network connectivity. A setting
|
||||
if 0 disables keepalives.
|
||||
if 0 disables keepalives. If no response is received for 3 consecutive keepalives the connection will be closed.
|
||||
.TP
|
||||
.B \-I \fIidle_timeout
|
||||
Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
|
||||
.TP
|
||||
.B \-V
|
||||
Print the version
|
||||
|
||||
.SH FILES
|
||||
|
||||
.TP
|
||||
Authorized Keys
|
||||
|
||||
~/.ssh/authorized_keys can be set up to allow remote login with a RSA or DSS
|
||||
~/.ssh/authorized_keys can be set up to allow remote login with a RSA,
|
||||
ECDSA, or DSS
|
||||
key. Each line is of the form
|
||||
.TP
|
||||
[restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment]
|
||||
@@ -124,7 +127,7 @@ Disable PTY allocation. Note that a user can still obtain most of the
|
||||
same functionality with other means even if no-pty is set.
|
||||
|
||||
.TP
|
||||
.B command="\fIforced_command\fR"
|
||||
.B command=\fR"\fIforced_command\fR"
|
||||
Disregard the command provided by the user and always run \fIforced_command\fR.
|
||||
|
||||
The authorized_keys file and its containing ~/.ssh directory must only be
|
||||
@@ -136,7 +139,7 @@ Host Key Files
|
||||
|
||||
Host key files are read at startup from a standard location, by default
|
||||
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key, and
|
||||
/etc/dropbear/dropbear-ecdsa_host_key
|
||||
/etc/dropbear/dropbear_ecdsa_host_key
|
||||
or specified on the commandline with -r. These are of the form generated
|
||||
by dropbearkey. The -R option can be used to automatically generate keys
|
||||
in the default location - keys will be generated after startup when the first
|
||||
|
||||
@@ -21,27 +21,27 @@ from a private key by using
|
||||
.P
|
||||
Encrypted private keys are not supported, use ssh-keygen(1) to decrypt them
|
||||
first.
|
||||
.SH OPTIONS
|
||||
.SH ARGUMENTS
|
||||
.TP
|
||||
.B input type
|
||||
.I input_type
|
||||
Either
|
||||
.I dropbear
|
||||
or
|
||||
.I openssh
|
||||
.TP
|
||||
.B output type
|
||||
.I output_type
|
||||
Either
|
||||
.I dropbear
|
||||
or
|
||||
.I openssh
|
||||
.TP
|
||||
.B input file
|
||||
.I input_file
|
||||
An existing Dropbear or OpenSSH private key file
|
||||
.TP
|
||||
.B output file
|
||||
The path to write the converted private key file
|
||||
.I output_file
|
||||
The path to write the converted private key file. For client authentication ~/.ssh/id_dropbear is loaded by default
|
||||
.SH EXAMPLE
|
||||
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/dropbear_priv
|
||||
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_dropbear
|
||||
.SH AUTHOR
|
||||
Matt Johnston (matt@ucc.asn.au).
|
||||
.SH SEE ALSO
|
||||
|
||||
@@ -9,13 +9,11 @@ dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
|
||||
.I file
|
||||
[\-s
|
||||
.IR bits ]
|
||||
[\-y]
|
||||
.SH DESCRIPTION
|
||||
.B dropbearkey
|
||||
generates a
|
||||
.I RSA
|
||||
.I DSS,
|
||||
or
|
||||
.I ECDSA
|
||||
\fIRSA\fR, \fIDSS\fR, or \fIECDSA\fR
|
||||
format SSH private key, and saves it to a file for the use with the
|
||||
Dropbear client or server.
|
||||
Note that
|
||||
@@ -33,18 +31,25 @@ or
|
||||
.TP
|
||||
.B \-f \fIfile
|
||||
Write the secret key to the file
|
||||
.IR file .
|
||||
\fIfile\fR. For client authentication ~/.ssh/id_dropbear is loaded by default
|
||||
.TP
|
||||
.B \-s \fIbits
|
||||
Set the key size to
|
||||
.I bits
|
||||
bits, should be multiple of 8 (optional).
|
||||
.TP
|
||||
.B \-y
|
||||
Just print the publickey and fingerprint for the private key in \fIfile\fR.
|
||||
.SH NOTES
|
||||
The program dropbearconvert(1) can be used to convert between Dropbear and OpenSSH key formats.
|
||||
.P
|
||||
Dropbear does not support encrypted keys.
|
||||
.SH EXAMPLE
|
||||
generate a host-key:
|
||||
# dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
|
||||
|
||||
extract a public key suitable for authorized_keys from private key:
|
||||
# dropbearkey -y -f id_rsa | grep "^ssh-rsa " >> authorized_keys
|
||||
.SH AUTHOR
|
||||
Matt Johnston (matt@ucc.asn.au).
|
||||
.br
|
||||
|
||||
@@ -76,7 +76,8 @@ static void printhelp(char * progname) {
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
" ecdsa\n"
|
||||
#endif
|
||||
"-f filename Use filename for the secret key\n"
|
||||
"-f filename Use filename for the secret key.\n"
|
||||
" ~/.ssh/id_dropbear is recommended for client keys.\n"
|
||||
"-s bits Key size in bits, should be a multiple of 8 (optional)\n"
|
||||
#ifdef DROPBEAR_DSS
|
||||
" DSS has a fixed size of 1024 bits\n"
|
||||
|
||||
6
dss.c
6
dss.c
@@ -165,7 +165,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
DEF_MP_INT(val3);
|
||||
DEF_MP_INT(val4);
|
||||
char * string = NULL;
|
||||
int stringlen;
|
||||
unsigned int stringlen;
|
||||
|
||||
TRACE(("enter buf_dss_verify"))
|
||||
dropbear_assert(key != NULL);
|
||||
@@ -186,7 +186,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
/* create the signature - s' and r' are the received signatures in buf */
|
||||
/* w = (s')-1 mod q */
|
||||
/* let val1 = s' */
|
||||
bytes_to_mp(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
|
||||
bytes_to_mp(&val1, (const unsigned char*) &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
|
||||
|
||||
if (mp_cmp(&val1, key->q) != MP_LT) {
|
||||
TRACE(("verify failed, s' >= q"))
|
||||
@@ -208,7 +208,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
|
||||
/* u2 = ((r')w) mod q */
|
||||
/* let val1 = r' */
|
||||
bytes_to_mp(&val1, &string[0], SHA1_HASH_SIZE);
|
||||
bytes_to_mp(&val1, (const unsigned char*) &string[0], SHA1_HASH_SIZE);
|
||||
if (mp_cmp(&val1, key->q) != MP_LT) {
|
||||
TRACE(("verify failed, r' >= q"))
|
||||
goto out;
|
||||
|
||||
6
dss.h
6
dss.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _DSS_H_
|
||||
#define _DSS_H_
|
||||
#ifndef DROPBEAR_DSS_H_
|
||||
#define DROPBEAR_DSS_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
@@ -53,4 +53,4 @@ void dss_key_free(dropbear_dss_key *key);
|
||||
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
#endif /* _DSS_H_ */
|
||||
#endif /* DROPBEAR_DSS_H_ */
|
||||
|
||||
5
ecc.c
5
ecc.c
@@ -86,11 +86,6 @@ static int ecc_is_point(ecc_key *key)
|
||||
{
|
||||
mp_int *prime, *b, *t1, *t2;
|
||||
int err;
|
||||
|
||||
prime = m_malloc(sizeof(mp_int));
|
||||
b = m_malloc(sizeof(mp_int));
|
||||
t1 = m_malloc(sizeof(mp_int));
|
||||
t2 = m_malloc(sizeof(mp_int));
|
||||
|
||||
m_mp_alloc_init_multi(&prime, &b, &t1, &t2, NULL);
|
||||
|
||||
|
||||
8
ecc.h
8
ecc.h
@@ -1,5 +1,5 @@
|
||||
#ifndef _DROPBEAR_ECC_H
|
||||
#define _DROPBEAR_ECC_H
|
||||
#ifndef DROPBEAR_DROPBEAR_ECC_H
|
||||
#define DROPBEAR_DROPBEAR_ECC_H
|
||||
|
||||
#include "includes.h"
|
||||
#include "options.h"
|
||||
@@ -12,7 +12,7 @@ struct dropbear_ecc_curve {
|
||||
int ltc_size; /* to match the byte sizes in ltc_ecc_sets[] */
|
||||
const ltc_ecc_set_type *dp; /* curve domain parameters */
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
const unsigned char *name;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
extern struct dropbear_ecc_curve ecc_curve_nistp256;
|
||||
@@ -33,4 +33,4 @@ mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, ecc_key *priv_key);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _DROPBEAR_ECC_H */
|
||||
#endif /* DROPBEAR_DROPBEAR_ECC_H */
|
||||
|
||||
15
ecdsa.c
15
ecdsa.c
@@ -83,9 +83,9 @@ ecc_key *buf_get_ecdsa_pub_key(buffer* buf) {
|
||||
ecc_key *new_key = NULL;
|
||||
|
||||
/* string "ecdsa-sha2-[identifier]" */
|
||||
key_ident = buf_getstring(buf, &key_ident_len);
|
||||
key_ident = (unsigned char*)buf_getstring(buf, &key_ident_len);
|
||||
/* string "[identifier]" */
|
||||
identifier = buf_getstring(buf, &identifier_len);
|
||||
identifier = (unsigned char*)buf_getstring(buf, &identifier_len);
|
||||
|
||||
if (key_ident_len != identifier_len + strlen("ecdsa-sha2-")) {
|
||||
TRACE(("Bad identifier lengths"))
|
||||
@@ -131,6 +131,7 @@ ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
|
||||
|
||||
if (buf_getmpint(buf, new_key->k) != DROPBEAR_SUCCESS) {
|
||||
ecc_free(new_key);
|
||||
m_free(new_key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -139,10 +140,10 @@ ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
|
||||
|
||||
void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) {
|
||||
struct dropbear_ecc_curve *curve = NULL;
|
||||
unsigned char key_ident[30];
|
||||
char key_ident[30];
|
||||
|
||||
curve = curve_for_dp(key->dp);
|
||||
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
|
||||
snprintf(key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
|
||||
buf_putstring(buf, key_ident, strlen(key_ident));
|
||||
buf_putstring(buf, curve->name, strlen(curve->name));
|
||||
buf_put_ecc_raw_pubkey_string(buf, key);
|
||||
@@ -160,7 +161,7 @@ void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) {
|
||||
hash_state hs;
|
||||
unsigned char hash[64];
|
||||
void *e = NULL, *p = NULL, *s = NULL, *r;
|
||||
unsigned char key_ident[30];
|
||||
char key_ident[30];
|
||||
buffer *sigbuf = NULL;
|
||||
|
||||
TRACE(("buf_put_ecdsa_sign"))
|
||||
@@ -221,7 +222,7 @@ void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) {
|
||||
}
|
||||
}
|
||||
|
||||
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
|
||||
snprintf(key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
|
||||
buf_putstring(buf, key_ident, strlen(key_ident));
|
||||
/* enough for nistp521 */
|
||||
sigbuf = buf_new(200);
|
||||
@@ -408,7 +409,7 @@ int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) {
|
||||
out:
|
||||
ltc_ecc_del_point(mG);
|
||||
ltc_ecc_del_point(mQ);
|
||||
mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL);
|
||||
ltc_deinit_multi(r, s, v, w, u1, u2, p, e, m, NULL);
|
||||
if (mp != NULL) {
|
||||
ltc_mp.montgomery_deinit(mp);
|
||||
}
|
||||
|
||||
6
ecdsa.h
6
ecdsa.h
@@ -1,5 +1,5 @@
|
||||
#ifndef _ECDSA_H_
|
||||
#define _ECDSA_H_
|
||||
#ifndef DROPBEAR_ECDSA_H_
|
||||
#define DROPBEAR_ECDSA_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
@@ -32,4 +32,4 @@ int signkey_is_ecdsa(enum signkey_type type);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _ECDSA_H_ */
|
||||
#endif /* DROPBEAR_ECDSA_H_ */
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
* that ai_family is AF_INET. Don't use it for another purpose.
|
||||
*/
|
||||
|
||||
#ifndef _FAKE_RFC2553_H
|
||||
#define _FAKE_RFC2553_H
|
||||
#ifndef DROPBEAR_FAKE_RFC2553_H
|
||||
#define DROPBEAR_FAKE_RFC2553_H
|
||||
|
||||
#include "includes.h"
|
||||
#include <sys/types.h>
|
||||
|
||||
2
gendss.c
2
gendss.c
@@ -67,7 +67,7 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
|
||||
|
||||
static void getq(dropbear_dss_key *key) {
|
||||
|
||||
char buf[QSIZE];
|
||||
unsigned char buf[QSIZE];
|
||||
|
||||
/* 160 bit prime */
|
||||
genrandom(buf, QSIZE);
|
||||
|
||||
6
gendss.h
6
gendss.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _GENDSS_H_
|
||||
#define _GENDSS_H_
|
||||
#ifndef DROPBEAR_GENDSS_H_
|
||||
#define DROPBEAR_GENDSS_H_
|
||||
|
||||
#include "dss.h"
|
||||
|
||||
@@ -33,4 +33,4 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size);
|
||||
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
#endif /* _GENDSS_H_ */
|
||||
#endif /* DROPBEAR_GENDSS_H_ */
|
||||
|
||||
26
genrsa.c
26
genrsa.c
@@ -58,12 +58,18 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
getrsaprime(key->p, &pminus, key->e, size/16);
|
||||
getrsaprime(key->q, &qminus, key->e, size/16);
|
||||
while (1) {
|
||||
getrsaprime(key->p, &pminus, key->e, size/16);
|
||||
getrsaprime(key->q, &qminus, key->e, size/16);
|
||||
|
||||
if (mp_mul(key->p, key->q, key->n) != MP_OKAY) {
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
if (mp_mul(key->p, key->q, key->n) != MP_OKAY) {
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((unsigned int)mp_count_bits(key->n) == size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* lcm(p-1, q-1) */
|
||||
@@ -91,16 +97,16 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
unsigned char *buf;
|
||||
DEF_MP_INT(temp_gcd);
|
||||
|
||||
buf = (unsigned char*)m_malloc(size_bytes+1);
|
||||
buf = (unsigned char*)m_malloc(size_bytes);
|
||||
|
||||
m_mp_init(&temp_gcd);
|
||||
do {
|
||||
/* generate a random odd number with MSB set, then find the
|
||||
the next prime above it */
|
||||
genrandom(buf, size_bytes+1);
|
||||
buf[0] |= 0x80; /* MSB set */
|
||||
genrandom(buf, size_bytes);
|
||||
buf[0] |= 0x80;
|
||||
|
||||
bytes_to_mp(prime, buf, size_bytes+1);
|
||||
bytes_to_mp(prime, buf, size_bytes);
|
||||
|
||||
/* find the next integer which is prime, 8 round of miller-rabin */
|
||||
if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) {
|
||||
@@ -122,7 +128,7 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
|
||||
/* now we have a good value for result */
|
||||
mp_clear(&temp_gcd);
|
||||
m_burn(buf, size_bytes+1);
|
||||
m_burn(buf, size_bytes);
|
||||
m_free(buf);
|
||||
}
|
||||
|
||||
|
||||
6
genrsa.h
6
genrsa.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _GENRSA_H_
|
||||
#define _GENRSA_H_
|
||||
#ifndef DROPBEAR_GENRSA_H_
|
||||
#define DROPBEAR_GENRSA_H_
|
||||
|
||||
#include "rsa.h"
|
||||
|
||||
@@ -33,4 +33,4 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size);
|
||||
|
||||
#endif /* DROPBEAR_RSA */
|
||||
|
||||
#endif /* _GENRSA_H_ */
|
||||
#endif /* DROPBEAR_GENRSA_H_ */
|
||||
|
||||
@@ -26,7 +26,7 @@ static int buf_writefile(buffer * buf, const char * filename) {
|
||||
while (buf->pos != buf->len) {
|
||||
int len = write(fd, buf_getptr(buf, buf->len - buf->pos),
|
||||
buf->len - buf->pos);
|
||||
if (errno == EINTR) {
|
||||
if (len == -1 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (len <= 0) {
|
||||
@@ -41,6 +41,9 @@ static int buf_writefile(buffer * buf, const char * filename) {
|
||||
|
||||
out:
|
||||
if (fd >= 0) {
|
||||
if (fsync(fd) != 0) {
|
||||
dropbear_log(LOG_ERR, "fsync of %s failed: %s", filename, strerror(errno));
|
||||
}
|
||||
m_close(fd);
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef _GENSIGNKEY_H
|
||||
#define _GENSIGNKEY_H
|
||||
#ifndef DROPBEAR_GENSIGNKEY_H
|
||||
#define DROPBEAR_GENSIGNKEY_H
|
||||
|
||||
#include "signkey.h"
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _INCLUDES_H_
|
||||
#define _INCLUDES_H_
|
||||
#ifndef DROPBEAR_INCLUDES_H_
|
||||
#define DROPBEAR_INCLUDES_H_
|
||||
|
||||
|
||||
#include "config.h"
|
||||
@@ -157,6 +157,7 @@ typedef u_int32_t uint32_t;
|
||||
#endif /* HAVE_UINT32_T */
|
||||
|
||||
#ifdef SO_PRIORITY
|
||||
#include <linux/types.h>
|
||||
#include <linux/pkt_sched.h>
|
||||
#endif
|
||||
|
||||
@@ -176,4 +177,4 @@ typedef u_int32_t uint32_t;
|
||||
# define UNUSED(x) x
|
||||
#endif
|
||||
|
||||
#endif /* _INCLUDES_H_ */
|
||||
#endif /* DROPBEAR_INCLUDES_H_ */
|
||||
|
||||
6
kex.h
6
kex.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _KEX_H_
|
||||
#define _KEX_H_
|
||||
#ifndef DROPBEAR_KEX_H_
|
||||
#define DROPBEAR_KEX_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
@@ -113,4 +113,4 @@ int curve25519_donna(unsigned char *out, const unsigned char *secret, const unsi
|
||||
|
||||
#define MAX_KEXHASHBUF 2000
|
||||
|
||||
#endif /* _KEX_H_ */
|
||||
#endif /* DROPBEAR_KEX_H_ */
|
||||
|
||||
51
keyimport.c
51
keyimport.c
@@ -193,7 +193,7 @@ out:
|
||||
static void base64_encode_fp(FILE * fp, unsigned char *data,
|
||||
int datalen, int cpl)
|
||||
{
|
||||
char out[100];
|
||||
unsigned char out[100];
|
||||
int n;
|
||||
unsigned long outlen;
|
||||
int rawcpl;
|
||||
@@ -445,7 +445,7 @@ static struct openssh_key *load_openssh_key(const char *filename)
|
||||
ret->keyblob_size);
|
||||
}
|
||||
outlen = ret->keyblob_size - ret->keyblob_len;
|
||||
if (base64_decode(buffer, len,
|
||||
if (base64_decode((const unsigned char *)buffer, len,
|
||||
ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){
|
||||
errmsg = "Error decoding base64";
|
||||
goto error;
|
||||
@@ -464,17 +464,16 @@ static struct openssh_key *load_openssh_key(const char *filename)
|
||||
goto error;
|
||||
}
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
m_burn(buffer, sizeof(buffer));
|
||||
return ret;
|
||||
|
||||
error:
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
m_burn(buffer, sizeof(buffer));
|
||||
if (ret) {
|
||||
if (ret->keyblob) {
|
||||
memset(ret->keyblob, 0, ret->keyblob_size);
|
||||
m_burn(ret->keyblob, ret->keyblob_size);
|
||||
m_free(ret->keyblob);
|
||||
}
|
||||
memset(&ret, 0, sizeof(ret));
|
||||
m_free(ret);
|
||||
}
|
||||
if (fp) {
|
||||
@@ -494,9 +493,8 @@ static int openssh_encrypted(const char *filename)
|
||||
if (!key)
|
||||
return 0;
|
||||
ret = key->encrypted;
|
||||
memset(key->keyblob, 0, key->keyblob_size);
|
||||
m_burn(key->keyblob, key->keyblob_size);
|
||||
m_free(key->keyblob);
|
||||
memset(&key, 0, sizeof(key));
|
||||
m_free(key);
|
||||
return ret;
|
||||
}
|
||||
@@ -509,7 +507,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
|
||||
int i, num_integers = 0;
|
||||
sign_key *retval = NULL;
|
||||
char *errmsg;
|
||||
char *modptr = NULL;
|
||||
unsigned char *modptr = NULL;
|
||||
int modlen = -9999;
|
||||
enum signkey_type type;
|
||||
|
||||
@@ -602,13 +600,18 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
|
||||
*/
|
||||
blobbuf = buf_new(3000);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (key->type == OSSH_DSA) {
|
||||
buf_putstring(blobbuf, "ssh-dss", 7);
|
||||
retkey->type = DROPBEAR_SIGNKEY_DSS;
|
||||
} else if (key->type == OSSH_RSA) {
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (key->type == OSSH_RSA) {
|
||||
buf_putstring(blobbuf, "ssh-rsa", 7);
|
||||
retkey->type = DROPBEAR_SIGNKEY_RSA;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < num_integers; i++) {
|
||||
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
|
||||
@@ -622,7 +625,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
|
||||
|
||||
if (i == 0) {
|
||||
/* First integer is a version indicator */
|
||||
int expected;
|
||||
int expected = -1;
|
||||
switch (key->type) {
|
||||
case OSSH_RSA:
|
||||
case OSSH_DSA:
|
||||
@@ -643,12 +646,12 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
|
||||
*/
|
||||
if (i == 1) {
|
||||
/* Save the details for after we deal with number 2. */
|
||||
modptr = (char *)p;
|
||||
modptr = p;
|
||||
modlen = len;
|
||||
} else if (i >= 2 && i <= 5) {
|
||||
buf_putstring(blobbuf, p, len);
|
||||
buf_putstring(blobbuf, (const char*)p, len);
|
||||
if (i == 2) {
|
||||
buf_putstring(blobbuf, modptr, modlen);
|
||||
buf_putstring(blobbuf, (const char*)modptr, modlen);
|
||||
}
|
||||
}
|
||||
} else if (key->type == OSSH_DSA) {
|
||||
@@ -656,7 +659,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
|
||||
* OpenSSH key order is p, q, g, y, x,
|
||||
* we want the same.
|
||||
*/
|
||||
buf_putstring(blobbuf, p, len);
|
||||
buf_putstring(blobbuf, (const char*)p, len);
|
||||
}
|
||||
|
||||
/* Skip past the number. */
|
||||
@@ -805,7 +808,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
|
||||
}
|
||||
m_burn(key->keyblob, key->keyblob_size);
|
||||
m_free(key->keyblob);
|
||||
m_burn(key, sizeof(key));
|
||||
m_burn(key, sizeof(*key));
|
||||
m_free(key);
|
||||
if (errmsg) {
|
||||
fprintf(stderr, "Error: %s\n", errmsg);
|
||||
@@ -821,7 +824,7 @@ static int openssh_write(const char *filename, sign_key *key,
|
||||
unsigned char *outblob = NULL;
|
||||
int outlen = -9999;
|
||||
struct mpint_pos numbers[9];
|
||||
int nnumbers = -1, pos, len, seqlen, i;
|
||||
int nnumbers = -1, pos = 0, len = 0, seqlen, i;
|
||||
char *header = NULL, *footer = NULL;
|
||||
char zero[1];
|
||||
int ret = 0;
|
||||
@@ -831,7 +834,14 @@ static int openssh_write(const char *filename, sign_key *key,
|
||||
mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */
|
||||
#endif
|
||||
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA || key->type == DROPBEAR_SIGNKEY_DSS)
|
||||
if (
|
||||
#ifdef DROPBEAR_RSA
|
||||
key->type == DROPBEAR_SIGNKEY_RSA ||
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
key->type == DROPBEAR_SIGNKEY_DSS ||
|
||||
#endif
|
||||
0)
|
||||
{
|
||||
/*
|
||||
* Fetch the key blobs.
|
||||
@@ -1033,7 +1043,8 @@ static int openssh_write(const char *filename, sign_key *key,
|
||||
int curve_oid_len = 0;
|
||||
const void* curve_oid = NULL;
|
||||
unsigned long pubkey_size = 2*curve_size+1;
|
||||
unsigned int k_size;
|
||||
int k_size;
|
||||
int err = 0;
|
||||
|
||||
/* version. less than 10 bytes */
|
||||
buf_incrwritepos(seq_buf,
|
||||
@@ -1079,7 +1090,7 @@ static int openssh_write(const char *filename, sign_key *key,
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 3, 1+pubkey_size, 0));
|
||||
buf_putbyte(seq_buf, 0);
|
||||
int err = ecc_ansi_x963_export(*eck, buf_getwriteptr(seq_buf, pubkey_size), &pubkey_size);
|
||||
err = ecc_ansi_x963_export(*eck, buf_getwriteptr(seq_buf, pubkey_size), &pubkey_size);
|
||||
if (err != CRYPT_OK) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _KEYIMPORT_H_
|
||||
#define _KEYIMPORT_H_
|
||||
#ifndef DROPBEAR_KEYIMPORT_H_
|
||||
#define DROPBEAR_KEYIMPORT_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
@@ -39,4 +39,4 @@ int import_write(const char *filename, sign_key *key, char *passphrase,
|
||||
sign_key *import_read(const char *filename, char *passphrase, int filetype);
|
||||
int import_encrypted(const char* filename, int filetype);
|
||||
|
||||
#endif /* _KEYIMPORT_H_ */
|
||||
#endif /* DROPBEAR_KEYIMPORT_H_ */
|
||||
|
||||
@@ -122,9 +122,10 @@ static ulong32 setup_mix2(ulong32 temp)
|
||||
*/
|
||||
int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
|
||||
{
|
||||
int i, j;
|
||||
int i;
|
||||
ulong32 temp, *rk;
|
||||
#ifndef ENCRYPT_ONLY
|
||||
int j;
|
||||
ulong32 *rrk;
|
||||
#endif
|
||||
LTC_ARGCHK(key != NULL);
|
||||
@@ -148,7 +149,9 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
|
||||
LOAD32H(rk[2], key + 8);
|
||||
LOAD32H(rk[3], key + 12);
|
||||
if (keylen == 16) {
|
||||
#ifndef ENCRYPT_ONLY
|
||||
j = 44;
|
||||
#endif
|
||||
for (;;) {
|
||||
temp = rk[3];
|
||||
rk[4] = rk[0] ^ setup_mix(temp) ^ rcon[i];
|
||||
@@ -161,7 +164,9 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
|
||||
rk += 4;
|
||||
}
|
||||
} else if (keylen == 24) {
|
||||
#ifndef ENCRYPT_ONLY
|
||||
j = 52;
|
||||
#endif
|
||||
LOAD32H(rk[4], key + 16);
|
||||
LOAD32H(rk[5], key + 20);
|
||||
for (;;) {
|
||||
@@ -182,7 +187,9 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
|
||||
rk += 6;
|
||||
}
|
||||
} else if (keylen == 32) {
|
||||
#ifndef ENCRYPT_ONLY
|
||||
j = 60;
|
||||
#endif
|
||||
LOAD32H(rk[4], key + 16);
|
||||
LOAD32H(rk[5], key + 20);
|
||||
LOAD32H(rk[6], key + 24);
|
||||
@@ -728,6 +735,7 @@ int ECB_TEST(void)
|
||||
*/
|
||||
void ECB_DONE(symmetric_key *skey)
|
||||
{
|
||||
(void)skey;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1871,6 +1871,7 @@ void des_done(symmetric_key *skey)
|
||||
*/
|
||||
void des3_done(symmetric_key *skey)
|
||||
{
|
||||
(void)skey;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -684,6 +684,7 @@ int twofish_test(void)
|
||||
*/
|
||||
void twofish_done(symmetric_key *skey)
|
||||
{
|
||||
(void)skey;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
int hash_file(int hash, const char *fname, unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
#ifdef LTC_NO_FILE
|
||||
(void)hash; (void)fname; (void)out; (void)outlen;
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
FILE *in;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
#ifdef LTC_NO_FILE
|
||||
(void)hash; (void)in; (void)out; (void)outlen;
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
hash_state md;
|
||||
|
||||
@@ -4,8 +4,16 @@
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
/* portability macros for compiler-specific code attributes */
|
||||
#ifdef __GNUC__
|
||||
#define ATTRIB_NORETURN __attribute__((noreturn))
|
||||
#else
|
||||
#define ATTRIB_NORETURN
|
||||
#endif
|
||||
|
||||
|
||||
/* this is the default LibTomCrypt macro */
|
||||
void crypt_argchk(char *v, char *s, int d);
|
||||
void crypt_argchk(char *v, char *s, int d) ATTRIB_NORETURN;
|
||||
#define LTC_ARGCHK(x) if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); }
|
||||
#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
*/
|
||||
int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
unsigned char *buf, *isha;
|
||||
unsigned char buf[MAXBLOCKSIZE], isha[MAXBLOCKSIZE];
|
||||
unsigned long hashsize, i;
|
||||
int hash, err;
|
||||
|
||||
@@ -44,19 +44,6 @@ int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen)
|
||||
/* get the hash message digest size */
|
||||
hashsize = hash_descriptor[hash].hashsize;
|
||||
|
||||
/* allocate buffers */
|
||||
buf = XMALLOC(HMAC_BLOCKSIZE);
|
||||
isha = XMALLOC(hashsize);
|
||||
if (buf == NULL || isha == NULL) {
|
||||
if (buf != NULL) {
|
||||
XFREE(buf);
|
||||
}
|
||||
if (isha != NULL) {
|
||||
XFREE(isha);
|
||||
}
|
||||
return CRYPT_MEM;
|
||||
}
|
||||
|
||||
/* Get the hash of the first HMAC vector plus the data */
|
||||
if ((err = hash_descriptor[hash].done(&hmac->md, isha)) != CRYPT_OK) {
|
||||
goto LBL_ERR;
|
||||
@@ -96,9 +83,6 @@ LBL_ERR:
|
||||
zeromem(hmac, sizeof(*hmac));
|
||||
#endif
|
||||
|
||||
XFREE(isha);
|
||||
XFREE(buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ int hmac_file(int hash, const char *fname,
|
||||
unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
#ifdef LTC_NO_FILE
|
||||
(void)hash; (void)fname; (void)key; (void)keylen; (void)out; (void)outlen;
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
hmac_state hmac;
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
*/
|
||||
int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen)
|
||||
{
|
||||
unsigned char *buf;
|
||||
unsigned char buf[MAXBLOCKSIZE];
|
||||
unsigned long hashsize;
|
||||
unsigned long i, z;
|
||||
int err;
|
||||
@@ -49,16 +49,9 @@ int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned lon
|
||||
return CRYPT_INVALID_KEYSIZE;
|
||||
}
|
||||
|
||||
/* allocate ram for buf */
|
||||
buf = XMALLOC(HMAC_BLOCKSIZE);
|
||||
if (buf == NULL) {
|
||||
return CRYPT_MEM;
|
||||
}
|
||||
|
||||
/* allocate memory for key */
|
||||
hmac->key = XMALLOC(HMAC_BLOCKSIZE);
|
||||
if (hmac->key == NULL) {
|
||||
XFREE(buf);
|
||||
return CRYPT_MEM;
|
||||
}
|
||||
|
||||
@@ -101,7 +94,6 @@ done:
|
||||
zeromem(buf, HMAC_BLOCKSIZE);
|
||||
#endif
|
||||
|
||||
XFREE(buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ void crypt_argchk(char *v, char *s, int d)
|
||||
{
|
||||
fprintf(stderr, "LTC_ARGCHK '%s' failure on line %d of file %s\n",
|
||||
v, d, s);
|
||||
(void)raise(SIGABRT);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map)
|
||||
int i, j, err;
|
||||
void *mu, *mp;
|
||||
unsigned long buf;
|
||||
int first, bitbuf, bitcpy, bitcnt, mode, digidx;
|
||||
int bitcnt, mode, digidx;
|
||||
|
||||
LTC_ARGCHK(k != NULL);
|
||||
LTC_ARGCHK(G != NULL);
|
||||
@@ -98,8 +98,6 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map)
|
||||
bitcnt = 1;
|
||||
buf = 0;
|
||||
digidx = mp_get_digit_count(k) - 1;
|
||||
bitcpy = bitbuf = 0;
|
||||
first = 1;
|
||||
|
||||
/* perform ops */
|
||||
for (;;) {
|
||||
|
||||
6
list.h
6
list.h
@@ -1,5 +1,5 @@
|
||||
#ifndef _DROPBEAR_LIST_H
|
||||
#define _DROPBEAR_LIST_H
|
||||
#ifndef DROPBEAR_DROPBEAR_LIST_H
|
||||
#define DROPBEAR_DROPBEAR_LIST_H
|
||||
|
||||
struct _m_list;
|
||||
|
||||
@@ -25,4 +25,4 @@ void list_append(m_list *list, void *item);
|
||||
void * list_remove(m_list_elem *elem);
|
||||
|
||||
|
||||
#endif /* _DROPBEAR_LIST_H */
|
||||
#endif /* DROPBEAR_DROPBEAR_LIST_H */
|
||||
|
||||
11
listener.c
11
listener.c
@@ -161,5 +161,14 @@ void remove_listener(struct Listener* listener) {
|
||||
}
|
||||
ses.listeners[listener->index] = NULL;
|
||||
m_free(listener);
|
||||
|
||||
}
|
||||
|
||||
void remove_all_listeners(void) {
|
||||
unsigned int i;
|
||||
for (i = 0; i < ses.listensize; i++) {
|
||||
if (ses.listeners[i]) {
|
||||
remove_listener(ses.listeners[i]);
|
||||
}
|
||||
}
|
||||
m_free(ses.listeners);
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _LISTENER_H
|
||||
#define _LISTENER_H
|
||||
#ifndef DROPBEAR_LISTENER_H
|
||||
#define DROPBEAR_LISTENER_H
|
||||
|
||||
#define MAX_LISTENERS 20
|
||||
#define LISTENER_EXTEND_SIZE 1
|
||||
@@ -60,4 +60,6 @@ struct Listener * get_listener(int type, void* typedata,
|
||||
|
||||
void remove_listener(struct Listener* listener);
|
||||
|
||||
#endif /* _LISTENER_H */
|
||||
void remove_all_listeners(void);
|
||||
|
||||
#endif /* DROPBEAR_LISTENER_H */
|
||||
|
||||
10
loginrec.h
10
loginrec.h
@@ -1,5 +1,5 @@
|
||||
#ifndef _HAVE_LOGINREC_H_
|
||||
#define _HAVE_LOGINREC_H_
|
||||
#ifndef DROPBEAR_HAVE_LOGINREC_H_
|
||||
#define DROPBEAR_HAVE_LOGINREC_H_
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Andre Lucas. All rights reserved.
|
||||
@@ -79,10 +79,10 @@
|
||||
# if defined(HAVE_UTMP_H) && defined(UTMP_FILE) && !defined(DISABLE_UTMP)
|
||||
# define USE_UTMP
|
||||
# endif
|
||||
# if defined(HAVE_WTMPX_H) && defined(WTMPX_FILE) && !defined(DISABLE_WTMPX)
|
||||
# if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX)
|
||||
# define USE_WTMPX
|
||||
# endif
|
||||
# if defined(HAVE_WTMP_H) && defined(WTMP_FILE) && !defined(DISABLE_WTMP)
|
||||
# if defined(WTMP_FILE) && !defined(DISABLE_WTMP)
|
||||
# define USE_WTMP
|
||||
# endif
|
||||
|
||||
@@ -182,4 +182,4 @@ char *line_fullname(char *dst, const char *src, size_t dstsize);
|
||||
char *line_stripname(char *dst, const char *src, size_t dstsize);
|
||||
char *line_abbrevname(char *dst, const char *src, size_t dstsize);
|
||||
|
||||
#endif /* _HAVE_LOGINREC_H_ */
|
||||
#endif /* DROPBEAR_HAVE_LOGINREC_H_ */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef _LTC_PRNG_H_DROPBEAR
|
||||
#define _LTC_PRNG_H_DROPBEAR
|
||||
#ifndef DROPBEAR_LTC_PRNG_H_DROPBEAR
|
||||
#define DROPBEAR_LTC_PRNG_H_DROPBEAR
|
||||
|
||||
#include "options.h"
|
||||
#include "includes.h"
|
||||
@@ -10,4 +10,4 @@ extern const struct ltc_prng_descriptor dropbear_prng_desc;
|
||||
|
||||
#endif /* DROPBEAR_LTC_PRNG */
|
||||
|
||||
#endif /* _LTC_PRNG_H_DROPBEAR */
|
||||
#endif /* DROPBEAR_LTC_PRNG_H_DROPBEAR */
|
||||
|
||||
560
netio.c
Normal file
560
netio.c
Normal file
@@ -0,0 +1,560 @@
|
||||
#include "netio.h"
|
||||
#include "list.h"
|
||||
#include "dbutil.h"
|
||||
#include "session.h"
|
||||
#include "debug.h"
|
||||
|
||||
struct dropbear_progress_connection {
|
||||
struct addrinfo *res;
|
||||
struct addrinfo *res_iter;
|
||||
|
||||
char *remotehost, *remoteport; /* For error reporting */
|
||||
|
||||
connect_callback cb;
|
||||
void *cb_data;
|
||||
|
||||
struct Queue *writequeue; /* A queue of encrypted packets to send with TCP fastopen,
|
||||
or NULL. */
|
||||
|
||||
int sock;
|
||||
|
||||
char* errstring;
|
||||
};
|
||||
|
||||
/* Deallocate a progress connection. Removes from the pending list if iter!=NULL.
|
||||
Does not close sockets */
|
||||
static void remove_connect(struct dropbear_progress_connection *c, m_list_elem *iter) {
|
||||
if (c->res) {
|
||||
freeaddrinfo(c->res);
|
||||
}
|
||||
m_free(c->remotehost);
|
||||
m_free(c->remoteport);
|
||||
m_free(c->errstring);
|
||||
m_free(c);
|
||||
|
||||
if (iter) {
|
||||
list_remove(iter);
|
||||
}
|
||||
}
|
||||
|
||||
static void cancel_callback(int result, int sock, void* UNUSED(data), const char* UNUSED(errstring)) {
|
||||
if (result == DROPBEAR_SUCCESS)
|
||||
{
|
||||
m_close(sock);
|
||||
}
|
||||
}
|
||||
|
||||
void cancel_connect(struct dropbear_progress_connection *c) {
|
||||
c->cb = cancel_callback;
|
||||
c->cb_data = NULL;
|
||||
}
|
||||
|
||||
static void connect_try_next(struct dropbear_progress_connection *c) {
|
||||
struct addrinfo *r;
|
||||
int res = 0;
|
||||
int fastopen = 0;
|
||||
#ifdef DROPBEAR_CLIENT_TCP_FAST_OPEN
|
||||
struct msghdr message;
|
||||
#endif
|
||||
|
||||
for (r = c->res_iter; r; r = r->ai_next)
|
||||
{
|
||||
dropbear_assert(c->sock == -1);
|
||||
|
||||
c->sock = socket(c->res_iter->ai_family, c->res_iter->ai_socktype, c->res_iter->ai_protocol);
|
||||
if (c->sock < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ses.maxfd = MAX(ses.maxfd, c->sock);
|
||||
set_sock_nodelay(c->sock);
|
||||
setnonblocking(c->sock);
|
||||
|
||||
#ifdef DROPBEAR_CLIENT_TCP_FAST_OPEN
|
||||
fastopen = (c->writequeue != NULL);
|
||||
|
||||
if (fastopen) {
|
||||
memset(&message, 0x0, sizeof(message));
|
||||
message.msg_name = r->ai_addr;
|
||||
message.msg_namelen = r->ai_addrlen;
|
||||
/* 6 is arbitrary, enough to hold initial packets */
|
||||
unsigned int iovlen = 6; /* Linux msg_iovlen is a size_t */
|
||||
struct iovec iov[6];
|
||||
packet_queue_to_iovec(c->writequeue, iov, &iovlen);
|
||||
message.msg_iov = iov;
|
||||
message.msg_iovlen = iovlen;
|
||||
res = sendmsg(c->sock, &message, MSG_FASTOPEN);
|
||||
/* Returns EINPROGRESS if FASTOPEN wasn't available */
|
||||
if (res < 0) {
|
||||
if (errno != EINPROGRESS) {
|
||||
m_free(c->errstring);
|
||||
c->errstring = m_strdup(strerror(errno));
|
||||
/* Not entirely sure which kind of errors are normal - 2.6.32 seems to
|
||||
return EPIPE for any (nonblocking?) sendmsg(). just fall back */
|
||||
TRACE(("sendmsg tcp_fastopen failed, falling back. %s", strerror(errno)));
|
||||
/* No kernel MSG_FASTOPEN support. Fall back below */
|
||||
fastopen = 0;
|
||||
/* Set to NULL to avoid trying again */
|
||||
c->writequeue = NULL;
|
||||
}
|
||||
} else {
|
||||
packet_queue_consume(c->writequeue, res);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Normal connect(), used as fallback for TCP fastopen too */
|
||||
if (!fastopen) {
|
||||
res = connect(c->sock, r->ai_addr, r->ai_addrlen);
|
||||
}
|
||||
|
||||
if (res < 0 && errno != EINPROGRESS) {
|
||||
/* failure */
|
||||
m_free(c->errstring);
|
||||
c->errstring = m_strdup(strerror(errno));
|
||||
close(c->sock);
|
||||
c->sock = -1;
|
||||
continue;
|
||||
} else {
|
||||
/* new connection was successful, wait for it to complete */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (r) {
|
||||
c->res_iter = r->ai_next;
|
||||
} else {
|
||||
c->res_iter = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Connect via TCP to a host. */
|
||||
struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport,
|
||||
connect_callback cb, void* cb_data)
|
||||
{
|
||||
struct dropbear_progress_connection *c = NULL;
|
||||
int err;
|
||||
struct addrinfo hints;
|
||||
|
||||
c = m_malloc(sizeof(*c));
|
||||
c->remotehost = m_strdup(remotehost);
|
||||
c->remoteport = m_strdup(remoteport);
|
||||
c->sock = -1;
|
||||
c->cb = cb;
|
||||
c->cb_data = cb_data;
|
||||
|
||||
list_append(&ses.conn_pending, c);
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
|
||||
err = getaddrinfo(remotehost, remoteport, &hints, &c->res);
|
||||
if (err) {
|
||||
int len;
|
||||
len = 100 + strlen(gai_strerror(err));
|
||||
c->errstring = (char*)m_malloc(len);
|
||||
snprintf(c->errstring, len, "Error resolving '%s' port '%s'. %s",
|
||||
remotehost, remoteport, gai_strerror(err));
|
||||
TRACE(("Error resolving: %s", gai_strerror(err)))
|
||||
} else {
|
||||
c->res_iter = c->res;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void remove_connect_pending() {
|
||||
while (ses.conn_pending.first) {
|
||||
struct dropbear_progress_connection *c = ses.conn_pending.first->item;
|
||||
remove_connect(c, ses.conn_pending.first);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void set_connect_fds(fd_set *writefd) {
|
||||
m_list_elem *iter;
|
||||
TRACE(("enter set_connect_fds"))
|
||||
iter = ses.conn_pending.first;
|
||||
while (iter) {
|
||||
m_list_elem *next_iter = iter->next;
|
||||
struct dropbear_progress_connection *c = iter->item;
|
||||
/* Set one going */
|
||||
while (c->res_iter && c->sock < 0) {
|
||||
connect_try_next(c);
|
||||
}
|
||||
if (c->sock >= 0) {
|
||||
FD_SET(c->sock, writefd);
|
||||
} else {
|
||||
/* Final failure */
|
||||
if (!c->errstring) {
|
||||
c->errstring = m_strdup("unexpected failure");
|
||||
}
|
||||
c->cb(DROPBEAR_FAILURE, -1, c->cb_data, c->errstring);
|
||||
remove_connect(c, iter);
|
||||
}
|
||||
iter = next_iter;
|
||||
}
|
||||
}
|
||||
|
||||
void handle_connect_fds(fd_set *writefd) {
|
||||
m_list_elem *iter;
|
||||
TRACE(("enter handle_connect_fds"))
|
||||
for (iter = ses.conn_pending.first; iter; iter = iter->next) {
|
||||
int val;
|
||||
socklen_t vallen = sizeof(val);
|
||||
struct dropbear_progress_connection *c = iter->item;
|
||||
|
||||
if (c->sock < 0 || !FD_ISSET(c->sock, writefd)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TRACE(("handling %s port %s socket %d", c->remotehost, c->remoteport, c->sock));
|
||||
|
||||
if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &val, &vallen) != 0) {
|
||||
TRACE(("handle_connect_fds getsockopt(%d) SO_ERROR failed: %s", c->sock, strerror(errno)))
|
||||
/* This isn't expected to happen - Unix has surprises though, continue gracefully. */
|
||||
m_close(c->sock);
|
||||
c->sock = -1;
|
||||
} else if (val != 0) {
|
||||
/* Connect failed */
|
||||
TRACE(("connect to %s port %s failed.", c->remotehost, c->remoteport))
|
||||
m_close(c->sock);
|
||||
c->sock = -1;
|
||||
|
||||
m_free(c->errstring);
|
||||
c->errstring = m_strdup(strerror(val));
|
||||
} else {
|
||||
/* New connection has been established */
|
||||
c->cb(DROPBEAR_SUCCESS, c->sock, c->cb_data, NULL);
|
||||
remove_connect(c, iter);
|
||||
TRACE(("leave handle_connect_fds - success"))
|
||||
/* Must return here - remove_connect() invalidates iter */
|
||||
return;
|
||||
}
|
||||
}
|
||||
TRACE(("leave handle_connect_fds - end iter"))
|
||||
}
|
||||
|
||||
void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue) {
|
||||
c->writequeue = writequeue;
|
||||
}
|
||||
|
||||
void packet_queue_to_iovec(struct Queue *queue, struct iovec *iov, unsigned int *iov_count) {
|
||||
struct Link *l;
|
||||
unsigned int i;
|
||||
int len;
|
||||
buffer *writebuf;
|
||||
|
||||
#ifndef IOV_MAX
|
||||
#define IOV_MAX UIO_MAXIOV
|
||||
#endif
|
||||
|
||||
*iov_count = MIN(MIN(queue->count, IOV_MAX), *iov_count);
|
||||
|
||||
for (l = queue->head, i = 0; i < *iov_count; l = l->link, i++)
|
||||
{
|
||||
writebuf = (buffer*)l->item;
|
||||
len = writebuf->len - 1 - writebuf->pos;
|
||||
dropbear_assert(len > 0);
|
||||
TRACE2(("write_packet writev #%d type %d len %d/%d", i, writebuf->data[writebuf->len-1],
|
||||
len, writebuf->len-1))
|
||||
iov[i].iov_base = buf_getptr(writebuf, len);
|
||||
iov[i].iov_len = len;
|
||||
}
|
||||
}
|
||||
|
||||
void packet_queue_consume(struct Queue *queue, ssize_t written) {
|
||||
buffer *writebuf;
|
||||
int len;
|
||||
while (written > 0) {
|
||||
writebuf = (buffer*)examine(queue);
|
||||
len = writebuf->len - 1 - writebuf->pos;
|
||||
if (len > written) {
|
||||
/* partial buffer write */
|
||||
buf_incrpos(writebuf, written);
|
||||
written = 0;
|
||||
} else {
|
||||
written -= len;
|
||||
dequeue(queue);
|
||||
buf_free(writebuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_sock_nodelay(int sock) {
|
||||
int val;
|
||||
|
||||
/* disable nagle */
|
||||
val = 1;
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_SERVER_TCP_FAST_OPEN
|
||||
void set_listen_fast_open(int sock) {
|
||||
int qlen = MAX(MAX_UNAUTH_PER_IP, 5);
|
||||
if (setsockopt(sock, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) != 0) {
|
||||
TRACE(("set_listen_fast_open failed for socket %d: %s", sock, strerror(errno)))
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void set_sock_priority(int sock, enum dropbear_prio prio) {
|
||||
|
||||
int rc;
|
||||
#ifdef IPTOS_LOWDELAY
|
||||
int iptos_val = 0;
|
||||
#endif
|
||||
#ifdef SO_PRIORITY
|
||||
int so_prio_val = 0;
|
||||
#endif
|
||||
|
||||
|
||||
/* Don't log ENOTSOCK errors so that this can harmlessly be called
|
||||
* on a client '-J' proxy pipe */
|
||||
|
||||
/* set the TOS bit for either ipv4 or ipv6 */
|
||||
#ifdef IPTOS_LOWDELAY
|
||||
if (prio == DROPBEAR_PRIO_LOWDELAY) {
|
||||
iptos_val = IPTOS_LOWDELAY;
|
||||
} else if (prio == DROPBEAR_PRIO_BULK) {
|
||||
iptos_val = IPTOS_THROUGHPUT;
|
||||
}
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
|
||||
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
|
||||
if (rc < 0 && errno != ENOTSOCK) {
|
||||
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
|
||||
}
|
||||
#endif
|
||||
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
|
||||
if (rc < 0 && errno != ENOTSOCK) {
|
||||
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SO_PRIORITY
|
||||
if (prio == DROPBEAR_PRIO_LOWDELAY) {
|
||||
so_prio_val = TC_PRIO_INTERACTIVE;
|
||||
} else if (prio == DROPBEAR_PRIO_BULK) {
|
||||
so_prio_val = TC_PRIO_BULK;
|
||||
}
|
||||
/* linux specific, sets QoS class. see tc-prio(8) */
|
||||
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val));
|
||||
if (rc < 0 && errno != ENOTSOCK)
|
||||
dropbear_log(LOG_WARNING, "Couldn't set SO_PRIORITY (%s)",
|
||||
strerror(errno));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* Listen on address:port.
|
||||
* Special cases are address of "" listening on everything,
|
||||
* and address of NULL listening on localhost only.
|
||||
* Returns the number of sockets bound on success, or -1 on failure. On
|
||||
* failure, if errstring wasn't NULL, it'll be a newly malloced error
|
||||
* string.*/
|
||||
int dropbear_listen(const char* address, const char* port,
|
||||
int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
|
||||
|
||||
struct addrinfo hints, *res = NULL, *res0 = NULL;
|
||||
int err;
|
||||
unsigned int nsock;
|
||||
struct linger linger;
|
||||
int val;
|
||||
int sock;
|
||||
|
||||
TRACE(("enter dropbear_listen"))
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
/* for calling getaddrinfo:
|
||||
address == NULL and !AI_PASSIVE: local loopback
|
||||
address == NULL and AI_PASSIVE: all interfaces
|
||||
address != NULL: whatever the address says */
|
||||
if (!address) {
|
||||
TRACE(("dropbear_listen: local loopback"))
|
||||
} else {
|
||||
if (address[0] == '\0') {
|
||||
TRACE(("dropbear_listen: all interfaces"))
|
||||
address = NULL;
|
||||
}
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
}
|
||||
err = getaddrinfo(address, port, &hints, &res0);
|
||||
|
||||
if (err) {
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
int len;
|
||||
len = 20 + strlen(gai_strerror(err));
|
||||
*errstring = (char*)m_malloc(len);
|
||||
snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
|
||||
}
|
||||
if (res0) {
|
||||
freeaddrinfo(res0);
|
||||
res0 = NULL;
|
||||
}
|
||||
TRACE(("leave dropbear_listen: failed resolving"))
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
nsock = 0;
|
||||
for (res = res0; res != NULL && nsock < sockcount;
|
||||
res = res->ai_next) {
|
||||
|
||||
/* Get a socket */
|
||||
socks[nsock] = socket(res->ai_family, res->ai_socktype,
|
||||
res->ai_protocol);
|
||||
|
||||
sock = socks[nsock]; /* For clarity */
|
||||
|
||||
if (sock < 0) {
|
||||
err = errno;
|
||||
TRACE(("socket() failed"))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Various useful socket options */
|
||||
val = 1;
|
||||
/* set to reuse, quick timeout */
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
|
||||
linger.l_onoff = 1;
|
||||
linger.l_linger = 5;
|
||||
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
|
||||
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
|
||||
if (res->ai_family == AF_INET6) {
|
||||
int on = 1;
|
||||
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
&on, sizeof(on)) == -1) {
|
||||
dropbear_log(LOG_WARNING, "Couldn't set IPV6_V6ONLY");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
set_sock_nodelay(sock);
|
||||
|
||||
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
err = errno;
|
||||
close(sock);
|
||||
TRACE(("bind(%s) failed", port))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) {
|
||||
err = errno;
|
||||
close(sock);
|
||||
TRACE(("listen() failed"))
|
||||
continue;
|
||||
}
|
||||
|
||||
*maxfd = MAX(*maxfd, sock);
|
||||
|
||||
nsock++;
|
||||
}
|
||||
|
||||
if (res0) {
|
||||
freeaddrinfo(res0);
|
||||
res0 = NULL;
|
||||
}
|
||||
|
||||
if (nsock == 0) {
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
int len;
|
||||
len = 20 + strlen(strerror(err));
|
||||
*errstring = (char*)m_malloc(len);
|
||||
snprintf(*errstring, len, "Error listening: %s", strerror(err));
|
||||
}
|
||||
TRACE(("leave dropbear_listen: failure, %s", strerror(err)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
TRACE(("leave dropbear_listen: success, %d socks bound", nsock))
|
||||
return nsock;
|
||||
}
|
||||
|
||||
void get_socket_address(int fd, char **local_host, char **local_port,
|
||||
char **remote_host, char **remote_port, int host_lookup)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
|
||||
if (local_host || local_port) {
|
||||
addrlen = sizeof(addr);
|
||||
if (getsockname(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
|
||||
dropbear_exit("Failed socket address: %s", strerror(errno));
|
||||
}
|
||||
getaddrstring(&addr, local_host, local_port, host_lookup);
|
||||
}
|
||||
if (remote_host || remote_port) {
|
||||
addrlen = sizeof(addr);
|
||||
if (getpeername(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
|
||||
dropbear_exit("Failed socket address: %s", strerror(errno));
|
||||
}
|
||||
getaddrstring(&addr, remote_host, remote_port, host_lookup);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return a string representation of the socket address passed. The return
|
||||
* value is allocated with malloc() */
|
||||
void getaddrstring(struct sockaddr_storage* addr,
|
||||
char **ret_host, char **ret_port,
|
||||
int host_lookup) {
|
||||
|
||||
char host[NI_MAXHOST+1], serv[NI_MAXSERV+1];
|
||||
unsigned int len;
|
||||
int ret;
|
||||
|
||||
int flags = NI_NUMERICSERV | NI_NUMERICHOST;
|
||||
|
||||
#ifndef DO_HOST_LOOKUP
|
||||
host_lookup = 0;
|
||||
#endif
|
||||
|
||||
if (host_lookup) {
|
||||
flags = NI_NUMERICSERV;
|
||||
}
|
||||
|
||||
len = sizeof(struct sockaddr_storage);
|
||||
/* Some platforms such as Solaris 8 require that len is the length
|
||||
* of the specific structure. Some older linux systems (glibc 2.1.3
|
||||
* such as debian potato) have sockaddr_storage.__ss_family instead
|
||||
* but we'll ignore them */
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
|
||||
if (addr->ss_family == AF_INET) {
|
||||
len = sizeof(struct sockaddr_in);
|
||||
}
|
||||
#ifdef AF_INET6
|
||||
if (addr->ss_family == AF_INET6) {
|
||||
len = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
|
||||
serv, sizeof(serv)-1, flags);
|
||||
|
||||
if (ret != 0) {
|
||||
if (host_lookup) {
|
||||
/* On some systems (Darwin does it) we get EINTR from getnameinfo
|
||||
* somehow. Eew. So we'll just return the IP, since that doesn't seem
|
||||
* to exhibit that behaviour. */
|
||||
getaddrstring(addr, ret_host, ret_port, 0);
|
||||
return;
|
||||
} else {
|
||||
/* if we can't do a numeric lookup, something's gone terribly wrong */
|
||||
dropbear_exit("Failed lookup: %s", gai_strerror(ret));
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_host) {
|
||||
*ret_host = m_strdup(host);
|
||||
}
|
||||
if (ret_port) {
|
||||
*ret_port = m_strdup(serv);
|
||||
}
|
||||
}
|
||||
|
||||
64
netio.h
Normal file
64
netio.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef DROPBEAR_NETIO_H
|
||||
#define DROPBEAR_NETIO_H
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "queue.h"
|
||||
|
||||
enum dropbear_prio {
|
||||
DROPBEAR_PRIO_DEFAULT = 10,
|
||||
DROPBEAR_PRIO_LOWDELAY = 11,
|
||||
DROPBEAR_PRIO_BULK = 12,
|
||||
};
|
||||
|
||||
void set_sock_nodelay(int sock);
|
||||
void set_sock_priority(int sock, enum dropbear_prio prio);
|
||||
|
||||
void get_socket_address(int fd, char **local_host, char **local_port,
|
||||
char **remote_host, char **remote_port, int host_lookup);
|
||||
void getaddrstring(struct sockaddr_storage* addr,
|
||||
char **ret_host, char **ret_port, int host_lookup);
|
||||
int dropbear_listen(const char* address, const char* port,
|
||||
int *socks, unsigned int sockcount, char **errstring, int *maxfd);
|
||||
|
||||
struct dropbear_progress_connection;
|
||||
|
||||
/* result is DROPBEAR_SUCCESS or DROPBEAR_FAILURE.
|
||||
errstring is only set on DROPBEAR_FAILURE, returns failure message for the last attempted socket */
|
||||
typedef void(*connect_callback)(int result, int sock, void* data, const char* errstring);
|
||||
|
||||
/* Always returns a progress connection, if it fails it will call the callback at a later point */
|
||||
struct dropbear_progress_connection * connect_remote (const char* remotehost, const char* remoteport,
|
||||
connect_callback cb, void *cb_data);
|
||||
|
||||
/* Sets up for select() */
|
||||
void set_connect_fds(fd_set *writefd);
|
||||
/* Handles ready sockets after select() */
|
||||
void handle_connect_fds(fd_set *writefd);
|
||||
/* Cleanup */
|
||||
void remove_connect_pending();
|
||||
|
||||
/* Doesn't actually stop the connect, but adds a dummy callback instead */
|
||||
void cancel_connect(struct dropbear_progress_connection *c);
|
||||
|
||||
void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue);
|
||||
|
||||
/* TODO: writev #ifdef guard */
|
||||
/* Fills out iov which contains iov_count slots, returning the number filled in iov_count */
|
||||
void packet_queue_to_iovec(struct Queue *queue, struct iovec *iov, unsigned int *iov_count);
|
||||
void packet_queue_consume(struct Queue *queue, ssize_t written);
|
||||
|
||||
#ifdef DROPBEAR_SERVER_TCP_FAST_OPEN
|
||||
/* Try for any Linux builds, will fall back if the kernel doesn't support it */
|
||||
void set_listen_fast_open(int sock);
|
||||
/* Define values which may be supported by the kernel even if the libc is too old */
|
||||
#ifndef TCP_FASTOPEN
|
||||
#define TCP_FASTOPEN 23
|
||||
#endif
|
||||
#ifndef MSG_FASTOPEN
|
||||
#define MSG_FASTOPEN 0x20000000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
60
options.h
60
options.h
@@ -2,8 +2,8 @@
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved. See LICENSE for the license. */
|
||||
|
||||
#ifndef _OPTIONS_H_
|
||||
#define _OPTIONS_H_
|
||||
#ifndef DROPBEAR_OPTIONS_H_
|
||||
#define DROPBEAR_OPTIONS_H_
|
||||
|
||||
/* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
|
||||
* parts are to allow for commandline -DDROPBEAR_XXX options etc. */
|
||||
@@ -98,11 +98,20 @@ much traffic. */
|
||||
#define DROPBEAR_TWOFISH256
|
||||
#define DROPBEAR_TWOFISH128
|
||||
|
||||
/* Enable CBC mode for ciphers. This has security issues though
|
||||
* is the most compatible with older SSH implementations */
|
||||
#define DROPBEAR_ENABLE_CBC_MODE
|
||||
|
||||
/* Enable "Counter Mode" for ciphers. This is more secure than normal
|
||||
* CBC mode against certain attacks. This adds around 1kB to binary
|
||||
* size and is recommended for most cases */
|
||||
* CBC mode against certain attacks. It is recommended for security
|
||||
* and forwards compatibility */
|
||||
#define DROPBEAR_ENABLE_CTR_MODE
|
||||
|
||||
/* Twofish counter mode is disabled by default because it
|
||||
has not been tested for interoperability with other SSH implementations.
|
||||
If you test it please contact the Dropbear author */
|
||||
/* #define DROPBEAR_TWOFISH_CTR */
|
||||
|
||||
/* You can compile with no encryption if you want. In some circumstances
|
||||
* this could be safe security-wise, though make sure you know what
|
||||
* you're doing. Anyone can see everything that goes over the wire, so
|
||||
@@ -123,8 +132,8 @@ much traffic. */
|
||||
* which are not the standard form. */
|
||||
#define DROPBEAR_SHA1_HMAC
|
||||
#define DROPBEAR_SHA1_96_HMAC
|
||||
/*#define DROPBEAR_SHA2_256_HMAC*/
|
||||
/*#define DROPBEAR_SHA2_512_HMAC*/
|
||||
#define DROPBEAR_SHA2_256_HMAC
|
||||
#define DROPBEAR_SHA2_512_HMAC
|
||||
#define DROPBEAR_MD5_HMAC
|
||||
|
||||
/* You can also disable integrity. Don't bother disabling this if you're
|
||||
@@ -170,6 +179,11 @@ much traffic. */
|
||||
#define DROPBEAR_ZLIB_WINDOW_BITS 15
|
||||
#endif
|
||||
|
||||
/* Server won't allow zlib compression until after authentication. Prevents
|
||||
flaws in the zlib library being unauthenticated exploitable flaws.
|
||||
Some old ssh clients may not support the alternative zlib@openssh.com method */
|
||||
#define DROPBEAR_SERVER_DELAY_ZLIB 1
|
||||
|
||||
/* Whether to do reverse DNS lookups. */
|
||||
/*#define DO_HOST_LOOKUP */
|
||||
|
||||
@@ -192,7 +206,10 @@ much traffic. */
|
||||
* PAM challenge/response.
|
||||
* You can't enable both PASSWORD and PAM. */
|
||||
|
||||
/* This requires crypt() */
|
||||
#ifdef HAVE_CRYPT
|
||||
#define ENABLE_SVR_PASSWORD_AUTH
|
||||
#endif
|
||||
/* PAM requires ./configure --enable-pam */
|
||||
/*#define ENABLE_SVR_PAM_AUTH */
|
||||
#define ENABLE_SVR_PUBKEY_AUTH
|
||||
@@ -203,9 +220,16 @@ much traffic. */
|
||||
#define ENABLE_SVR_PUBKEY_OPTIONS
|
||||
#endif
|
||||
|
||||
/* This requires getpass. */
|
||||
#ifdef HAVE_GETPASS
|
||||
#define ENABLE_CLI_PASSWORD_AUTH
|
||||
#define ENABLE_CLI_PUBKEY_AUTH
|
||||
#define ENABLE_CLI_INTERACT_AUTH
|
||||
#endif
|
||||
#define ENABLE_CLI_PUBKEY_AUTH
|
||||
|
||||
/* A default argument for dbclient -i <privatekey>.
|
||||
Homedir is prepended unless path begins with / */
|
||||
#define DROPBEAR_DEFAULT_CLI_AUTHKEY ".ssh/id_dropbear"
|
||||
|
||||
/* This variable can be used to set a password for client
|
||||
* authentication on the commandline. Beware of platforms
|
||||
@@ -222,12 +246,11 @@ much traffic. */
|
||||
* return the password on standard output */
|
||||
/*#define ENABLE_CLI_ASKPASS_HELPER*/
|
||||
|
||||
/* Send a real auth request first rather than requesting a list of available methods.
|
||||
* It saves a network round trip at login but prevents immediate login to
|
||||
* accounts with no password, and might be rejected by some strict servers (none
|
||||
* encountered yet) - hence it isn't enabled by default. */
|
||||
/* #define CLI_IMMEDIATE_AUTH */
|
||||
|
||||
/* Save a network roundtrip by sendng a real auth request immediately after
|
||||
* sending a query for the available methods. It is at the expense of < 100
|
||||
* bytes of extra network traffic. This is not yet enabled by default since it
|
||||
* could cause problems with non-compliant servers */
|
||||
/* #define DROPBEAR_CLI_IMMEDIATE_AUTH */
|
||||
|
||||
/* Source for randomness. This must be able to provide hundreds of bytes per SSH
|
||||
* connection without blocking. In addition /dev/random is used for seeding
|
||||
@@ -265,7 +288,7 @@ much traffic. */
|
||||
/* The command to invoke for xauth when using X11 forwarding.
|
||||
* "-q" for quiet */
|
||||
#ifndef XAUTH_COMMAND
|
||||
#define XAUTH_COMMAND "/usr/bin/X11/xauth -q"
|
||||
#define XAUTH_COMMAND "/usr/bin/xauth -q"
|
||||
#endif
|
||||
|
||||
/* if you want to enable running an sftp server (such as the one included with
|
||||
@@ -277,7 +300,7 @@ much traffic. */
|
||||
|
||||
/* This is used by the scp binary when used as a client binary. If you're
|
||||
* not using the Dropbear client, you'll need to change it */
|
||||
#define _PATH_SSH_PROGRAM "/usr/bin/dbclient"
|
||||
#define DROPBEAR_PATH_SSH_PROGRAM "/usr/bin/dbclient"
|
||||
|
||||
/* Whether to log commands executed by a client. This only logs the
|
||||
* (single) command sent to the server, not what a user did in a
|
||||
@@ -309,6 +332,11 @@ much traffic. */
|
||||
be overridden at runtime with -K. 0 disables keepalives */
|
||||
#define DEFAULT_KEEPALIVE 0
|
||||
|
||||
/* If this many KEEPALIVES are sent with no packets received from the
|
||||
other side, exit. Not run-time configurable - if you have a need
|
||||
for runtime configuration please mail the Dropbear list */
|
||||
#define DEFAULT_KEEPALIVE_LIMIT 3
|
||||
|
||||
/* Ensure that data is received within IDLE_TIMEOUT seconds. This can
|
||||
be overridden at runtime with -I. 0 disables idle timeouts */
|
||||
#define DEFAULT_IDLE_TIMEOUT 0
|
||||
@@ -320,4 +348,4 @@ be overridden at runtime with -I. 0 disables idle timeouts */
|
||||
* in sysoptions.h */
|
||||
#include "sysoptions.h"
|
||||
|
||||
#endif /* _OPTIONS_H_ */
|
||||
#endif /* DROPBEAR_OPTIONS_H_ */
|
||||
|
||||
211
packet.c
211
packet.c
@@ -34,6 +34,7 @@
|
||||
#include "service.h"
|
||||
#include "auth.h"
|
||||
#include "channel.h"
|
||||
#include "netio.h"
|
||||
|
||||
static int read_packet_init();
|
||||
static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
|
||||
@@ -41,7 +42,11 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
|
||||
unsigned char *output_mac);
|
||||
static int checkmac();
|
||||
|
||||
#define ZLIB_COMPRESS_INCR 100
|
||||
/* For exact details see http://www.zlib.net/zlib_tech.html
|
||||
* 5 bytes per 16kB block, plus 6 bytes for the stream.
|
||||
* We might allocate 5 unnecessary bytes here if it's an
|
||||
* exact multiple. */
|
||||
#define ZLIB_COMPRESS_EXPANSION (((RECV_MAX_PAYLOAD_LEN/16384)+1)*5 + 6)
|
||||
#define ZLIB_DECOMPRESS_INCR 1024
|
||||
#ifndef DISABLE_ZLIB
|
||||
static buffer* buf_decompress(buffer* buf, unsigned int len);
|
||||
@@ -51,66 +56,44 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len);
|
||||
/* non-blocking function writing out a current encrypted packet */
|
||||
void write_packet() {
|
||||
|
||||
int len, written;
|
||||
buffer * writebuf = NULL;
|
||||
time_t now;
|
||||
unsigned packet_type;
|
||||
int all_ignore = 1;
|
||||
ssize_t written;
|
||||
#ifdef HAVE_WRITEV
|
||||
struct iovec *iov = NULL;
|
||||
int i;
|
||||
struct Link *l;
|
||||
/* 50 is somewhat arbitrary */
|
||||
unsigned int iov_count = 50;
|
||||
struct iovec iov[50];
|
||||
#else
|
||||
int len;
|
||||
buffer* writebuf;
|
||||
int packet_type;
|
||||
#endif
|
||||
|
||||
TRACE2(("enter write_packet"))
|
||||
dropbear_assert(!isempty(&ses.writequeue));
|
||||
|
||||
#ifdef HAVE_WRITEV
|
||||
iov = m_malloc(sizeof(*iov) * ses.writequeue.count);
|
||||
for (l = ses.writequeue.head, i = 0; l; l = l->link, i++)
|
||||
{
|
||||
writebuf = (buffer*)l->item;
|
||||
packet_type = writebuf->data[writebuf->len-1];
|
||||
len = writebuf->len - 1 - writebuf->pos;
|
||||
dropbear_assert(len > 0);
|
||||
all_ignore &= (packet_type == SSH_MSG_IGNORE);
|
||||
TRACE2(("write_packet writev #%d type %d len %d/%d", i, packet_type,
|
||||
len, writebuf->len-1))
|
||||
iov[i].iov_base = buf_getptr(writebuf, len);
|
||||
iov[i].iov_len = len;
|
||||
}
|
||||
written = writev(ses.sock_out, iov, ses.writequeue.count);
|
||||
#if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
|
||||
|
||||
packet_queue_to_iovec(&ses.writequeue, iov, &iov_count);
|
||||
/* This may return EAGAIN. The main loop sometimes
|
||||
calls write_packet() without bothering to test with select() since
|
||||
it's likely to be necessary */
|
||||
written = writev(ses.sock_out, iov, iov_count);
|
||||
if (written < 0) {
|
||||
if (errno == EINTR) {
|
||||
m_free(iov);
|
||||
TRACE2(("leave writepacket: EINTR"))
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
TRACE2(("leave write_packet: EINTR"))
|
||||
return;
|
||||
} else {
|
||||
dropbear_exit("Error writing");
|
||||
dropbear_exit("Error writing: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
packet_queue_consume(&ses.writequeue, written);
|
||||
ses.writequeue_len -= written;
|
||||
|
||||
if (written == 0) {
|
||||
ses.remoteclosed();
|
||||
}
|
||||
|
||||
while (written > 0) {
|
||||
writebuf = (buffer*)examine(&ses.writequeue);
|
||||
len = writebuf->len - 1 - writebuf->pos;
|
||||
if (len > written) {
|
||||
/* partial buffer write */
|
||||
buf_incrpos(writebuf, written);
|
||||
written = 0;
|
||||
} else {
|
||||
written -= len;
|
||||
dequeue(&ses.writequeue);
|
||||
buf_free(writebuf);
|
||||
}
|
||||
}
|
||||
|
||||
m_free(iov);
|
||||
|
||||
#else
|
||||
#else /* No writev () */
|
||||
/* Get the next buffer in the queue of encrypted packets to write*/
|
||||
writebuf = (buffer*)examine(&ses.writequeue);
|
||||
|
||||
@@ -118,24 +101,27 @@ void write_packet() {
|
||||
* a cleartext packet_type indicator */
|
||||
packet_type = writebuf->data[writebuf->len-1];
|
||||
len = writebuf->len - 1 - writebuf->pos;
|
||||
TRACE2(("write_packet type %d len %d/%d", packet_type,
|
||||
len, writebuf->len-1))
|
||||
dropbear_assert(len > 0);
|
||||
/* Try to write as much as possible */
|
||||
written = write(ses.sock_out, buf_getptr(writebuf, len), len);
|
||||
|
||||
if (written < 0) {
|
||||
if (errno == EINTR) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
TRACE2(("leave writepacket: EINTR"))
|
||||
return;
|
||||
} else {
|
||||
dropbear_exit("Error writing");
|
||||
dropbear_exit("Error writing: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
all_ignore = (packet_type == SSH_MSG_IGNORE);
|
||||
|
||||
if (written == 0) {
|
||||
ses.remoteclosed();
|
||||
}
|
||||
|
||||
ses.writequeue_len -= written;
|
||||
|
||||
if (written == len) {
|
||||
/* We've finished with the packet, free it */
|
||||
dequeue(&ses.writequeue);
|
||||
@@ -145,14 +131,7 @@ void write_packet() {
|
||||
/* More packet left to write, leave it in the queue for later */
|
||||
buf_incrpos(writebuf, written);
|
||||
}
|
||||
|
||||
#endif
|
||||
now = time(NULL);
|
||||
ses.last_trx_packet_time = now;
|
||||
|
||||
if (!all_ignore) {
|
||||
ses.last_packet_time = now;
|
||||
}
|
||||
#endif /* writev */
|
||||
|
||||
TRACE2(("leave write_packet"))
|
||||
}
|
||||
@@ -250,7 +229,7 @@ static int read_packet_init() {
|
||||
ses.remoteclosed();
|
||||
}
|
||||
if (slen < 0) {
|
||||
if (errno == EINTR) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
TRACE2(("leave read_packet_init: EINTR"))
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
@@ -275,18 +254,18 @@ static int read_packet_init() {
|
||||
}
|
||||
len = buf_getint(ses.readbuf) + 4 + macsize;
|
||||
|
||||
TRACE2(("packet size is %d, block %d mac %d", len, blocksize, macsize))
|
||||
TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize))
|
||||
|
||||
|
||||
/* check packet length */
|
||||
if ((len > RECV_MAX_PACKET_LEN) ||
|
||||
(len < MIN_PACKET_LEN + macsize) ||
|
||||
((len - macsize) % blocksize != 0)) {
|
||||
dropbear_exit("Integrity error (bad packet size %d)", len);
|
||||
dropbear_exit("Integrity error (bad packet size %u)", len);
|
||||
}
|
||||
|
||||
if (len > ses.readbuf->size) {
|
||||
buf_resize(ses.readbuf, len);
|
||||
ses.readbuf = buf_resize(ses.readbuf, len);
|
||||
}
|
||||
buf_setlen(ses.readbuf, len);
|
||||
buf_setpos(ses.readbuf, blocksize);
|
||||
@@ -333,8 +312,8 @@ void decrypt_packet() {
|
||||
/* payload length */
|
||||
/* - 4 - 1 is for LEN and PADLEN values */
|
||||
len = ses.readbuf->len - padlen - 4 - 1 - macsize;
|
||||
if ((len > RECV_MAX_PAYLOAD_LEN) || (len < 1)) {
|
||||
dropbear_exit("Bad packet size %d", len);
|
||||
if ((len > RECV_MAX_PAYLOAD_LEN+ZLIB_COMPRESS_EXPANSION) || (len < 1)) {
|
||||
dropbear_exit("Bad packet size %u", len);
|
||||
}
|
||||
|
||||
buf_setpos(ses.readbuf, PACKET_PAYLOAD_OFF);
|
||||
@@ -343,18 +322,21 @@ void decrypt_packet() {
|
||||
if (is_compress_recv()) {
|
||||
/* decompress */
|
||||
ses.payload = buf_decompress(ses.readbuf, len);
|
||||
buf_setpos(ses.payload, 0);
|
||||
ses.payload_beginning = 0;
|
||||
buf_free(ses.readbuf);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ses.payload = ses.readbuf;
|
||||
ses.payload_beginning = ses.payload->pos;
|
||||
buf_setlen(ses.payload, ses.payload->pos + len);
|
||||
/* copy payload */
|
||||
ses.payload = buf_new(len);
|
||||
memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len);
|
||||
buf_incrlen(ses.payload, len);
|
||||
//ses.payload = buf_new(len);
|
||||
//memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len);
|
||||
//buf_incrlen(ses.payload, len);
|
||||
}
|
||||
|
||||
buf_free(ses.readbuf);
|
||||
ses.readbuf = NULL;
|
||||
buf_setpos(ses.payload, 0);
|
||||
|
||||
ses.recvseq++;
|
||||
|
||||
@@ -422,10 +404,12 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) {
|
||||
if (zstream->avail_out == 0) {
|
||||
int new_size = 0;
|
||||
if (ret->size >= RECV_MAX_PAYLOAD_LEN) {
|
||||
/* Already been increased as large as it can go,
|
||||
* yet didn't finish up the decompression */
|
||||
dropbear_exit("bad packet, oversized decompressed");
|
||||
}
|
||||
new_size = MIN(RECV_MAX_PAYLOAD_LEN, ret->size + ZLIB_DECOMPRESS_INCR);
|
||||
buf_resize(ret, new_size);
|
||||
ret = buf_resize(ret, new_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -497,6 +481,8 @@ void encrypt_packet() {
|
||||
unsigned char packet_type;
|
||||
unsigned int len, encrypt_buf_size;
|
||||
unsigned char mac_bytes[MAX_MAC_LEN];
|
||||
|
||||
time_t now;
|
||||
|
||||
TRACE2(("enter encrypt_packet()"))
|
||||
|
||||
@@ -526,7 +512,7 @@ void encrypt_packet() {
|
||||
+ mac_size
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* some extra in case 'compression' makes it larger */
|
||||
+ ZLIB_COMPRESS_INCR
|
||||
+ ZLIB_COMPRESS_EXPANSION
|
||||
#endif
|
||||
/* and an extra cleartext (stripped before transmission) byte for the
|
||||
* packet type */
|
||||
@@ -539,14 +525,7 @@ void encrypt_packet() {
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* compression */
|
||||
if (is_compress_trans()) {
|
||||
int compress_delta;
|
||||
buf_compress(writebuf, ses.writepayload, ses.writepayload->len);
|
||||
compress_delta = (writebuf->len - PACKET_PAYLOAD_OFF) - ses.writepayload->len;
|
||||
|
||||
/* Handle the case where 'compress' increased the size. */
|
||||
if (compress_delta > ZLIB_COMPRESS_INCR) {
|
||||
buf_resize(writebuf, writebuf->size + compress_delta);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -600,18 +579,37 @@ void encrypt_packet() {
|
||||
/* stick the MAC on it */
|
||||
buf_putbytes(writebuf, mac_bytes, mac_size);
|
||||
|
||||
/* Update counts */
|
||||
ses.kexstate.datatrans += writebuf->len;
|
||||
|
||||
writebuf_enqueue(writebuf, packet_type);
|
||||
|
||||
/* Update counts */
|
||||
ses.transseq++;
|
||||
|
||||
now = monotonic_now();
|
||||
ses.last_packet_time_any_sent = now;
|
||||
/* idle timeout shouldn't be affected by responses to keepalives.
|
||||
send_msg_keepalive() itself also does tricks with
|
||||
ses.last_packet_idle_time - read that if modifying this code */
|
||||
if (packet_type != SSH_MSG_REQUEST_FAILURE
|
||||
&& packet_type != SSH_MSG_UNIMPLEMENTED
|
||||
&& packet_type != SSH_MSG_IGNORE) {
|
||||
ses.last_packet_time_idle = now;
|
||||
|
||||
}
|
||||
|
||||
TRACE2(("leave encrypt_packet()"))
|
||||
}
|
||||
|
||||
void writebuf_enqueue(buffer * writebuf, unsigned char packet_type) {
|
||||
/* The last byte of the buffer stores the cleartext packet_type. It is not
|
||||
* transmitted but is used for transmit timeout purposes */
|
||||
buf_putbyte(writebuf, packet_type);
|
||||
/* enqueue the packet for sending. It will get freed after transmission. */
|
||||
buf_setpos(writebuf, 0);
|
||||
enqueue(&ses.writequeue, (void*)writebuf);
|
||||
|
||||
/* Update counts */
|
||||
ses.kexstate.datatrans += writebuf->len;
|
||||
ses.transseq++;
|
||||
|
||||
TRACE2(("leave encrypt_packet()"))
|
||||
ses.writequeue_len += writebuf->len-1;
|
||||
}
|
||||
|
||||
|
||||
@@ -657,7 +655,8 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* compresses len bytes from src, outputting to dest (starting from the
|
||||
* respective current positions. */
|
||||
* respective current positions. dest must have sufficient space,
|
||||
* len+ZLIB_COMPRESS_EXPANSION */
|
||||
static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
|
||||
|
||||
unsigned int endpos = src->pos + len;
|
||||
@@ -665,38 +664,28 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
|
||||
|
||||
TRACE2(("enter buf_compress"))
|
||||
|
||||
while (1) {
|
||||
dropbear_assert(dest->size - dest->pos >= len+ZLIB_COMPRESS_EXPANSION);
|
||||
|
||||
ses.keys->trans.zstream->avail_in = endpos - src->pos;
|
||||
ses.keys->trans.zstream->next_in =
|
||||
buf_getptr(src, ses.keys->trans.zstream->avail_in);
|
||||
ses.keys->trans.zstream->avail_in = endpos - src->pos;
|
||||
ses.keys->trans.zstream->next_in =
|
||||
buf_getptr(src, ses.keys->trans.zstream->avail_in);
|
||||
|
||||
ses.keys->trans.zstream->avail_out = dest->size - dest->pos;
|
||||
ses.keys->trans.zstream->next_out =
|
||||
buf_getwriteptr(dest, ses.keys->trans.zstream->avail_out);
|
||||
ses.keys->trans.zstream->avail_out = dest->size - dest->pos;
|
||||
ses.keys->trans.zstream->next_out =
|
||||
buf_getwriteptr(dest, ses.keys->trans.zstream->avail_out);
|
||||
|
||||
result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH);
|
||||
result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH);
|
||||
|
||||
buf_setpos(src, endpos - ses.keys->trans.zstream->avail_in);
|
||||
buf_setlen(dest, dest->size - ses.keys->trans.zstream->avail_out);
|
||||
buf_setpos(dest, dest->len);
|
||||
|
||||
if (result != Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
}
|
||||
|
||||
if (ses.keys->trans.zstream->avail_in == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
dropbear_assert(ses.keys->trans.zstream->avail_out == 0);
|
||||
|
||||
/* the buffer has been filled, we must extend. This only happens in
|
||||
* unusual circumstances where the data grows in size after deflate(),
|
||||
* but it is possible */
|
||||
buf_resize(dest, dest->size + ZLIB_COMPRESS_INCR);
|
||||
buf_setpos(src, endpos - ses.keys->trans.zstream->avail_in);
|
||||
buf_setlen(dest, dest->size - ses.keys->trans.zstream->avail_out);
|
||||
buf_setpos(dest, dest->len);
|
||||
|
||||
if (result != Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
}
|
||||
|
||||
/* fails if destination buffer wasn't large enough */
|
||||
dropbear_assert(ses.keys->trans.zstream->avail_in == 0);
|
||||
TRACE2(("leave buf_compress"))
|
||||
}
|
||||
#endif
|
||||
|
||||
10
packet.h
10
packet.h
@@ -22,17 +22,21 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _PACKET_H_
|
||||
#ifndef DROPBEAR_PACKET_H_
|
||||
|
||||
#define _PACKET_H_
|
||||
#define DROPBEAR_PACKET_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "queue.h"
|
||||
#include "buffer.h"
|
||||
|
||||
void write_packet();
|
||||
void read_packet();
|
||||
void decrypt_packet();
|
||||
void encrypt_packet();
|
||||
|
||||
void writebuf_enqueue(buffer * writebuf, unsigned char packet_type);
|
||||
|
||||
void process_packet();
|
||||
|
||||
void maybe_flush_reply_queue();
|
||||
@@ -46,4 +50,4 @@ typedef struct PacketType {
|
||||
|
||||
#define INIT_READBUF 128
|
||||
|
||||
#endif /* _PACKET_H_ */
|
||||
#endif /* DROPBEAR_PACKET_H_ */
|
||||
|
||||
@@ -44,6 +44,7 @@ void process_packet() {
|
||||
|
||||
unsigned char type;
|
||||
unsigned int i;
|
||||
time_t now;
|
||||
|
||||
TRACE2(("enter process_packet"))
|
||||
|
||||
@@ -52,7 +53,8 @@ void process_packet() {
|
||||
|
||||
ses.lastpacket = type;
|
||||
|
||||
ses.last_packet_time = time(NULL);
|
||||
now = monotonic_now();
|
||||
ses.last_packet_time_keepalive_recv = now;
|
||||
|
||||
/* These packets we can receive at any time */
|
||||
switch(type) {
|
||||
@@ -65,24 +67,49 @@ void process_packet() {
|
||||
case SSH_MSG_UNIMPLEMENTED:
|
||||
/* debugging XXX */
|
||||
TRACE(("SSH_MSG_UNIMPLEMENTED"))
|
||||
dropbear_exit("Received SSH_MSG_UNIMPLEMENTED");
|
||||
goto out;
|
||||
|
||||
case SSH_MSG_DISCONNECT:
|
||||
/* TODO cleanup? */
|
||||
dropbear_close("Disconnect received");
|
||||
}
|
||||
|
||||
/* Ignore these packet types so that keepalives don't interfere with
|
||||
idle detection. This is slightly incorrect since a tcp forwarded
|
||||
global request with failure won't trigger the idle timeout,
|
||||
but that's probably acceptable */
|
||||
if (!(type == SSH_MSG_GLOBAL_REQUEST || type == SSH_MSG_REQUEST_FAILURE)) {
|
||||
ses.last_packet_time_idle = now;
|
||||
}
|
||||
|
||||
/* This applies for KEX, where the spec says the next packet MUST be
|
||||
* NEWKEYS */
|
||||
if (ses.requirenext[0] != 0) {
|
||||
if (ses.requirenext[0] != type
|
||||
&& (ses.requirenext[1] == 0 || ses.requirenext[1] != type)) {
|
||||
dropbear_exit("Unexpected packet type %d, expected [%d,%d]", type,
|
||||
ses.requirenext[0], ses.requirenext[1]);
|
||||
} else {
|
||||
if (ses.requirenext != 0) {
|
||||
if (ses.requirenext == type)
|
||||
{
|
||||
/* Got what we expected */
|
||||
ses.requirenext[0] = 0;
|
||||
ses.requirenext[1] = 0;
|
||||
TRACE(("got expected packet %d during kexinit", type))
|
||||
}
|
||||
else
|
||||
{
|
||||
/* RFC4253 7.1 - various messages are allowed at this point.
|
||||
The only ones we know about have already been handled though,
|
||||
so just return "unimplemented" */
|
||||
if (type >= 1 && type <= 49
|
||||
&& type != SSH_MSG_SERVICE_REQUEST
|
||||
&& type != SSH_MSG_SERVICE_ACCEPT
|
||||
&& type != SSH_MSG_KEXINIT)
|
||||
{
|
||||
TRACE(("unknown allowed packet during kexinit"))
|
||||
recv_unimplemented();
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE(("disallowed packet during kexinit"))
|
||||
dropbear_exit("Unexpected packet type %d, expected %d", type,
|
||||
ses.requirenext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +121,12 @@ void process_packet() {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Only clear the flag after we have checked ignorenext */
|
||||
if (ses.requirenext != 0 && ses.requirenext == type)
|
||||
{
|
||||
ses.requirenext = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Kindly the protocol authors gave all the preauth packets type values
|
||||
* less-than-or-equal-to 60 ( == MAX_UNAUTH_PACKET_TYPE ).
|
||||
|
||||
4
queue.h
4
queue.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _QUEUE_H_
|
||||
#define _QUEUE_H_
|
||||
#ifndef DROPBEAR_QUEUE_H_
|
||||
#define DROPBEAR_QUEUE_H_
|
||||
|
||||
struct Link {
|
||||
|
||||
|
||||
42
release.sh
Executable file
42
release.sh
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
VERSION=$(echo '#include "sysoptions.h"\necho DROPBEAR_VERSION' | cpp - | sh)
|
||||
echo Releasing version "$VERSION" ...
|
||||
if ! head -n1 CHANGES | grep -q $VERSION ; then
|
||||
echo "CHANGES needs updating"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! head -n1 debian/changelog | grep -q $VERSION ; then
|
||||
echo "debian/changelog needs updating"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
head -n1 CHANGES
|
||||
|
||||
#sleep 3
|
||||
|
||||
RELDIR=$PWD/../dropbear-$VERSION
|
||||
ARCHIVE=${RELDIR}.tar.bz2
|
||||
if test -e $RELDIR; then
|
||||
echo "$RELDIR exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -e $ARCHIVE; then
|
||||
echo "$ARCHIVE exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
hg archive "$RELDIR" || exit 2
|
||||
|
||||
(cd "$RELDIR" && autoconf && autoheader) || exit 2
|
||||
|
||||
rm -r "$RELDIR/autom4te.cache" || exit 2
|
||||
|
||||
rm "$RELDIR/.hgtags"
|
||||
|
||||
(cd "$RELDIR/.." && tar cjf $ARCHIVE `basename "$RELDIR"`) || exit 2
|
||||
|
||||
ls -l $ARCHIVE
|
||||
openssl sha -sha256 $ARCHIVE
|
||||
echo "Done to $ARCHIVE"
|
||||
4
rsa.c
4
rsa.c
@@ -347,7 +347,9 @@ void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, buffer *data_buf) {
|
||||
mp_clear(&rsa_s);
|
||||
|
||||
#if defined(DEBUG_RSA) && defined(DEBUG_TRACE)
|
||||
printhex("RSA sig", buf->data, buf->len);
|
||||
if (!debug_trace) {
|
||||
printhex("RSA sig", buf->data, buf->len);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
6
rsa.h
6
rsa.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _RSA_H_
|
||||
#define _RSA_H_
|
||||
#ifndef DROPBEAR_RSA_H_
|
||||
#define DROPBEAR_RSA_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
@@ -55,4 +55,4 @@ void rsa_key_free(dropbear_rsa_key *key);
|
||||
|
||||
#endif /* DROPBEAR_RSA */
|
||||
|
||||
#endif /* _RSA_H_ */
|
||||
#endif /* DROPBEAR_RSA_H_ */
|
||||
|
||||
18
runopts.h
18
runopts.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _RUNOPTS_H_
|
||||
#define _RUNOPTS_H_
|
||||
#ifndef DROPBEAR_RUNOPTS_H_
|
||||
#define DROPBEAR_RUNOPTS_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
@@ -37,14 +37,18 @@ typedef struct runopts {
|
||||
int listen_fwd_all;
|
||||
#endif
|
||||
unsigned int recv_window;
|
||||
time_t keepalive_secs;
|
||||
time_t idle_timeout_secs;
|
||||
time_t keepalive_secs; /* Time between sending keepalives. 0 is off */
|
||||
time_t idle_timeout_secs; /* Exit if no traffic is sent/received in this time */
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* TODO: add a commandline flag. Currently this is on by default if compression
|
||||
* is compiled in, but disabled for a client's non-final multihop stages. (The
|
||||
* intermediate stages are compressed streams, so are uncompressible. */
|
||||
int enable_compress;
|
||||
enum {
|
||||
DROPBEAR_COMPRESS_DELAYED, /* Server only */
|
||||
DROPBEAR_COMPRESS_ON,
|
||||
DROPBEAR_COMPRESS_OFF,
|
||||
} compress_mode;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
@@ -164,4 +168,6 @@ void cli_getopts(int argc, char ** argv);
|
||||
void parse_ciphers_macs();
|
||||
#endif
|
||||
|
||||
#endif /* _RUNOPTS_H_ */
|
||||
void print_version(void);
|
||||
|
||||
#endif /* DROPBEAR_RUNOPTS_H_ */
|
||||
|
||||
8
scp.c
8
scp.c
@@ -96,7 +96,7 @@ int verbose_mode = 0;
|
||||
int showprogress = 1;
|
||||
|
||||
/* This is the program to execute for the secured connection. ("ssh" or -S) */
|
||||
char *ssh_program = _PATH_SSH_PROGRAM;
|
||||
char *ssh_program = DROPBEAR_PATH_SSH_PROGRAM;
|
||||
|
||||
/* This is used to store the pid of ssh_program */
|
||||
pid_t do_cmd_pid = -1;
|
||||
@@ -437,7 +437,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
/*
|
||||
* Finally check the exit status of the ssh process, if one was forked
|
||||
* and no error has occured yet
|
||||
* and no error has occurred yet
|
||||
*/
|
||||
if (do_cmd_pid != -1 && errs == 0) {
|
||||
if (remin != -1)
|
||||
@@ -992,7 +992,7 @@ sink(int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
omode = mode;
|
||||
mode |= S_IWRITE;
|
||||
mode |= S_IWUSR;
|
||||
if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
|
||||
bad: run_err("%s: %s", np, strerror(errno));
|
||||
continue;
|
||||
@@ -1146,7 +1146,7 @@ usage(void)
|
||||
{
|
||||
(void) fprintf(stderr,
|
||||
"usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
|
||||
" [-l limit] [-o ssh_option] [-P port] [-S program]\n"
|
||||
" [-l limit] [-P port] [-S program]\n"
|
||||
" [[user@]host1:]file1 [...] [[user@]host2:]file2\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _SERVICE_H_
|
||||
#define _SERVICE_H_
|
||||
#ifndef DROPBEAR_SERVICE_H_
|
||||
#define DROPBEAR_SERVICE_H_
|
||||
|
||||
void recv_msg_service_request(); /* Server */
|
||||
|
||||
#endif /* _SERVICE_H_ */
|
||||
#endif /* DROPBEAR_SERVICE_H_ */
|
||||
|
||||
61
session.h
61
session.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _SESSION_H_
|
||||
#define _SESSION_H_
|
||||
#ifndef DROPBEAR_SESSION_H_
|
||||
#define DROPBEAR_SESSION_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "options.h"
|
||||
@@ -38,27 +38,32 @@
|
||||
#include "tcpfwd.h"
|
||||
#include "chansession.h"
|
||||
#include "dbutil.h"
|
||||
#include "netio.h"
|
||||
|
||||
extern int sessinitdone; /* Is set to 0 somewhere */
|
||||
extern int exitflag;
|
||||
|
||||
void common_session_init(int sock_in, int sock_out);
|
||||
void session_loop(void(*loophandler)());
|
||||
void session_loop(void(*loophandler)()) ATTRIB_NORETURN;
|
||||
void session_cleanup();
|
||||
void send_session_identification();
|
||||
void send_msg_ignore();
|
||||
void ignore_recv_response();
|
||||
|
||||
void update_channel_prio();
|
||||
|
||||
const char* get_user_shell();
|
||||
void fill_passwd(const char* username);
|
||||
|
||||
/* Server */
|
||||
void svr_session(int sock, int childpipe);
|
||||
void svr_session(int sock, int childpipe) ATTRIB_NORETURN;
|
||||
void svr_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
|
||||
void svr_dropbear_log(int priority, const char* format, va_list param);
|
||||
|
||||
/* Client */
|
||||
void cli_session(int sock_in, int sock_out);
|
||||
void cleantext(unsigned char* dirtytext);
|
||||
void cli_session(int sock_in, int sock_out, struct dropbear_progress_connection *progress) ATTRIB_NORETURN;
|
||||
void cli_connected(int result, int sock, void* userdata, const char *errstring);
|
||||
void cleantext(char* dirtytext);
|
||||
|
||||
/* crypto parameters that are stored individually for transmit and receive */
|
||||
struct key_context_directional {
|
||||
@@ -106,7 +111,8 @@ struct sshsession {
|
||||
|
||||
time_t connect_time; /* time the connection was established
|
||||
(cleared after auth once we're not
|
||||
respecting AUTH_TIMEOUT any more) */
|
||||
respecting AUTH_TIMEOUT any more).
|
||||
A monotonic time, not realworld */
|
||||
|
||||
int sock_in;
|
||||
int sock_out;
|
||||
@@ -114,7 +120,7 @@ struct sshsession {
|
||||
/* remotehost will be initially NULL as we delay
|
||||
* reading the remote version string. it will be set
|
||||
* by the time any recv_() packet methods are called */
|
||||
unsigned char *remoteident;
|
||||
char *remoteident;
|
||||
|
||||
int maxfd; /* the maximum file descriptor to check with select() */
|
||||
|
||||
@@ -124,8 +130,13 @@ struct sshsession {
|
||||
throughout the code, as handlers fill out this
|
||||
buffer with the packet to send. */
|
||||
struct Queue writequeue; /* A queue of encrypted packets to send */
|
||||
unsigned int writequeue_len; /* Number of bytes pending to send in writequeue */
|
||||
buffer *readbuf; /* From the wire, decrypted in-place */
|
||||
buffer *payload; /* Post-decompression, the actual SSH packet */
|
||||
buffer *payload; /* Post-decompression, the actual SSH packet.
|
||||
May have extra data at the beginning, will be
|
||||
passed to packet processing functions positioned past
|
||||
that, see payload_beginning */
|
||||
unsigned int payload_beginning;
|
||||
unsigned int transseq, recvseq; /* Sequence IDs */
|
||||
|
||||
/* Packet-handling flags */
|
||||
@@ -135,9 +146,8 @@ struct sshsession {
|
||||
unsigned dataallowed : 1; /* whether we can send data packets or we are in
|
||||
the middle of a KEX or something */
|
||||
|
||||
unsigned char requirenext[2]; /* bytes indicating what packets we require next,
|
||||
or 0x00 for any. Second option can only be
|
||||
used if the first byte is also set */
|
||||
unsigned char requirenext; /* byte indicating what packets we require next,
|
||||
or 0x00 for any. */
|
||||
|
||||
unsigned char ignorenext; /* whether to ignore the next packet,
|
||||
used for kex_follows stuff */
|
||||
@@ -146,12 +156,17 @@ struct sshsession {
|
||||
|
||||
int signal_pipe[2]; /* stores endpoints of a self-pipe used for
|
||||
race-free signal handling */
|
||||
|
||||
time_t last_trx_packet_time; /* time of the last packet transmission, for
|
||||
keepalive purposes */
|
||||
|
||||
time_t last_packet_time; /* time of the last packet transmission or receive, for
|
||||
idle timeout purposes */
|
||||
m_list conn_pending;
|
||||
|
||||
/* time of the last packet send/receive, for keepalive. Not real-world clock */
|
||||
time_t last_packet_time_keepalive_sent;
|
||||
time_t last_packet_time_keepalive_recv;
|
||||
time_t last_packet_time_any_sent;
|
||||
|
||||
time_t last_packet_time_idle; /* time of the last packet transmission or receive, for
|
||||
idle timeout purposes so ignores SSH_MSG_IGNORE
|
||||
or responses to keepalives. Not real-world clock */
|
||||
|
||||
|
||||
/* KEX/encryption related */
|
||||
@@ -187,8 +202,11 @@ struct sshsession {
|
||||
unsigned int chansize; /* the number of Channel*s allocated for channels */
|
||||
unsigned int chancount; /* the number of Channel*s in use */
|
||||
const struct ChanType **chantypes; /* The valid channel types */
|
||||
int channel_signal_pending; /* Flag set by sigchld handler */
|
||||
|
||||
/* TCP priority level for the main "port 22" tcp socket */
|
||||
enum dropbear_prio socket_prio;
|
||||
|
||||
|
||||
/* TCP forwarding - where manage listeners */
|
||||
struct Listener ** listeners;
|
||||
unsigned int listensize;
|
||||
@@ -233,6 +251,7 @@ typedef enum {
|
||||
|
||||
typedef enum {
|
||||
STATE_NOTHING,
|
||||
USERAUTH_WAIT,
|
||||
USERAUTH_REQ_SENT,
|
||||
USERAUTH_FAIL_RCVD,
|
||||
USERAUTH_SUCCESS_RCVD,
|
||||
@@ -267,16 +286,16 @@ struct clientsession {
|
||||
|
||||
int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
|
||||
for the last type of auth we tried */
|
||||
int ignore_next_auth_response;
|
||||
#ifdef ENABLE_CLI_INTERACT_AUTH
|
||||
int auth_interact_failed; /* flag whether interactive auth can still
|
||||
be used */
|
||||
int interact_request_received; /* flag whether we've received an
|
||||
info request from the server for
|
||||
interactive auth.*/
|
||||
|
||||
#endif
|
||||
int cipher_none_after_auth; /* Set to 1 if the user requested "none"
|
||||
auth */
|
||||
#endif
|
||||
sign_key *lastprivkey;
|
||||
|
||||
int retval; /* What the command exit status was - we emulate it */
|
||||
@@ -298,4 +317,4 @@ extern struct serversession svr_ses;
|
||||
extern struct clientsession cli_ses;
|
||||
#endif /* DROPBEAR_CLIENT */
|
||||
|
||||
#endif /* _SESSION_H_ */
|
||||
#endif /* DROPBEAR_SESSION_H_ */
|
||||
|
||||
17
signkey.c
17
signkey.c
@@ -106,6 +106,7 @@ enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen)
|
||||
void **
|
||||
signkey_key_ptr(sign_key *key, enum signkey_type type) {
|
||||
switch (type) {
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
|
||||
return (void**)&key->ecckey256;
|
||||
@@ -118,6 +119,7 @@ signkey_key_ptr(sign_key *key, enum signkey_type type) {
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
|
||||
return (void**)&key->ecckey521;
|
||||
#endif
|
||||
#endif /* DROPBEAR_ECDSA */
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
return (void**)&key->rsakey;
|
||||
@@ -136,9 +138,9 @@ signkey_key_ptr(sign_key *key, enum signkey_type type) {
|
||||
* on return is set to the type read (useful when type = _ANY) */
|
||||
int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
|
||||
|
||||
unsigned char* ident;
|
||||
char *ident;
|
||||
unsigned int len;
|
||||
int keytype;
|
||||
enum signkey_type keytype;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
TRACE2(("enter buf_get_pub_key"))
|
||||
@@ -185,6 +187,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
|
||||
if (eck) {
|
||||
if (*eck) {
|
||||
ecc_free(*eck);
|
||||
m_free(*eck);
|
||||
*eck = NULL;
|
||||
}
|
||||
*eck = buf_get_ecdsa_pub_key(buf);
|
||||
@@ -206,9 +209,9 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
|
||||
* on return is set to the type read (useful when type = _ANY) */
|
||||
int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
|
||||
|
||||
unsigned char* ident;
|
||||
char *ident;
|
||||
unsigned int len;
|
||||
int keytype;
|
||||
enum signkey_type keytype;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
TRACE2(("enter buf_get_priv_key"))
|
||||
@@ -253,6 +256,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
|
||||
if (eck) {
|
||||
if (*eck) {
|
||||
ecc_free(*eck);
|
||||
m_free(*eck);
|
||||
*eck = NULL;
|
||||
}
|
||||
*eck = buf_get_ecdsa_priv_key(buf);
|
||||
@@ -353,18 +357,21 @@ void sign_key_free(sign_key *key) {
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
if (key->ecckey256) {
|
||||
ecc_free(key->ecckey256);
|
||||
m_free(key->ecckey256);
|
||||
key->ecckey256 = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
if (key->ecckey384) {
|
||||
ecc_free(key->ecckey384);
|
||||
m_free(key->ecckey384);
|
||||
key->ecckey384 = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
if (key->ecckey521) {
|
||||
ecc_free(key->ecckey521);
|
||||
m_free(key->ecckey521);
|
||||
key->ecckey521 = NULL;
|
||||
}
|
||||
#endif
|
||||
@@ -508,7 +515,7 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type type,
|
||||
* signature blob */
|
||||
int buf_verify(buffer * buf, sign_key *key, buffer *data_buf) {
|
||||
|
||||
unsigned char * type_name = NULL;
|
||||
char *type_name = NULL;
|
||||
unsigned int type_name_len = 0;
|
||||
enum signkey_type type;
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _SIGNKEY_H_
|
||||
#define _SIGNKEY_H_
|
||||
#ifndef DROPBEAR_SIGNKEY_H_
|
||||
#define DROPBEAR_SIGNKEY_H_
|
||||
|
||||
#include "buffer.h"
|
||||
#include "dss.h"
|
||||
@@ -101,4 +101,4 @@ int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,
|
||||
|
||||
void** signkey_key_ptr(sign_key *key, enum signkey_type type);
|
||||
|
||||
#endif /* _SIGNKEY_H_ */
|
||||
#endif /* DROPBEAR_SIGNKEY_H_ */
|
||||
|
||||
@@ -117,7 +117,7 @@ static void agentaccept(struct Listener *UNUSED(listener), int sock) {
|
||||
}
|
||||
|
||||
/* set up the environment variable pointing to the socket. This is called
|
||||
* just before command/shell execution, after dropping priveleges */
|
||||
* just before command/shell execution, after dropping privileges */
|
||||
void svr_agentset(struct ChanSess * chansess) {
|
||||
|
||||
char *path = NULL;
|
||||
|
||||
10
svr-auth.c
10
svr-auth.c
@@ -36,7 +36,7 @@
|
||||
#include "dbrandom.h"
|
||||
|
||||
static void authclear();
|
||||
static int checkusername(unsigned char *username, unsigned int userlen);
|
||||
static int checkusername(char *username, unsigned int userlen);
|
||||
|
||||
/* initialise the first time for a session, resetting all parameters */
|
||||
void svr_authinitialise() {
|
||||
@@ -100,7 +100,7 @@ void send_msg_userauth_banner(buffer *banner) {
|
||||
* checking, and handle success or failure */
|
||||
void recv_msg_userauth_request() {
|
||||
|
||||
unsigned char *username = NULL, *servicename = NULL, *methodname = NULL;
|
||||
char *username = NULL, *servicename = NULL, *methodname = NULL;
|
||||
unsigned int userlen, servicelen, methodlen;
|
||||
int valid_user = 0;
|
||||
|
||||
@@ -227,7 +227,7 @@ out:
|
||||
|
||||
/* Check that the username exists and isn't disallowed (root), and has a valid shell.
|
||||
* returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */
|
||||
static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
static int checkusername(char *username, unsigned int userlen) {
|
||||
|
||||
char* listshell = NULL;
|
||||
char* usershell = NULL;
|
||||
@@ -333,14 +333,14 @@ void send_msg_userauth_failure(int partial, int incrfail) {
|
||||
typebuf = buf_new(30); /* long enough for PUBKEY and PASSWORD */
|
||||
|
||||
if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
|
||||
buf_putbytes(typebuf, AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN);
|
||||
buf_putbytes(typebuf, (const unsigned char *)AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN);
|
||||
if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
|
||||
buf_putbyte(typebuf, ',');
|
||||
}
|
||||
}
|
||||
|
||||
if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
|
||||
buf_putbytes(typebuf, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
|
||||
buf_putbytes(typebuf, (const unsigned char *)AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
|
||||
}
|
||||
|
||||
buf_putbufstring(ses.writepayload, typebuf);
|
||||
|
||||
@@ -188,7 +188,7 @@ void svr_auth_pam() {
|
||||
|
||||
pam_handle_t* pamHandlep = NULL;
|
||||
|
||||
unsigned char * password = NULL;
|
||||
char * password = NULL;
|
||||
unsigned int passwordlen;
|
||||
|
||||
int rc = PAM_SUCCESS;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user