From eb6601a93d8836de9edd22958f177843c1ed8a33 Mon Sep 17 00:00:00 2001 From: Shibby Date: Thu, 18 Feb 2016 14:39:25 +0100 Subject: [PATCH] dropbear 2015.71 --- release/src/router/dropbear/.hg_archival.txt | 7 +- release/src/router/dropbear/.hgsigs | 5 + release/src/router/dropbear/.hgtags | 49 -- release/src/router/dropbear/.travis.yml | 7 +- release/src/router/dropbear/CHANGES | 86 ++++ release/src/router/dropbear/LICENSE | 2 +- release/src/router/dropbear/Makefile.in | 6 +- release/src/router/dropbear/agentfwd.h | 6 +- release/src/router/dropbear/algo.h | 8 +- release/src/router/dropbear/auth.h | 8 +- release/src/router/dropbear/bignum.h | 6 +- release/src/router/dropbear/buffer.c | 48 +- release/src/router/dropbear/buffer.h | 16 +- release/src/router/dropbear/channel.h | 16 +- release/src/router/dropbear/chansession.h | 12 +- release/src/router/dropbear/circbuffer.c | 54 +- release/src/router/dropbear/circbuffer.h | 10 +- release/src/router/dropbear/cli-agentfwd.c | 2 +- release/src/router/dropbear/cli-auth.c | 12 +- release/src/router/dropbear/cli-authinteract.c | 20 +- release/src/router/dropbear/cli-authpasswd.c | 4 +- release/src/router/dropbear/cli-authpubkey.c | 8 +- release/src/router/dropbear/cli-chansession.c | 10 +- release/src/router/dropbear/cli-kex.c | 12 +- release/src/router/dropbear/cli-main.c | 20 +- release/src/router/dropbear/cli-runopts.c | 208 ++++---- release/src/router/dropbear/cli-session.c | 28 +- release/src/router/dropbear/cli-tcpfwd.c | 16 +- release/src/router/dropbear/common-algo.c | 37 +- release/src/router/dropbear/common-channel.c | 268 ++++++---- release/src/router/dropbear/common-kex.c | 55 +- release/src/router/dropbear/common-session.c | 178 +++++-- release/src/router/dropbear/compat.h | 10 +- release/src/router/dropbear/config.h.in | 6 + release/src/router/dropbear/configure | 41 +- release/src/router/dropbear/configure.ac | 41 +- release/src/router/dropbear/crypto_desc.h | 6 +- release/src/router/dropbear/curve25519-donna.c | 10 +- release/src/router/dropbear/dbclient.1 | 35 +- release/src/router/dropbear/dbrandom.c | 4 +- release/src/router/dropbear/dbrandom.h | 8 +- release/src/router/dropbear/dbutil.c | 399 ++------------- release/src/router/dropbear/dbutil.h | 29 +- release/src/router/dropbear/debian/changelog | 24 + release/src/router/dropbear/debug.h | 6 +- release/src/router/dropbear/dropbear.8 | 14 +- release/src/router/dropbear/dropbearconvert.1 | 10 +- release/src/router/dropbear/dropbearkey.1 | 15 +- release/src/router/dropbear/dss.c | 6 +- release/src/router/dropbear/dss.h | 6 +- release/src/router/dropbear/ecc.c | 5 - release/src/router/dropbear/ecc.h | 8 +- release/src/router/dropbear/ecdsa.c | 14 +- release/src/router/dropbear/ecdsa.h | 6 +- release/src/router/dropbear/fake-rfc2553.h | 4 +- release/src/router/dropbear/gendss.c | 2 +- release/src/router/dropbear/gendss.h | 6 +- release/src/router/dropbear/genrsa.h | 6 +- release/src/router/dropbear/gensignkey.h | 4 +- release/src/router/dropbear/includes.h | 6 +- release/src/router/dropbear/kex.h | 6 +- release/src/router/dropbear/keyimport.c | 29 +- release/src/router/dropbear/keyimport.h | 6 +- .../dropbear/libtomcrypt/src/ciphers/aes/aes.c | 10 +- .../router/dropbear/libtomcrypt/src/ciphers/des.c | 1 + .../libtomcrypt/src/ciphers/twofish/twofish.c | 1 + .../libtomcrypt/src/hashes/helper/hash_file.c | 1 + .../src/hashes/helper/hash_filehandle.c | 1 + .../libtomcrypt/src/headers/tomcrypt_argchk.h | 10 +- .../dropbear/libtomcrypt/src/mac/hmac/hmac_done.c | 18 +- .../dropbear/libtomcrypt/src/mac/hmac/hmac_file.c | 1 + .../dropbear/libtomcrypt/src/mac/hmac/hmac_init.c | 10 +- .../libtomcrypt/src/misc/crypt/crypt_argchk.c | 2 +- .../libtomcrypt/src/pk/ecc/ltc_ecc_mulmod_timing.c | 4 +- release/src/router/dropbear/list.h | 6 +- release/src/router/dropbear/listener.c | 9 + release/src/router/dropbear/listener.h | 8 +- release/src/router/dropbear/loginrec.h | 6 +- release/src/router/dropbear/ltc_prng.h | 6 +- release/src/router/dropbear/netio.c | 560 +++++++++++++++++++++ release/src/router/dropbear/netio.h | 64 +++ release/src/router/dropbear/options.h | 39 +- release/src/router/dropbear/packet.c | 150 +++--- release/src/router/dropbear/packet.h | 10 +- release/src/router/dropbear/queue.h | 4 +- release/src/router/dropbear/release.sh | 11 +- release/src/router/dropbear/rsa.h | 6 +- release/src/router/dropbear/runopts.h | 12 +- release/src/router/dropbear/scp.c | 6 +- release/src/router/dropbear/service.h | 6 +- release/src/router/dropbear/session.h | 40 +- release/src/router/dropbear/signkey.c | 15 +- release/src/router/dropbear/signkey.h | 6 +- release/src/router/dropbear/svr-agentfwd.c | 2 +- release/src/router/dropbear/svr-auth.c | 13 +- release/src/router/dropbear/svr-authpam.c | 2 +- release/src/router/dropbear/svr-authpasswd.c | 6 +- release/src/router/dropbear/svr-authpubkey.c | 32 +- .../src/router/dropbear/svr-authpubkeyoptions.c | 4 +- release/src/router/dropbear/svr-chansession.c | 14 +- release/src/router/dropbear/svr-kex.c | 2 +- release/src/router/dropbear/svr-main.c | 17 +- release/src/router/dropbear/svr-runopts.c | 101 ++-- release/src/router/dropbear/svr-service.c | 6 +- release/src/router/dropbear/svr-session.c | 30 +- release/src/router/dropbear/svr-tcpfwd.c | 28 +- release/src/router/dropbear/svr-x11fwd.c | 4 +- release/src/router/dropbear/sysoptions.h | 20 +- release/src/router/dropbear/tcp-accept.c | 2 +- release/src/router/dropbear/tcpfwd.h | 14 +- release/src/router/dropbear/termcodes.h | 6 +- release/src/router/dropbear/x11fwd.h | 6 +- 112 files changed, 2008 insertions(+), 1320 deletions(-) delete mode 100644 release/src/router/dropbear/.hgtags create mode 100644 release/src/router/dropbear/netio.c create mode 100644 release/src/router/dropbear/netio.h mode change 100644 => 100755 release/src/router/dropbear/release.sh diff --git a/release/src/router/dropbear/.hg_archival.txt b/release/src/router/dropbear/.hg_archival.txt index ada464d087..d01ec4fcc7 100644 --- a/release/src/router/dropbear/.hg_archival.txt +++ b/release/src/router/dropbear/.hg_archival.txt @@ -1,5 +1,6 @@ repo: d7da3b1e15401eb234ec866d5eac992fc4cd5878 -node: 48a0ba346de446e413433f93b731187fb4772508 +node: 9a944a243f08be6b22d32f166a0690eb4872462b branch: default -latesttag: DROPBEAR_2015.67 -latesttagdistance: 2 +latesttag: DROPBEAR_2015.70 +latesttagdistance: 10 +changessincelatesttag: 11 diff --git a/release/src/router/dropbear/.hgsigs b/release/src/router/dropbear/.hgsigs index 10bf8f5a14..c3ac393b05 100644 --- a/release/src/router/dropbear/.hgsigs +++ b/release/src/router/dropbear/.hgsigs @@ -13,3 +13,8 @@ a50a1dc743317fad9b3737bc68fbca640659bb6d 0 iEYEABECAAYFAlJeqL0ACgkQjPn4sExkf7yVq 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 +af074dbcb68ff8670b3818e0d66d5dc6f1bd5877 0 iQIcBAABCgAGBQJWVdQfAAoJEPSYMBLCC7qs+n4P/RgZU3GsLFJN7v7Cn6NOdKdfjJBmlbCtK9KwlZZaj8fW4noqnLDcDd6a2xT4mDV3rCE6+QYialGXjNkkNCBwD9Z+gFc8spOtThrpQ54dgWzbgDlYB1y7Hp7DoWoJQIlU6Od9nWBemcSrAviOFNAX8+S6poRdEhrHgMcv2xJoqHjvT7X8gob0RnJcYxW5nLWzDaJV58QnX6QlXg4ClSB6IoCeEawdW6WzXlZ9MGsRycTtx1ool7Uo6Vo2xg48n9TaJqM/lbSsMAjHxO/fdTJMWzTId1fuZxJGFVeJbkhjSwlf7fkVXxrgDxjvIAmFDR8TSTfJo50CD82j5rPcd7KSEpQ12ImBUsntPDgOtt/mJZ3HcFds86OZ7NkPpqoJGVFFQ8yUpe//DNSB2Ovg1FrwhSKOq/9N61BBwk1INVFDp1hMq45PIa9gI9zW/99inGDeSSQlxa4iafEUEjXZTRYuX7mFjnWm5q7r134J7kyWQtN/jNUZ71F0mvhnemufgpNY/I/D7K6qkONpbDZ2nuzkhfoqugzhHYp467UePM0qmLTLdXGPPMukoGorpWeiSb2T25AEKm7N4A9NwPmdAnoFjAibjF9FAuU03sl+pu9MqFb+1ldsqjNfxhcJmoAUR5vy3pED9ailCb/OCBVTHkDPfTEhGU3waO9tPM+5x2rGB5fe +5bb5976e6902a0c9fba974a880c68c9487ee1e77 0 iQIcBAABCgAGBQJWVyIKAAoJEESTFJTynGdzQosP/0k5bVTerpUKZLjyNuMU8o0eyc7njkX8EyMOyGbtcArKpzO2opSBTRsuCT9Zsk1iiQ1GMTY1quKD7aNr86Hipqo4th/+ZXmLe9mmaCDukKjD0ZYC4dBVUy6RSUAMvdkDP9sZs7CMTO/22a9SqOsKTv3s2NN6XnsBGnmNbvVx5hkAk5hMVNFrjKIaexzI/7bWQIDRo2HQCaWaL06JvWEDSEQd2mynGSXxT/+m4hBnuGg6qxn2pd4XfG0g10tDAFx64HQkWgZqSB+F8z71Cvfjondy1zjJYgtABqNlwCKQJZhRUW2+PblqQnz08TUy83XN2vtisOju4avGcHSaBgBbMvg8Wx4ZtM7sPP9pLrhhOTd5ceERHeTceTJy+iI1SQFvccjrRfs5aJ0zAQX5q6f4bV0zp5SmxkvnZUEkZIoetkM8VrPOYugqx31LtHAWfVT9NM+VkV/rrxLhk6J0giIQvC9MPWxRDileFVDszPiOgTLcxWjOziOLT+xijcj7dtx1b/f2bNCduN5G7i+icjjTlCNtyRPRqhBqn705W7F+xESP2gsscM/1BjQ7TGidU5m1njdkUjbrqm3+Qic6iqkG7SfETHmQB9mHqpJ0hACRPvZlhwB7oimNHllkrlw8UJw9f0SiuLjfERIgVS2EOp+mAia0RU7MlTt19o017M1ffEYL diff --git a/release/src/router/dropbear/.hgtags b/release/src/router/dropbear/.hgtags deleted file mode 100644 index afd75ca938..0000000000 --- a/release/src/router/dropbear/.hgtags +++ /dev/null @@ -1,49 +0,0 @@ -03f65e461915a940939e4cc689fc89721ffc40de DROPBEAR_0.48.1 -0f967bfef5cd0056b7ec60e2305d917e51cbf30d DROPBEAR_0.44 -170329dc8ce5dfcf6298e1ad6699f109bf78e73d DROPBEAR_0.51 -1dbd2473482f320ea59f76ce961385cb3a0150a9 DROPBEAR_0.46 -2098857ab826dd42ae05a9a22c3ce2cc835b9844 DROPBEAR_0.45 -36160290a1b27451178be36752ed038840f59cdd LTC_DB_0.46 -39d5d58461d6e93337636e69d4cdf184a09c8d24 LTC_1.05 -55a99934db873be2e63b5968fb6532e5d9bd02e4 DROPBEAR_0.48 -59400faa4b44708c5d0b595e81193bc621e752d3 libtomcrypt-1.05 -66087d87c3555c78b47cf01f32bb5a32054c3ceb DROPBEAR_0.44test4 -677843bfa734238a67636b461a02c110c462ffaf DROPBEAR_0.44test1 -7faae8f46238e23975430876547b8950b4e75481 t:ltc-0.95-orig -8220862baae829ebc762587b99c662480d57bb23 DROPBEAR_0.53 -86e0b50a9b588239c3fc9cc9cfe255ef586df17b ltm-0.30-orig -88e0a1ad951add46b795511dc2698e36b4aee922 DROPBEAR_0.44test3 -8e94663164c6e106ccc5c9e997dedf6e04d77dd2 LTM_DB_0.44 -91fbc376f01084037cd5f6a5bf2e2db4903e8e99 libtommath-0.35 -97db060d0ef5f8cf8e67eb602ef037055a185ca9 libtommath-0.40 -aa2f51a6b81d33de5e9898a7f27c792a173d9b26 DROPBEAR_0.53.1 -ab370c629d363f8c9a3eca512bfa86e362034654 DROPBEAR_0.49 -c2ac796b130eeb6fa840873d8c230544c8ec7e4b DROPBEAR_0.44test2 -cd1143579f00b0248c79f63ca70efee4a35a57e8 LTC_DB_0.44 -ce104c8b0be1ff3f2c2590b7cdc3fd6870c865cd DROPBEAR_0.52 -d5faf4814ddbc5abd9e209409bb9e7a4686c8cd7 libtomcrypt-1.16 -d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1 -d8254fc979e99560c93ca2cece77a6df31927ea5 LTM_0.35 -e109027b9edfb02f0bdf96ec45bb1cd9ad41e7da LTM_DB_0.46 -e109027b9edfb02f0bdf96ec45bb1cd9ad41e7da LTM_DB_0.47 -e37b160c414cab6466622f63b0c4dcbf6ebc47a9 DROPBEAR_0.47 -e430a26064ee86ab79aef372118d6d03b2441996 DROPBEAR_0.50 -e5d119ea4c63656bc54ecfd865d04591ac2ed225 LTC_DB_0.47 -3f12086c2ef2b9ffe36a822fdb3ff647fcec1831 DROPBEAR_2011.54 -d354464b2aa6f6ba0bf44d43bcae5aa798435393 DROPBEAR_2012.55 -7faae8f46238e23975430876547b8950b4e75481 t:ltc-0.95-orig -0000000000000000000000000000000000000000 t:ltc-0.95-orig -d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1 -0000000000000000000000000000000000000000 t:ltc-0.95-db-merge1 -1b8b2b9d6e94bc3cc5e61b620476ea36cc466e1b DROPBEAR_2013.56 -96b8bcb88017815040949a417caa55686271e8a9 DROPBEAR_2013.57 -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 diff --git a/release/src/router/dropbear/.travis.yml b/release/src/router/dropbear/.travis.yml index 7e5302abfa..4bfef9f060 100644 --- a/release/src/router/dropbear/.travis.yml +++ b/release/src/router/dropbear/.travis.yml @@ -3,7 +3,9 @@ compiler: - gcc script: - - autoconf && autoheader && ./configure $BUNDLEDLIBTOM CFLAGS="-O2 -Wall -Wno-pointer-sign" --prefix=$HOME/inst && make install + - 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 @@ -15,6 +17,7 @@ before_install: - sudo apt-get install -qq libz-dev libtomcrypt-dev libtommath-dev env: - - BUNDLEDLIBTOM=--disable-bundled-libtom + - BUNDLEDLIBTOM=--disable-bundled-libtom WEXTRAFLAGS=-Werror - BUNDLEDLIBTOM=--enable-bundled-libtom - MULTI=1 + - NOWRITEV=1 diff --git a/release/src/router/dropbear/CHANGES b/release/src/router/dropbear/CHANGES index 6621e8d506..7b1e2da733 100644 --- a/release/src/router/dropbear/CHANGES +++ b/release/src/router/dropbear/CHANGES @@ -1,3 +1,89 @@ +2015.71 - 3 December 2015 + +- Fix "bad buf_incrpos" when data is transferred, broke in 2015.69 + +- Fix crash on exit when -p address:port is used, broke in 2015.68 + +- Fix building with only ENABLE_CLI_REMOTETCPFWD given, patch from Konstantin Tokarev + +- Fix bad configure script test which didn't work with dash shell, patch from Juergen Daubert, + broke in 2015.70 + +- Fix server race condition that could cause sessions to hang on exit, + https://github.com/robotframework/SSHLibrary/issues/128 + +2015.70 - 26 November 2015 + +- Fix server password authentication on Linux, broke in 2015.69 + +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 diff --git a/release/src/router/dropbear/LICENSE b/release/src/router/dropbear/LICENSE index 828b9af3f6..c400d946ea 100644 --- a/release/src/router/dropbear/LICENSE +++ b/release/src/router/dropbear/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-2014 Matt Johnston +Copyright (c) 2002-2015 Matt Johnston Portions copyright (c) 2004 Mihnea Stoenescu All rights reserved. diff --git a/release/src/router/dropbear/Makefile.in b/release/src/router/dropbear/Makefile.in index 8cde521819..b2e7a270bf 100644 --- a/release/src/router/dropbear/Makefile.in +++ b/release/src/router/dropbear/Makefile.in @@ -40,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 @@ -140,7 +140,7 @@ insmulti%: dropbearmulti $(INSTALL) -d $(DESTDIR)$(mandir)/man1 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) diff --git a/release/src/router/dropbear/agentfwd.h b/release/src/router/dropbear/agentfwd.h index 113370cfe6..53c297a112 100644 --- a/release/src/router/dropbear/agentfwd.h +++ b/release/src/router/dropbear/agentfwd.h @@ -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_ */ diff --git a/release/src/router/dropbear/algo.h b/release/src/router/dropbear/algo.h index 1758c51ceb..49c4f41c8b 100644 --- a/release/src/router/dropbear/algo.h +++ b/release/src/router/dropbear/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 */ @@ -134,4 +134,4 @@ enum { DROPBEAR_COMP_ZLIB_DELAY, }; -#endif /* _ALGO_H_ */ +#endif /* DROPBEAR_ALGO_H_ */ diff --git a/release/src/router/dropbear/auth.h b/release/src/router/dropbear/auth.h index 66f5b6a470..250a7f7bf9 100644 --- a/release/src/router/dropbear/auth.h +++ b/release/src/router/dropbear/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" @@ -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_ */ diff --git a/release/src/router/dropbear/bignum.h b/release/src/router/dropbear/bignum.h index f9710d7287..d05e8b7736 100644 --- a/release/src/router/dropbear/bignum.h +++ b/release/src/router/dropbear/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_ */ diff --git a/release/src/router/dropbear/buffer.c b/release/src/router/dropbear/buffer.c index 9bda65288a..1e5a864e7f 100644 --- a/release/src/router/dropbear/buffer.c +++ b/release/src/router/dropbear/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 diff --git a/release/src/router/dropbear/buffer.h b/release/src/router/dropbear/buffer.h index 1d83f8e3cd..c32b84b9f5 100644 --- a/release/src/router/dropbear/buffer.h +++ b/release/src/router/dropbear/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_ */ diff --git a/release/src/router/dropbear/channel.h b/release/src/router/dropbear/channel.h index a310d44eac..c73fbe8c90 100644 --- a/release/src/router/dropbear/channel.h +++ b/release/src/router/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 _CHANNEL_H_ -#define _CHANNEL_H_ +#ifndef DROPBEAR_CHANNEL_H_ +#define DROPBEAR_CHANNEL_H_ #include "includes.h" #include "buffer.h" @@ -73,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 */ @@ -92,7 +93,7 @@ struct Channel { 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*); @@ -100,9 +101,12 @@ struct ChanType { 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 @@ -131,10 +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, unsigned char *type); +void start_send_channel_request(struct Channel *channel, char *type); void send_msg_request_success(); void send_msg_request_failure(); -#endif /* _CHANNEL_H_ */ +#endif /* DROPBEAR_CHANNEL_H_ */ diff --git a/release/src/router/dropbear/chansession.h b/release/src/router/dropbear/chansession.h index 4078123c65..6eb8c76486 100644 --- a/release/src/router/dropbear/chansession.h +++ b/release/src/router/dropbear/chansession.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,14 +39,14 @@ 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; @@ -103,4 +103,4 @@ struct SigMap { extern const struct SigMap signames[]; -#endif /* _CHANSESSION_H_ */ +#endif /* DROPBEAR_CHANSESSION_H_ */ diff --git a/release/src/router/dropbear/circbuffer.c b/release/src/router/dropbear/circbuffer.c index 55c4422807..1b8304c691 100644 --- a/release/src/router/dropbear/circbuffer.c +++ b/release/src/router/dropbear/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); + + if (*len1 < cbuf->used) { + *p2 = cbuf->data; + *len2 = cbuf->used - *len1; + } else { + *p2 = NULL; + *len2 = 0; } - - return &cbuf->data[cbuf->readpos]; } 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; diff --git a/release/src/router/dropbear/circbuffer.h b/release/src/router/dropbear/circbuffer.h index 21c5134b74..744a2c1069 100644 --- a/release/src/router/dropbear/circbuffer.h +++ b/release/src/router/dropbear/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); diff --git a/release/src/router/dropbear/cli-agentfwd.c b/release/src/router/dropbear/cli-agentfwd.c index aea5e647a8..c9bc9dbf25 100644 --- a/release/src/router/dropbear/cli-agentfwd.c +++ b/release/src/router/dropbear/cli-agentfwd.c @@ -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) { diff --git a/release/src/router/dropbear/cli-auth.c b/release/src/router/dropbear/cli-auth.c index 70ace65861..da0d9d537b 100644 --- a/release/src/router/dropbear/cli-auth.c +++ b/release/src/router/dropbear/cli-auth.c @@ -43,9 +43,9 @@ void cli_auth_getmethods() { TRACE(("enter cli_auth_getmethods")) 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 */ @@ -75,7 +75,7 @@ void cli_auth_getmethods() { void recv_msg_userauth_banner() { - unsigned char* banner = NULL; + char* banner = NULL; unsigned int bannerlen; unsigned int i, linecount; @@ -151,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; @@ -324,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) @@ -347,3 +348,4 @@ char* getpass_or_cancel(char* prompt) } return password; } +#endif diff --git a/release/src/router/dropbear/cli-authinteract.c b/release/src/router/dropbear/cli-authinteract.c index a06c9ca8e1..49d65a7837 100644 --- a/release/src/router/dropbear/cli-authinteract.c +++ b/release/src/router/dropbear/cli-authinteract.c @@ -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 */ diff --git a/release/src/router/dropbear/cli-authpasswd.c b/release/src/router/dropbear/cli-authpasswd.c index 1e0bd41e3b..3cf49a2787 100644 --- a/release/src/router/dropbear/cli-authpasswd.c +++ b/release/src/router/dropbear/cli-authpasswd.c @@ -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 */ diff --git a/release/src/router/dropbear/cli-authpubkey.c b/release/src/router/dropbear/cli-authpubkey.c index 9fcc25656c..d53178e604 100644 --- a/release/src/router/dropbear/cli-authpubkey.c +++ b/release/src/router/dropbear/cli-authpubkey.c @@ -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); diff --git a/release/src/router/dropbear/cli-chansession.c b/release/src/router/dropbear/cli-chansession.c index 57457d2362..5e00149298 100644 --- a/release/src/router/dropbear/cli-chansession.c +++ b/release/src/router/dropbear/cli-chansession.c @@ -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")) @@ -272,7 +272,7 @@ 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")) @@ -305,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")) @@ -392,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")) @@ -403,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); diff --git a/release/src/router/dropbear/cli-kex.c b/release/src/router/dropbear/cli-kex.c index a590157913..07ee431a58 100644 --- a/release/src/router/dropbear/cli-kex.c +++ b/release/src/router/dropbear/cli-kex.c @@ -79,7 +79,7 @@ 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; } @@ -322,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; } @@ -334,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; } @@ -346,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) { @@ -382,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 diff --git a/release/src/router/dropbear/cli-main.c b/release/src/router/dropbear/cli-main.c index 0b4047c240..c7c90359dc 100644 --- a/release/src/router/dropbear/cli-main.c +++ b/release/src/router/dropbear/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,16 +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; + 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; @@ -91,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", @@ -102,12 +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); } diff --git a/release/src/router/dropbear/cli-runopts.c b/release/src/router/dropbear/cli-runopts.c index 467776b5bc..e8cb3136bf 100644 --- a/release/src/router/dropbear/cli-runopts.c +++ b/release/src/router/dropbear/cli-runopts.c @@ -105,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]; @@ -172,54 +177,23 @@ void cli_getopts(int argc, char ** argv) { 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], 1); - 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 */ @@ -232,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], 1); - } else { - nextiskey = 1; - } + opt = OPT_AUTHKEY; break; #endif case 't': /* we want a pty */ @@ -257,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; @@ -265,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 @@ -336,50 +305,85 @@ void cli_getopts(int argc, char ** argv) { 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 */ + if (!next && opt == OPT_OTHER) /* got a flag */ + continue; - } else { - TRACE(("non-flag arg: '%s'", argv[i])) + if (c == '\0') { + i++; + j = 0; + if (!argv[i]) + dropbear_exit("Missing argument"); + } - /* Either the hostname or commands */ +#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; + } + } - 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; - } + /* 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 */ @@ -388,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 */ @@ -447,9 +446,9 @@ void cli_getopts(int argc, char ** argv) { } #endif -#ifdef DROPBEAR_DEFAULT_CLI_AUTHKEY +#if defined(DROPBEAR_DEFAULT_CLI_AUTHKEY) && defined(ENABLE_CLI_PUBKEY_AUTH) { - char *expand_path = expand_tilde(DROPBEAR_DEFAULT_CLI_AUTHKEY); + char *expand_path = expand_homedir_path(DROPBEAR_DEFAULT_CLI_AUTHKEY); loadidentityfile(expand_path, 0); m_free(expand_path); } @@ -498,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 , terminator. */ ret = m_malloc(len); total = 0; @@ -524,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; @@ -532,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) diff --git a/release/src/router/dropbear/cli-session.c b/release/src/router/dropbear/cli-session.c index a484bf731a..10244a7207 100644 --- a/release/src/router/dropbear/cli-session.c +++ b/release/src/router/dropbear/cli-session.c @@ -37,11 +37,12 @@ #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); @@ -93,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); @@ -356,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++) { diff --git a/release/src/router/dropbear/cli-tcpfwd.c b/release/src/router/dropbear/cli-tcpfwd.c index fa61d13f88..ec65f410f2 100644 --- a/release/src/router/dropbear/cli-tcpfwd.c +++ b/release/src/router/dropbear/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); @@ -215,7 +216,6 @@ 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); @@ -254,19 +254,7 @@ static int newtcpforwarded(struct Channel * channel) { } 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; - } - - 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->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel); channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE; diff --git a/release/src/router/dropbear/common-algo.c b/release/src/router/dropbear/common-algo.c index 9abc330311..002ae667fd 100644 --- a/release/src/router/dropbear/common-algo.c +++ b/release/src/router/dropbear/common-algo.c @@ -87,7 +87,7 @@ const struct dropbear_cipher dropbear_nocipher = #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 +#endif /* DROPBEAR_ENABLE_CBC_MODE */ const struct dropbear_cipher_mode dropbear_mode_none = {void_start, void_cipher, void_cipher}; @@ -102,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 // DROPBEAR_ENABLE_CTR_MODE +#endif /* DROPBEAR_ENABLE_CTR_MODE */ /* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc. {&hash_desc, keysize, hashsize} */ @@ -144,6 +144,15 @@ algo_type sshciphers[] = { #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 */ #ifdef DROPBEAR_ENABLE_CBC_MODE @@ -177,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 @@ -316,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); } @@ -332,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; @@ -482,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; } diff --git a/release/src/router/dropbear/common-channel.c b/release/src/router/dropbear/common-channel.c index 049658d929..40353c2c7e 100644 --- a/release/src/router/dropbear/common-channel.c +++ b/release/src/router/dropbear/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); @@ -99,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 @@ -163,12 +155,11 @@ 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; @@ -242,27 +233,20 @@ void channelio(fd_set *readfds, fd_set *writefds) { /* 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; - ses.channel_signal_pending = 0; } /* handle any channel closing etc */ @@ -374,27 +358,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) { + if (result == DROPBEAR_SUCCESS) + { + channel->readfd = channel->writefd = sock; + channel->conn_pending = NULL; + send_msg_channel_open_confirmation(channel, channel->recvwindow, + channel->recvmaxpacket); + TRACE(("leave channel_connect_done: success")) + } + else + { 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); - send_msg_channel_open_confirmation(channel, channel->recvwindow, - channel->recvmaxpacket); - channel->readfd = channel->writefd; - channel->initconn = 0; - TRACE(("leave check_in_progress: success")) } } @@ -402,7 +385,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); @@ -440,35 +423,120 @@ 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)) + if (morelen) { + /* fallback doesn't consume moredata */ + *morelen = 0; + } + + /* 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; + } + } else { + cbuf_incrread(cbuf, written); + channel->recvdonelen += written; + } + return DROPBEAR_SUCCESS; +} +#endif /* !HAVE_WRITEV */ - maxlen = cbuf_readlen(cbuf); +#ifdef HAVE_WRITEV +static int writechannel_writev(struct Channel* channel, int fd, circbuffer *cbuf, + const unsigned char *moredata, unsigned int *morelen) { - /* 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) { + struct iovec iov[3]; + unsigned char *circ_p1, *circ_p2; + unsigned int circ_len1, circ_len2; + int io_count = 0; + + 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; } - TRACE(("leave writechannel: len <= 0")) - return; + } else { + int cbuf_written = MIN(circ_len1+circ_len2, (unsigned int)written); + cbuf_incrread(cbuf, cbuf_written); + if (morelen) { + *morelen = written - cbuf_written; + } + channel->recvdonelen += written; } - TRACE(("writechannel wrote %d", len)) + return DROPBEAR_SUCCESS; +} +#endif /* HAVE_WRITEV */ - cbuf_incrread(cbuf, len); - channel->recvdonelen += len; +/* 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; @@ -480,11 +548,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; @@ -502,7 +572,7 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) { FD if there's the possibility of "~."" to kill an interactive session (the read_mangler) */ if (channel->transwindow > 0 - && (ses.dataallowed || channel->read_mangler)) { + && ((ses.dataallowed && allow_reads) || channel->read_mangler)) { if (channel->readfd >= 0) { FD_SET(channel->readfd, readfds); @@ -514,8 +584,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); } @@ -586,11 +655,11 @@ 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); + m_close(channel->writefd); TRACE(("CLOSE readfd %d", channel->readfd)) - close(channel->readfd); + m_close(channel->readfd); TRACE(("CLOSE errfd %d", channel->errfd)) - close(channel->errfd); + m_close(channel->errfd); } if (!channel->close_handler_done @@ -599,6 +668,10 @@ 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--; @@ -616,7 +689,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")) @@ -749,6 +822,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")) @@ -775,25 +850,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")) } @@ -834,7 +920,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; @@ -883,6 +969,7 @@ void recv_msg_channel_open() { if (channel == NULL) { TRACE(("newchannel returned NULL")) + errtype = SSH_OPEN_RESOURCE_SHORTAGE; goto failure; } @@ -904,8 +991,6 @@ void recv_msg_channel_open() { channel->prio = DROPBEAR_CHANNEL_PRIO_BULK; } - chan_initwritebuf(channel); - /* success */ send_msg_channel_open_confirmation(channel, channel->recvwindow, channel->recvmaxpacket); @@ -952,7 +1037,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(); @@ -960,8 +1045,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")) @@ -1001,7 +1086,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; } @@ -1024,7 +1109,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); } } @@ -1048,7 +1133,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); @@ -1141,15 +1225,15 @@ void send_msg_request_failure() { } struct Channel* get_any_ready_channel() { + size_t i; if (ses.chancount == 0) { return NULL; } - size_t i; for (i = 0; i < ses.chansize; i++) { struct Channel *chan = ses.channels[i]; if (chan && !(chan->sent_eof || chan->recv_eof) - && !(chan->await_open || chan->initconn)) { + && !(chan->await_open)) { return chan; } } @@ -1157,7 +1241,7 @@ struct Channel* get_any_ready_channel() { } void start_send_channel_request(struct Channel *channel, - unsigned char *type) { + char *type) { CHECKCLEARTOWRITE(); buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST); diff --git a/release/src/router/dropbear/common-kex.c b/release/src/router/dropbear/common-kex.c index 7d93708ef1..b233819b44 100644 --- a/release/src/router/dropbear/common-kex.c +++ b/release/src/router/dropbear/common-kex.c @@ -511,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 @@ -525,17 +525,18 @@ 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 */ @@ -545,16 +546,17 @@ 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 = SSH_MSG_KEXDH_INIT; } @@ -629,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"); } @@ -649,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 */ @@ -697,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); @@ -751,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) { @@ -758,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)); @@ -775,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); diff --git a/release/src/router/dropbear/common-session.c b/release/src/router/dropbear/common-session.c index 83fb7f41d6..874d5396a3 100644 --- a/release/src/router/dropbear/common-session.c +++ b/release/src/router/dropbear/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(); @@ -53,17 +54,29 @@ int exitflag = 0; /* GLOBAL */ void common_session_init(int sock_in, int sock_out) { time_t now; +#ifdef DEBUG_TRACE + debug_start_net(); +#endif + TRACE(("enter session_init")) ses.sock_in = sock_in; ses.sock_out = sock_out; ses.maxfd = MAX(sock_in, sock_out); + 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; @@ -78,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; @@ -140,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; @@ -147,21 +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); + ses.channel_signal_pending = 0; /* set up for channels which can be read/written */ - setchannelfds(&readfd, &writefd); + 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); @@ -187,7 +212,9 @@ void session_loop(void(*loophandler)()) { wake up the select() above. */ if (FD_ISSET(ses.signal_pipe[0], &readfd)) { char x; + TRACE(("signal pipe set")) while (read(ses.signal_pipe[0], &x, 1) > 0) {} + ses.channel_signal_pending = 1; } /* check for auth timeout, rekeying required etc */ @@ -210,11 +237,13 @@ 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 ) */ channelio(&readfd, &writefd); @@ -236,6 +265,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() { @@ -247,24 +285,47 @@ 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(); } - chancleanup(); - - /* Cleaning up keys must happen after other cleanup - functions which might queue packets */ - 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); @@ -273,10 +334,8 @@ void 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() { @@ -395,16 +454,16 @@ static int ident_readln(int fd, char* buf, int count) { } void ignore_recv_response() { - // Do nothing + /* Do nothing */ TRACE(("Ignored msg_request_response")) } static void send_msg_keepalive() { - CHECKCLEARTOWRITE(); time_t old_time_idle = ses.last_packet_time_idle; - struct Channel *chan = get_any_ready_channel(); + CHECKCLEARTOWRITE(); + if (chan) { /* Channel requests are preferable, more implementations handle them than SSH_MSG_GLOBAL_REQUEST */ @@ -434,6 +493,11 @@ static void checktimeouts() { time_t now; now = monotonic_now(); + if (IS_DROPBEAR_SERVER && ses.connect_time != 0 + && now - ses.connect_time >= AUTH_TIMEOUT) { + dropbear_close("Timeout before auth"); + } + /* we can't rekey if we haven't done remote ident exchange yet */ if (ses.remoteident == NULL) { return; @@ -474,20 +538,39 @@ static void checktimeouts() { } } +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); - /* AUTH_TIMEOUT is only relevant before authdone */ - if (ses.authstate.authdone != 1 && 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() { @@ -543,6 +626,11 @@ void update_channel_prio() { 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]; @@ -573,7 +661,7 @@ void update_channel_prio() { } if (new_prio != ses.socket_prio) { - TRACE(("Dropbear priority transitioning %4.4s -> %4.4s", (char*)&ses.socket_prio, (char*)&new_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; } diff --git a/release/src/router/dropbear/compat.h b/release/src/router/dropbear/compat.h index 1ab344fe7e..4bd1a121df 100644 --- a/release/src/router/dropbear/compat.h +++ b/release/src/router/dropbear/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_ */ diff --git a/release/src/router/dropbear/config.h.in b/release/src/router/dropbear/config.h.in index 924633ddd9..6813683456 100644 --- a/release/src/router/dropbear/config.h.in +++ b/release/src/router/dropbear/config.h.in @@ -63,6 +63,9 @@ /* Define if gai_strerror() returns const char * */ #undef HAVE_CONST_GAI_STRERROR_PROTO +/* crypt() function */ +#undef HAVE_CRYPT + /* Define to 1 if you have the header file. */ #undef HAVE_CRYPT_H @@ -99,6 +102,9 @@ /* Define to 1 if you have the `getnameinfo' function. */ #undef HAVE_GETNAMEINFO +/* Define to 1 if you have the `getpass' function. */ +#undef HAVE_GETPASS + /* Define to 1 if you have the `getspnam' function. */ #undef HAVE_GETSPNAM diff --git a/release/src/router/dropbear/configure b/release/src/router/dropbear/configure index cc61d70185..c4a2bebbf5 100755 --- a/release/src/router/dropbear/configure +++ b/release/src/router/dropbear/configure @@ -4349,7 +4349,11 @@ $as_echo "$as_me: Using uClibc - login() and logout() probably don't work, so we fi -# Checks for libraries. +ac_fn_c_check_func "$LINENO" "crypt" "ac_cv_func_crypt" +if test "x$ac_cv_func_crypt" = xyes; then : + found_crypt_func=here +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5 $as_echo_n "checking for crypt in -lcrypt... " >&6; } if ${ac_cv_lib_crypt_crypt+:} false; then : @@ -4387,10 +4391,18 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5 $as_echo "$ac_cv_lib_crypt_crypt" >&6; } if test "x$ac_cv_lib_crypt_crypt" = xyes; then : - CRYPTLIB="-lcrypt" + + CRYPTLIB="-lcrypt" + found_crypt_func=here + fi +if test "t$found_crypt_func" = there; then + +$as_echo "#define HAVE_CRYPT 1" >>confdefs.h + +fi # Check if zlib is needed @@ -5336,7 +5348,7 @@ else int main () { - struct sockaddr_storage s; + if (sizeof(struct sockaddr_storage)) return 0 ; return 0; } @@ -5372,7 +5384,7 @@ else int main () { - struct sockaddr_in6 s; s.sin6_family = 0; + if (sizeof(struct sockaddr_in6)) return 0 ; return 0; } @@ -5409,7 +5421,7 @@ else int main () { - struct in6_addr s; s.s6_addr[0] = 0; + if (sizeof(struct in6_addr)) return 0 ; return 0; } @@ -5447,7 +5459,7 @@ else int main () { - struct addrinfo s; s.ai_flags = AI_PASSIVE; + if (sizeof(struct addrinfo)) return 0 ; return 0; } @@ -6697,7 +6709,7 @@ _ACEOF rm -f conftest* -for ac_func in dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev +for ac_func in dup2 getpass getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -8139,6 +8151,21 @@ else $as_echo "$as_me: Using system libtomcrypt and libtommath" >&6;} fi + +if test "x$ac_cv_func_getpass" != xyes; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5 +$as_echo "$as_me: " >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: getpass() not available, dbclient will only have public-key authentication" >&5 +$as_echo "$as_me: getpass() not available, dbclient will only have public-key authentication" >&6;} +fi + +if test "t$found_crypt_func" != there; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5 +$as_echo "$as_me: " >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: crypt() not available, dropbear server will not have password authentication" >&5 +$as_echo "$as_me: crypt() not available, dropbear server will not have password authentication" >&6;} +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: " >&5 $as_echo "$as_me: " >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: Now edit options.h to choose features." >&5 diff --git a/release/src/router/dropbear/configure.ac b/release/src/router/dropbear/configure.ac index b0e85e5405..9fd8ef2059 100644 --- a/release/src/router/dropbear/configure.ac +++ b/release/src/router/dropbear/configure.ac @@ -82,9 +82,19 @@ AC_CHECK_DECL(__UCLIBC__, AC_MSG_NOTICE([Using uClibc - login() and logout() probably don't work, so we won't use them.]) ],,,) -# Checks for libraries. -AC_CHECK_LIB(crypt, crypt, CRYPTLIB="-lcrypt") +dnl We test for crypt() specially. On Linux (and others?) it resides in libcrypt +dnl but we don't want link all binaries to -lcrypt, just dropbear server. +dnl OS X doesn't need -lcrypt +AC_CHECK_FUNC(crypt, found_crypt_func=here) +AC_CHECK_LIB(crypt, crypt, + [ + CRYPTLIB="-lcrypt" + found_crypt_func=here + ]) AC_SUBST(CRYPTLIB) +if test "t$found_crypt_func" = there; then +AC_DEFINE(HAVE_CRYPT, 1, [crypt() function]) +fi # Check if zlib is needed AC_ARG_WITH(zlib, @@ -265,7 +275,7 @@ AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage #include #include ]], - [[ 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 +289,7 @@ AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [ #include #include ]], - [[ 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 +303,7 @@ AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [ #include #include ]], - [[ 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 +318,7 @@ AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [ #include #include ]], - [[ 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" ] ) @@ -632,7 +642,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]) AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME)) @@ -719,10 +729,21 @@ 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 "t$found_crypt_func" != there; 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.]) diff --git a/release/src/router/dropbear/crypto_desc.h b/release/src/router/dropbear/crypto_desc.h index d05096b402..54da73490a 100644 --- a/release/src/router/dropbear/crypto_desc.h +++ b/release/src/router/dropbear/crypto_desc.h @@ -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 */ diff --git a/release/src/router/dropbear/curve25519-donna.c b/release/src/router/dropbear/curve25519-donna.c index bb1262e5e9..33096104bf 100644 --- a/release/src/router/dropbear/curve25519-donna.c +++ b/release/src/router/dropbear/curve25519-donna.c @@ -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]; diff --git a/release/src/router/dropbear/dbclient.1 b/release/src/router/dropbear/dbclient.1 index cf9c64776f..d9e7631ccf 100644 --- a/release/src/router/dropbear/dbclient.1 +++ b/release/src/router/dropbear/dbclient.1 @@ -3,25 +3,32 @@ 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 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 @@ -35,7 +42,7 @@ Read the identity key from file (multiple allowed). This file is created with dropbearkey(1) or converted 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 @@ -44,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 @@ -60,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. @@ -129,7 +138,7 @@ Dropbear will also allow multiple "hops" to be specified, separated by commas. I 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 @@ -157,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 diff --git a/release/src/router/dropbear/dbrandom.c b/release/src/router/dropbear/dbrandom.c index e2f55c2c9d..02e78036ab 100644 --- a/release/src/router/dropbear/dbrandom.c +++ b/release/src/router/dropbear/dbrandom.c @@ -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); } diff --git a/release/src/router/dropbear/dbrandom.h b/release/src/router/dropbear/dbrandom.h index 2c79ec3a57..6e262f3841 100644 --- a/release/src/router/dropbear/dbrandom.h +++ b/release/src/router/dropbear/dbrandom.h @@ -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_ */ diff --git a/release/src/router/dropbear/dbutil.c b/release/src/router/dropbear/dbutil.c index ae7313207e..d87835b5b0 100644 --- a/release/src/router/dropbear/dbutil.c +++ b/release/src/router/dropbear/dbutil.c @@ -150,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(), (int)tv.tv_sec, (int)tv.tv_usec); + fprintf(stderr, "TRACE (%d) %f: ", getpid(), time_since_start()); vfprintf(stderr, format, param); fprintf(stderr, "\n"); va_end(param); @@ -170,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; @@ -180,193 +205,14 @@ void dropbear_trace2(const char* format, ...) { return; } - gettimeofday(&tv, NULL); - va_start(param, format); - fprintf(stderr, "TRACE2 (%d) %d.%d: ", getpid(), (int)tv.tv_sec, (int)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; - - /* 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; -} - /* Connect to a given unix socket. The socket is blocking */ #ifdef ENABLE_CONNECT_UNIX int connect_unix(const char* path) { @@ -390,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. @@ -612,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) { @@ -827,12 +504,12 @@ out: /* make sure that the socket closes */ void m_close(int fd) { + int val; if (fd == -1) { return; } - int val; do { val = close(fd); } while (val < 0 && errno == EINTR); @@ -936,15 +613,16 @@ int m_str_to_uint(const char* str, unsigned int *val) { } } -/* Returns malloced path. Only expands ~ in first character */ -char * expand_tilde(const char *inpath) { +/* 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] == '~') { + if (inpath[0] != '/') { pw = getpwuid(getuid()); if (pw && pw->pw_dir) { - int len = strlen(inpath) + strlen(pw->pw_dir) + 1; + int len = strlen(inpath) + strlen(pw->pw_dir) + 2; char *buf = m_malloc(len); - snprintf(buf, len, "%s/%s", pw->pw_dir, &inpath[1]); + snprintf(buf, len, "%s/%s", pw->pw_dir, inpath); return buf; } } @@ -1018,3 +696,4 @@ time_t monotonic_now() { return time(NULL); } + diff --git a/release/src/router/dropbear/dbutil.h b/release/src/router/dropbear/dbutil.h index cdad9bca5b..e1db32801f 100644 --- a/release/src/router/dropbear/dbutil.h +++ b/release/src/router/dropbear/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 = 10, - DROPBEAR_PRIO_LOWDELAY = 11, - DROPBEAR_PRIO_BULK = 12, -}; - 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) do {free(X); (X) = NULL;} while (0); +#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(); @@ -110,6 +97,6 @@ int constant_time_memcmp(const void* a, const void *b, size_t n); a real-world clock */ time_t monotonic_now(); -char * expand_tilde(const char *inpath); +char * expand_homedir_path(const char *inpath); -#endif /* _DBUTIL_H_ */ +#endif /* DROPBEAR_DBUTIL_H_ */ diff --git a/release/src/router/dropbear/debian/changelog b/release/src/router/dropbear/debian/changelog index 12484cc962..79ea11770b 100644 --- a/release/src/router/dropbear/debian/changelog +++ b/release/src/router/dropbear/debian/changelog @@ -1,3 +1,27 @@ +dropbear (2015.71-0.1) unstable; urgency=low + + * New upstream release. + + -- Matt Johnston Thu, 3 Dec 2015 22:52:58 +0800 + +dropbear (2015.70-0.1) unstable; urgency=low + + * New upstream release. + + -- Matt Johnston Thu, 26 Nov 2015 22:52:58 +0800 + +dropbear (2015.69-0.1) unstable; urgency=low + + * New upstream release. + + -- Matt Johnston Wed, 25 Nov 2015 22:52:58 +0800 + +dropbear (2015.68-0.1) unstable; urgency=low + + * New upstream release. + + -- Matt Johnston Sat, 8 Aug 2015 22:52:58 +0800 + dropbear (2015.67-0.1) unstable; urgency=low * New upstream release. diff --git a/release/src/router/dropbear/debug.h b/release/src/router/dropbear/debug.h index 289c5773c8..cbfa7e97f6 100644 --- a/release/src/router/dropbear/debug.h +++ b/release/src/router/dropbear/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 diff --git a/release/src/router/dropbear/dropbear.8 b/release/src/router/dropbear/dropbear.8 index 42f8ddb350..71200d9054 100644 --- a/release/src/router/dropbear/dropbear.8 +++ b/release/src/router/dropbear/dropbear.8 @@ -3,11 +3,10 @@ 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 small SSH server @@ -54,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 @@ -100,7 +99,8 @@ Print the version .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] @@ -127,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 @@ -139,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 diff --git a/release/src/router/dropbear/dropbearconvert.1 b/release/src/router/dropbear/dropbearconvert.1 index b2f34ef59b..dd97ad49a1 100644 --- a/release/src/router/dropbear/dropbearconvert.1 +++ b/release/src/router/dropbear/dropbearconvert.1 @@ -21,24 +21,24 @@ 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 +.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/id_dropbear diff --git a/release/src/router/dropbear/dropbearkey.1 b/release/src/router/dropbear/dropbearkey.1 index b4d202ee16..9bc4ed91c9 100644 --- a/release/src/router/dropbear/dropbearkey.1 +++ b/release/src/router/dropbear/dropbearkey.1 @@ -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 . For client authentication ~/.ssh/id_dropbear is loaded by default +\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 diff --git a/release/src/router/dropbear/dss.c b/release/src/router/dropbear/dss.c index d4c4407a2c..b771ec0439 100644 --- a/release/src/router/dropbear/dss.c +++ b/release/src/router/dropbear/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; diff --git a/release/src/router/dropbear/dss.h b/release/src/router/dropbear/dss.h index f921ae4fab..4f164f3032 100644 --- a/release/src/router/dropbear/dss.h +++ b/release/src/router/dropbear/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_ */ diff --git a/release/src/router/dropbear/ecc.c b/release/src/router/dropbear/ecc.c index c733c9ed61..e252884d2c 100644 --- a/release/src/router/dropbear/ecc.c +++ b/release/src/router/dropbear/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); diff --git a/release/src/router/dropbear/ecc.h b/release/src/router/dropbear/ecc.h index 40213f454b..93f85cf04f 100644 --- a/release/src/router/dropbear/ecc.h +++ b/release/src/router/dropbear/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 */ diff --git a/release/src/router/dropbear/ecdsa.c b/release/src/router/dropbear/ecdsa.c index 039601499d..5568131992 100644 --- a/release/src/router/dropbear/ecdsa.c +++ b/release/src/router/dropbear/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")) @@ -140,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); @@ -161,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")) @@ -222,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); @@ -409,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); } diff --git a/release/src/router/dropbear/ecdsa.h b/release/src/router/dropbear/ecdsa.h index f578171f79..24792cb6c7 100644 --- a/release/src/router/dropbear/ecdsa.h +++ b/release/src/router/dropbear/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_ */ diff --git a/release/src/router/dropbear/fake-rfc2553.h b/release/src/router/dropbear/fake-rfc2553.h index 876fa146ce..c64136c1be 100644 --- a/release/src/router/dropbear/fake-rfc2553.h +++ b/release/src/router/dropbear/fake-rfc2553.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 diff --git a/release/src/router/dropbear/gendss.c b/release/src/router/dropbear/gendss.c index 21d13a0488..783e25ffc6 100644 --- a/release/src/router/dropbear/gendss.c +++ b/release/src/router/dropbear/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); diff --git a/release/src/router/dropbear/gendss.h b/release/src/router/dropbear/gendss.h index 44335bca20..8292ac99b1 100644 --- a/release/src/router/dropbear/gendss.h +++ b/release/src/router/dropbear/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_ */ diff --git a/release/src/router/dropbear/genrsa.h b/release/src/router/dropbear/genrsa.h index 4aad94805d..acb43fb0f8 100644 --- a/release/src/router/dropbear/genrsa.h +++ b/release/src/router/dropbear/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_ */ diff --git a/release/src/router/dropbear/gensignkey.h b/release/src/router/dropbear/gensignkey.h index b463a42c43..508eca04de 100644 --- a/release/src/router/dropbear/gensignkey.h +++ b/release/src/router/dropbear/gensignkey.h @@ -1,5 +1,5 @@ -#ifndef _GENSIGNKEY_H -#define _GENSIGNKEY_H +#ifndef DROPBEAR_GENSIGNKEY_H +#define DROPBEAR_GENSIGNKEY_H #include "signkey.h" diff --git a/release/src/router/dropbear/includes.h b/release/src/router/dropbear/includes.h index 2a5b6c196f..f91a2c2f05 100644 --- a/release/src/router/dropbear/includes.h +++ b/release/src/router/dropbear/includes.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" @@ -177,4 +177,4 @@ typedef u_int32_t uint32_t; # define UNUSED(x) x #endif -#endif /* _INCLUDES_H_ */ +#endif /* DROPBEAR_INCLUDES_H_ */ diff --git a/release/src/router/dropbear/kex.h b/release/src/router/dropbear/kex.h index 144df5973f..4cee8e3edd 100644 --- a/release/src/router/dropbear/kex.h +++ b/release/src/router/dropbear/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_ */ diff --git a/release/src/router/dropbear/keyimport.c b/release/src/router/dropbear/keyimport.c index 6f2634fa45..d45914f895 100644 --- a/release/src/router/dropbear/keyimport.c +++ b/release/src/router/dropbear/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; @@ -648,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) { @@ -661,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. */ @@ -1045,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, @@ -1091,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"); } diff --git a/release/src/router/dropbear/keyimport.h b/release/src/router/dropbear/keyimport.h index 19f212f633..af9a30023a 100644 --- a/release/src/router/dropbear/keyimport.h +++ b/release/src/router/dropbear/keyimport.h @@ -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_ */ diff --git a/release/src/router/dropbear/libtomcrypt/src/ciphers/aes/aes.c b/release/src/router/dropbear/libtomcrypt/src/ciphers/aes/aes.c index 74798e8c4a..55f633393a 100644 --- a/release/src/router/dropbear/libtomcrypt/src/ciphers/aes/aes.c +++ b/release/src/router/dropbear/libtomcrypt/src/ciphers/aes/aes.c @@ -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; } diff --git a/release/src/router/dropbear/libtomcrypt/src/ciphers/des.c b/release/src/router/dropbear/libtomcrypt/src/ciphers/des.c index e505b148a7..6005e84916 100644 --- a/release/src/router/dropbear/libtomcrypt/src/ciphers/des.c +++ b/release/src/router/dropbear/libtomcrypt/src/ciphers/des.c @@ -1871,6 +1871,7 @@ void des_done(symmetric_key *skey) */ void des3_done(symmetric_key *skey) { + (void)skey; } diff --git a/release/src/router/dropbear/libtomcrypt/src/ciphers/twofish/twofish.c b/release/src/router/dropbear/libtomcrypt/src/ciphers/twofish/twofish.c index 9e6d0d4370..8f81bdd293 100644 --- a/release/src/router/dropbear/libtomcrypt/src/ciphers/twofish/twofish.c +++ b/release/src/router/dropbear/libtomcrypt/src/ciphers/twofish/twofish.c @@ -684,6 +684,7 @@ int twofish_test(void) */ void twofish_done(symmetric_key *skey) { + (void)skey; } /** diff --git a/release/src/router/dropbear/libtomcrypt/src/hashes/helper/hash_file.c b/release/src/router/dropbear/libtomcrypt/src/hashes/helper/hash_file.c index a92025cf10..df316069d1 100644 --- a/release/src/router/dropbear/libtomcrypt/src/hashes/helper/hash_file.c +++ b/release/src/router/dropbear/libtomcrypt/src/hashes/helper/hash_file.c @@ -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; diff --git a/release/src/router/dropbear/libtomcrypt/src/hashes/helper/hash_filehandle.c b/release/src/router/dropbear/libtomcrypt/src/hashes/helper/hash_filehandle.c index be2cbf9d8a..03155ead95 100644 --- a/release/src/router/dropbear/libtomcrypt/src/hashes/helper/hash_filehandle.c +++ b/release/src/router/dropbear/libtomcrypt/src/hashes/helper/hash_filehandle.c @@ -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; diff --git a/release/src/router/dropbear/libtomcrypt/src/headers/tomcrypt_argchk.h b/release/src/router/dropbear/libtomcrypt/src/headers/tomcrypt_argchk.h index cfc93ad7ea..38e1bdd8de 100644 --- a/release/src/router/dropbear/libtomcrypt/src/headers/tomcrypt_argchk.h +++ b/release/src/router/dropbear/libtomcrypt/src/headers/tomcrypt_argchk.h @@ -4,8 +4,16 @@ #include +/* 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) diff --git a/release/src/router/dropbear/libtomcrypt/src/mac/hmac/hmac_done.c b/release/src/router/dropbear/libtomcrypt/src/mac/hmac/hmac_done.c index 5ba541a629..f48d672600 100644 --- a/release/src/router/dropbear/libtomcrypt/src/mac/hmac/hmac_done.c +++ b/release/src/router/dropbear/libtomcrypt/src/mac/hmac/hmac_done.c @@ -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; } diff --git a/release/src/router/dropbear/libtomcrypt/src/mac/hmac/hmac_file.c b/release/src/router/dropbear/libtomcrypt/src/mac/hmac/hmac_file.c index b2963208d9..d7c40b1f63 100644 --- a/release/src/router/dropbear/libtomcrypt/src/mac/hmac/hmac_file.c +++ b/release/src/router/dropbear/libtomcrypt/src/mac/hmac/hmac_file.c @@ -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; diff --git a/release/src/router/dropbear/libtomcrypt/src/mac/hmac/hmac_init.c b/release/src/router/dropbear/libtomcrypt/src/mac/hmac/hmac_init.c index 2d61a9af92..a4a4377ebc 100644 --- a/release/src/router/dropbear/libtomcrypt/src/mac/hmac/hmac_init.c +++ b/release/src/router/dropbear/libtomcrypt/src/mac/hmac/hmac_init.c @@ -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; } diff --git a/release/src/router/dropbear/libtomcrypt/src/misc/crypt/crypt_argchk.c b/release/src/router/dropbear/libtomcrypt/src/misc/crypt/crypt_argchk.c index c6675ef963..a6d2a48fa9 100644 --- a/release/src/router/dropbear/libtomcrypt/src/misc/crypt/crypt_argchk.c +++ b/release/src/router/dropbear/libtomcrypt/src/misc/crypt/crypt_argchk.c @@ -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 diff --git a/release/src/router/dropbear/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod_timing.c b/release/src/router/dropbear/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod_timing.c index b94a50c62c..8cbcdf3b0d 100644 --- a/release/src/router/dropbear/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod_timing.c +++ b/release/src/router/dropbear/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod_timing.c @@ -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 (;;) { diff --git a/release/src/router/dropbear/list.h b/release/src/router/dropbear/list.h index 23ef9bb83b..35c0d4976d 100644 --- a/release/src/router/dropbear/list.h +++ b/release/src/router/dropbear/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 */ diff --git a/release/src/router/dropbear/listener.c b/release/src/router/dropbear/listener.c index dd90c6bfe7..a7f07304d3 100644 --- a/release/src/router/dropbear/listener.c +++ b/release/src/router/dropbear/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); } diff --git a/release/src/router/dropbear/listener.h b/release/src/router/dropbear/listener.h index 5092efd9a2..b531ed6db8 100644 --- a/release/src/router/dropbear/listener.h +++ b/release/src/router/dropbear/listener.h @@ -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 */ diff --git a/release/src/router/dropbear/loginrec.h b/release/src/router/dropbear/loginrec.h index d2da8d24f6..830c04516c 100644 --- a/release/src/router/dropbear/loginrec.h +++ b/release/src/router/dropbear/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. @@ -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_ */ diff --git a/release/src/router/dropbear/ltc_prng.h b/release/src/router/dropbear/ltc_prng.h index f5391e0409..688851289c 100644 --- a/release/src/router/dropbear/ltc_prng.h +++ b/release/src/router/dropbear/ltc_prng.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 */ diff --git a/release/src/router/dropbear/netio.c b/release/src/router/dropbear/netio.c new file mode 100644 index 0000000000..6c13a00675 --- /dev/null +++ b/release/src/router/dropbear/netio.c @@ -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); + } +} + diff --git a/release/src/router/dropbear/netio.h b/release/src/router/dropbear/netio.h new file mode 100644 index 0000000000..b413bdce74 --- /dev/null +++ b/release/src/router/dropbear/netio.h @@ -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 + diff --git a/release/src/router/dropbear/options.h b/release/src/router/dropbear/options.h index fa08b270a2..27e2a02705 100644 --- a/release/src/router/dropbear/options.h +++ b/release/src/router/dropbear/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. */ @@ -95,18 +95,23 @@ much traffic. */ #define DROPBEAR_AES256 /* Compiling in Blowfish will add ~6kB to runtime heap memory usage */ /*#define DROPBEAR_BLOWFISH*/ -/*#define DROPBEAR_TWOFISH256*/ -/*#define DROPBEAR_TWOFISH128*/ +#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 @@ -201,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 @@ -212,13 +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 . - leading "~" is expanded */ -#define DROPBEAR_DEFAULT_CLI_AUTHKEY "~/.ssh/id_dropbear" +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 @@ -277,19 +288,19 @@ much traffic. */ /* The command to invoke for xauth when using X11 forwarding. * "-q" for quiet */ #ifndef XAUTH_COMMAND -#define XAUTH_COMMAND "/opt/X11R6/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 * OpenSSH), set the path below. If the path isn't defined, sftp will not * be enabled */ #ifndef SFTPSERVER_PATH -#define SFTPSERVER_PATH "/opt/libexec/sftp-server" +#define SFTPSERVER_PATH "/usr/libexec/sftp-server" #endif /* 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 @@ -331,10 +342,10 @@ be overridden at runtime with -I. 0 disables idle timeouts */ #define DEFAULT_IDLE_TIMEOUT 0 /* The default path. This will often get replaced by the shell */ -#define DEFAULT_PATH "/bin:/usr/bin:/sbin:/usr/sbin:/opt/bin:/opt/sbin" +#define DEFAULT_PATH "/usr/bin:/bin" /* Some other defines (that mostly should be left alone) are defined * in sysoptions.h */ #include "sysoptions.h" -#endif /* _OPTIONS_H_ */ +#endif /* DROPBEAR_OPTIONS_H_ */ diff --git a/release/src/router/dropbear/packet.c b/release/src/router/dropbear/packet.c index 89b1bcfde1..19b57592f7 100644 --- a/release/src/router/dropbear/packet.c +++ b/release/src/router/dropbear/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, @@ -55,14 +56,15 @@ 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; - unsigned packet_type; + ssize_t written; #ifdef HAVE_WRITEV - struct iovec *iov = NULL; - int i; - struct Link *l; - int iov_max_count; + /* 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")) @@ -70,36 +72,13 @@ void write_packet() { #if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV)) -#ifndef IOV_MAX -#define IOV_MAX UIO_MAXIOV -#endif - - /* Make sure the size of the iov is below the maximum allowed by the OS. */ - iov_max_count = ses.writequeue.count; - if (iov_max_count > IOV_MAX) - { - iov_max_count = IOV_MAX; - } - - iov = m_malloc(sizeof(*iov) * iov_max_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); - 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; - } + 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_max_count); + written = writev(ses.sock_out, iov, iov_count); if (written < 0) { if (errno == EINTR || errno == EAGAIN) { - m_free(iov); TRACE2(("leave write_packet: EINTR")) return; } else { @@ -107,25 +86,13 @@ void write_packet() { } } + 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 /* No writev () */ /* Get the next buffer in the queue of encrypted packets to write*/ writebuf = (buffer*)examine(&ses.writequeue); @@ -134,6 +101,8 @@ 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); @@ -151,6 +120,8 @@ void write_packet() { ses.remoteclosed(); } + ses.writequeue_len -= written; + if (written == len) { /* We've finished with the packet, free it */ dequeue(&ses.writequeue); @@ -294,7 +265,7 @@ static int read_packet_init() { } 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); @@ -351,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++; @@ -435,7 +409,7 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) { 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); } } } @@ -605,15 +579,12 @@ void encrypt_packet() { /* stick the MAC on it */ buf_putbytes(writebuf, mac_bytes, mac_size); - /* 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; + + writebuf_enqueue(writebuf, packet_type); + + /* Update counts */ ses.transseq++; now = monotonic_now(); @@ -631,6 +602,16 @@ void encrypt_packet() { 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); + ses.writequeue_len += writebuf->len-1; +} + /* Create the packet mac, and append H(seqno|clearbuf) to the output */ /* output_mac must have ses.keys->trans.algo_mac->hashsize bytes. */ @@ -674,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; @@ -682,38 +664,28 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) { TRACE2(("enter buf_compress")) - while (1) { - - 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); - - result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH); + dropbear_assert(dest->size - dest->pos >= len+ZLIB_COMPRESS_EXPANSION); - 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); + ses.keys->trans.zstream->avail_in = endpos - src->pos; + ses.keys->trans.zstream->next_in = + buf_getptr(src, ses.keys->trans.zstream->avail_in); - if (result != Z_OK) { - dropbear_exit("zlib error"); - } + 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); - if (ses.keys->trans.zstream->avail_in == 0) { - break; - } + result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH); - 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_EXPANSION); + 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 diff --git a/release/src/router/dropbear/packet.h b/release/src/router/dropbear/packet.h index 4645b14639..6013b7258e 100644 --- a/release/src/router/dropbear/packet.h +++ b/release/src/router/dropbear/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_ */ diff --git a/release/src/router/dropbear/queue.h b/release/src/router/dropbear/queue.h index 8cffab757e..d2227ac417 100644 --- a/release/src/router/dropbear/queue.h +++ b/release/src/router/dropbear/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 { diff --git a/release/src/router/dropbear/release.sh b/release/src/router/dropbear/release.sh old mode 100644 new mode 100755 index f377d0e305..d2abe14cb9 --- a/release/src/router/dropbear/release.sh +++ b/release/src/router/dropbear/release.sh @@ -33,8 +33,13 @@ hg archive "$RELDIR" || exit 2 rm -r "$RELDIR/autom4te.cache" || exit 2 -(cd $RELDIR/.. && tar cjf $ARCHIVE `basename "$RELDIR"`) || exit 2 +rm "$RELDIR/.hgtags" + +(cd "$RELDIR/.." && tar cjf $ARCHIVE `basename "$RELDIR"`) || exit 2 ls -l $ARCHIVE -openssl sha1 $ARCHIVE -echo "Done to $ARCHIVE" +openssl sha -sha256 $ARCHIVE +echo Done to +echo "$ARCHIVE" +echo Sign it with +echo gpg2 --detach-sign -a -u F29C6773 "$ARCHIVE" diff --git a/release/src/router/dropbear/rsa.h b/release/src/router/dropbear/rsa.h index 7c99282804..800be59fe2 100644 --- a/release/src/router/dropbear/rsa.h +++ b/release/src/router/dropbear/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_ */ diff --git a/release/src/router/dropbear/runopts.h b/release/src/router/dropbear/runopts.h index 87567164a6..7d6ae06245 100644 --- a/release/src/router/dropbear/runopts.h +++ b/release/src/router/dropbear/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" @@ -33,7 +33,8 @@ typedef struct runopts { -#if defined(ENABLE_SVR_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD) +#if defined(ENABLE_SVR_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD) \ + || defined(ENABLE_CLI_REMOTETCPFWD) int listen_fwd_all; #endif unsigned int recv_window; @@ -71,7 +72,8 @@ typedef struct svr_runopts { int forkbg; int usingsyslog; - /* ports is an array of the portcount listening ports */ + /* ports and addresses are arrays of the portcount + listening ports. strings are malloced. */ char *ports[DROPBEAR_MAX_PORTS]; unsigned int portcount; char *addresses[DROPBEAR_MAX_PORTS]; @@ -170,4 +172,4 @@ void parse_ciphers_macs(); void print_version(void); -#endif /* _RUNOPTS_H_ */ +#endif /* DROPBEAR_RUNOPTS_H_ */ diff --git a/release/src/router/dropbear/scp.c b/release/src/router/dropbear/scp.c index 11c966546d..70f45e32cd 100644 --- a/release/src/router/dropbear/scp.c +++ b/release/src/router/dropbear/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; diff --git a/release/src/router/dropbear/service.h b/release/src/router/dropbear/service.h index 9c60c09278..de3572420c 100644 --- a/release/src/router/dropbear/service.h +++ b/release/src/router/dropbear/service.h @@ -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_ */ diff --git a/release/src/router/dropbear/session.h b/release/src/router/dropbear/session.h index ed0f5be16f..debebabe9e 100644 --- a/release/src/router/dropbear/session.h +++ b/release/src/router/dropbear/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,12 +38,13 @@ #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(); @@ -55,13 +56,14 @@ 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 { @@ -107,13 +109,18 @@ struct sshsession { /* Is it a client or server? */ unsigned char isserver; + time_t connect_time; /* time the connection was established + (cleared after auth once we're not + respecting AUTH_TIMEOUT any more). + A monotonic time, not realworld */ + int sock_in; int sock_out; /* 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() */ @@ -123,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 */ @@ -144,6 +156,8 @@ struct sshsession { int signal_pipe[2]; /* stores endpoints of a self-pipe used for race-free signal handling */ + + m_list conn_pending; /* time of the last packet send/receive, for keepalive. Not real-world clock */ time_t last_packet_time_keepalive_sent; @@ -222,11 +236,6 @@ struct serversession { /* The resolved remote address, used for lastlog etc */ char *remotehost; - time_t connect_time; /* time the connection was established - (cleared after auth once we're not - respecting AUTH_TIMEOUT any more). - A monotonic time, not realworld */ - #ifdef USE_VFORK pid_t server_pid; #endif @@ -284,10 +293,9 @@ struct clientsession { 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 */ @@ -309,4 +317,4 @@ extern struct serversession svr_ses; extern struct clientsession cli_ses; #endif /* DROPBEAR_CLIENT */ -#endif /* _SESSION_H_ */ +#endif /* DROPBEAR_SESSION_H_ */ diff --git a/release/src/router/dropbear/signkey.c b/release/src/router/dropbear/signkey.c index ea7c67d414..ac5d887530 100644 --- a/release/src/router/dropbear/signkey.c +++ b/release/src/router/dropbear/signkey.c @@ -138,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")) @@ -187,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); @@ -208,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")) @@ -255,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); @@ -355,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 @@ -510,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; diff --git a/release/src/router/dropbear/signkey.h b/release/src/router/dropbear/signkey.h index 60c04d9d0e..475b51ae01 100644 --- a/release/src/router/dropbear/signkey.h +++ b/release/src/router/dropbear/signkey.h @@ -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_ */ diff --git a/release/src/router/dropbear/svr-agentfwd.c b/release/src/router/dropbear/svr-agentfwd.c index 3c4daab18c..512cbd2d68 100644 --- a/release/src/router/dropbear/svr-agentfwd.c +++ b/release/src/router/dropbear/svr-agentfwd.c @@ -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; diff --git a/release/src/router/dropbear/svr-auth.c b/release/src/router/dropbear/svr-auth.c index 89760ef9e5..66db4fc43e 100644 --- a/release/src/router/dropbear/svr-auth.c +++ b/release/src/router/dropbear/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); @@ -392,7 +392,8 @@ void send_msg_userauth_success() { /* authdone must be set after encrypt_packet() for * delayed-zlib mode */ ses.authstate.authdone = 1; - svr_ses.connect_time = 0; + ses.connect_time = 0; + if (ses.authstate.pw_uid == 0) { ses.allowprivport = 1; diff --git a/release/src/router/dropbear/svr-authpam.c b/release/src/router/dropbear/svr-authpam.c index 0b1d69fcd8..101017c5ac 100644 --- a/release/src/router/dropbear/svr-authpam.c +++ b/release/src/router/dropbear/svr-authpam.c @@ -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; diff --git a/release/src/router/dropbear/svr-authpasswd.c b/release/src/router/dropbear/svr-authpasswd.c index 7a5a121023..9852ac66f9 100644 --- a/release/src/router/dropbear/svr-authpasswd.c +++ b/release/src/router/dropbear/svr-authpasswd.c @@ -33,6 +33,8 @@ #ifdef ENABLE_SVR_PASSWORD_AUTH +/* not constant time when strings are differing lengths. + string content isn't leaked, and crypt hashes are predictable length. */ static int constant_time_strcmp(const char* a, const char* b) { size_t la = strlen(a); size_t lb = strlen(b); @@ -50,7 +52,7 @@ void svr_auth_password() { char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */ char * testcrypt = NULL; /* crypt generated from the user's password sent */ - unsigned char * password; + char * password; unsigned int passwordlen; unsigned int changepw; @@ -73,7 +75,7 @@ void svr_auth_password() { password = buf_getstring(ses.payload, &passwordlen); /* the first bytes of passwdcrypt are the salt */ - testcrypt = crypt((char*)password, passwdcrypt); + testcrypt = crypt(password, passwdcrypt); m_burn(password, passwordlen); m_free(password); diff --git a/release/src/router/dropbear/svr-authpubkey.c b/release/src/router/dropbear/svr-authpubkey.c index 66fe5e5f4f..89d77ed501 100644 --- a/release/src/router/dropbear/svr-authpubkey.c +++ b/release/src/router/dropbear/svr-authpubkey.c @@ -70,10 +70,10 @@ #define MIN_AUTHKEYS_LINE 10 /* "ssh-rsa AB" - short but doesn't matter */ #define MAX_AUTHKEYS_LINE 4200 /* max length of a line in authkeys */ -static int checkpubkey(unsigned char* algo, unsigned int algolen, +static int checkpubkey(char* algo, unsigned int algolen, unsigned char* keyblob, unsigned int keybloblen); static int checkpubkeyperms(); -static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen, +static void send_msg_userauth_pk_ok(char* algo, unsigned int algolen, unsigned char* keyblob, unsigned int keybloblen); static int checkfileperm(char * filename); @@ -82,10 +82,11 @@ static int checkfileperm(char * filename); void svr_auth_pubkey() { unsigned char testkey; /* whether we're just checking if a key is usable */ - unsigned char* algo = NULL; /* pubkey algo */ + char* algo = NULL; /* pubkey algo */ unsigned int algolen; unsigned char* keyblob = NULL; unsigned int keybloblen; + unsigned int sign_payload_length; buffer * signbuf = NULL; sign_key * key = NULL; char* fp = NULL; @@ -125,9 +126,18 @@ void svr_auth_pubkey() { /* create the data which has been signed - this a string containing * session_id, concatenated with the payload packet up to the signature */ + assert(ses.payload_beginning <= ses.payload->pos); + sign_payload_length = ses.payload->pos - ses.payload_beginning; signbuf = buf_new(ses.payload->pos + 4 + ses.session_id->len); buf_putbufstring(signbuf, ses.session_id); - buf_putbytes(signbuf, ses.payload->data, ses.payload->pos); + + /* The entire contents of the payload prior. */ + buf_setpos(ses.payload, ses.payload_beginning); + buf_putbytes(signbuf, + buf_getptr(ses.payload, sign_payload_length), + sign_payload_length); + buf_incrpos(ses.payload, sign_payload_length); + buf_setpos(signbuf, 0); /* ... and finally verify the signature */ @@ -163,7 +173,7 @@ out: /* Reply that the key is valid for auth, this is sent when the user sends * a straight copy of their pubkey to test, to avoid having to perform * expensive signing operations with a worthless key */ -static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen, +static void send_msg_userauth_pk_ok(char* algo, unsigned int algolen, unsigned char* keyblob, unsigned int keybloblen) { TRACE(("enter send_msg_userauth_pk_ok")) @@ -171,7 +181,7 @@ static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen, buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_PK_OK); buf_putstring(ses.writepayload, algo, algolen); - buf_putstring(ses.writepayload, keyblob, keybloblen); + buf_putstring(ses.writepayload, (const char*)keyblob, keybloblen); encrypt_packet(); TRACE(("leave send_msg_userauth_pk_ok")) @@ -181,7 +191,7 @@ static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen, /* Checks whether a specified publickey (and associated algorithm) is an * acceptable key for authentication */ /* Returns DROPBEAR_SUCCESS if key is ok for auth, DROPBEAR_FAILURE otherwise */ -static int checkpubkey(unsigned char* algo, unsigned int algolen, +static int checkpubkey(char* algo, unsigned int algolen, unsigned char* keyblob, unsigned int keybloblen) { FILE * authfile = NULL; @@ -250,9 +260,9 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen, /* check the key type - will fail if there are options */ TRACE(("a line!")) - if (strncmp(buf_getptr(line, algolen), algo, algolen) != 0) { + if (strncmp((const char *) buf_getptr(line, algolen), algo, algolen) != 0) { int is_comment = 0; - char *options_start = NULL; + unsigned char *options_start = NULL; int options_len = 0; int escape, quoted; @@ -298,7 +308,7 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen, if (line->pos + algolen+3 > line->len) { continue; } - if (strncmp(buf_getptr(line, algolen), algo, algolen) != 0) { + if (strncmp((const char *) buf_getptr(line, algolen), algo, algolen) != 0) { continue; } } @@ -320,7 +330,7 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen, TRACE(("checkpubkey: line pos = %d len = %d", line->pos, line->len)) - ret = cmp_base64_key(keyblob, keybloblen, algo, algolen, line, NULL); + ret = cmp_base64_key(keyblob, keybloblen, (const unsigned char *) algo, algolen, line, NULL); if (ret == DROPBEAR_SUCCESS && options_buf) { ret = svr_add_pubkey_options(options_buf, line_num, filename); diff --git a/release/src/router/dropbear/svr-authpubkeyoptions.c b/release/src/router/dropbear/svr-authpubkeyoptions.c index 71d7c146ec..9bdf99d104 100644 --- a/release/src/router/dropbear/svr-authpubkeyoptions.c +++ b/release/src/router/dropbear/svr-authpubkeyoptions.c @@ -91,7 +91,7 @@ int svr_pubkey_allows_pty() { /* Set chansession command to the one forced * by any 'command' public key option. */ void svr_pubkey_set_forced_command(struct ChanSess *chansess) { - if (ses.authstate.pubkey_options) { + if (ses.authstate.pubkey_options && ses.authstate.pubkey_options->forced_command) { if (chansess->cmd) { /* original_command takes ownership */ chansess->original_command = chansess->cmd; @@ -120,7 +120,7 @@ static int match_option(buffer *options_buf, const char *opt_name) { if (options_buf->len - options_buf->pos < len) { return DROPBEAR_FAILURE; } - if (strncasecmp(buf_getptr(options_buf, len), opt_name, len) == 0) { + if (strncasecmp((const char *) buf_getptr(options_buf, len), opt_name, len) == 0) { buf_incrpos(options_buf, len); return DROPBEAR_SUCCESS; } diff --git a/release/src/router/dropbear/svr-chansession.c b/release/src/router/dropbear/svr-chansession.c index 67122bb11a..bfaf7f695f 100644 --- a/release/src/router/dropbear/svr-chansession.c +++ b/release/src/router/dropbear/svr-chansession.c @@ -234,7 +234,7 @@ static int newchansess(struct Channel *channel) { struct ChanSess *chansess; - TRACE(("new chansess %p", channel)) + TRACE(("new chansess %p", (void*)channel)) dropbear_assert(channel->typedata == NULL); @@ -343,7 +343,7 @@ static void closechansess(struct Channel *channel) { * or x11/authagent forwarding. These are passed to appropriate handlers */ static void chansessionrequest(struct Channel *channel) { - unsigned char * type = NULL; + char * type = NULL; unsigned int typelen; unsigned char wantreply; int ret = 1; @@ -406,7 +406,7 @@ out: static int sessionsignal(struct ChanSess *chansess) { int sig = 0; - unsigned char* signame = NULL; + char* signame = NULL; int i; if (chansess->pid == 0) { @@ -557,7 +557,7 @@ static void get_termmodes(struct ChanSess *chansess) { static int sessionpty(struct ChanSess * chansess) { unsigned int termlen; - unsigned char namebuf[65]; + char namebuf[65]; struct passwd * pw = NULL; TRACE(("enter sessionpty")) @@ -583,7 +583,7 @@ static int sessionpty(struct ChanSess * chansess) { return DROPBEAR_FAILURE; } - chansess->tty = (char*)m_strdup(namebuf); + chansess->tty = m_strdup(namebuf); if (!chansess->tty) { dropbear_exit("Out of memory"); /* TODO disconnect */ } @@ -603,6 +603,7 @@ static int sessionpty(struct ChanSess * chansess) { return DROPBEAR_SUCCESS; } +#ifndef USE_VFORK static void make_connection_string(struct ChanSess *chansess) { char *local_ip, *local_port, *remote_ip, *remote_port; size_t len; @@ -624,6 +625,7 @@ static void make_connection_string(struct ChanSess *chansess) { m_free(remote_ip); m_free(remote_port); } +#endif /* Handle a command request from the client. This is used for both shell * and command-execution requests, and passes the command to @@ -812,7 +814,7 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) { login_free_entry(li); #ifdef DO_MOTD - if (svr_opts.domotd) { + if (svr_opts.domotd && !chansess->cmd) { /* don't show the motd if ~/.hushlogin exists */ /* 12 == strlen("/.hushlogin\0") */ diff --git a/release/src/router/dropbear/svr-kex.c b/release/src/router/dropbear/svr-kex.c index 6cc5433a3c..96f4508f09 100644 --- a/release/src/router/dropbear/svr-kex.c +++ b/release/src/router/dropbear/svr-kex.c @@ -247,7 +247,7 @@ static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) { { struct kex_curve25519_param *param = gen_kexcurve25519_param(); kexcurve25519_comb_key(param, ecdh_qs, svr_opts.hostkey); - buf_putstring(ses.writepayload, param->pub, CURVE25519_LEN); + buf_putstring(ses.writepayload, (const char*)param->pub, CURVE25519_LEN); free_kexcurve25519_param(param); } #endif diff --git a/release/src/router/dropbear/svr-main.c b/release/src/router/dropbear/svr-main.c index 284e02d901..cc59332df9 100644 --- a/release/src/router/dropbear/svr-main.c +++ b/release/src/router/dropbear/svr-main.c @@ -138,7 +138,6 @@ void main_noinetd() { } for (i = 0; i < listensockcount; i++) { - set_sock_priority(listensocks[i], DROPBEAR_PRIO_LOWDELAY); FD_SET(listensocks[i], &fds); } @@ -403,9 +402,9 @@ static void commonsetup() { } /* Set up listening sockets for all the requested ports */ -static size_t listensockets(int *sock, size_t sockcount, int *maxfd) { - - unsigned int i; +static size_t listensockets(int *socks, size_t sockcount, int *maxfd) { + + unsigned int i, n; char* errstring = NULL; size_t sockpos = 0; int nsock; @@ -416,7 +415,7 @@ static size_t listensockets(int *sock, size_t sockcount, int *maxfd) { TRACE(("listening on '%s:%s'", svr_opts.addresses[i], svr_opts.ports[i])) - nsock = dropbear_listen(svr_opts.addresses[i], svr_opts.ports[i], &sock[sockpos], + nsock = dropbear_listen(svr_opts.addresses[i], svr_opts.ports[i], &socks[sockpos], sockcount - sockpos, &errstring, maxfd); @@ -427,6 +426,14 @@ static size_t listensockets(int *sock, size_t sockcount, int *maxfd) { continue; } + for (n = 0; n < (unsigned int)nsock; n++) { + int sock = socks[sockpos + n]; + set_sock_priority(sock, DROPBEAR_PRIO_LOWDELAY); +#ifdef DROPBEAR_SERVER_TCP_FAST_OPEN + set_listen_fast_open(sock); +#endif + } + sockpos += nsock; } diff --git a/release/src/router/dropbear/svr-runopts.c b/release/src/router/dropbear/svr-runopts.c index 09fc9af56c..0e70998755 100644 --- a/release/src/router/dropbear/svr-runopts.c +++ b/release/src/router/dropbear/svr-runopts.c @@ -33,7 +33,7 @@ svr_runopts svr_opts; /* GLOBAL */ static void printhelp(const char * progname); -static void addportandaddress(char* spec); +static void addportandaddress(const char* spec); static void loadhostkey(const char *keyfile, int fatal_duplicate); static void addhostkey(const char *keyfile); @@ -112,13 +112,14 @@ static void printhelp(const char * progname) { void svr_getopts(int argc, char ** argv) { - unsigned int i; + unsigned int i, j; char ** next = 0; int nextisport = 0; char* recv_window_arg = NULL; char* keepalive_arg = NULL; char* idle_timeout_arg = NULL; char* keyfile = NULL; + char c; /* see printhelp() for options */ @@ -168,28 +169,11 @@ void svr_getopts(int argc, char ** argv) { #endif for (i = 1; i < (unsigned int)argc; i++) { - if (nextisport) { - addportandaddress(argv[i]); - nextisport = 0; - continue; - } - - if (next) { - *next = argv[i]; - if (*next == NULL) { - dropbear_exit("Invalid null argument"); - } - next = 0x00; - - if (keyfile) { - addhostkey(keyfile); - keyfile = NULL; - } - continue; - } + if (argv[i][0] != '-' || argv[i][1] == '\0') + dropbear_exit("Invalid argument: %s", argv[i]); - if (argv[i][0] == '-') { - switch (argv[i][1]) { + for (j = 1; (c = argv[i][j]) != '\0' && !next && !nextisport; j++) { + switch (c) { case 'b': next = &svr_opts.bannerfile; break; @@ -278,12 +262,39 @@ void svr_getopts(int argc, char ** argv) { exit(EXIT_SUCCESS); break; default: - fprintf(stderr, "Unknown argument %s\n", argv[i]); + fprintf(stderr, "Invalid option -%c\n", c); printhelp(argv[0]); exit(EXIT_FAILURE); break; } } + + if (!next && !nextisport) + continue; + + if (c == '\0') { + i++; + j = 0; + if (!argv[i]) { + dropbear_exit("Missing argument"); + } + } + + if (nextisport) { + addportandaddress(&argv[i][j]); + nextisport = 0; + } else if (next) { + *next = &argv[i][j]; + if (*next == NULL) { + dropbear_exit("Invalid null argument"); + } + next = 0x00; + + if (keyfile) { + addhostkey(keyfile); + keyfile = NULL; + } + } } /* Set up listening ports */ @@ -337,54 +348,56 @@ void svr_getopts(int argc, char ** argv) { } } -static void addportandaddress(char* spec) { - - char *myspec = NULL; +static void addportandaddress(const char* spec) { + char *spec_copy = NULL, *myspec = NULL, *port = NULL, *address = NULL; if (svr_opts.portcount < DROPBEAR_MAX_PORTS) { /* We don't free it, it becomes part of the runopt state */ - myspec = m_strdup(spec); + spec_copy = m_strdup(spec); + myspec = spec_copy; if (myspec[0] == '[') { myspec++; - svr_opts.ports[svr_opts.portcount] = strchr(myspec, ']'); - if (svr_opts.ports[svr_opts.portcount] == NULL) { + port = strchr(myspec, ']'); + if (!port) { /* Unmatched [ -> exit */ dropbear_exit("Bad listen address"); } - svr_opts.ports[svr_opts.portcount][0] = '\0'; - svr_opts.ports[svr_opts.portcount]++; - if (svr_opts.ports[svr_opts.portcount][0] != ':') { + port[0] = '\0'; + port++; + if (port[0] != ':') { /* Missing port -> exit */ dropbear_exit("Missing port"); } } else { /* search for ':', that separates address and port */ - svr_opts.ports[svr_opts.portcount] = strrchr(myspec, ':'); + port = strrchr(myspec, ':'); } - if (svr_opts.ports[svr_opts.portcount] == NULL) { + if (!port) { /* no ':' -> the whole string specifies just a port */ - svr_opts.ports[svr_opts.portcount] = myspec; + port = myspec; } else { /* Split the address/port */ - svr_opts.ports[svr_opts.portcount][0] = '\0'; - svr_opts.ports[svr_opts.portcount]++; - svr_opts.addresses[svr_opts.portcount] = myspec; + port[0] = '\0'; + port++; + address = myspec; } - if (svr_opts.addresses[svr_opts.portcount] == NULL) { + if (!address) { /* no address given -> fill in the default address */ - svr_opts.addresses[svr_opts.portcount] = m_strdup(DROPBEAR_DEFADDRESS); + address = DROPBEAR_DEFADDRESS; } - if (svr_opts.ports[svr_opts.portcount][0] == '\0') { + if (port[0] == '\0') { /* empty port -> exit */ dropbear_exit("Bad port"); } - + svr_opts.ports[svr_opts.portcount] = m_strdup(port); + svr_opts.addresses[svr_opts.portcount] = m_strdup(address); svr_opts.portcount++; + m_free(spec_copy); } } @@ -540,6 +553,6 @@ void load_all_hostkeys() { #endif /* DROPBEAR_ECDSA */ if (!any_keys) { - dropbear_exit("No hostkeys available"); + dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey."); } } diff --git a/release/src/router/dropbear/svr-service.c b/release/src/router/dropbear/svr-service.c index 9c5e5804c4..1f72ea52b0 100644 --- a/release/src/router/dropbear/svr-service.c +++ b/release/src/router/dropbear/svr-service.c @@ -30,13 +30,13 @@ #include "ssh.h" #include "auth.h" -static void send_msg_service_accept(unsigned char *name, int len); +static void send_msg_service_accept(char *name, int len); /* processes a SSH_MSG_SERVICE_REQUEST, returning 0 if finished, * 1 if not */ void recv_msg_service_request() { - unsigned char * name; + char * name; unsigned int len; TRACE(("enter recv_msg_service_request")) @@ -73,7 +73,7 @@ void recv_msg_service_request() { } -static void send_msg_service_accept(unsigned char *name, int len) { +static void send_msg_service_accept(char *name, int len) { TRACE(("accepting service %s", name)) diff --git a/release/src/router/dropbear/svr-session.c b/release/src/router/dropbear/svr-session.c index 343cb30cca..ea9ca7e264 100644 --- a/release/src/router/dropbear/svr-session.c +++ b/release/src/router/dropbear/svr-session.c @@ -78,18 +78,14 @@ static const struct ChanType *svr_chantypes[] = { }; static void -svr_session_cleanup(void) -{ +svr_session_cleanup(void) { /* free potential public key options */ svr_pubkey_options_cleanup(); -} -static void -svr_sessionloop() { - if (svr_ses.connect_time != 0 - && monotonic_now() - svr_ses.connect_time >= AUTH_TIMEOUT) { - dropbear_close("Timeout before auth"); - } + m_free(svr_ses.addrstring); + m_free(svr_ses.remotehost); + m_free(svr_ses.childpids); + svr_ses.childpidsize = 0; } void svr_session(int sock, int childpipe) { @@ -98,8 +94,6 @@ void svr_session(int sock, int childpipe) { common_session_init(sock, sock); - svr_ses.connect_time = monotonic_now();; - /* Initialise server specific parts of the session */ svr_ses.childpipe = childpipe; #ifdef USE_VFORK @@ -134,13 +128,15 @@ void svr_session(int sock, int childpipe) { /* exchange identification, version etc */ send_session_identification(); + + kexfirstinitialise(); /* initialise the kex state */ /* start off with key exchange */ send_msg_kexinit(); /* Run the main for loop. NULL is for the dispatcher - only the client * code makes use of it */ - session_loop(svr_sessionloop); + session_loop(NULL); /* Not reached */ @@ -150,6 +146,7 @@ void svr_session(int sock, int childpipe) { void svr_dropbear_exit(int exitcode, const char* format, va_list param) { char fmtbuf[300]; + int i; if (!sessinitdone) { /* before session init */ @@ -183,6 +180,15 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) { session_cleanup(); } + if (svr_opts.hostkey) { + sign_key_free(svr_opts.hostkey); + svr_opts.hostkey = NULL; + } + for (i = 0; i < DROPBEAR_MAX_PORTS; i++) { + m_free(svr_opts.addresses[i]); + m_free(svr_opts.ports[i]); + } + exit(exitcode); } diff --git a/release/src/router/dropbear/svr-tcpfwd.c b/release/src/router/dropbear/svr-tcpfwd.c index e5f219e4b4..d2f1427110 100644 --- a/release/src/router/dropbear/svr-tcpfwd.c +++ b/release/src/router/dropbear/svr-tcpfwd.c @@ -33,6 +33,7 @@ #include "listener.h" #include "runopts.h" #include "auth.h" +#include "netio.h" #ifndef ENABLE_SVR_REMOTETCPFWD @@ -64,7 +65,7 @@ static const struct ChanType svr_chan_tcpremote = { * similar to the request-switching in chansession.c */ void recv_msg_global_request_remotetcp() { - unsigned char* reqname = NULL; + char* reqname = NULL; unsigned int namelen; unsigned int wantreply = 0; int ret = DROPBEAR_FAILURE; @@ -119,7 +120,7 @@ static int matchtcp(void* typedata1, void* typedata2) { static int svr_cancelremotetcp() { int ret = DROPBEAR_FAILURE; - unsigned char * bindaddr = NULL; + char * bindaddr = NULL; unsigned int addrlen; unsigned int port; struct Listener * listener = NULL; @@ -154,7 +155,7 @@ out: static int svr_remotetcpreq() { int ret = DROPBEAR_FAILURE; - unsigned char * request_addr = NULL; + char * request_addr = NULL; unsigned int addrlen; struct TCPListener *tcpinfo = NULL; unsigned int port; @@ -231,13 +232,12 @@ const struct ChanType svr_chan_tcpdirect = { * address */ static int newtcpdirect(struct Channel * channel) { - unsigned char* desthost = NULL; + char* desthost = NULL; unsigned int destport; - unsigned char* orighost = NULL; + char* orighost = NULL; unsigned int origport; char portstring[NI_MAXSERV]; - int sock; - int len; + unsigned int len; int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; TRACE(("newtcpdirect channel %d", channel->index)) @@ -270,19 +270,7 @@ static int newtcpdirect(struct Channel * channel) { } snprintf(portstring, sizeof(portstring), "%d", destport); - sock = connect_remote(desthost, portstring, 1, NULL); - if (sock < 0) { - err = SSH_OPEN_CONNECT_FAILED; - TRACE(("leave newtcpdirect: sock failed")) - goto out; - } - - 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->conn_pending = connect_remote(desthost, portstring, channel_connect_done, channel); channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE; diff --git a/release/src/router/dropbear/svr-x11fwd.c b/release/src/router/dropbear/svr-x11fwd.c index ceca26a991..144ec0b00c 100644 --- a/release/src/router/dropbear/svr-x11fwd.c +++ b/release/src/router/dropbear/svr-x11fwd.c @@ -107,7 +107,7 @@ static void x11accept(struct Listener* listener, int sock) { int fd; struct sockaddr_in addr; - int len; + socklen_t len; int ret; struct ChanSess * chansess = (struct ChanSess *)(listener->typedata); @@ -175,7 +175,7 @@ void x11cleanup(struct ChanSess *chansess) { m_free(chansess->x11authprot); m_free(chansess->x11authcookie); - TRACE(("chansess %p", chansess)) + TRACE(("chansess %p", (void*)chansess)) if (chansess->x11listener != NULL) { remove_listener(chansess->x11listener); chansess->x11listener = NULL; diff --git a/release/src/router/dropbear/sysoptions.h b/release/src/router/dropbear/sysoptions.h index bec72461d8..a29cbbe32b 100644 --- a/release/src/router/dropbear/sysoptions.h +++ b/release/src/router/dropbear/sysoptions.h @@ -4,7 +4,7 @@ *******************************************************************/ #ifndef DROPBEAR_VERSION -#define DROPBEAR_VERSION "2015.67" +#define DROPBEAR_VERSION "2015.71" #endif #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION @@ -47,7 +47,7 @@ * the clearenv() function */ #define ENV_SIZE 100 -#define MAX_CMD_LEN 1024 /* max length of a command */ +#define MAX_CMD_LEN 9000 /* max length of a command */ #define MAX_TERM_LEN 200 /* max length of TERM name */ #define MAX_HOST_LEN 254 /* max hostname len for tcp fwding */ @@ -150,10 +150,11 @@ RECV_WINDOWEXTEND bytes */ #define MAX_RECV_WINDOW (1024*1024) /* 1 MB should be enough */ -#define MAX_CHANNELS 100 /* simple mem restriction, includes each tcp/x11 +#define MAX_CHANNELS 1000 /* simple mem restriction, includes each tcp/x11 connection, so can't be _too_ small */ -#define MAX_STRING_LEN 2400 /* Sun SSH needs this long for algos */ +#define MAX_STRING_LEN (MAX(MAX_CMD_LEN, 2400)) /* Sun SSH needs 2400 for algos, + MAX_CMD_LEN is usually longer */ /* For a 4096 bit DSS key, empirically determined */ #define MAX_PUBKEY_SIZE 1700 @@ -256,7 +257,18 @@ #define DROPBEAR_LISTEN_BACKLOG MAX_CHANNELS #endif +/* free memory before exiting */ +#define DROPBEAR_CLEANUP + /* Use this string since some implementations might special-case it */ #define DROPBEAR_KEEPALIVE_STRING "keepalive@openssh.com" +/* Linux will attempt TCP fast open, falling back if not supported by the kernel. + * Currently server is enabled but client is disabled by default until there + * is further compatibility testing */ +#ifdef __linux__ +#define DROPBEAR_SERVER_TCP_FAST_OPEN +/* #define DROPBEAR_CLIENT_TCP_FAST_OPEN */ +#endif + /* no include guard for this file */ diff --git a/release/src/router/dropbear/tcp-accept.c b/release/src/router/dropbear/tcp-accept.c index 35be32d870..445692026e 100644 --- a/release/src/router/dropbear/tcp-accept.c +++ b/release/src/router/dropbear/tcp-accept.c @@ -75,7 +75,7 @@ static void tcp_acceptor(struct Listener *listener, int sock) { } if (send_msg_channel_open_init(fd, tcpinfo->chantype) == DROPBEAR_SUCCESS) { - unsigned char* addr = NULL; + char* addr = NULL; unsigned int port = 0; if (tcpinfo->tcp_type == direct) { diff --git a/release/src/router/dropbear/tcpfwd.h b/release/src/router/dropbear/tcpfwd.h index 654664cc62..64139f0dc1 100644 --- a/release/src/router/dropbear/tcpfwd.h +++ b/release/src/router/dropbear/tcpfwd.h @@ -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 _TCPFWD_H -#define _TCPFWD_H +#ifndef DROPBEAR_TCPFWD_H +#define DROPBEAR_TCPFWD_H #include "channel.h" #include "list.h" @@ -31,16 +31,16 @@ struct TCPListener { /* For a direct-tcpip request, it's the addr/port we want the other * end to connect to */ - unsigned char *sendaddr; + char *sendaddr; unsigned int sendport; /* This is the address/port that we listen on. The address has special * meanings as per the rfc, "" for all interfaces, "localhost" for * localhost, or a normal interface name. */ - unsigned char *listenaddr; + char *listenaddr; unsigned int listenport; /* The address that the remote host asked to listen on */ - unsigned char *request_listenaddr; + char *request_listenaddr; const struct ChanType *chantype; enum {direct, forwarded} tcp_type; @@ -48,9 +48,9 @@ struct TCPListener { /* A forwarding entry */ struct TCPFwdEntry { - const unsigned char* connectaddr; + const char *connectaddr; unsigned int connectport; - const unsigned char* listenaddr; + const char *listenaddr; unsigned int listenport; unsigned int have_reply; /* is set to 1 after a reply has been received when setting up the forwarding */ diff --git a/release/src/router/dropbear/termcodes.h b/release/src/router/dropbear/termcodes.h index 00792ea050..cd76b7fd43 100644 --- a/release/src/router/dropbear/termcodes.h +++ b/release/src/router/dropbear/termcodes.h @@ -22,8 +22,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _TERMCODES_H_ -#define _TERMCODES_H_ +#ifndef DROPBEAR_TERMCODES_H_ +#define DROPBEAR_TERMCODES_H_ #define TERMCODE_NONE 0 #define TERMCODE_CONTROL 1 @@ -43,4 +43,4 @@ struct TermCode { extern const struct TermCode termcodes[]; -#endif /* _TERMCODES_H_ */ +#endif /* DROPBEAR_TERMCODES_H_ */ diff --git a/release/src/router/dropbear/x11fwd.h b/release/src/router/dropbear/x11fwd.h index 5855a6862c..e142226b57 100644 --- a/release/src/router/dropbear/x11fwd.h +++ b/release/src/router/dropbear/x11fwd.h @@ -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 _X11FWD_H_ -#define _X11FWD_H_ +#ifndef DROPBEAR__X11FWD_H_ +#define DROPBEAR__X11FWD_H_ #ifndef DISABLE_X11FWD #include "includes.h" @@ -34,4 +34,4 @@ void x11setauth(struct ChanSess *chansess); void x11cleanup(struct ChanSess *chansess); #endif /* DROPBEAR_X11FWD */ -#endif /* _X11FWD_H_ */ +#endif /* DROPBEAR__X11FWD_H_ */ -- 2.11.4.GIT