1
0
mirror of http://galexander.org/git/simplesshd.git synced 2024-12-29 09:28:07 +00:00

Merge branch 'dropbear'

Update to dropbear-2019.78.
Probably does not build...
This commit is contained in:
Greg Alexander 2019-06-15 23:36:15 -04:00
commit 258e88e458
859 changed files with 119276 additions and 22203 deletions

View File

@ -1,5 +1,6 @@
repo: d7da3b1e15401eb234ec866d5eac992fc4cd5878 repo: d7da3b1e15401eb234ec866d5eac992fc4cd5878
node: 735511a4c761141416ad0e6728989d2dafa55bc2 node: d2753238f35f2f80507d1241f03639a20285ef46
branch: default branch: default
latesttag: DROPBEAR_2014.65 latesttag: DROPBEAR_2019.78
latesttagdistance: 12 latesttagdistance: 2
changessincelatesttag: 2

View File

@ -12,3 +12,17 @@ a50a1dc743317fad9b3737bc68fbca640659bb6d 0 iEYEABECAAYFAlJeqL0ACgkQjPn4sExkf7yVq
277429102f1337bd10c89107d3e01de509cc1a7e 0 iEYEABECAAYFAlMEvF4ACgkQjPn4sExkf7xeVQCgtbxJ4G3hsFwUOM0K1WGr1J2vsbEAoMM8dEyr1mdrbgO1tzNLfD1nxbyn 277429102f1337bd10c89107d3e01de509cc1a7e 0 iEYEABECAAYFAlMEvF4ACgkQjPn4sExkf7xeVQCgtbxJ4G3hsFwUOM0K1WGr1J2vsbEAoMM8dEyr1mdrbgO1tzNLfD1nxbyn
96584b934d04ebab443f603e78d38fe692d36313 0 iEYEABECAAYFAlPVFrQACgkQjPn4sExkf7xr6ACglRiLE21vRrS1rJ809o2yMADIKtwAn1f5SyZUngSde8eE55JxCMwtMC5m 96584b934d04ebab443f603e78d38fe692d36313 0 iEYEABECAAYFAlPVFrQACgkQjPn4sExkf7xr6ACglRiLE21vRrS1rJ809o2yMADIKtwAn1f5SyZUngSde8eE55JxCMwtMC5m
caac692b366c153cea0e9cd59aa2d79a7d843d4e 0 iEYEABECAAYFAlPk1mcACgkQjPn4sExkf7wLpgCeOqMYqpkf4lYUuyrn9VYThNpc7PkAn3JOSNgIqkKUcmSy6FstrI8jwJzq 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
926e7275cef4f4f2a4251597ee4814748394824c 0 iQIcBAABCgAGBQJWYES4AAoJEESTFJTynGdzdT0P/0O/1frevtr698DwMe6kmJx35P6Bqq8szntMxYucv0HROTfr85JRcCCSvl/2SflDS215QmOxdvYLGLUWPJNz/gURCLpzsT88KLF68Y1tC72nl4Fj+LGIOlsWsvwEqQqw0v4iQkHIfcxI6q7g1r9Hfldf/ju4bzQ4HnKLxm6KNcLLoAsuehVpQ+njHpLmlLAGHU5a84B7xeXHFR+U/EBPxSdm637rNhmpLpkuK2Mym/Mzv7BThKDstpB8lhFHIwAVNqi3Cy4nGYxFZOJpooUN9pDornqAwuzHmOAMs9+49L8GZ1de5PBRGyFKibzjBIUWPEU9EIkfJVaVwTlqYK8Q/IRi9HjITPx6GpE8cZhdSvAibrQdb6BbIDrZ8eCvD9vnod6Uk0Jb9/ui6nCF9x+CN/3Qez4epV5+JCMYsqCiXFkVPm9Lab6L2eGZis7Q2TXImA/sSV+E4BGfH2urpkKlnuXTTtDp4XRG+lOISkIBXgjVY+uy8soVKNdx1gv+LeY8hu/oQ2NyOlaOeL47aSQ3who4Pk6pVRUOl6zfcKo9Vs6xDWm35A3Z6x/mrAENaXasB0JrfY5nIbefJUpbeSmi76fYldU98HdQNHPHCSeiKVYl7v/B6gi2JXp5xngLZz/5VVAurago7sRmpIp7G/AqU6LNE85IUzG8aQz8AfR0d1dW
fd1981f41c626a969f07b4823848deaefef3c8aa 0 iQIcBAABCgAGBQJW4W2TAAoJEESTFJTynGdzuOcP/j6tvB2WRwSj39KoJuRcRebFWWv4ZHiQXYMXWa3X0Ppzz52r9W0cXDjjlp5FyGdovCQsK+IXmjPo5cCvWBrZJYA6usFr9ssnUtTC+45lvPxPYwj47ZGPngCXDt7LD+v08XhqCu4LsctXIP/zejd30KVS1eR2RHI+tnEyaIKC0Xaa0igcv74MZX7Q8/U+B730QMX5adfYAHoeyRhoctRWaxVV3To7Vadd9jNXP45MRY5auhRcK7XyQcS85vJeCRoysfDUas4ERRQWYkX+68GyzO9GrkYFle931Akw2K6ZZfUuiC2TrF5xv1eRP1Zm2GX481U4ZGFTI8IzZL8sVQ6tvzq2Mxsecu589JNui9aB2d8Gp2Su/E2zn0h0ShIRmviGzf2HiBt+Bnji5X2h/fJKWbLaWge0MdOU5Jidfyh9k0YT7xo4piJLJYSaZ3nv+j4jTYnTfL7uYvuWbYkJ1T32aQVCan7Eup3BFAgQjzbWYi1XQVg6fvu8uHPpS3tNNA9EAMeeyTyg1l6zI2EIU5gPfd/dKmdyotY2lZBkFZNJqFkKRZuzjWekcw7hAxS+Bd68GKklt/DGrQiVycAgimqwXrfkzzQagawq2fXL2uXB8ghlsyxKLSQPnAtBF2Jcn5FH2z7HOQ+e18ZrFfNy0cYa/4OdH6K5aK1igTzhZZP2Urn0
70705edee9dd29cd3d410f19fbd15cc3489313e2 0 iQIcBAABCgAGBQJW7CQRAAoJEESTFJTynGdzTj0QAJL38CKSZthBAeI9c6B+IlwIeT6kPZaPqk1pkycCTWOe87NiNU9abrsF+JrjTuRQiO1EpM2IvfQEIXTijUcMxvld3PnzrZDDv6UvBLtOkn3i++HSVRO0MOuTKI8gFDEPUxRtcaCKXEbqYnf1OTK25FT09Vb//qP9mK1thvlLJmbV+D2a9MkMK66rom1d1h+347IsuwsM+ycHjB80VVAQLA7VYLC5YIwmL17dSmcQLvetfikAMwwmUE+KES4qiLSaqOcAWcKcU67RZzgMMv5o0rESlQmv1nj0mHZtHoUR71sd21emPaRXLOr0oT5YogWUphKq2qVthRn2B06+vd3hPdtn92CmJw9j7zT2jl4OeSjNm9qfAajsRzHIANssFxkGAb7w/LxcMoO29JC+01iUUJMdOVm+4Ns6wGI7qxssWPKdB+VbQUDlHrXLR+sopO524uhkYoWB6DVfTj4R6tImaHtj5/VXON0lsYaLGj8cSH60emL6nNQ0lYV/bSlk6l0s+0x3uXGZnp9oKA+vqMzHfG3vJeMm6KUqtFVjUsYx+q8nHm5/SlWxj1EwnkH8s8ELKZAUXjd76nWEwJ7JFRNRSQWvjOUh3/rsOo4JopzZXPsjCjm+Vql9TG0X6hB21noai32oD5RvfhtR/NX6sXNS5TKZz/j/cMsMnAAsSKb6W7Jm
9030ffdbe5625e35ed7189ab84a41dfc8d413e9c 0 iQIcBAABCgAGBQJXkOg0AAoJEESTFJTynGdzc1kP/3vSKCnhOOvjCjnpTQadYcCUq8vTNnfLHYVu0R4ItPa/jT6RmxoaYP+lZnLnnBx9+aX7kzwHsa9BUX3MbMEyLrOzX2I+bDJbNPhQyupyCuPYlf5Q9KVcO9YlpbsC4q5XBzCn3j2+pT8kSfi9uD8fgY3TgE4w9meINrfQAealfjwMLT8S/I49/ni0r+usSfk/dnSShJYDUO7Ja0VWbJea/GkkZTu30bCnMUZPjRApipU3hPP63WFjkSMT1rp2mAXbWqyr9lf8z32yxzM9nMSjq4ViRFzFlkGtE3EVRJ4PwkO7JuiWAMPJpiQcEr+r52cCsmWhiGyHuINo01MwoMO9/n6uL1WVa3mJcE9se3xBOvfgDu2FRFGCAdm1tef+AGVo9EG1uJXi0sX2yUc6DMeuYaRWrXMMlZh7zp9cuNU9Y/lLui9RFmq66yeXG3Z2B72doju3Ig5QGrNNw2AOsSzeHdAtOp6ychqPcl9QfIeJQG18KyPSefZKM3G8YRKBRIwXFEH6iZJe5ZIP4iXrHDMn2JqtTRtDqKR8VNDAgb9z4Ffx8QRxFyj5JzTTMM1GddHb9udLvTQlO0ULYG7hCSMRNzvUBE2aTw8frjLRyfyyg3QpDu/hz8op8s1ecE8rTCD8RuX9DiiylNozypPtGNS+UDbAmkc1PCWaRpPVl+9K6787
5c9207ceedaea794f958224c19214d66af6e2d56 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlkdtooACgkQRJMUlPKcZ3P6ZxAAmLy/buZB/d96DJF/pViRWt/fWdjQFC4MqWfeSLW02OZ8Qkm1vPL3ln6WPHC2thy3xZWVg2uan3pLk/XXnsIFu8Q7r1EAfFFpvlMUmdl7asE8V6ilaeqmiI7bIvGMFbf4cZkQliLjiFkJX56tFHRCNi+rb7WgRuru3/GzPXUq2AvXZvFpFJgik0B72TxVlmCKeBRZq1FvP0UhAH48RJWYJksdEyzh2paMfjX9ZO5Q2SFFrmPw6k2ArdJFC1AYcgceZC84y06RKJ0WiSntUPlEUXgQbQVVWbtQDhjfJXMr/beuroNdT/vsRraLVkAzvhaDXNnHlAJNLQxci+AcLpnzZhxMW+ax7RRtrpXGxRN4cs0lBGUcSkaDybFqMYXwEjXAE8w6fdJRWCIlxctkAW/iNEO4kAG97hI2Qwcw5oU2Ymnv09zyGR+XJE35pJqPulJHExdwanJHvmjH0QF7TNFS82yxS5dKnP954cj3Lu9SWGYWjxQJRmLtOwb+lqqol4VTxG7Ois4uef9/Tpp9skeMZXVeNlpn2wrp6iFcX3uiiVDg9VKkl3ig6UqCiqQSuiIN87RXwUOeHXlCnW3adz3Xei0ziBrwLSql7lBIHGEAlUUNmJ3CrR8IwQtcynGEMKfNIeZ/XK+uNlm9cJIqZf1fzqc8KexlyS9AS0i/kiYZTr4=
2f0c3f3361d3ea4eb9129ed8810699fda7e7a8ee 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlqVb+IACgkQRJMUlPKcZ3OENA//R9HsOUJQB2QZjRgAvqgLn2AMLUvmWb2etTZEc3Nps957Fw1F4kjh6VGfIpWuytfsDx1W8qRx09ikTdb3YteMWCuX8/aFreSPrioYmzrAEcxkZdA7B/jciqU0iXuHiJ9saKk5TR70aNp+iRy0hjAgiYEsVMF9YKHzULOJcHr70x9XVKquubQkwNqJA+/b2JbK2j46wM5nVK/alGSI2kMmEzXmAHQxsvf1OLMvgH8ou/l0xsg/CuFEK299XKfZAbsFEXrjuoWZ1aSa6rTeOWsWli5T+czyyJHI4Eu0Sz/gaR8+MPhJSYes8YjvzEdv32rRMDVOdBq4e+HoTgFt/THYABP6/R1H5fX3Lm4K8u9F9SwJbb/YKRAIrfWDob8ApnGFHk2dyYO20Fskbbg6b1pC7ulDWsufu8lYkQyMlTc3dR6P4eTB6mKO4x+gMG6tIYZ60fiULoEnMJCgegPtevmz+TG1rzdjh3ljiw9Dxz5lNtL+W7sBKKHwhyG0u+bavgmvBMKNL/rdHEM+0yCIz1U6Lb8sVaST1E4zbdm7cWHbSozBij3G0GBSkLFEq7ZLlh8wco9rELRh0Y9fFsWY9j6H/PTOu0GfHrYluFb9WGywHAquQY8j2croRx+MrvTbR1wZrbevPNm9gqk3vgOiDWu7KwxLLqcj+dEQ7tccptVYtbM=
07b0d56d186d7eeef4106137a3eba554959ba0e3 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlyWOo8ACgkQRJMUlPKcZ3O+MQ//c5oeDUvZuFiI4FHZqfIK/59YAciTP+9TQmoWDVSuOdkd9ZYJA7b7DCusqP2TWFEIl9M7i5hTLTMD21xuEQQtfOSP6EXpUw6JNdh/lsJs7EDlFANtwkdEozAQozFKnXbJEV3y9WldEWUlmPFjt4fJQIuG10SU7MTJHcSaQddJCh3I1//F4EvgRe+OqyrFwKekGiFdvfjcIFN3lQmk6K1Sc0MgyIO/VVZm/AQpBi0Dlg0yOl+EDcxxlmeSInbvLceWSP6op35I4dE5YWH1UetjzIsr5AIM15/k3viAKDDefY1EMAzK9b7YAF4BLw0a6XoQu0apvcWaALE/bJzWNSg/QbCm2JAZzk21WLLvR+AELzPfKXrHX3o0h51lpQ4rs7EWKUm43dJPoWkcFNOU+BDsNzffcJgChbRs48ut89DYLiGmSxhRxE77VPbA+klgTGdctOTLd8psseRlGYCuGe8zeota80bV9fUZ9WJZHwNgEWGowKUoTjy6l5k9OH3iQuQX3OXoy78ufRgWDulE7noVTMhXurQ8a0Jf2k/MW9dcnqGVkWitCFKPEvZwVmWyW2AWsdMcBJnFFGzDsNSxWTtCF9XcxieDO1IB8vGwYcb1TwEVuVzvR/wwvc3PgVikF+4Qv2NqdoQc1yn2PkocY2hwXyIZUAwz7erNumlTbeC/JK8=
ebcdb893992d286d363e60f5353d6e1401e7084b 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlybhXAACgkQRJMUlPKcZ3O7pQ//QuNJfBVa7ROaOJOR2H/xr6PRn1Fnc6rr/GCF9cqWrbGP6wNo24dRjcu5LxviqPvzfwRXIMXwVz8L/y61/sm6XcA7VFP4+MBoltfeUOdMbfBdtwEUo3WMBdP1w2q5GgYj8ZY6MawiLEqFba5aua7dokTNBOQM3Yebj+9I16MiWEaRSnuwYPoieHW2Fo6oftcIgs/GCXwT2xYzc0n3FpYAbK7u6sEkpL16EstV0Y/G70+X1/4Mg3GM96S5fl9Zbun47W7/+gT4AQVQjE+UnPNDudObAe+2BaOZLFvEbd7iJBBcqtjpBktuP58IEAb3A3srUCy49LNLWk43lj+PtoslK/U6TShKQ2vAgfd//bbn6ieXFJY8N+wYPpJo1m7zpTiEtS7J7wu6vkGGZlqUAj6MHXZj223CgazhSAlg/XFPs9oz3Y96c33Tnd4jB9iEXNNt5jzCAMImx2huSGgnP0JFAbcniq/ug5tl1VWaracvSuJl7fmf17DbmehsLbvtZBoMlePY7Ssfb5IokfVvptt4zRpRZnjtWfHCjtC6zYhtvXTmXH/bqWwx9MMjOf5WPfZoCMvXfMqdVI15FVbxU15WnqjvdvKUCkdz1aMFzxqc4MXgyvjtB9CvO/8WwBOJ2m2nDdiZfh8/H8SawYqEHgB61FX5xA5aXecgXcjQnqWDDxw=

View File

@ -1,47 +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

View File

@ -1,20 +1,66 @@
language: c language: c
compiler:
- gcc
script: git:
- autoconf && autoheader && ./configure $BUNDLEDLIBTOM CFLAGS="-O2 -Wall -Wno-pointer-sign" --prefix=$HOME/inst && make install depth: 3
matrix:
include:
# subsequent matrix options use these first settings
- os: linux
compiler: gcc
env: WEXTRAFLAGS=-Werror
sudo: false
- env: MULTI=1 WEXTRAFLAGS=-Werror
# libtom has some warnings, so no WEXTRAFLAGS
- env: CONFIGURE_FLAGS=--enable-bundled-libtom WEXTRAFLAGS=""
- env: NOWRITEV=1 WEXTRAFLAGS=-Werror
# libtomcrypt 1.18.1 fixes clang problems, distro doesn't have that yet
- os: linux
compiler: clang
env: CONFIGURE_FLAGS=--enable-bundled-libtom WEXTRAFLAGS=""
- os: osx
compiler: clang
env: WEXTRAFLAGS=""
# Note: the fuzzing malloc wrapper doesn't replace free() in system libtomcrypt, so need bundled.
- env: DO_FUZZ=1 CONFIGURE_FLAGS="--enable-fuzz --disable-harden --enable-bundled-libtom" WEXTRAFLAGS="" LDFLAGS=-fsanitize=address EXTRACFLAGS=-fsanitize=address CXX=clang++
compiler: clang
# sanitizers need ptrace which is privileged https://github.com/travis-ci/travis-ci/issues/9033
sudo: required
# container-based builds
addons:
apt:
packages:
# packages list: https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
- zlib1g-dev
- libtomcrypt-dev
- libtommath-dev
- mercurial
before_install:
- if [ "$CC" = "clang" ]; then WEXTRAFLAGS="$WEXTRAFLAGS -Wno-error=incompatible-library-redeclaration" ; fi # workaround
install:
- autoconf
- autoheader
- ./configure $CONFIGURE_FLAGS CFLAGS="-O2 -Wall -Wno-pointer-sign $WEXTRAFLAGS $EXTRACFLAGS" --prefix="$HOME/inst" || (cat config.log; exit 1)
- if [ "$NOWRITEV" = "1" ]; then sed -i -e s/HAVE_WRITEV/DONT_HAVE_WRITEV/ config.h ; fi
- make -j3
- test -z $DO_FUZZ || make fuzzstandalone
# avoid concurrent install, osx/freebsd is racey (https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=208093)
- make install
script:
- ~/inst/bin/dropbearkey -t rsa -f testrsa - ~/inst/bin/dropbearkey -t rsa -f testrsa
- ~/inst/bin/dropbearkey -t dss -f testdss - ~/inst/bin/dropbearkey -t dss -f testdss
- ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256 - ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
- ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384 - ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384
- ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521 - ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521
- test -z $DO_FUZZ || ./fuzzers_test.sh
before_install: branches:
- sudo apt-get update -qq only:
- sudo apt-get install -qq libz-dev libtomcrypt-dev libtommath-dev - master
- coverity
env:
- BUNDLEDLIBTOM=--disable-bundled-libtom
- BUNDLEDLIBTOM=--enable-bundled-libtom
- MULTI=1

View File

@ -1,3 +1,363 @@
2019.78 - 27 March 2019
- Fix dbclient regression in 2019.77. After exiting the terminal would be left
in a bad state. Reported by Ryan Woodsmall
2019.77 - 23 March 2019
- Fix server -R option with ECDSA - only advertise one key size which will be accepted.
Reported by Peter Krefting, 2018.76 regression.
- Fix server regression in 2018.76 where multiple client -R forwards were all forwarded
to the first destination. Reported by Iddo Samet.
- Make failure delay more consistent to avoid revealing valid usernames, set server password
limit of 100 characters. Problem reported by usd responsible disclosure team
- Change handling of failed authentication to avoid disclosing valid usernames,
CVE-2018-15599.
- Fix dbclient to reliably return the exit code from the remote server.
Reported by W. Mike Petullo
- Fix export of 521-bit ECDSA keys, from Christian Hohnstädt
- Add -o Port=xxx option to work with sshfs, from xcko
- Merged fuzzing code, see FUZZER-NOTES.md
- Add a DROPBEAR_SVR_MULTIUSER=0 compile option to run on
single-user Linux kernels (CONFIG_MULTIUSER disabled). From Patrick Stewart
- Increase allowed username to 100 characters, reported by W. Mike Petullo
- Update config.sub and config.guess, should now work with RISC-V
- Cygwin compile fix from karel-m
- Don't require GNU sed (accidentally in 2018.76), reported by Samuel Hsu
- Fix for IRIX and writev(), reported by Kazuo Kuroi
- Other fixes and cleanups from François Perrad, Andre McCurdy, Konstantin Demin,
Michael Jones, Pawel Rapkiewicz
2018.76 - 27 February 2018
> > > Configuration/compatibility changes
IMPORTANT
Custom configuration is now specified in localoptions.h rather than options.h
Available options and defaults can be seen in default_options.h
To migrate your configuration, compare your customised options.h against the
upstream options.h from your relevant version. Any customised options should
be put in localoptions.h in the build directory.
- "configure --enable-static" should now be used instead of "make STATIC=1"
This will avoid 'hardened build' flags that conflict with static binaries
- Set 'hardened build' flags by default if supported by the compiler.
These can be disabled with configure --disable-harden if needed.
-Wl,-pie
-Wl,-z,now -Wl,-z,relro
-fstack-protector-strong
-D_FORTIFY_SOURCE=2
# spectre v2 mitigation
-mfunction-return=thunk
-mindirect-branch=thunk
Spectre patch from Loganaden Velvindron
- "dropbear -r" option for hostkeys no longer attempts to load the default
hostkey paths as well. If desired these can be specified manually.
Patch from CamVan Nguyen
- group1-sha1 key exchange is disabled in the server by default since
the fixed 1024-bit group may be susceptible to attacks
- twofish ciphers are now disabled in the default configuration
- Default generated ECDSA key size is now 256 (rather than 521)
for better interoperability
- Minimum RSA key length has been increased to 1024 bits
> > > Other features and fixes
- Add runtime -T max_auth_tries option from Kevin Darbyshire-Bryant
- Add 'dbclient -J &fd' to allow dbclient to connect over an existing socket.
See dbclient manpage for a socat example. Patch from Harald Becker
- Add "-c forced_command" option. Patch from Jeremy Kerr
- Restricted group -G option added with patch from stellarpower
- Support server-chosen TCP forwarding ports, patch from houseofkodai
- Allow choosing outgoing address for dbclient with -b [bind_address][:bind_port]
Patch from houseofkodai
- Makefile will now rebuild object files when header files are modified
- Add group14-256 and group16 key exchange options
- curve25519-sha256 also supported without @libssh.org suffix
- Update bundled libtomcrypt to 1.18.1, libtommath to 1.0.1
This fixes building with some recent versions of clang
- Set PAM_RHOST which is needed by modules such as pam_abl
- Improvements to DSS and RSA public key validation, found by OSS-Fuzz.
- Don't exit when an authorized_keys file has malformed entries. Found by OSS-Fuzz
- Fix null-pointer crash with malformed ECDSA or DSS keys. Found by OSS-Fuzz
- Numerous code cleanups and small issues fixed by Francois Perrad
- Test for pkt_sched.h rather than SO_PRIORITY which was problematic with some musl
platforms. Reported by Oliver Schneider and Andrew Bainbridge
- Fix some platform portability problems, from Ben Gardner
- Add EXEEXT filename suffix for building dropbearmulti, from William Foster
- Support --enable-<option> properly for configure, from Stefan Hauser
- configure have_openpty result can be cached, from Eric Bénard
- handle platforms that return close() < -1 on failure, from Marco Wenzel
- Build and configuration cleanups from Michael Witten
- Fix libtomcrypt/libtommath linking order, from Andre McCurdy
- Fix old Linux platforms that have SYS_clock_gettime but not CLOCK_MONOTONIC
- Update curve25519-donna implementation to current version
2017.75 - 18 May 2017
- Security: Fix double-free in server TCP listener cleanup
A double-free in the server could be triggered by an authenticated user if
dropbear is running with -a (Allow connections to forwarded ports from any host)
This could potentially allow arbitrary code execution as root by an authenticated user.
Affects versions 2013.56 to 2016.74. Thanks to Mark Shepard for reporting the crash.
CVE-2017-9078 https://secure.ucc.asn.au/hg/dropbear/rev/c8114a48837c
- Security: Fix information disclosure with ~/.ssh/authorized_keys symlink.
Dropbear parsed authorized_keys as root, even if it were a symlink. The fix
is to switch to user permissions when opening authorized_keys
A user could symlink their ~/.ssh/authorized_keys to a root-owned file they
couldn't normally read. If they managed to get that file to contain valid
authorized_keys with command= options it might be possible to read other
contents of that file.
This information disclosure is to an already authenticated user.
Thanks to Jann Horn of Google Project Zero for reporting this.
CVE-2017-9079 https://secure.ucc.asn.au/hg/dropbear/rev/0d889b068123
- Generate hostkeys with dropbearkey atomically and flush to disk with fsync
Thanks to Andrei Gherzan for a patch
- Fix out of tree builds with bundled libtom
Thanks to Henrik Nordström and Peter Krefting for patches.
2016.74 - 21 July 2016
- Security: Message printout was vulnerable to format string injection.
If specific usernames including "%" symbols can be created on a system
(validated by getpwnam()) then an attacker could run arbitrary code as root
when connecting to Dropbear server.
A dbclient user who can control username or host arguments could potentially
run arbitrary code as the dbclient user. This could be a problem if scripts
or webpages pass untrusted input to the dbclient program.
CVE-2016-7406
https://secure.ucc.asn.au/hg/dropbear/rev/b66a483f3dcb
- Security: dropbearconvert import of OpenSSH keys could run arbitrary code as
the local dropbearconvert user when parsing malicious key files
CVE-2016-7407
https://secure.ucc.asn.au/hg/dropbear/rev/34e6127ef02e
- Security: dbclient could run arbitrary code as the local dbclient user if
particular -m or -c arguments are provided. This could be an issue where
dbclient is used in scripts.
CVE-2016-7408
https://secure.ucc.asn.au/hg/dropbear/rev/eed9376a4ad6
- Security: dbclient or dropbear server could expose process memory to the
running user if compiled with DEBUG_TRACE and running with -v
CVE-2016-7409
https://secure.ucc.asn.au/hg/dropbear/rev/6a14b1f6dc04
The security issues were reported by an anonymous researcher working with
Beyond Security's SecuriTeam Secure Disclosure www.beyondsecurity.com/ssd.html
- Fix port forwarding failure when connecting to domains that have both
IPv4 and IPv6 addresses. The bug was introduced in 2015.68
- Fix 100% CPU use while waiting for rekey to complete. Thanks to Zhang Hui P
for the patch
2016.73 - 18 March 2016
- Support syslog in dbclient, option -o usesyslog=yes. Patch from Konstantin Tokarev
- Kill a proxycommand when dbclient exits, patch from Konstantin Tokarev
- Option to exit when a TCP forward fails, patch from Konstantin Tokarev
- New "-o" option parsing from Konstantin Tokarev. This allows handling some extra options
in the style of OpenSSH, though implementing all OpenSSH options is not planned.
- Fix crash when fallback initshells() is used, reported by Michael Nowak and Mike Tzou
- Allow specifying commands eg "dropbearmulti dbclient ..." instead of symlinks
- Various cleanups for issues found by a lint tool, patch from Francois Perrad
- Fix tab indent consistency, patch from Francois Perrad
- Fix issues found by cppcheck, reported by Mike Tzou
- Use system memset_s() or explicit_bzero() if available to clear memory. Also make
libtomcrypt/libtommath routines use that (or Dropbear's own m_burn()).
- Prevent scp failing when the local user doesn't exist. Based on patch from Michael Witten.
- Improved Travis CI test running, thanks to Mike Tzou
- Improve some code that was flagged by Coverity and Fortify Static Code Analyzer
2016.72 - 9 March 2016
- Validate X11 forwarding input. Could allow bypass of authorized_keys command= restrictions,
found by github.com/tintinweb. Thanks for Damien Miller for a patch. CVE-2016-3116
https://secure.ucc.asn.au/hg/dropbear/rev/a3e8389e01ff
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, thanks to
Frank Stollenwerk for reporting and investigation
- 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
reboot occurs. Thanks to Peter Korsgaard
- Disable non-delayed zlib compression by default on the server. Can be
enabled if required for old clients with DROPBEAR_SERVER_DELAY_ZLIB
- Default client key path ~/.ssh/id_dropbear
- Prefer stronger algorithms by default, from Fedor Brunner.
AES256 over 3DES
Diffie-hellman group14 over group1
- Add option to disable CBC ciphers.
- Disable twofish in default options.h
- Enable sha2 HMAC algorithms by default, the code was already required
for ECC key exchange. sha1 is the first preference still for performance.
- Fix installing dropbear.8 in a separate build directory, from Like Ma
- Allow configure to succeed if libtomcrypt/libtommath are missing, from Elan Ruusamäe
- Don't crash if ssh-agent provides an unknown type of key. From Catalin Patulea
- Minor bug fixes, a few issues found by Coverity scan
2014.66 - Thursday 23 October 2014 2014.66 - Thursday 23 October 2014
- Use the same keepalive handling behaviour as OpenSSH. This will work better - Use the same keepalive handling behaviour as OpenSSH. This will work better
@ -114,6 +474,8 @@ kernels, from Steve Dover
2013.61test - Thursday 14 November 2013 2013.61test - Thursday 14 November 2013
- Default generated RSA key size changed from 1024 to 2048 bits
- ECC (elliptic curve) support. Supports ECDSA hostkeys (requires new keys to - ECC (elliptic curve) support. Supports ECDSA hostkeys (requires new keys to
be generated) and ECDH for setting up encryption keys (no intervention be generated) and ECDH for setting up encryption keys (no intervention
required). This is significantly faster. required). This is significantly faster.
@ -159,9 +521,11 @@ kernels, from Steve Dover
- Limit the size of decompressed payloads, avoids memory exhaustion denial - Limit the size of decompressed payloads, avoids memory exhaustion denial
of service of service
Thanks to Logan Lamb for reporting and investigating it. CVE-2013-4421 Thanks to Logan Lamb for reporting and investigating it. CVE-2013-4421
https://secure.ucc.asn.au/hg/dropbear/rev/0bf76f54de6f
- Avoid disclosing existence of valid users through inconsistent delays - Avoid disclosing existence of valid users through inconsistent delays
Thanks to Logan Lamb for reporting. CVE-2013-4434 Thanks to Logan Lamb for reporting. CVE-2013-4434
https://secure.ucc.asn.au/hg/dropbear/rev/d7784616409a
- Update config.guess and config.sub for newer architectures - Update config.guess and config.sub for newer architectures
@ -264,6 +628,7 @@ though probably will be soon
This bug affects releases 0.52 onwards. Ref CVE-2012-0920. This bug affects releases 0.52 onwards. Ref CVE-2012-0920.
Thanks to Danny Fullerton of Mantor Organization for reporting Thanks to Danny Fullerton of Mantor Organization for reporting
the bug. the bug.
https://secure.ucc.asn.au/hg/dropbear/rev/818108bf7749
- Compile fix, only apply IPV6 socket options if they are available in headers - Compile fix, only apply IPV6 socket options if they are available in headers
Thanks to Gustavo Zacarias for the patch Thanks to Gustavo Zacarias for the patch

74
dropbear/FUZZER-NOTES.md Normal file
View File

@ -0,0 +1,74 @@
# Fuzzing Dropbear
Dropbear is process-per-session so it assumes calling `dropbear_exit()`
is fine at any point to clean up. This makes fuzzing a bit trickier.
A few pieces of wrapping infrastructure are used to work around this.
The [libfuzzer](http://llvm.org/docs/LibFuzzer.html#fuzz-target) harness
expects a long running process to continually run a test function with
a string of crafted input. That process should not leak resources or exit.
## longjmp
When dropbear runs in fuzz mode it sets up a
[`setjmp()`](http://man7.org/linux/man-pages/man3/setjmp.3.html) target prior
to launching the code to be fuzzed, and then [`dropbear_exit()`](dbutil.c#L125)
calls `longjmp()` back there. This avoids exiting though it doesn't free
memory or other resources.
## malloc Wrapper
Dropbear normally uses a [`m_malloc()`](dbmalloc.c) function that is the same as `malloc()` but
exits if allocation fails. In fuzzing mode this is replaced with a tracking allocator
that stores all allocations in a linked list. After the `longjmp()` occurs the fuzzer target
calls [`m_malloc_free_epoch(1, 1)`](dbmalloc.c) to clean up any unreleased memory.
If the fuzz target runs to completion it calls `m_malloc_free_epoch(1, 0)` which will reset
the tracked allocations but will not free memory - that allows libfuzzer's leak checking
to detect leaks in normal operation.
## File Descriptor Input
As a network process Dropbear reads and writes from a socket. The wrappers for
`read()`/`write()`/`select()` in [fuzz-wrapfd.c](fuzz-wrapfd.c) will read from the
fuzzer input that has been set up with `wrapfd_add()`. `write()` output is
currently discarded.
These also test error paths such as EINTR and short reads with certain probabilities.
This allows running the entire dropbear server process with network input provided by the
fuzzer, without many modifications to the main code. At the time of writing this
only runs the pre-authentication stages, though post-authentication could be run similarly.
## Encryption and Randomness
When running in fuzzing mode Dropbear uses a [fixed seed](dbrandom.c#L185)
every time so that failures can be reproduced.
Since the fuzzer cannot generate valid encrypted input the packet decryption and
message authentication calls are disabled, see [packet.c](packet.c).
MAC failures are set to occur with a low probability to test that error path.
## Fuzzers
Current fuzzers are
- [fuzzer-preauth](fuzzer-preauth.c) - the fuzzer input is treated as a stream of session input. This will
test key exchange, packet ordering, authentication attempts etc.
- [fuzzer-preauth_nomaths](fuzzer-preauth_nomaths.c) - the same as fuzzer-preauth but with asymmetric crypto
routines replaced with dummies for faster runtime. corpora are shared
between fuzzers by [oss-fuzz](https://github.com/google/oss-fuzz) so this
will help fuzzer-preauth too.
- [fuzzer-verify](fuzzer-verify.c) - read a key and signature from fuzzer input and verify that signature.
It would not be expected to pass, though some keys with bad parameters are
able to validate with a trivial signature - extra checks are added for that.
- [fuzzer-pubkey](fuzzer-pubkey.c) - test parsing of an `authorized_keys` line.
- [fuzzer-kexdh](fuzzer-kexdh.c) - test Diffie-Hellman key exchange where the fuzz input is the
ephemeral public key that would be received over the network. This is testing `mp_expt_mod()`
and and other libtommath routines.
- [fuzzer-kexecdh](fuzzer-kexecdh.c) - test Elliptic Curve Diffie-Hellman key exchange like fuzzer-kexdh.
This is testing libtommath ECC routines.

View File

@ -1,20 +1,28 @@
Basic Dropbear build instructions: Basic Dropbear build instructions:
- Edit options.h to set which features you want. - Edit localoptions.h to set which features you want. Available options
- Edit debug.h if you want any debug options (not usually required). are described in default_options.h, these will be overridden by
anything set in localoptions.h
localoptions.h should be located in the build directory if you are
building out of tree.
(If using a non-tarball copy, "autoconf; autoheader") - If using a Mercurial or Git checkout, "autoconf; autoheader"
./configure (optionally with --disable-zlib or --disable-syslog, - Configure for your system:
./configure (optionally with --disable-zlib or --disable-syslog,
or --help for other options) or --help for other options)
Now compile: - Compile:
make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp"
And install (/usr/local/bin is usual default): - Optionally install, or copy the binaries another way
make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" install make install (/usr/local/bin is usual default):
or
make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" install
(you can leave items out of the PROGRAMS list to avoid compiling them. If you (you can leave items out of the PROGRAMS list to avoid compiling them. If you
recompile after changing the PROGRAMS list, you *MUST* "make clean" before recompile after changing the PROGRAMS list, you *MUST* "make clean" before
@ -22,7 +30,11 @@ recompiling - bad things will happen otherwise)
See MULTI for instructions on making all-in-one binaries. See MULTI for instructions on making all-in-one binaries.
If you want to compile statically, add "STATIC=1" to the make command-line. If you want to compile statically use ./configure --enable-static
By default Dropbear adds various build flags that improve robustness
against programming bugs (good for security). If these cause problems
they can be disabled with ./configure --disable-harden
Binaries can be stripped with "make strip" Binaries can be stripped with "make strip"

View File

@ -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 Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the
same license: same license:
Copyright (c) 2002-2014 Matt Johnston Copyright (c) 2002-2015 Matt Johnston
Portions copyright (c) 2004 Mihnea Stoenescu Portions copyright (c) 2004 Mihnea Stoenescu
All rights reserved. All rights reserved.

View File

@ -2,12 +2,11 @@
# @configure_input@ # @configure_input@
# invocation: # invocation:
# make PROGRAMS="dropbear dbclient scp" MULTI=1 STATIC=1 SCPPROGRESS=1 # make PROGRAMS="dropbear dbclient scp" MULTI=1 SCPPROGRESS=1
# #
# to make a multiple-program statically linked binary "staticdropbearmulti". # to make a multiple-program binary "dropbearmulti".
# This example will include dropbear, scp, dropbearkey, dropbearconvert, and # This example will include dropbear, scp, dropbearkey, dropbearconvert, and
# dbclient functionality, and includes the progress-bar functionality in scp. # dbclient functionality, and includes the progress-bar functionality in scp.
# Hopefully that seems intuitive.
ifndef PROGRAMS ifndef PROGRAMS
PROGRAMS=dropbear dbclient dropbearkey dropbearconvert PROGRAMS=dropbear dbclient dropbearkey dropbearconvert
@ -20,16 +19,24 @@ LIBTOM_LIBS=@LIBTOM_LIBS@
ifeq (@BUNDLED_LIBTOM@, 1) ifeq (@BUNDLED_LIBTOM@, 1)
LIBTOM_DEPS=$(STATIC_LTC) $(STATIC_LTM) LIBTOM_DEPS=$(STATIC_LTC) $(STATIC_LTM)
LIBTOM_CLEAN=ltc-clean ltm-clean
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/ CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM) LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
endif endif
COMMONOBJS=dbutil.o buffer.o \ OPTION_HEADERS = default_options_guard.h sysoptions.h
ifneq ($(wildcard localoptions.h),)
CFLAGS+=-DLOCALOPTIONS_H_EXISTS
OPTION_HEADERS += localoptions.h
endif
COMMONOBJS=dbutil.o buffer.o dbhelpers.o \
dss.o bignum.o \ dss.o bignum.o \
signkey.o rsa.o dbrandom.o \ signkey.o rsa.o dbrandom.o \
queue.o \ queue.o \
atomicio.o compat.o fake-rfc2553.o \ atomicio.o compat.o fake-rfc2553.o \
ltc_prng.o ecc.o ecdsa.o crypto_desc.o \ ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
dbmalloc.o \
gensignkey.o gendss.o genrsa.o gensignkey.o gendss.o genrsa.o
SVROBJS=svr-kex.o svr-auth.o sshpty.o \ SVROBJS=svr-kex.o svr-auth.o sshpty.o \
@ -40,12 +47,12 @@ SVROBJS=svr-kex.o svr-auth.o sshpty.o \
CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
cli-session.o cli-runopts.o cli-chansession.o \ cli-session.o cli-runopts.o cli-chansession.o \
cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.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 \ CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
common-channel.o common-chansession.o termcodes.o loginrec.o \ common-channel.o common-chansession.o termcodes.o loginrec.o \
tcp-accept.o listener.o process-packet.o \ tcp-accept.o listener.o process-packet.o dh_groups.o \
common-runopts.o circbuffer.o curve25519-donna.o common-runopts.o circbuffer.o curve25519-donna.o list.o netio.o
KEYOBJS=dropbearkey.o KEYOBJS=dropbearkey.o
@ -53,18 +60,25 @@ CONVERTOBJS=dropbearconvert.o keyimport.o
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \ ifeq (@DROPBEAR_FUZZ@, 1)
dss.h bignum.h signkey.h rsa.h dbrandom.h service.h auth.h \ allobjs = $(COMMONOBJS) fuzz-common.o fuzz-wrapfd.o $(CLISVROBJS) $(CLIOBJS) $(SVROBJS) @CRYPTLIB@
debug.h channel.h chansession.h config.h queue.h sshpty.h \ allobjs:=$(subst svr-main.o, ,$(allobjs))
termcodes.h gendss.h genrsa.h runopts.h includes.h \ allobjs:=$(subst cli-main.o, ,$(allobjs))
loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \ allobjs:=$(sort $(allobjs))
listener.h fake-rfc2553.h ecc.h ecdsa.h
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) dropbearobjs=$(allobjs) svr-main.o
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS) dbclientobjs=$(allobjs) cli-main.o
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS) dropbearkeyobjs=$(allobjs) $(KEYOBJS)
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS) dropbearconvertobjs=$(allobjs) $(CONVERTOBJS)
scpobjs=$(SCPOBJS) # CXX only set when fuzzing
CXX=@CXX@
else
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
scpobjs=$(SCPOBJS)
endif
VPATH=@srcdir@ VPATH=@srcdir@
srcdir=@srcdir@ srcdir=@srcdir@
@ -76,6 +90,8 @@ bindir=@bindir@
sbindir=@sbindir@ sbindir=@sbindir@
mandir=@mandir@ mandir=@mandir@
.DELETE_ON_ERROR:
CC=@CC@ CC=@CC@
AR=@AR@ AR=@AR@
RANLIB=@RANLIB@ RANLIB=@RANLIB@
@ -88,9 +104,10 @@ LDFLAGS=@LDFLAGS@
EXEEXT=@EXEEXT@ EXEEXT=@EXEEXT@
STATIC=@STATIC@
# whether we're building client, server, or both for the common objects. # whether we're building client, server, or both for the common objects.
# evilness so we detect 'dropbear' by itself as a word # evilness so we detect 'dropbear' by itself as a word
space:= $(empty) $(empty)
ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdropbearZ, Z$(prog)Z)))) ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdropbearZ, Z$(prog)Z))))
CFLAGS+= -DDROPBEAR_SERVER CFLAGS+= -DDROPBEAR_SERVER
endif endif
@ -98,7 +115,6 @@ ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdbclientZ, Z$(prog)Z)
CFLAGS+= -DDROPBEAR_CLIENT CFLAGS+= -DDROPBEAR_CLIENT
endif endif
# these are exported so that libtomcrypt's makefile will use them # these are exported so that libtomcrypt's makefile will use them
export CC export CC
export CFLAGS export CFLAGS
@ -109,7 +125,7 @@ ifeq ($(STATIC), 1)
endif endif
ifeq ($(MULTI), 1) ifeq ($(MULTI), 1)
TARGETS=dropbearmulti TARGETS=dropbearmulti$(EXEEXT)
else else
TARGETS=$(PROGRAMS) TARGETS=$(PROGRAMS)
endif endif
@ -121,31 +137,42 @@ endif
all: $(TARGETS) all: $(TARGETS)
# for simplicity assume all source depends on all headers
HEADERS=$(wildcard $(srcdir)/*.h *.h) $(OPTION_HEADERS)
%.o : %.c $(HEADERS)
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
default_options_guard.h: default_options.h
@echo Creating $@
@printf "/*\n > > > Do not edit this file (default_options_guard.h) < < <\nGenerated from "$^"\nLocal customisation goes in localoptions.h\n*/\n\n" > $@.tmp
@$(srcdir)/ifndef_wrapper.sh < $^ >> $@.tmp
@mv $@.tmp $@
strip: $(TARGETS) strip: $(TARGETS)
$(STRIP) $(addsuffix $(EXEEXT), $(TARGETS)) $(STRIP) $(addsuffix $(EXEEXT), $(TARGETS))
install: $(addprefix inst_, $(TARGETS)) install: $(addprefix inst_, $(TARGETS))
insmultidropbear: dropbearmulti insmultidropbear: dropbearmulti$(EXEEXT)
$(INSTALL) -d $(DESTDIR)$(sbindir) $(INSTALL) -d $(DESTDIR)$(sbindir)
-rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT) -rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT) -ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
$(INSTALL) -d $(DESTDIR)$(mandir)/man8 $(INSTALL) -d $(DESTDIR)$(mandir)/man8
$(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8 $(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
insmulti%: dropbearmulti insmulti%: dropbearmulti$(EXEEXT)
$(INSTALL) -d $(DESTDIR)$(bindir) $(INSTALL) -d $(DESTDIR)$(bindir)
-rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT) -rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT)
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT) -ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT)
$(INSTALL) -d $(DESTDIR)$(mandir)/man1 $(INSTALL) -d $(DESTDIR)$(mandir)/man1
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi 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 inst_dropbear: dropbear
$(INSTALL) -d $(DESTDIR)$(sbindir) $(INSTALL) -d $(DESTDIR)$(sbindir)
$(INSTALL) dropbear$(EXEEXT) $(DESTDIR)$(sbindir) $(INSTALL) dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
$(INSTALL) -d $(DESTDIR)$(mandir)/man8 $(INSTALL) -d $(DESTDIR)$(mandir)/man8
$(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8 $(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
inst_%: % inst_%: %
$(INSTALL) -d $(DESTDIR)$(bindir) $(INSTALL) -d $(DESTDIR)$(bindir)
@ -155,7 +182,6 @@ inst_%: %
inst_dropbearmulti: $(addprefix insmulti, $(PROGRAMS)) inst_dropbearmulti: $(addprefix insmulti, $(PROGRAMS))
# for some reason the rule further down doesn't like $($@objs) as a prereq. # for some reason the rule further down doesn't like $($@objs) as a prereq.
dropbear: $(dropbearobjs) dropbear: $(dropbearobjs)
dbclient: $(dbclientobjs) dbclient: $(dbclientobjs)
@ -169,7 +195,7 @@ dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) $(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
# scp doesn't use the libs so is special. # scp doesn't use the libs so is special.
scp: $(SCPOBJS) $(HEADERS) Makefile scp: $(SCPOBJS) $(HEADERS) Makefile
@ -194,32 +220,89 @@ link%:
-rm -f $*$(EXEEXT) -rm -f $*$(EXEEXT)
-ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT) -ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT)
$(STATIC_LTC): options.h $(STATIC_LTC): $(OPTION_HEADERS)
cd libtomcrypt && $(MAKE) $(MAKE) -C libtomcrypt
$(STATIC_LTM): options.h $(STATIC_LTM): $(OPTION_HEADERS)
cd libtommath && $(MAKE) $(MAKE) -C libtommath
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean .PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean
ltc-clean: ltc-clean:
cd libtomcrypt && $(MAKE) clean $(MAKE) -C libtomcrypt clean
ltm-clean: ltm-clean:
cd libtommath && $(MAKE) clean $(MAKE) -C libtommath clean
sizes: dropbear sizes: dropbear
objdump -t dropbear|grep ".text"|cut -d "." -f 2|sort -rn objdump -t dropbear|grep ".text"|cut -d "." -f 2|sort -rn
clean: ltc-clean ltm-clean thisclean clean: $(LIBTOM_CLEAN) thisclean
thisclean: thisclean:
-rm -f dropbear dbclient dropbearkey dropbearconvert scp scp-progress \ -rm -f dropbear$(EXEEXT) dbclient$(EXEEXT) dropbearkey$(EXEEXT) \
dropbearmulti *.o *.da *.bb *.bbg *.prof dropbearconvert$(EXEEXT) scp$(EXEEXT) scp-progress$(EXEEXT) \
dropbearmulti$(EXEEXT) *.o *.da *.bb *.bbg *.prof
distclean: clean tidy distclean: clean tidy
-rm -f config.h -rm -f config.h
-rm -f Makefile -rm -f Makefile
-rm -f default_options_guard.h
tidy: tidy:
-rm -f *~ *.gcov */*~ -rm -f *~ *.gcov */*~
## Fuzzing targets
# list of fuzz targets
FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh
FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS))
list-fuzz-targets:
@echo $(FUZZ_TARGETS)
# fuzzers that don't use libfuzzer, just a standalone harness that feeds inputs
fuzzstandalone: FUZZLIB=fuzz-harness.o
fuzzstandalone: fuzz-harness.o fuzz-targets
# exclude svr-main.o to avoid duplicate main
svrfuzzobjs=$(subst svr-main.o, ,$(dropbearobjs))
# build all the fuzzers. This will require fail to link unless built with
# make fuzz-targets FUZZLIB=-lFuzzer.a
# or similar - the library provides main().
fuzz-targets: $(FUZZ_TARGETS) $(FUZZER_OPTIONS)
fuzzer-preauth: fuzzer-preauth.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-pubkey: fuzzer-pubkey.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-verify: fuzzer-verify.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexdh: fuzzer-kexdh.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexecdh: fuzzer-kexecdh.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-%.options: Makefile
echo "[libfuzzer]" > $@
echo "max_len = 50000" >> $@
# run this to update hardcoded hostkeys for for fuzzing.
# hostkeys.c is checked in to hg.
fuzz-hostkeys:
dropbearkey -t rsa -f keyr
dropbearkey -t dss -f keyd
dropbearkey -t ecdsa -size 256 -f keye
echo > hostkeys.c
/usr/bin/xxd -i -a keyr >> hostkeys.c
/usr/bin/xxd -i -a keye >> hostkeys.c
/usr/bin/xxd -i -a keyd >> hostkeys.c

View File

@ -8,8 +8,8 @@ which performs multiple tasks, to save disk space)
SMALL has some tips on creating small binaries. SMALL has some tips on creating small binaries.
See TODO for a few of the things I know need looking at, and please contact Please contact me if you have any questions/bugs found/features/ideas/comments etc :)
me if you have any questions/bugs found/features/ideas/comments etc :) There is also a mailing list http://lists.ucc.gu.uwa.edu.au/mailman/listinfo/dropbear
Matt Johnston Matt Johnston
matt@ucc.asn.au matt@ucc.asn.au
@ -51,7 +51,7 @@ dropbearkey's '-y' option.
============================================================================ ============================================================================
To run the server, you need to server keys, this is one-off: To run the server, you need to generate server keys, this is one-off:
./dropbearkey -t rsa -f dropbear_rsa_host_key ./dropbearkey -t rsa -f dropbear_rsa_host_key
./dropbearkey -t dss -f dropbear_dss_host_key ./dropbearkey -t dss -f dropbear_dss_host_key
./dropbearkey -t ecdsa -f dropbear_ecdsa_host_key ./dropbearkey -t ecdsa -f dropbear_ecdsa_host_key

View File

@ -1,27 +0,0 @@
Current:
Things which might need doing:
- default private dbclient keys
- Make options.h generated from configure perhaps?
- handle /etc/environment in AIX
- check that there aren't timing issues with valid/invalid user authentication
feedback.
- Binding to different interfaces
- CTR mode
- SSH_MSG_IGNORE sending to improve CBC security
- DH Group Exchange possibly, or just add group14 (whatever it's called today)
- fix scp.c for IRIX
- Be able to use OpenSSH keys for the client? or at least have some form of
encrypted keys.
- Client agent forwarding
- Handle restrictions in ~/.ssh/authorized_keys ?

View File

@ -21,8 +21,8 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * 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 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _AGENTFWD_H_ #ifndef DROPBEAR_AGENTFWD_H_
#define _AGENTFWD_H_ #define DROPBEAR_AGENTFWD_H_
#include "includes.h" #include "includes.h"
#include "chansession.h" #include "chansession.h"
@ -30,7 +30,7 @@
#include "auth.h" #include "auth.h"
#include "list.h" #include "list.h"
#ifdef ENABLE_CLI_AGENTFWD #if DROPBEAR_CLI_AGENTFWD
/* An agent reply can be reasonably large, as it can /* An agent reply can be reasonably large, as it can
* contain a list of all public keys held by the agent. * contain a list of all public keys held by the agent.
@ -40,8 +40,8 @@
/* client functions */ /* client functions */
void cli_load_agent_keys(m_list * ret_list); void cli_load_agent_keys(m_list * ret_list);
void agent_buf_sign(buffer *sigblob, sign_key *key, void agent_buf_sign(buffer *sigblob, sign_key *key,
buffer *data_buf); const buffer *data_buf);
void cli_setup_agent(struct Channel *channel); void cli_setup_agent(const struct Channel *channel);
#ifdef __hpux #ifdef __hpux
#define seteuid(a) setresuid(-1, (a), -1) #define seteuid(a) setresuid(-1, (a), -1)
@ -50,14 +50,14 @@ void cli_setup_agent(struct Channel *channel);
extern const struct ChanType cli_chan_agent; extern const struct ChanType cli_chan_agent;
#endif /* ENABLE_CLI_AGENTFWD */ #endif /* DROPBEAR_CLI_AGENTFWD */
#ifdef ENABLE_SVR_AGENTFWD #if DROPBEAR_SVR_AGENTFWD
int svr_agentreq(struct ChanSess * chansess); int svr_agentreq(struct ChanSess * chansess);
void svr_agentcleanup(struct ChanSess * chansess); void svr_agentcleanup(struct ChanSess * chansess);
void svr_agentset(struct ChanSess *chansess); void svr_agentset(const struct ChanSess *chansess);
#endif /* ENABLE_SVR_AGENTFWD */ #endif /* DROPBEAR_SVR_AGENTFWD */
#endif /* _AGENTFWD_H_ */ #endif /* DROPBEAR_AGENTFWD_H_ */

View File

@ -22,9 +22,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _ALGO_H_ #ifndef DROPBEAR_ALGO_H_
#define _ALGO_H_ #define DROPBEAR_ALGO_H_
#include "includes.h" #include "includes.h"
#include "buffer.h" #include "buffer.h"
@ -35,7 +35,7 @@
struct Algo_Type { 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 */ char val; /* a value for this cipher, or -1 for invalid */
const void *data; /* algorithm specific data */ const void *data; /* algorithm specific data */
char usable; /* whether we can use this algorithm */ char usable; /* whether we can use this algorithm */
@ -51,6 +51,7 @@ extern algo_type sshhostkey[];
extern algo_type sshciphers[]; extern algo_type sshciphers[];
extern algo_type sshhashes[]; extern algo_type sshhashes[];
extern algo_type ssh_compress[]; extern algo_type ssh_compress[];
extern algo_type ssh_delaycompress[];
extern algo_type ssh_nocompress[]; extern algo_type ssh_nocompress[];
extern const struct dropbear_cipher dropbear_nocipher; extern const struct dropbear_cipher dropbear_nocipher;
@ -82,9 +83,15 @@ struct dropbear_hash {
}; };
enum dropbear_kex_mode { enum dropbear_kex_mode {
#if DROPBEAR_NORMAL_DH
DROPBEAR_KEX_NORMAL_DH, DROPBEAR_KEX_NORMAL_DH,
#endif
#if DROPBEAR_ECDH
DROPBEAR_KEX_ECDH, DROPBEAR_KEX_ECDH,
#endif
#if DROPBEAR_CURVE25519
DROPBEAR_KEX_CURVE25519, DROPBEAR_KEX_CURVE25519,
#endif
}; };
struct dropbear_kex { struct dropbear_kex {
@ -95,7 +102,7 @@ struct dropbear_kex {
const int dh_p_len; const int dh_p_len;
/* elliptic curve DH KEX */ /* elliptic curve DH KEX */
#ifdef DROPBEAR_ECDH #if DROPBEAR_ECDH
const struct dropbear_ecc_curve *ecc_curve; const struct dropbear_ecc_curve *ecc_curve;
#else #else
const void* dummy; const void* dummy;
@ -105,8 +112,8 @@ struct dropbear_kex {
const struct ltc_hash_descriptor *hash_desc; const struct ltc_hash_descriptor *hash_desc;
}; };
int have_algo(char* algo, size_t algolen, algo_type algos[]); int have_algo(const char* algo, size_t algolen, const algo_type algos[]);
void buf_put_algolist(buffer * buf, algo_type localalgos[]); void buf_put_algolist(buffer * buf, const algo_type localalgos[]);
enum kexguess2_used { enum kexguess2_used {
KEXGUESS2_LOOK, KEXGUESS2_LOOK,
@ -121,10 +128,10 @@ enum kexguess2_used {
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[], algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
enum kexguess2_used *kexguess2, int *goodguess); enum kexguess2_used *kexguess2, int *goodguess);
#ifdef ENABLE_USER_ALGO_LIST #if DROPBEAR_USER_ALGO_LIST
int check_user_algos(const char* user_algo_list, algo_type * algos, int check_user_algos(const char* user_algo_list, algo_type * algos,
const char *algo_desc); const char *algo_desc);
char * algolist_string(algo_type algos[]); char * algolist_string(const algo_type algos[]);
#endif #endif
enum { enum {
@ -133,4 +140,4 @@ enum {
DROPBEAR_COMP_ZLIB_DELAY, DROPBEAR_COMP_ZLIB_DELAY,
}; };
#endif /* _ALGO_H_ */ #endif /* DROPBEAR_ALGO_H_ */

View File

@ -1,6 +1,8 @@
/* $OpenBSD: atomicio.c,v 1.17 2006/04/01 05:51:34 djm Exp $ */
/* /*
* Copied from OpenSSH 3.6.1p2. * Copied from OpenSSH/OpenBSD.
* *
* Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved. * All rights reserved.
* *
@ -25,38 +27,32 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/* RCSID("OpenBSD: atomicio.c,v 1.10 2001/05/08 22:48:07 markus Exp "); */ #include "includes.h"
#include "atomicio.h" #include "atomicio.h"
/* /*
* ensure all of data on socket comes through. f==read || f==write * ensure all of data on socket comes through. f==read || f==vwrite
*/ */
ssize_t size_t
atomicio(f, fd, _s, n) atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
ssize_t (*f) ();
int fd;
void *_s;
size_t n;
{ {
char *s = _s; char *s = _s;
ssize_t res;
size_t pos = 0; size_t pos = 0;
ssize_t res;
while (n > pos) { while (n > pos) {
res = (f) (fd, s + pos, n - pos); res = (f) (fd, s + pos, n - pos);
switch (res) { switch (res) {
case -1: case -1:
#ifdef EWOULDBLOCK
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
#else
if (errno == EINTR || errno == EAGAIN) if (errno == EINTR || errno == EAGAIN)
#endif
continue; continue;
return 0;
case 0: case 0:
return (res); errno = EPIPE;
return pos;
default: default:
pos += res; pos += (size_t)res;
} }
} }
return (pos); return (pos);

View File

@ -1,8 +1,7 @@
/* $OpenBSD: atomicio.h,v 1.7 2006/03/25 22:22:42 djm Exp $ */
/* /*
* Copied from OpenSSH 3.6.1p2, required for loginrec.c * Copied from OpenSSH/OpenBSD, required for loginrec.c
*
* $OpenBSD: atomicio.h,v 1.4 2001/06/26 06:32:46 itojun Exp $
* *
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved. * All rights reserved.
@ -28,9 +27,9 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h"
/* /*
* Ensure all of data on socket comes through. f==read || f==write * Ensure all of data on socket comes through. f==read || f==vwrite
*/ */
ssize_t atomicio(ssize_t (*)(), int, void *, size_t); size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
#define vwrite (ssize_t (*)(int, void *, size_t))write

View File

@ -22,33 +22,33 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _AUTH_H_ #ifndef DROPBEAR_AUTH_H_
#define _AUTH_H_ #define DROPBEAR_AUTH_H_
#include "includes.h" #include "includes.h"
#include "signkey.h" #include "signkey.h"
#include "chansession.h" #include "chansession.h"
void svr_authinitialise(); void svr_authinitialise(void);
void cli_authinitialise(); void cli_authinitialise(void);
/* Server functions */ /* Server functions */
void recv_msg_userauth_request(); void recv_msg_userauth_request(void);
void send_msg_userauth_failure(int partial, int incrfail); void send_msg_userauth_failure(int partial, int incrfail);
void send_msg_userauth_success(); void send_msg_userauth_success(void);
void send_msg_userauth_banner(buffer *msg); void send_msg_userauth_banner(const buffer *msg);
void svr_auth_password(); void svr_auth_password(int valid_user);
void svr_auth_pubkey(); void svr_auth_pubkey(int valid_user);
int authkeys_exists(void); int authkeys_exists(void);
void svr_auth_pam(); void svr_auth_pam(int valid_user);
#ifdef ENABLE_SVR_PUBKEY_OPTIONS #if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
int svr_pubkey_allows_agentfwd(); int svr_pubkey_allows_agentfwd(void);
int svr_pubkey_allows_tcpfwd(); int svr_pubkey_allows_tcpfwd(void);
int svr_pubkey_allows_x11fwd(); int svr_pubkey_allows_x11fwd(void);
int svr_pubkey_allows_pty(); int svr_pubkey_allows_pty(void);
void svr_pubkey_set_forced_command(struct ChanSess *chansess); void svr_pubkey_set_forced_command(struct ChanSess *chansess);
void svr_pubkey_options_cleanup(); void svr_pubkey_options_cleanup(void);
int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filename); int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filename);
#else #else
/* no option : success */ /* no option : success */
@ -57,34 +57,34 @@ int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filena
#define svr_pubkey_allows_x11fwd() 1 #define svr_pubkey_allows_x11fwd() 1
#define svr_pubkey_allows_pty() 1 #define svr_pubkey_allows_pty() 1
static inline void svr_pubkey_set_forced_command(struct ChanSess *chansess) { } static inline void svr_pubkey_set_forced_command(struct ChanSess *chansess) { }
static inline void svr_pubkey_options_cleanup() { } static inline void svr_pubkey_options_cleanup(void) { }
#define svr_add_pubkey_options(x,y,z) DROPBEAR_SUCCESS #define svr_add_pubkey_options(x,y,z) DROPBEAR_SUCCESS
#endif #endif
/* Client functions */ /* Client functions */
void recv_msg_userauth_failure(); void recv_msg_userauth_failure(void);
void recv_msg_userauth_success(); void recv_msg_userauth_success(void);
void recv_msg_userauth_specific_60(); void recv_msg_userauth_specific_60(void);
void recv_msg_userauth_pk_ok(); void recv_msg_userauth_pk_ok(void);
void recv_msg_userauth_info_request(); void recv_msg_userauth_info_request(void);
void cli_get_user(); void cli_get_user(void);
void cli_auth_getmethods(); void cli_auth_getmethods(void);
int cli_auth_try(); int cli_auth_try(void);
void recv_msg_userauth_banner(); void recv_msg_userauth_banner(void);
void cli_pubkeyfail(); void cli_pubkeyfail(void);
void cli_auth_password(); void cli_auth_password(void);
int cli_auth_pubkey(); int cli_auth_pubkey(void);
void cli_auth_interactive(); void cli_auth_interactive(void);
char* getpass_or_cancel(char* prompt); char* getpass_or_cancel(const char* prompt);
void cli_auth_pubkey_cleanup(); void cli_auth_pubkey_cleanup(void);
#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */ #define MAX_USERNAME_LEN 100 /* arbitrary for the moment */
#define AUTH_TYPE_NONE 1 #define AUTH_TYPE_NONE 1
#define AUTH_TYPE_PUBKEY 1 << 1 #define AUTH_TYPE_PUBKEY (1 << 1)
#define AUTH_TYPE_PASSWORD 1 << 2 #define AUTH_TYPE_PASSWORD (1 << 2)
#define AUTH_TYPE_INTERACT 1 << 3 #define AUTH_TYPE_INTERACT (1 << 3)
#define AUTH_METHOD_NONE "none" #define AUTH_METHOD_NONE "none"
#define AUTH_METHOD_NONE_LEN 4 #define AUTH_METHOD_NONE_LEN 4
@ -106,12 +106,17 @@ struct AuthState {
unsigned char authtypes; /* Flags indicating which auth types are still unsigned char authtypes; /* Flags indicating which auth types are still
valid */ valid */
unsigned int failcount; /* Number of (failed) authentication attempts.*/ unsigned int failcount; /* Number of (failed) authentication attempts.*/
unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have. Applies for unsigned int authdone; /* 0 if we haven't authed, 1 if we have. Applies for
client and server (though has differing client and server (though has differing
meanings). */ meanings). */
unsigned perm_warn : 1; /* Server only, set if bad permissions on
unsigned int perm_warn; /* Server only, set if bad permissions on
~/.ssh/authorized_keys have already been ~/.ssh/authorized_keys have already been
logged. */ logged. */
unsigned int checkusername_failed; /* Server only, set if checkusername
has already failed */
struct timespec auth_starttime; /* Server only, time of receiving current
SSH_MSG_USERAUTH_REQUEST */
/* These are only used for the server */ /* These are only used for the server */
uid_t pw_uid; uid_t pw_uid;
@ -120,12 +125,12 @@ struct AuthState {
char *pw_shell; char *pw_shell;
char *pw_name; char *pw_name;
char *pw_passwd; char *pw_passwd;
#ifdef ENABLE_SVR_PUBKEY_OPTIONS #if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
struct PubKeyOptions* pubkey_options; struct PubKeyOptions* pubkey_options;
#endif #endif
}; };
#ifdef ENABLE_SVR_PUBKEY_OPTIONS #if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
struct PubKeyOptions; struct PubKeyOptions;
struct PubKeyOptions { struct PubKeyOptions {
/* Flags */ /* Flags */
@ -134,8 +139,8 @@ struct PubKeyOptions {
int no_x11_forwarding_flag; int no_x11_forwarding_flag;
int no_pty_flag; int no_pty_flag;
/* "command=" option. */ /* "command=" option. */
unsigned char * forced_command; char * forced_command;
}; };
#endif #endif
#endif /* _AUTH_H_ */ #endif /* DROPBEAR_AUTH_H_ */

View File

@ -39,33 +39,49 @@ void m_mp_init(mp_int *mp) {
* on error */ * on error */
void m_mp_init_multi(mp_int *mp, ...) void m_mp_init_multi(mp_int *mp, ...)
{ {
mp_int* cur_arg = mp; mp_int* cur_arg = mp;
va_list args; va_list args;
va_start(args, mp); /* init args to next argument from caller */ va_start(args, mp); /* init args to next argument from caller */
while (cur_arg != NULL) { while (cur_arg != NULL) {
if (mp_init(cur_arg) != MP_OKAY) { if (mp_init(cur_arg) != MP_OKAY) {
dropbear_exit("Mem alloc error"); dropbear_exit("Mem alloc error");
} }
cur_arg = va_arg(args, mp_int*); cur_arg = va_arg(args, mp_int*);
} }
va_end(args); va_end(args);
} }
void m_mp_alloc_init_multi(mp_int **mp, ...) void m_mp_alloc_init_multi(mp_int **mp, ...)
{ {
mp_int** cur_arg = mp; mp_int** cur_arg = mp;
va_list args; va_list args;
va_start(args, mp); /* init args to next argument from caller */ va_start(args, mp); /* init args to next argument from caller */
while (cur_arg != NULL) { while (cur_arg != NULL) {
*cur_arg = m_malloc(sizeof(mp_int)); *cur_arg = m_malloc(sizeof(mp_int));
if (mp_init(*cur_arg) != MP_OKAY) { if (mp_init(*cur_arg) != MP_OKAY) {
dropbear_exit("Mem alloc error"); dropbear_exit("Mem alloc error");
} }
cur_arg = va_arg(args, mp_int**); cur_arg = va_arg(args, mp_int**);
} }
va_end(args); va_end(args);
}
void m_mp_free_multi(mp_int **mp, ...)
{
mp_int** cur_arg = mp;
va_list args;
va_start(args, mp); /* init args to next argument from caller */
while (cur_arg != NULL) {
if (*cur_arg) {
mp_clear(*cur_arg);
}
m_free(*cur_arg);
cur_arg = va_arg(args, mp_int**);
}
va_end(args);
} }
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) { void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {

View File

@ -22,17 +22,17 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _BIGNUM_H_ #ifndef DROPBEAR_BIGNUM_H_
#define _BIGNUM_H_ #define DROPBEAR_BIGNUM_H_
#include "includes.h" #include "dbhelpers.h"
#include "dbutil.h"
void m_mp_init(mp_int *mp); void m_mp_init(mp_int *mp);
void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL; void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL;
void m_mp_alloc_init_multi(mp_int **mp, ...) ATTRIB_SENTINEL; void m_mp_alloc_init_multi(mp_int **mp, ...) ATTRIB_SENTINEL;
void m_mp_free_multi(mp_int **mp, ...) ATTRIB_SENTINEL;
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len); 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, void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
hash_state *hs, mp_int *mp); hash_state *hs, mp_int *mp);
#endif /* _BIGNUM_H_ */ #endif /* DROPBEAR_BIGNUM_H_ */

View File

@ -46,17 +46,15 @@ buffer* buf_new(unsigned int size) {
dropbear_exit("buf->size too big"); dropbear_exit("buf->size too big");
} }
buf = (buffer*)m_malloc(sizeof(buffer)); buf = (buffer*)m_malloc(sizeof(buffer)+size);
if (size > 0) { if (size > 0) {
buf->data = (unsigned char*)m_malloc(size); buf->data = (unsigned char*)buf + sizeof(buffer);
} else { } else {
buf->data = NULL; buf->data = NULL;
} }
buf->size = size; buf->size = size;
buf->pos = 0;
buf->len = 0;
return buf; return buf;
@ -65,12 +63,11 @@ buffer* buf_new(unsigned int size) {
/* free the buffer's data and the buffer itself */ /* free the buffer's data and the buffer itself */
void buf_free(buffer* buf) { void buf_free(buffer* buf) {
m_free(buf->data)
m_free(buf); m_free(buf);
} }
/* overwrite the contents of the buffer to clear it */ /* overwrite the contents of the buffer to clear it */
void buf_burn(buffer* buf) { void buf_burn(const buffer* buf) {
m_burn(buf->data, buf->size); m_burn(buf->data, buf->size);
@ -78,28 +75,31 @@ void buf_burn(buffer* buf) {
/* resize a buffer, pos and len will be repositioned if required when /* resize a buffer, pos and len will be repositioned if required when
* downsizing */ * downsizing */
void buf_resize(buffer *buf, unsigned int newsize) { buffer* buf_resize(buffer *buf, unsigned int newsize) {
if (newsize > BUF_MAX_SIZE) { if (newsize > BUF_MAX_SIZE) {
dropbear_exit("buf->size too big"); 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->size = newsize;
buf->len = MIN(newsize, buf->len); buf->len = MIN(newsize, buf->len);
buf->pos = MIN(newsize, buf->pos); buf->pos = MIN(newsize, buf->pos);
return buf;
} }
/* Create a copy of buf, allocating required memory etc. */ /* Create a copy of buf, allocating required memory etc. */
/* The new buffer is sized the same as the length of the source buffer. */ /* The new buffer is sized the same as the length of the source buffer. */
buffer* buf_newcopy(buffer* buf) { buffer* buf_newcopy(const buffer* buf) {
buffer* ret; buffer* ret;
ret = buf_new(buf->len); ret = buf_new(buf->len);
ret->len = 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; return ret;
} }
@ -109,6 +109,7 @@ void buf_setlen(buffer* buf, unsigned int len) {
dropbear_exit("Bad buf_setlen"); dropbear_exit("Bad buf_setlen");
} }
buf->len = len; buf->len = len;
buf->pos = MIN(buf->pos, buf->len);
} }
/* Increment the length of the buffer */ /* Increment the length of the buffer */
@ -127,7 +128,7 @@ void buf_setpos(buffer* buf, unsigned int pos) {
buf->pos = 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) { void buf_incrwritepos(buffer* buf, unsigned int incr) {
if (incr > BUF_MAX_INCR || buf->pos + incr > buf->size) { if (incr > BUF_MAX_INCR || buf->pos + incr > buf->size) {
dropbear_exit("Bad buf_incrwritepos"); dropbear_exit("Bad buf_incrwritepos");
@ -141,9 +142,10 @@ void buf_incrwritepos(buffer* buf, unsigned int incr) {
/* increment the position by incr, negative values are allowed, to /* increment the position by incr, negative values are allowed, to
* decrement the pos*/ * decrement the pos*/
void buf_incrpos(buffer* buf, int incr) { void buf_incrpos(buffer* buf, int incr) {
if (incr > BUF_MAX_INCR || if (incr > BUF_MAX_INCR
(unsigned int)((int)buf->pos + incr) > buf->len || incr < -BUF_MAX_INCR
|| ((int)buf->pos + incr) < 0) { || (unsigned int)((int)buf->pos + incr) > buf->len
|| ((int)buf->pos + incr) < 0) {
dropbear_exit("Bad buf_incrpos"); dropbear_exit("Bad buf_incrpos");
} }
buf->pos += incr; buf->pos += incr;
@ -182,9 +184,9 @@ void buf_putbyte(buffer* buf, unsigned char val) {
/* returns an in-place pointer to the buffer, checking that /* returns an in-place pointer to the buffer, checking that
* the next len bytes from that position can be used */ * the next len bytes from that position can be used */
unsigned char* buf_getptr(buffer* buf, unsigned int len) { unsigned char* buf_getptr(const buffer* buf, unsigned int len) {
if (buf->pos + len > buf->len) { if (len > BUF_MAX_INCR || buf->pos + len > buf->len) {
dropbear_exit("Bad buf_getptr"); dropbear_exit("Bad buf_getptr");
} }
return &buf->data[buf->pos]; return &buf->data[buf->pos];
@ -192,9 +194,9 @@ unsigned char* buf_getptr(buffer* buf, unsigned int len) {
/* like buf_getptr, but checks against total size, not used length. /* like buf_getptr, but checks against total size, not used length.
* This allows writing past the used length, but not past the size */ * This allows writing past the used length, but not past the size */
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) { unsigned char* buf_getwriteptr(const buffer* buf, unsigned int len) {
if (buf->pos + len > buf->size) { if (len > BUF_MAX_INCR || buf->pos + len > buf->size) {
dropbear_exit("Bad buf_getwriteptr"); dropbear_exit("Bad buf_getwriteptr");
} }
return &buf->data[buf->pos]; return &buf->data[buf->pos];
@ -203,10 +205,11 @@ unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) {
/* Return a null-terminated string, it is malloced, so must be free()ed /* 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 * Note that the string isn't checked for null bytes, hence the retlen
* may be longer than what is returned by strlen */ * 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 int len;
unsigned char* ret; char* ret;
void* src = NULL;
len = buf_getint(buf); len = buf_getint(buf);
if (len > MAX_STRING_LEN) { if (len > MAX_STRING_LEN) {
dropbear_exit("String too long"); dropbear_exit("String too long");
@ -215,8 +218,9 @@ unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
if (retlen != NULL) { if (retlen != NULL) {
*retlen = len; *retlen = len;
} }
src = buf_getptr(buf, len);
ret = m_malloc(len+1); ret = m_malloc(len+1);
memcpy(ret, buf_getptr(buf, len), len); memcpy(ret, src, len);
buf_incrpos(buf, len); buf_incrpos(buf, len);
ret[len] = '\0'; ret[len] = '\0';
@ -225,15 +229,15 @@ unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
/* Return a string as a newly allocated buffer */ /* Return a string as a newly allocated buffer */
buffer * buf_getstringbuf(buffer *buf) { buffer * buf_getstringbuf(buffer *buf) {
buffer *ret; buffer *ret = NULL;
unsigned char* str; unsigned int len = buf_getint(buf);
unsigned int len; if (len > MAX_STRING_LEN) {
str = buf_getstring(buf, &len); dropbear_exit("String too long");
ret = m_malloc(sizeof(*ret)); }
ret->data = str; ret = buf_new(len);
ret->len = len; memcpy(buf_getwriteptr(ret, len), buf_getptr(buf, len), len);
ret->size = len; buf_incrpos(buf, len);
ret->pos = 0; buf_incrlen(ret, len);
return ret; return ret;
} }
@ -262,16 +266,16 @@ void buf_putint(buffer* buf, int unsigned val) {
} }
/* put a SSH style string into the buffer, increasing buffer len if required */ /* 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_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. */ /* puts an entire buffer as a SSH string. ignore pos of buf_str. */
void buf_putbufstring(buffer *buf, const buffer* 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 /* put the set of len bytes into the buffer, incrementing the pos, increasing

View File

@ -22,14 +22,15 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _BUFFER_H_ #ifndef DROPBEAR_BUFFER_H_
#define _BUFFER_H_ #define DROPBEAR_BUFFER_H_
#include "includes.h" #include "includes.h"
struct buf { 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 char * data;
unsigned int len; /* the used size */ unsigned int len; /* the used size */
unsigned int pos; unsigned int pos;
@ -40,10 +41,11 @@ struct buf {
typedef struct buf buffer; typedef struct buf buffer;
buffer * buf_new(unsigned int size); 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_free(buffer* buf);
void buf_burn(buffer* buf); void buf_burn(const buffer* buf);
buffer* buf_newcopy(buffer* buf); buffer* buf_newcopy(const buffer* buf);
void buf_setlen(buffer* buf, unsigned int len); void buf_setlen(buffer* buf, unsigned int len);
void buf_incrlen(buffer* buf, unsigned int incr); void buf_incrlen(buffer* buf, unsigned int incr);
void buf_setpos(buffer* buf, unsigned int pos); void buf_setpos(buffer* buf, unsigned int pos);
@ -52,17 +54,17 @@ void buf_incrwritepos(buffer* buf, unsigned int incr);
unsigned char buf_getbyte(buffer* buf); unsigned char buf_getbyte(buffer* buf);
unsigned char buf_getbool(buffer* buf); unsigned char buf_getbool(buffer* buf);
void buf_putbyte(buffer* buf, unsigned char val); void buf_putbyte(buffer* buf, unsigned char val);
unsigned char* buf_getptr(buffer* buf, unsigned int len); unsigned char* buf_getptr(const buffer* buf, unsigned int len);
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len); unsigned char* buf_getwriteptr(const 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); buffer * buf_getstringbuf(buffer *buf);
void buf_eatstring(buffer *buf); void buf_eatstring(buffer *buf);
void buf_putint(buffer* buf, unsigned int val); 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_putbufstring(buffer *buf, const buffer* buf_str);
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len); void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
void buf_putmpint(buffer* buf, mp_int * mp); void buf_putmpint(buffer* buf, mp_int * mp);
int buf_getmpint(buffer* buf, mp_int* mp); int buf_getmpint(buffer* buf, mp_int* mp);
unsigned int buf_getint(buffer* buf); unsigned int buf_getint(buffer* buf);
#endif /* _BUFFER_H_ */ #endif /* DROPBEAR_BUFFER_H_ */

View File

@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _CHANNEL_H_ #ifndef DROPBEAR_CHANNEL_H_
#define _CHANNEL_H_ #define DROPBEAR_CHANNEL_H_
#include "includes.h" #include "includes.h"
#include "buffer.h" #include "buffer.h"
@ -69,10 +69,7 @@ struct Channel {
int sent_close, recv_close; int sent_close, recv_close;
int recv_eof, sent_eof; int recv_eof, sent_eof;
/* Set after running the ChanType-specific close hander struct dropbear_progress_connection *conn_pending;
* to ensure we don't run it twice (nor type->checkclose()). */
int close_handler_done;
int initconn; /* used for TCP forwarding, whether the channel has been int initconn; /* used for TCP forwarding, whether the channel has been
fully initialised */ fully initialised */
@ -83,7 +80,7 @@ struct Channel {
int flushing; int flushing;
/* Used by client chansession to handle ~ escaping, NULL ignored otherwise */ /* Used by client chansession to handle ~ escaping, NULL ignored otherwise */
void (*read_mangler)(struct Channel*, unsigned char* bytes, int *len); void (*read_mangler)(const struct Channel*, const unsigned char* bytes, int *len);
const struct ChanType* type; const struct ChanType* type;
@ -92,49 +89,59 @@ struct Channel {
struct ChanType { 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; const char *name;
/* Sets up the channel */
int (*inithandler)(struct Channel*); int (*inithandler)(struct Channel*);
int (*check_close)(struct Channel*); /* Called to check whether a channel should close, separately from the FD being closed.
Used for noticing process exiting */
int (*check_close)(const struct Channel*);
/* Handler for ssh_msg_channel_request */
void (*reqhandler)(struct Channel*); void (*reqhandler)(struct Channel*);
void (*closehandler)(struct Channel*); /* Called prior to sending ssh_msg_channel_close, used for sending exit status */
void (*closehandler)(const struct Channel*);
/* Frees resources, called just prior to channel being removed */
void (*cleanup)(const 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 chaninitialise(const struct ChanType *chantypes[]);
void chancleanup(); void chancleanup(void);
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); void channelio(const fd_set *readfd, const fd_set *writefd);
struct Channel* getchannel(); struct Channel* getchannel(void);
/* Returns an arbitrary channel that is in a ready state - not /* Returns an arbitrary channel that is in a ready state - not
being initialised and no EOF in either direction. NULL if none. */ being initialised and no EOF in either direction. NULL if none. */
struct Channel* get_any_ready_channel(); struct Channel* get_any_ready_channel(void);
void recv_msg_channel_open(); void recv_msg_channel_open(void);
void recv_msg_channel_request(); void recv_msg_channel_request(void);
void send_msg_channel_failure(struct Channel *channel); void send_msg_channel_failure(const struct Channel *channel);
void send_msg_channel_success(struct Channel *channel); void send_msg_channel_success(const struct Channel *channel);
void recv_msg_channel_data(); void recv_msg_channel_data(void);
void recv_msg_channel_extended_data(); void recv_msg_channel_extended_data(void);
void recv_msg_channel_window_adjust(); void recv_msg_channel_window_adjust(void);
void recv_msg_channel_close(); void recv_msg_channel_close(void);
void recv_msg_channel_eof(); void recv_msg_channel_eof(void);
void common_recv_msg_channel_data(struct Channel *channel, int fd, void common_recv_msg_channel_data(struct Channel *channel, int fd,
circbuffer * buf); circbuffer * buf);
#ifdef DROPBEAR_CLIENT #if DROPBEAR_CLIENT
extern const struct ChanType clichansess; extern const struct ChanType clichansess;
#endif #endif
#if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT) #if DROPBEAR_LISTENERS || DROPBEAR_CLIENT
int send_msg_channel_open_init(int fd, const struct ChanType *type); int send_msg_channel_open_init(int fd, const struct ChanType *type);
void recv_msg_channel_open_confirmation(); void recv_msg_channel_open_confirmation(void);
void recv_msg_channel_open_failure(); void recv_msg_channel_open_failure(void);
#endif #endif
void start_send_channel_request(struct Channel *channel, unsigned char *type); void start_send_channel_request(const struct Channel *channel, const char *type);
void send_msg_request_success(); void send_msg_request_success(void);
void send_msg_request_failure(); void send_msg_request_failure(void);
#endif /* _CHANNEL_H_ */ #endif /* DROPBEAR_CHANNEL_H_ */

View File

@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _CHANSESSION_H_ #ifndef DROPBEAR_CHANSESSION_H_
#define _CHANSESSION_H_ #define DROPBEAR_CHANSESSION_H_
#include "loginrec.h" #include "loginrec.h"
#include "channel.h" #include "channel.h"
@ -39,14 +39,14 @@ struct exitinfo {
struct ChanSess { struct ChanSess {
unsigned char * cmd; /* command to exec */ char * cmd; /* command to exec */
pid_t pid; /* child process pid */ pid_t pid; /* child process pid */
/* pty details */ /* pty details */
int master; /* the master terminal fd*/ int master; /* the master terminal fd*/
int slave; int slave;
unsigned char * tty; char * tty;
unsigned char * term; char * term;
/* exit details */ /* exit details */
struct exitinfo exit; struct exitinfo exit;
@ -58,7 +58,7 @@ struct ChanSess {
/* Used to set $SSH_CLIENT in the child session. */ /* Used to set $SSH_CLIENT in the child session. */
char *client_string; char *client_string;
#ifndef DISABLE_X11FWD #if DROPBEAR_X11FWD
struct Listener * x11listener; struct Listener * x11listener;
int x11port; int x11port;
char * x11authprot; char * x11authprot;
@ -67,13 +67,13 @@ struct ChanSess {
unsigned char x11singleconn; unsigned char x11singleconn;
#endif #endif
#ifdef ENABLE_SVR_AGENTFWD #if DROPBEAR_SVR_AGENTFWD
struct Listener * agentlistener; struct Listener * agentlistener;
char * agentfile; char * agentfile;
char * agentdir; char * agentdir;
#endif #endif
#ifdef ENABLE_SVR_PUBKEY_OPTIONS #if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
char *original_command; char *original_command;
#endif #endif
}; };
@ -86,14 +86,15 @@ struct ChildPid {
void addnewvar(const char* param, const char* var); void addnewvar(const char* param, const char* var);
void cli_send_chansess_request(); void cli_send_chansess_request(void);
void cli_tty_cleanup(); void cli_tty_cleanup(void);
void cli_chansess_winchange(); void cli_chansess_winchange(void);
#ifdef ENABLE_CLI_NETCAT #if DROPBEAR_CLI_NETCAT
void cli_send_netcat_request(); void cli_send_netcat_request(void);
#endif #endif
void svr_chansessinitialise(); void svr_chansessinitialise(void);
void svr_chansess_checksignal(void);
extern const struct ChanType svrchansess; extern const struct ChanType svrchansess;
struct SigMap { struct SigMap {
@ -103,4 +104,4 @@ struct SigMap {
extern const struct SigMap signames[]; extern const struct SigMap signames[];
#endif /* _CHANSESSION_H_ */ #endif /* DROPBEAR_CHANSESSION_H_ */

View File

@ -37,9 +37,8 @@ circbuffer * cbuf_new(unsigned int size) {
} }
cbuf = (circbuffer*)m_malloc(sizeof(circbuffer)); cbuf = (circbuffer*)m_malloc(sizeof(circbuffer));
if (size > 0) { /* data is malloced on first write */
cbuf->data = (unsigned char*)m_malloc(size); cbuf->data = NULL;
}
cbuf->used = 0; cbuf->used = 0;
cbuf->readpos = 0; cbuf->readpos = 0;
cbuf->writepos = 0; cbuf->writepos = 0;
@ -50,41 +49,26 @@ circbuffer * cbuf_new(unsigned int size) {
void cbuf_free(circbuffer * cbuf) { void cbuf_free(circbuffer * cbuf) {
m_burn(cbuf->data, cbuf->size); if (cbuf->data) {
m_free(cbuf->data); m_burn(cbuf->data, cbuf->size);
m_free(cbuf->data);
}
m_free(cbuf); m_free(cbuf);
} }
unsigned int cbuf_getused(circbuffer * cbuf) { unsigned int cbuf_getused(const circbuffer * cbuf) {
return cbuf->used; return cbuf->used;
} }
unsigned int cbuf_getavail(circbuffer * cbuf) { unsigned int cbuf_getavail(const circbuffer * cbuf) {
return cbuf->size - cbuf->used; return cbuf->size - cbuf->used;
} }
unsigned int cbuf_readlen(circbuffer *cbuf) { unsigned int cbuf_writelen(const 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); dropbear_assert(cbuf->used <= cbuf->size);
dropbear_assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size); dropbear_assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
@ -102,12 +86,19 @@ unsigned int cbuf_writelen(circbuffer *cbuf) {
return cbuf->size - cbuf->writepos; return cbuf->size - cbuf->writepos;
} }
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) { void cbuf_readptrs(const circbuffer *cbuf,
if (len > cbuf_readlen(cbuf)) { unsigned char **p1, unsigned int *len1,
dropbear_exit("Bad cbuf read"); unsigned char **p2, unsigned int *len2) {
} *p1 = &cbuf->data[cbuf->readpos];
*len1 = MIN(cbuf->used, cbuf->size - cbuf->readpos);
return &cbuf->data[cbuf->readpos]; if (*len1 < cbuf->used) {
*p2 = cbuf->data;
*len2 = cbuf->used - *len1;
} else {
*p2 = NULL;
*len2 = 0;
}
} }
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) { 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"); dropbear_exit("Bad cbuf write");
} }
if (!cbuf->data) {
/* lazy allocation */
cbuf->data = (unsigned char*)m_malloc(cbuf->size);
}
return &cbuf->data[cbuf->writepos]; 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) { void cbuf_incrread(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_readlen(cbuf)) {
dropbear_exit("Bad cbuf read");
}
dropbear_assert(cbuf->used >= len); dropbear_assert(cbuf->used >= len);
cbuf->used -= len; cbuf->used -= len;
cbuf->readpos = (cbuf->readpos + len) % cbuf->size; cbuf->readpos = (cbuf->readpos + len) % cbuf->size;

View File

@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _CIRCBUFFER_H_ #ifndef DROPBEAR_CIRCBUFFER_H_
#define _CIRCBUFFER_H_ #define DROPBEAR_CIRCBUFFER_H_
struct circbuf { struct circbuf {
unsigned int size; unsigned int size;
@ -38,12 +38,14 @@ typedef struct circbuf circbuffer;
circbuffer * cbuf_new(unsigned int size); circbuffer * cbuf_new(unsigned int size);
void cbuf_free(circbuffer * cbuf); void cbuf_free(circbuffer * cbuf);
unsigned int cbuf_getused(circbuffer * cbuf); /* how much data stored */ unsigned int cbuf_getused(const circbuffer * cbuf); /* how much data stored */
unsigned int cbuf_getavail(circbuffer * cbuf); /* how much we can write */ unsigned int cbuf_getavail(const circbuffer * cbuf); /* how much we can write */
unsigned int cbuf_readlen(circbuffer *cbuf); /* max linear read len */ unsigned int cbuf_writelen(const circbuffer *cbuf); /* max linear write 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(const circbuffer *cbuf,
unsigned char **p1, unsigned int *len1,
unsigned char **p2, unsigned int *len2);
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len); unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len);
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len); void cbuf_incrwrite(circbuffer *cbuf, unsigned int len);
void cbuf_incrread(circbuffer *cbuf, unsigned int len); void cbuf_incrread(circbuffer *cbuf, unsigned int len);

View File

@ -24,7 +24,7 @@
#include "includes.h" #include "includes.h"
#ifdef ENABLE_CLI_AGENTFWD #if DROPBEAR_CLI_AGENTFWD
#include "agentfwd.h" #include "agentfwd.h"
#include "session.h" #include "session.h"
@ -52,6 +52,7 @@ const struct ChanType cli_chan_agent = {
new_agent_chan, new_agent_chan,
NULL, NULL,
NULL, NULL,
NULL,
NULL NULL
}; };
@ -108,7 +109,7 @@ static int new_agent_chan(struct Channel * channel) {
data Any data, depending on packet type. Encoding as in the ssh packet data Any data, depending on packet type. Encoding as in the ssh packet
protocol. protocol.
*/ */
static buffer * agent_request(unsigned char type, buffer *data) { static buffer * agent_request(unsigned char type, const buffer *data) {
buffer * payload = NULL; buffer * payload = NULL;
buffer * inbuf = NULL; buffer * inbuf = NULL;
@ -130,7 +131,7 @@ static buffer * agent_request(unsigned char type, buffer *data) {
} }
buf_setpos(payload, 0); buf_setpos(payload, 0);
ret = atomicio(write, fd, buf_getptr(payload, payload->len), payload->len); ret = atomicio(vwrite, fd, buf_getptr(payload, payload->len), payload->len);
if ((size_t)ret != payload->len) { if ((size_t)ret != payload->len) {
TRACE(("write failed fd %d for agent_request, %s", fd, strerror(errno))) TRACE(("write failed fd %d for agent_request, %s", fd, strerror(errno)))
goto out; goto out;
@ -155,7 +156,7 @@ static buffer * agent_request(unsigned char type, buffer *data) {
goto out; goto out;
} }
buf_resize(inbuf, readlen); inbuf = buf_resize(inbuf, readlen);
buf_setpos(inbuf, 0); buf_setpos(inbuf, 0);
ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen); ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
if ((size_t)ret != readlen) { if ((size_t)ret != readlen) {
@ -210,13 +211,14 @@ static void agent_get_key_list(m_list * ret_list)
ret = buf_get_pub_key(key_buf, pubkey, &key_type); ret = buf_get_pub_key(key_buf, pubkey, &key_type);
buf_free(key_buf); buf_free(key_buf);
if (ret != DROPBEAR_SUCCESS) { if (ret != DROPBEAR_SUCCESS) {
/* This is slack, properly would cleanup vars etc */ TRACE(("Skipping bad/unknown type pubkey from agent"));
dropbear_exit("Bad pubkey received from agent"); sign_key_free(pubkey);
} } else {
pubkey->type = key_type; pubkey->type = key_type;
pubkey->source = SIGNKEY_SOURCE_AGENT; pubkey->source = SIGNKEY_SOURCE_AGENT;
list_append(ret_list, pubkey); list_append(ret_list, pubkey);
}
/* We'll ignore the comment for now. might want it later.*/ /* We'll ignore the comment for now. might want it later.*/
buf_eatstring(inbuf); buf_eatstring(inbuf);
@ -229,7 +231,7 @@ out:
} }
} }
void cli_setup_agent(struct Channel *channel) { void cli_setup_agent(const struct Channel *channel) {
if (!getenv("SSH_AUTH_SOCK")) { if (!getenv("SSH_AUTH_SOCK")) {
return; return;
} }
@ -253,7 +255,7 @@ void cli_load_agent_keys(m_list *ret_list) {
} }
void agent_buf_sign(buffer *sigblob, sign_key *key, void agent_buf_sign(buffer *sigblob, sign_key *key,
buffer *data_buf) { const buffer *data_buf) {
buffer *request_data = NULL; buffer *request_data = NULL;
buffer *response = NULL; buffer *response = NULL;
unsigned int siglen; unsigned int siglen;

View File

@ -43,15 +43,15 @@ void cli_auth_getmethods() {
TRACE(("enter cli_auth_getmethods")) TRACE(("enter cli_auth_getmethods"))
CHECKCLEARTOWRITE(); CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST); 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)); strlen(cli_opts.username));
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION, buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
SSH_SERVICE_CONNECTION_LEN); SSH_SERVICE_CONNECTION_LEN);
buf_putstring(ses.writepayload, "none", 4); /* 'none' method */ buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
encrypt_packet(); encrypt_packet();
#ifdef DROPBEAR_CLI_IMMEDIATE_AUTH #if DROPBEAR_CLI_IMMEDIATE_AUTH
/* We can't haven't two auth requests in-flight with delayed zlib mode /* We can't haven't two auth requests in-flight with delayed zlib mode
since if the first one succeeds then the remote side will since if the first one succeeds then the remote side will
expect the second one to be compressed. expect the second one to be compressed.
@ -60,9 +60,11 @@ void cli_auth_getmethods() {
*/ */
if (ses.keys->trans.algo_comp != DROPBEAR_COMP_ZLIB_DELAY) { if (ses.keys->trans.algo_comp != DROPBEAR_COMP_ZLIB_DELAY) {
ses.authstate.authtypes = AUTH_TYPE_PUBKEY; ses.authstate.authtypes = AUTH_TYPE_PUBKEY;
#if DROPBEAR_USE_PASSWORD_ENV
if (getenv(DROPBEAR_PASSWORD_ENV)) { if (getenv(DROPBEAR_PASSWORD_ENV)) {
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT; ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT;
} }
#endif
if (cli_auth_try() == DROPBEAR_SUCCESS) { if (cli_auth_try() == DROPBEAR_SUCCESS) {
TRACE(("skipped initial none auth query")) TRACE(("skipped initial none auth query"))
/* Note that there will be two auth responses in-flight */ /* Note that there will be two auth responses in-flight */
@ -75,9 +77,10 @@ void cli_auth_getmethods() {
void recv_msg_userauth_banner() { void recv_msg_userauth_banner() {
unsigned char* banner = NULL; char* banner = NULL;
unsigned int bannerlen; unsigned int bannerlen;
unsigned int i, linecount; unsigned int i, linecount;
int truncated = 0;
TRACE(("enter recv_msg_userauth_banner")) TRACE(("enter recv_msg_userauth_banner"))
if (ses.authstate.authdone) { if (ses.authstate.authdone) {
@ -90,26 +93,29 @@ void recv_msg_userauth_banner() {
if (bannerlen > MAX_BANNER_SIZE) { if (bannerlen > MAX_BANNER_SIZE) {
TRACE(("recv_msg_userauth_banner: bannerlen too long: %d", bannerlen)) TRACE(("recv_msg_userauth_banner: bannerlen too long: %d", bannerlen))
goto out; truncated = 1;
} } else {
cleantext(banner);
cleantext(banner); /* Limit to 24 lines */
linecount = 1;
/* Limit to 25 lines */ for (i = 0; i < bannerlen; i++) {
linecount = 1; if (banner[i] == '\n') {
for (i = 0; i < bannerlen; i++) { if (linecount >= MAX_BANNER_LINES) {
if (banner[i] == '\n') { banner[i] = '\0';
if (linecount >= MAX_BANNER_LINES) { truncated = 1;
banner[i] = '\0'; break;
break; }
linecount++;
} }
linecount++;
} }
fprintf(stderr, "%s\n", banner);
} }
fprintf(stderr, "%s\n", banner); if (truncated) {
fprintf(stderr, "[Banner from the server is too long]\n");
}
out:
m_free(banner); m_free(banner);
TRACE(("leave recv_msg_userauth_banner")) TRACE(("leave recv_msg_userauth_banner"))
} }
@ -121,21 +127,21 @@ out:
* SSH_MSG_USERAUTH_INFO_REQUEST. */ * SSH_MSG_USERAUTH_INFO_REQUEST. */
void recv_msg_userauth_specific_60() { void recv_msg_userauth_specific_60() {
#ifdef ENABLE_CLI_PUBKEY_AUTH #if DROPBEAR_CLI_PUBKEY_AUTH
if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) { if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
recv_msg_userauth_pk_ok(); recv_msg_userauth_pk_ok();
return; return;
} }
#endif #endif
#ifdef ENABLE_CLI_INTERACT_AUTH #if DROPBEAR_CLI_INTERACT_AUTH
if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT) { if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT) {
recv_msg_userauth_info_request(); recv_msg_userauth_info_request();
return; return;
} }
#endif #endif
#ifdef ENABLE_CLI_PASSWORD_AUTH #if DROPBEAR_CLI_PASSWORD_AUTH
if (cli_ses.lastauthtype == AUTH_TYPE_PASSWORD) { if (cli_ses.lastauthtype == AUTH_TYPE_PASSWORD) {
/* Eventually there could be proper password-changing /* Eventually there could be proper password-changing
* support. However currently few servers seem to * support. However currently few servers seem to
@ -151,8 +157,8 @@ void recv_msg_userauth_specific_60() {
void recv_msg_userauth_failure() { void recv_msg_userauth_failure() {
unsigned char * methods = NULL; char * methods = NULL;
unsigned char * tok = NULL; char * tok = NULL;
unsigned int methlen = 0; unsigned int methlen = 0;
unsigned int partial = 0; unsigned int partial = 0;
unsigned int i = 0; unsigned int i = 0;
@ -179,7 +185,7 @@ void recv_msg_userauth_failure() {
TRACE(("leave recv_msg_userauth_failure, ignored response, state set to USERAUTH_REQ_SENT")); TRACE(("leave recv_msg_userauth_failure, ignored response, state set to USERAUTH_REQ_SENT"));
return; return;
} else { } else {
#ifdef ENABLE_CLI_PUBKEY_AUTH #if DROPBEAR_CLI_PUBKEY_AUTH
/* If it was a pubkey auth request, we should cross that key /* If it was a pubkey auth request, we should cross that key
* off the list. */ * off the list. */
if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) { if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
@ -187,7 +193,7 @@ void recv_msg_userauth_failure() {
} }
#endif #endif
#ifdef ENABLE_CLI_INTERACT_AUTH #if DROPBEAR_CLI_INTERACT_AUTH
/* If we get a failure message for keyboard interactive without /* If we get a failure message for keyboard interactive without
* receiving any request info packet, then we don't bother trying * receiving any request info packet, then we don't bother trying
* keyboard interactive again */ * keyboard interactive again */
@ -227,19 +233,19 @@ void recv_msg_userauth_failure() {
for (i = 0; i <= methlen; i++) { for (i = 0; i <= methlen; i++) {
if (methods[i] == '\0') { if (methods[i] == '\0') {
TRACE(("auth method '%s'", tok)) TRACE(("auth method '%s'", tok))
#ifdef ENABLE_CLI_PUBKEY_AUTH #if DROPBEAR_CLI_PUBKEY_AUTH
if (strncmp(AUTH_METHOD_PUBKEY, tok, if (strncmp(AUTH_METHOD_PUBKEY, tok,
AUTH_METHOD_PUBKEY_LEN) == 0) { AUTH_METHOD_PUBKEY_LEN) == 0) {
ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
} }
#endif #endif
#ifdef ENABLE_CLI_INTERACT_AUTH #if DROPBEAR_CLI_INTERACT_AUTH
if (strncmp(AUTH_METHOD_INTERACT, tok, if (strncmp(AUTH_METHOD_INTERACT, tok,
AUTH_METHOD_INTERACT_LEN) == 0) { AUTH_METHOD_INTERACT_LEN) == 0) {
ses.authstate.authtypes |= AUTH_TYPE_INTERACT; ses.authstate.authtypes |= AUTH_TYPE_INTERACT;
} }
#endif #endif
#ifdef ENABLE_CLI_PASSWORD_AUTH #if DROPBEAR_CLI_PASSWORD_AUTH
if (strncmp(AUTH_METHOD_PASSWORD, tok, if (strncmp(AUTH_METHOD_PASSWORD, tok,
AUTH_METHOD_PASSWORD_LEN) == 0) { AUTH_METHOD_PASSWORD_LEN) == 0) {
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
@ -267,7 +273,7 @@ void recv_msg_userauth_success() {
cli_ses.state = USERAUTH_SUCCESS_RCVD; cli_ses.state = USERAUTH_SUCCESS_RCVD;
cli_ses.lastauthtype = AUTH_TYPE_NONE; cli_ses.lastauthtype = AUTH_TYPE_NONE;
#ifdef ENABLE_CLI_PUBKEY_AUTH #if DROPBEAR_CLI_PUBKEY_AUTH
cli_auth_pubkey_cleanup(); cli_auth_pubkey_cleanup();
#endif #endif
} }
@ -281,14 +287,14 @@ int cli_auth_try() {
/* Order to try is pubkey, interactive, password. /* Order to try is pubkey, interactive, password.
* As soon as "finished" is set for one, we don't do any more. */ * As soon as "finished" is set for one, we don't do any more. */
#ifdef ENABLE_CLI_PUBKEY_AUTH #if DROPBEAR_CLI_PUBKEY_AUTH
if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) { if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
finished = cli_auth_pubkey(); finished = cli_auth_pubkey();
cli_ses.lastauthtype = AUTH_TYPE_PUBKEY; cli_ses.lastauthtype = AUTH_TYPE_PUBKEY;
} }
#endif #endif
#ifdef ENABLE_CLI_PASSWORD_AUTH #if DROPBEAR_CLI_PASSWORD_AUTH
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_PASSWORD)) { if (!finished && (ses.authstate.authtypes & AUTH_TYPE_PASSWORD)) {
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) { if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n"); fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n");
@ -300,7 +306,7 @@ int cli_auth_try() {
} }
#endif #endif
#ifdef ENABLE_CLI_INTERACT_AUTH #if DROPBEAR_CLI_INTERACT_AUTH
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) { if (!finished && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) {
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) { if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n"); fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n");
@ -324,19 +330,20 @@ int cli_auth_try() {
return DROPBEAR_FAILURE; return DROPBEAR_FAILURE;
} }
#if DROPBEAR_CLI_PASSWORD_AUTH || DROPBEAR_CLI_INTERACT_AUTH
/* A helper for getpass() that exits if the user cancels. The returned /* A helper for getpass() that exits if the user cancels. The returned
* password is statically allocated by getpass() */ * password is statically allocated by getpass() */
char* getpass_or_cancel(char* prompt) char* getpass_or_cancel(const char* prompt)
{ {
char* password = NULL; char* password = NULL;
#ifdef DROPBEAR_PASSWORD_ENV #if DROPBEAR_USE_PASSWORD_ENV
/* Password provided in an environment var */ /* Password provided in an environment var */
password = getenv(DROPBEAR_PASSWORD_ENV); password = getenv(DROPBEAR_PASSWORD_ENV);
if (password) if (password)
{ {
return password; return password;
} }
#endif #endif
password = getpass(prompt); password = getpass(prompt);
@ -347,3 +354,4 @@ char* getpass_or_cancel(char* prompt)
} }
return password; return password;
} }
#endif

View File

@ -29,12 +29,12 @@
#include "ssh.h" #include "ssh.h"
#include "runopts.h" #include "runopts.h"
#ifdef ENABLE_CLI_INTERACT_AUTH #if DROPBEAR_CLI_INTERACT_AUTH
static unsigned char* get_response(unsigned char* prompt) static char* get_response(char* prompt)
{ {
FILE* tty = NULL; FILE* tty = NULL;
unsigned char* response = NULL; char* response = NULL;
/* not a password, but a reasonable limit */ /* not a password, but a reasonable limit */
char buf[DROPBEAR_MAX_CLI_PASS]; char buf[DROPBEAR_MAX_CLI_PASS];
char* ret = NULL; char* ret = NULL;
@ -50,13 +50,13 @@ static unsigned char* get_response(unsigned char* prompt)
} }
if (ret == NULL) { if (ret == NULL) {
response = (unsigned char*)m_strdup(""); response = m_strdup("");
} else { } else {
unsigned int buflen = strlen(buf); unsigned int buflen = strlen(buf);
/* fgets includes newlines */ /* fgets includes newlines */
if (buflen > 0 && buf[buflen-1] == '\n') if (buflen > 0 && buf[buflen-1] == '\n')
buf[buflen-1] = '\0'; buf[buflen-1] = '\0';
response = (unsigned char*)m_strdup(buf); response = m_strdup(buf);
} }
m_burn(buf, sizeof(buf)); m_burn(buf, sizeof(buf));
@ -66,14 +66,14 @@ static unsigned char* get_response(unsigned char* prompt)
void recv_msg_userauth_info_request() { void recv_msg_userauth_info_request() {
unsigned char *name = NULL; char *name = NULL;
unsigned char *instruction = NULL; char *instruction = NULL;
unsigned int num_prompts = 0; unsigned int num_prompts = 0;
unsigned int i; unsigned int i;
unsigned char *prompt = NULL; char *prompt = NULL;
unsigned int echo = 0; unsigned int echo = 0;
unsigned char *response = NULL; char *response = NULL;
TRACE(("enter recv_msg_recv_userauth_info_request")) TRACE(("enter recv_msg_recv_userauth_info_request"))
@ -121,7 +121,7 @@ void recv_msg_userauth_info_request() {
echo = buf_getbool(ses.payload); echo = buf_getbool(ses.payload);
if (!echo) { if (!echo) {
unsigned char* p = getpass_or_cancel(prompt); char* p = getpass_or_cancel(prompt);
response = m_strdup(p); response = m_strdup(p);
m_burn(p, strlen(p)); m_burn(p, strlen(p));
} else { } else {
@ -153,7 +153,7 @@ void cli_auth_interactive() {
strlen(cli_opts.username)); strlen(cli_opts.username));
/* service name */ /* service name */
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION, buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
SSH_SERVICE_CONNECTION_LEN); SSH_SERVICE_CONNECTION_LEN);
/* method */ /* method */
@ -172,4 +172,4 @@ void cli_auth_interactive() {
TRACE(("leave cli_auth_interactive")) TRACE(("leave cli_auth_interactive"))
} }
#endif /* ENABLE_CLI_INTERACT_AUTH */ #endif /* DROPBEAR_CLI_INTERACT_AUTH */

View File

@ -29,9 +29,9 @@
#include "ssh.h" #include "ssh.h"
#include "runopts.h" #include "runopts.h"
#ifdef ENABLE_CLI_PASSWORD_AUTH #if DROPBEAR_CLI_PASSWORD_AUTH
#ifdef ENABLE_CLI_ASKPASS_HELPER #if DROPBEAR_CLI_ASKPASS_HELPER
/* Returns 1 if we want to use the askpass program, 0 otherwise */ /* Returns 1 if we want to use the askpass program, 0 otherwise */
static int want_askpass() static int want_askpass()
{ {
@ -113,7 +113,7 @@ static char *gui_getpass(const char *prompt) {
TRACE(("leave gui_getpass")) TRACE(("leave gui_getpass"))
return(buf); return(buf);
} }
#endif /* ENABLE_CLI_ASKPASS_HELPER */ #endif /* DROPBEAR_CLI_ASKPASS_HELPER */
void cli_auth_password() { void cli_auth_password() {
@ -125,7 +125,7 @@ void cli_auth_password() {
snprintf(prompt, sizeof(prompt), "%s@%s's password: ", snprintf(prompt, sizeof(prompt), "%s@%s's password: ",
cli_opts.username, cli_opts.remotehost); cli_opts.username, cli_opts.remotehost);
#ifdef ENABLE_CLI_ASKPASS_HELPER #if DROPBEAR_CLI_ASKPASS_HELPER
if (want_askpass()) if (want_askpass())
{ {
password = gui_getpass(prompt); password = gui_getpass(prompt);
@ -143,10 +143,10 @@ void cli_auth_password() {
buf_putstring(ses.writepayload, cli_opts.username, buf_putstring(ses.writepayload, cli_opts.username,
strlen(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); SSH_SERVICE_CONNECTION_LEN);
buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD, buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD,
AUTH_METHOD_PASSWORD_LEN); AUTH_METHOD_PASSWORD_LEN);
buf_putbyte(ses.writepayload, 0); /* FALSE - so says the spec */ buf_putbyte(ses.writepayload, 0); /* FALSE - so says the spec */
@ -158,4 +158,4 @@ void cli_auth_password() {
TRACE(("leave cli_auth_password")) TRACE(("leave cli_auth_password"))
} }
#endif /* ENABLE_CLI_PASSWORD_AUTH */ #endif /* DROPBEAR_CLI_PASSWORD_AUTH */

View File

@ -32,7 +32,7 @@
#include "auth.h" #include "auth.h"
#include "agentfwd.h" #include "agentfwd.h"
#ifdef ENABLE_CLI_PUBKEY_AUTH #if DROPBEAR_CLI_PUBKEY_AUTH
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign); static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
/* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request. /* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request.
@ -58,7 +58,7 @@ void recv_msg_userauth_pk_ok() {
buffer* keybuf = NULL; buffer* keybuf = NULL;
char* algotype = NULL; char* algotype = NULL;
unsigned int algolen; unsigned int algolen;
int keytype; enum signkey_type keytype;
unsigned int remotelen; unsigned int remotelen;
TRACE(("enter recv_msg_userauth_pk_ok")) TRACE(("enter recv_msg_userauth_pk_ok"))
@ -121,8 +121,8 @@ void recv_msg_userauth_pk_ok() {
} }
void cli_buf_put_sign(buffer* buf, sign_key *key, int type, void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
buffer *data_buf) { const buffer *data_buf) {
#ifdef ENABLE_CLI_AGENTFWD #if DROPBEAR_CLI_AGENTFWD
if (key->source == SIGNKEY_SOURCE_AGENT) { if (key->source == SIGNKEY_SOURCE_AGENT) {
/* Format the agent signature ourselves, as buf_put_sign would. */ /* Format the agent signature ourselves, as buf_put_sign would. */
buffer *sigblob; buffer *sigblob;
@ -131,7 +131,7 @@ void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
buf_putbufstring(buf, sigblob); buf_putbufstring(buf, sigblob);
buf_free(sigblob); buf_free(sigblob);
} else } else
#endif /* ENABLE_CLI_AGENTFWD */ #endif /* DROPBEAR_CLI_AGENTFWD */
{ {
buf_put_sign(buf, key, type, data_buf); buf_put_sign(buf, key, type, data_buf);
} }
@ -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) { static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
const char *algoname = NULL; const char *algoname = NULL;
int algolen; unsigned int algolen;
buffer* sigbuf = NULL; buffer* sigbuf = NULL;
TRACE(("enter send_msg_userauth_pubkey")) 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, buf_putstring(ses.writepayload, cli_opts.username,
strlen(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); SSH_SERVICE_CONNECTION_LEN);
buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY, buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
AUTH_METHOD_PUBKEY_LEN); AUTH_METHOD_PUBKEY_LEN);
buf_putbyte(ses.writepayload, realsign); buf_putbyte(ses.writepayload, realsign);
@ -185,7 +185,7 @@ int cli_auth_pubkey() {
TRACE(("enter cli_auth_pubkey")) TRACE(("enter cli_auth_pubkey"))
#ifdef ENABLE_CLI_AGENTFWD #if DROPBEAR_CLI_AGENTFWD
if (!cli_opts.agent_keys_loaded) { if (!cli_opts.agent_keys_loaded) {
/* get the list of available keys from the agent */ /* get the list of available keys from the agent */
cli_load_agent_keys(cli_opts.privkeys); cli_load_agent_keys(cli_opts.privkeys);
@ -209,7 +209,7 @@ int cli_auth_pubkey() {
void cli_auth_pubkey_cleanup() { void cli_auth_pubkey_cleanup() {
#ifdef ENABLE_CLI_AGENTFWD #if DROPBEAR_CLI_AGENTFWD
m_close(cli_opts.agent_fd); m_close(cli_opts.agent_fd);
cli_opts.agent_fd = -1; cli_opts.agent_fd = -1;
#endif #endif

View File

@ -35,15 +35,15 @@
#include "chansession.h" #include "chansession.h"
#include "agentfwd.h" #include "agentfwd.h"
static void cli_closechansess(struct Channel *channel); static void cli_closechansess(const struct Channel *channel);
static int cli_initchansess(struct Channel *channel); static int cli_initchansess(struct Channel *channel);
static void cli_chansessreq(struct Channel *channel); static void cli_chansessreq(struct Channel *channel);
static void send_chansess_pty_req(struct Channel *channel); static void send_chansess_pty_req(const struct Channel *channel);
static void send_chansess_shell_req(struct Channel *channel); static void send_chansess_shell_req(const struct Channel *channel);
static void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len); static void cli_escape_handler(const struct Channel *channel, const unsigned char* buf, int *len);
static int cli_init_netcat(struct Channel *channel); static int cli_init_netcat(struct Channel *channel);
static void cli_tty_setup(); static void cli_tty_setup(void);
const struct ChanType clichansess = { const struct ChanType clichansess = {
0, /* sepfds */ 0, /* sepfds */
@ -52,11 +52,12 @@ const struct ChanType clichansess = {
NULL, /* checkclosehandler */ NULL, /* checkclosehandler */
cli_chansessreq, /* reqhandler */ cli_chansessreq, /* reqhandler */
cli_closechansess, /* closehandler */ cli_closechansess, /* closehandler */
NULL, /* cleanup */
}; };
static void cli_chansessreq(struct Channel *channel) { static void cli_chansessreq(struct Channel *channel) {
unsigned char* type = NULL; char* type = NULL;
int wantreply; int wantreply;
TRACE(("enter cli_chansessreq")) TRACE(("enter cli_chansessreq"))
@ -83,7 +84,7 @@ out:
/* If the main session goes, we close it up */ /* If the main session goes, we close it up */
static void cli_closechansess(struct Channel *UNUSED(channel)) { static void cli_closechansess(const struct Channel *UNUSED(channel)) {
cli_tty_cleanup(); /* Restore tty modes etc */ cli_tty_cleanup(); /* Restore tty modes etc */
/* This channel hasn't gone yet, so we have > 1 */ /* This channel hasn't gone yet, so we have > 1 */
@ -270,9 +271,9 @@ void cli_chansess_winchange() {
cli_ses.winchange = 0; cli_ses.winchange = 0;
} }
static void send_chansess_pty_req(struct Channel *channel) { static void send_chansess_pty_req(const struct Channel *channel) {
unsigned char* term = NULL; char* term = NULL;
TRACE(("enter send_chansess_pty_req")) TRACE(("enter send_chansess_pty_req"))
@ -303,9 +304,9 @@ static void send_chansess_pty_req(struct Channel *channel) {
TRACE(("leave send_chansess_pty_req")) TRACE(("leave send_chansess_pty_req"))
} }
static void send_chansess_shell_req(struct Channel *channel) { static void send_chansess_shell_req(const struct Channel *channel) {
unsigned char* reqtype = NULL; char* reqtype = NULL;
TRACE(("enter send_chansess_shell_req")) TRACE(("enter send_chansess_shell_req"))
@ -355,7 +356,7 @@ static int cli_initchansess(struct Channel *channel) {
cli_init_stdpipe_sess(channel); cli_init_stdpipe_sess(channel);
#ifdef ENABLE_CLI_AGENTFWD #if DROPBEAR_CLI_AGENTFWD
if (cli_opts.agent_fwd) { if (cli_opts.agent_fwd) {
cli_setup_agent(channel); cli_setup_agent(channel);
} }
@ -379,7 +380,7 @@ static int cli_initchansess(struct Channel *channel) {
return 0; /* Success */ return 0; /* Success */
} }
#ifdef ENABLE_CLI_NETCAT #if DROPBEAR_CLI_NETCAT
static const struct ChanType cli_chan_netcat = { static const struct ChanType cli_chan_netcat = {
0, /* sepfds */ 0, /* sepfds */
@ -387,12 +388,13 @@ static const struct ChanType cli_chan_netcat = {
cli_init_netcat, /* inithandler */ cli_init_netcat, /* inithandler */
NULL, NULL,
NULL, NULL,
cli_closechansess cli_closechansess,
NULL,
}; };
void cli_send_netcat_request() { 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; const int source_port = 22;
TRACE(("enter cli_send_netcat_request")) TRACE(("enter cli_send_netcat_request"))
@ -403,7 +405,7 @@ void cli_send_netcat_request() {
dropbear_exit("Couldn't open initial channel"); 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)); strlen(cli_opts.netcat_host));
buf_putint(ses.writepayload, cli_opts.netcat_port); buf_putint(ses.writepayload, cli_opts.netcat_port);
@ -438,7 +440,6 @@ do_escape(unsigned char c) {
case '.': case '.':
dropbear_exit("Terminated"); dropbear_exit("Terminated");
return 1; return 1;
break;
case 0x1a: case 0x1a:
/* ctrl-z */ /* ctrl-z */
cli_tty_cleanup(); cli_tty_cleanup();
@ -447,13 +448,13 @@ do_escape(unsigned char c) {
cli_tty_setup(); cli_tty_setup();
cli_ses.winchange = 1; cli_ses.winchange = 1;
return 1; return 1;
break; default:
return 0;
} }
return 0;
} }
static static
void cli_escape_handler(struct Channel* UNUSED(channel), unsigned char* buf, int *len) { void cli_escape_handler(const struct Channel* UNUSED(channel), const unsigned char* buf, int *len) {
char c; char c;
int skip_char = 0; int skip_char = 0;

View File

@ -39,7 +39,7 @@
#include "ecc.h" #include "ecc.h"
static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen); static void checkhostkey(const unsigned char* keyblob, unsigned int keybloblen);
#define MAX_KNOWNHOSTS_LINE 4500 #define MAX_KNOWNHOSTS_LINE 4500
void send_msg_kexdh_init() { void send_msg_kexdh_init() {
@ -48,6 +48,7 @@ void send_msg_kexdh_init() {
CHECKCLEARTOWRITE(); CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT); buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
switch (ses.newkeys->algo_kex->mode) { switch (ses.newkeys->algo_kex->mode) {
#if DROPBEAR_NORMAL_DH
case DROPBEAR_KEX_NORMAL_DH: case DROPBEAR_KEX_NORMAL_DH:
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|| !cli_ses.dh_param) { || !cli_ses.dh_param) {
@ -58,8 +59,9 @@ void send_msg_kexdh_init() {
} }
buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub); buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub);
break; break;
#endif
#if DROPBEAR_ECDH
case DROPBEAR_KEX_ECDH: case DROPBEAR_KEX_ECDH:
#ifdef DROPBEAR_ECDH
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|| !cli_ses.ecdh_param) { || !cli_ses.ecdh_param) {
if (cli_ses.ecdh_param) { if (cli_ses.ecdh_param) {
@ -68,9 +70,9 @@ void send_msg_kexdh_init() {
cli_ses.ecdh_param = gen_kexecdh_param(); cli_ses.ecdh_param = gen_kexecdh_param();
} }
buf_put_ecc_raw_pubkey_string(ses.writepayload, &cli_ses.ecdh_param->key); buf_put_ecc_raw_pubkey_string(ses.writepayload, &cli_ses.ecdh_param->key);
#endif
break; break;
#ifdef DROPBEAR_CURVE25519 #endif
#if DROPBEAR_CURVE25519
case DROPBEAR_KEX_CURVE25519: case DROPBEAR_KEX_CURVE25519:
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|| !cli_ses.curve25519_param) { || !cli_ses.curve25519_param) {
@ -79,9 +81,9 @@ void send_msg_kexdh_init() {
} }
cli_ses.curve25519_param = gen_kexcurve25519_param(); 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; break;
#endif
} }
cli_ses.param_kex_algo = ses.newkeys->algo_kex; cli_ses.param_kex_algo = ses.newkeys->algo_kex;
@ -118,6 +120,7 @@ void recv_msg_kexdh_reply() {
} }
switch (ses.newkeys->algo_kex->mode) { switch (ses.newkeys->algo_kex->mode) {
#if DROPBEAR_NORMAL_DH
case DROPBEAR_KEX_NORMAL_DH: case DROPBEAR_KEX_NORMAL_DH:
{ {
DEF_MP_INT(dh_f); DEF_MP_INT(dh_f);
@ -131,37 +134,38 @@ void recv_msg_kexdh_reply() {
mp_clear(&dh_f); mp_clear(&dh_f);
} }
break; break;
#endif
#if DROPBEAR_ECDH
case DROPBEAR_KEX_ECDH: case DROPBEAR_KEX_ECDH:
#ifdef DROPBEAR_ECDH
{ {
buffer *ecdh_qs = buf_getstringbuf(ses.payload); buffer *ecdh_qs = buf_getstringbuf(ses.payload);
kexecdh_comb_key(cli_ses.ecdh_param, ecdh_qs, hostkey); kexecdh_comb_key(cli_ses.ecdh_param, ecdh_qs, hostkey);
buf_free(ecdh_qs); buf_free(ecdh_qs);
} }
#endif
break; break;
#ifdef DROPBEAR_CURVE25519 #endif
#if DROPBEAR_CURVE25519
case DROPBEAR_KEX_CURVE25519: case DROPBEAR_KEX_CURVE25519:
{ {
buffer *ecdh_qs = buf_getstringbuf(ses.payload); buffer *ecdh_qs = buf_getstringbuf(ses.payload);
kexcurve25519_comb_key(cli_ses.curve25519_param, ecdh_qs, hostkey); kexcurve25519_comb_key(cli_ses.curve25519_param, ecdh_qs, hostkey);
buf_free(ecdh_qs); buf_free(ecdh_qs);
} }
#endif
break; break;
#endif
} }
if (cli_ses.dh_param) { if (cli_ses.dh_param) {
free_kexdh_param(cli_ses.dh_param); free_kexdh_param(cli_ses.dh_param);
cli_ses.dh_param = NULL; cli_ses.dh_param = NULL;
} }
#ifdef DROPBEAR_ECDH #if DROPBEAR_ECDH
if (cli_ses.ecdh_param) { if (cli_ses.ecdh_param) {
free_kexecdh_param(cli_ses.ecdh_param); free_kexecdh_param(cli_ses.ecdh_param);
cli_ses.ecdh_param = NULL; cli_ses.ecdh_param = NULL;
} }
#endif #endif
#ifdef DROPBEAR_CURVE25519 #if DROPBEAR_CURVE25519
if (cli_ses.curve25519_param) { if (cli_ses.curve25519_param) {
free_kexcurve25519_param(cli_ses.curve25519_param); free_kexcurve25519_param(cli_ses.curve25519_param);
cli_ses.curve25519_param = NULL; cli_ses.curve25519_param = NULL;
@ -181,16 +185,16 @@ void recv_msg_kexdh_reply() {
TRACE(("leave recv_msg_kexdh_init")) TRACE(("leave recv_msg_kexdh_init"))
} }
static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen, static void ask_to_confirm(const unsigned char* keyblob, unsigned int keybloblen,
const char* algoname) { const char* algoname) {
char* fp = NULL; char* fp = NULL;
FILE *tty = NULL; FILE *tty = NULL;
char response = 'z'; int response = 'z';
fp = sign_key_fingerprint(keyblob, keybloblen); fp = sign_key_fingerprint(keyblob, keybloblen);
if (cli_opts.always_accept_key) { if (cli_opts.always_accept_key) {
fprintf(stderr, "\nHost '%s' key accepted unconditionally.\n(%s fingerprint %s)\n", dropbear_log(LOG_INFO, "\nHost '%s' key accepted unconditionally.\n(%s fingerprint %s)\n",
cli_opts.remotehost, cli_opts.remotehost,
algoname, algoname,
fp); fp);
@ -278,7 +282,7 @@ out:
return hostsfile; return hostsfile;
} }
static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) { static void checkhostkey(const unsigned char* keyblob, unsigned int keybloblen) {
FILE *hostsfile = NULL; FILE *hostsfile = NULL;
int readonly = 0; int readonly = 0;
@ -290,7 +294,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
int ret; int ret;
if (cli_opts.no_hostkey_check) { if (cli_opts.no_hostkey_check) {
fprintf(stderr, "Caution, skipping hostkey check for %s\n", cli_opts.remotehost); dropbear_log(LOG_INFO, "Caution, skipping hostkey check for %s\n", cli_opts.remotehost);
return; return;
} }
@ -322,7 +326,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
} }
/* Compare hostnames */ /* Compare hostnames */
if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen), if (strncmp(cli_opts.remotehost, (const char *) buf_getptr(line, hostlen),
hostlen) != 0) { hostlen) != 0) {
continue; continue;
} }
@ -334,7 +338,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
continue; 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")) TRACE(("algo doesn't match"))
continue; continue;
} }
@ -346,7 +350,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
} }
/* Now we're at the interesting hostkey */ /* 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); line, &fingerprint);
if (ret == DROPBEAR_SUCCESS) { if (ret == DROPBEAR_SUCCESS) {
@ -382,9 +386,9 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */ fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */
buf_setpos(line, 0); buf_setpos(line, 0);
buf_setlen(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_putbyte(line, ' ');
buf_putbytes(line, algoname, algolen); buf_putbytes(line, (const unsigned char *) algoname, algolen);
buf_putbyte(line, ' '); buf_putbyte(line, ' ');
len = line->size - line->pos; len = line->size - line->pos;
/* The only failure with base64 is buffer_overflow, but buf_getwriteptr /* The only failure with base64 is buffer_overflow, but buf_getwriteptr

View File

@ -30,23 +30,25 @@
#include "session.h" #include "session.h"
#include "dbrandom.h" #include "dbrandom.h"
#include "crypto_desc.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_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
static void cli_dropbear_log(int priority, const char* format, va_list param); static void cli_dropbear_log(int priority, const char* format, va_list param);
#ifdef ENABLE_CLI_PROXYCMD #if DROPBEAR_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out); static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out);
static void kill_proxy_sighandler(int signo);
#endif #endif
#if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI) #if defined(DBMULTI_dbclient) || !DROPBEAR_MULTI
#if defined(DBMULTI_dbclient) && defined(DROPBEAR_MULTI) #if defined(DBMULTI_dbclient) && DROPBEAR_MULTI
int cli_main(int argc, char ** argv) { int cli_main(int argc, char ** argv) {
#else #else
int main(int argc, char ** argv) { int main(int argc, char ** argv) {
#endif #endif
int sock_in, sock_out; int sock_in, sock_out;
char* error = NULL; struct dropbear_progress_connection *progress = NULL;
_dropbear_exit = cli_dropbear_exit; _dropbear_exit = cli_dropbear_exit;
_dropbear_log = cli_dropbear_log; _dropbear_log = cli_dropbear_log;
@ -58,30 +60,38 @@ int main(int argc, char ** argv) {
cli_getopts(argc, argv); cli_getopts(argc, argv);
TRACE(("user='%s' host='%s' port='%s'", cli_opts.username, #ifndef DISABLE_SYSLOG
cli_opts.remotehost, cli_opts.remoteport)) if (opts.usingsyslog) {
startsyslog("dbclient");
}
#endif
TRACE(("user='%s' host='%s' port='%s' bind_address='%s' bind_port='%s'", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport, cli_opts.bind_address, cli_opts.bind_port))
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
dropbear_exit("signal() error"); dropbear_exit("signal() error");
} }
#ifdef ENABLE_CLI_PROXYCMD pid_t proxy_cmd_pid = 0;
#if DROPBEAR_CLI_PROXYCMD
if (cli_opts.proxycmd) { if (cli_opts.proxycmd) {
cli_proxy_cmd(&sock_in, &sock_out); cli_proxy_cmd(&sock_in, &sock_out, &proxy_cmd_pid);
m_free(cli_opts.proxycmd); m_free(cli_opts.proxycmd);
if (signal(SIGINT, kill_proxy_sighandler) == SIG_ERR ||
signal(SIGTERM, kill_proxy_sighandler) == SIG_ERR ||
signal(SIGHUP, kill_proxy_sighandler) == SIG_ERR) {
dropbear_exit("signal() error");
}
} else } else
#endif #endif
{ {
int sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport, progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
0, &error); cli_connected, &ses, cli_opts.bind_address, cli_opts.bind_port);
sock_in = sock_out = sock; sock_in = sock_out = -1;
} }
if (sock_in < 0) { cli_session(sock_in, sock_out, progress, proxy_cmd_pid);
dropbear_exit("%s", error);
}
cli_session(sock_in, sock_out);
/* not reached */ /* not reached */
return -1; return -1;
@ -89,17 +99,22 @@ int main(int argc, char ** argv) {
#endif /* DBMULTI stuff */ #endif /* DBMULTI stuff */
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) { static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
char exitmsg[150];
char fullmsg[300];
char fmtbuf[300]; /* Note that exit message must be rendered before session cleanup */
if (!sessinitdone) { /* Render the formatted exit message */
snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s", vsnprintf(exitmsg, sizeof(exitmsg), format, param);
format);
/* Add the prefix depending on session/auth state */
if (!ses.init_done) {
snprintf(fullmsg, sizeof(fullmsg), "Exited: %s", exitmsg);
} else { } else {
snprintf(fmtbuf, sizeof(fmtbuf), snprintf(fullmsg, sizeof(fullmsg),
"Connection to %s@%s:%s exited: %s", "Connection to %s@%s:%s exited: %s",
cli_opts.username, cli_opts.remotehost, cli_opts.username, cli_opts.remotehost,
cli_opts.remoteport, format); cli_opts.remoteport, exitmsg);
} }
/* Do the cleanup first, since then the terminal will be reset */ /* Do the cleanup first, since then the terminal will be reset */
@ -107,22 +122,28 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
/* Avoid printing onwards from terminal cruft */ /* Avoid printing onwards from terminal cruft */
fprintf(stderr, "\n"); fprintf(stderr, "\n");
_dropbear_log(LOG_INFO, fmtbuf, param); dropbear_log(LOG_INFO, "%s", fullmsg);
exit(exitcode); exit(exitcode);
} }
static void cli_dropbear_log(int UNUSED(priority), static void cli_dropbear_log(int priority,
const char* format, va_list param) { const char* format, va_list param) {
char printbuf[1024]; char printbuf[1024];
vsnprintf(printbuf, sizeof(printbuf), format, param); vsnprintf(printbuf, sizeof(printbuf), format, param);
#ifndef DISABLE_SYSLOG
if (opts.usingsyslog) {
syslog(priority, "%s", printbuf);
}
#endif
fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf); fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf);
fflush(stderr); fflush(stderr);
} }
static void exec_proxy_cmd(void *user_data_cmd) { static void exec_proxy_cmd(const void *user_data_cmd) {
const char *cmd = user_data_cmd; const char *cmd = user_data_cmd;
char *usershell; char *usershell;
@ -131,17 +152,44 @@ static void exec_proxy_cmd(void *user_data_cmd) {
dropbear_exit("Failed to run '%s'\n", cmd); dropbear_exit("Failed to run '%s'\n", cmd);
} }
#ifdef ENABLE_CLI_PROXYCMD #if DROPBEAR_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out) { static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out) {
char * ex_cmd = NULL;
size_t ex_cmdlen;
int ret; int ret;
/* File descriptor "-j &3" */
if (*cli_opts.proxycmd == '&') {
char *p = cli_opts.proxycmd + 1;
int sock = strtoul(p, &p, 10);
/* must be a single number, and not stdin/stdout/stderr */
if (sock > 2 && sock < 1024 && *p == '\0') {
*sock_in = sock;
*sock_out = sock;
return;
}
}
/* Normal proxycommand */
/* So that spawn_command knows which shell to run */
fill_passwd(cli_opts.own_user); fill_passwd(cli_opts.own_user);
ret = spawn_command(exec_proxy_cmd, cli_opts.proxycmd, ex_cmdlen = strlen(cli_opts.proxycmd) + 6; /* "exec " + command + '\0' */
sock_out, sock_in, NULL, NULL); ex_cmd = m_malloc(ex_cmdlen);
snprintf(ex_cmd, ex_cmdlen, "exec %s", cli_opts.proxycmd);
ret = spawn_command(exec_proxy_cmd, ex_cmd,
sock_out, sock_in, NULL, pid_out);
m_free(ex_cmd);
if (ret == DROPBEAR_FAILURE) { if (ret == DROPBEAR_FAILURE) {
dropbear_exit("Failed running proxy command"); dropbear_exit("Failed running proxy command");
*sock_in = *sock_out = -1; *sock_in = *sock_out = -1;
} }
} }
#endif /* ENABLE_CLI_PROXYCMD */
static void kill_proxy_sighandler(int UNUSED(signo)) {
kill_proxy_command();
_exit(1);
}
#endif /* DROPBEAR_CLI_PROXYCMD */

View File

@ -33,24 +33,25 @@
cli_runopts cli_opts; /* GLOBAL */ cli_runopts cli_opts; /* GLOBAL */
static void printhelp(); static void printhelp(void);
static void parse_hostname(const char* orighostarg); static void parse_hostname(const char* orighostarg);
static void parse_multihop_hostname(const char* orighostarg, const char* argv0); static void parse_multihop_hostname(const char* orighostarg, const char* argv0);
static void fill_own_user(); static void fill_own_user(void);
#ifdef ENABLE_CLI_PUBKEY_AUTH #if DROPBEAR_CLI_PUBKEY_AUTH
static void loadidentityfile(const char* filename); static void loadidentityfile(const char* filename, int warnfail);
#endif #endif
#ifdef ENABLE_CLI_ANYTCPFWD #if DROPBEAR_CLI_ANYTCPFWD
static void addforward(const char* str, m_list *fwdlist); static void addforward(const char* str, m_list *fwdlist);
#endif #endif
#ifdef ENABLE_CLI_NETCAT #if DROPBEAR_CLI_NETCAT
static void add_netcat(const char *str); static void add_netcat(const char *str);
#endif #endif
static void add_extendedopt(const char *str);
static void printhelp() { static void printhelp() {
fprintf(stderr, "Dropbear SSH client v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n" fprintf(stderr, "Dropbear SSH client v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n"
#ifdef ENABLE_CLI_MULTIHOP #if DROPBEAR_CLI_MULTIHOP
"Usage: %s [options] [user@]host[/port][,[user@]host/port],...] [command]\n" "Usage: %s [options] [user@]host[/port][,[user@]host/port],...] [command]\n"
#else #else
"Usage: %s [options] [user@]host[/port] [command]\n" "Usage: %s [options] [user@]host[/port] [command]\n"
@ -64,63 +65,74 @@ static void printhelp() {
"-y Always accept remote host key if unknown\n" "-y Always accept remote host key if unknown\n"
"-y -y Don't perform any remote host key checking (caution)\n" "-y -y Don't perform any remote host key checking (caution)\n"
"-s Request a subsystem (use by external sftp)\n" "-s Request a subsystem (use by external sftp)\n"
#ifdef ENABLE_CLI_PUBKEY_AUTH "-o option Set option in OpenSSH-like format ('-o help' to list options)\n"
"-i <identityfile> (multiple allowed)\n" #if DROPBEAR_CLI_PUBKEY_AUTH
"-i <identityfile> (multiple allowed, default %s)\n"
#endif #endif
#ifdef ENABLE_CLI_AGENTFWD #if DROPBEAR_CLI_AGENTFWD
"-A Enable agent auth forwarding\n" "-A Enable agent auth forwarding\n"
#endif #endif
#ifdef ENABLE_CLI_LOCALTCPFWD #if DROPBEAR_CLI_LOCALTCPFWD
"-L <[listenaddress:]listenport:remotehost:remoteport> Local port forwarding\n" "-L <[listenaddress:]listenport:remotehost:remoteport> Local port forwarding\n"
"-g Allow remote hosts to connect to forwarded ports\n" "-g Allow remote hosts to connect to forwarded ports\n"
#endif #endif
#ifdef ENABLE_CLI_REMOTETCPFWD #if DROPBEAR_CLI_REMOTETCPFWD
"-R <[listenaddress:]listenport:remotehost:remoteport> Remote port forwarding\n" "-R <[listenaddress:]listenport:remotehost:remoteport> Remote port forwarding\n"
#endif #endif
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n" "-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
"-K <keepalive> (0 is never, default %d)\n" "-K <keepalive> (0 is never, default %d)\n"
"-I <idle_timeout> (0 is never, default %d)\n" "-I <idle_timeout> (0 is never, default %d)\n"
#ifdef ENABLE_CLI_NETCAT #if DROPBEAR_CLI_NETCAT
"-B <endhost:endport> Netcat-alike forwarding\n" "-B <endhost:endport> Netcat-alike forwarding\n"
#endif #endif
#ifdef ENABLE_CLI_PROXYCMD #if DROPBEAR_CLI_PROXYCMD
"-J <proxy_program> Use program pipe rather than TCP connection\n" "-J <proxy_program> Use program pipe rather than TCP connection\n"
#endif #endif
#ifdef ENABLE_USER_ALGO_LIST #if DROPBEAR_USER_ALGO_LIST
"-c <cipher list> Specify preferred ciphers ('-c help' to list options)\n" "-c <cipher list> Specify preferred ciphers ('-c help' to list options)\n"
"-m <MAC list> Specify preferred MACs for packet verification (or '-m help')\n" "-m <MAC list> Specify preferred MACs for packet verification (or '-m help')\n"
#endif #endif
"-b [bind_address][:bind_port]\n"
"-V Version\n" "-V Version\n"
#ifdef DEBUG_TRACE #if DEBUG_TRACE
"-v verbose (compiled with DEBUG_TRACE)\n" "-v verbose (compiled with DEBUG_TRACE)\n"
#endif #endif
,DROPBEAR_VERSION, cli_opts.progname, ,DROPBEAR_VERSION, cli_opts.progname,
#if DROPBEAR_CLI_PUBKEY_AUTH
DROPBEAR_DEFAULT_CLI_AUTHKEY,
#endif
DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT); DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
} }
void cli_getopts(int argc, char ** argv) { void cli_getopts(int argc, char ** argv) {
unsigned int i, j; unsigned int i, j;
char ** next = 0; char ** next = NULL;
enum {
OPT_EXTENDED_OPTIONS,
#if DROPBEAR_CLI_PUBKEY_AUTH
OPT_AUTHKEY,
#endif
#if DROPBEAR_CLI_LOCALTCPFWD
OPT_LOCALTCPFWD,
#endif
#if DROPBEAR_CLI_REMOTETCPFWD
OPT_REMOTETCPFWD,
#endif
#if DROPBEAR_CLI_NETCAT
OPT_NETCAT,
#endif
/* a flag (no arg) if 'next' is NULL, a string-valued option otherwise */
OPT_OTHER
} opt;
unsigned int cmdlen; unsigned int cmdlen;
#ifdef ENABLE_CLI_PUBKEY_AUTH
int nextiskey = 0; /* A flag if the next argument is a keyfile */
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
int nextislocal = 0;
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
int nextisremote = 0;
#endif
#ifdef ENABLE_CLI_NETCAT
int nextisnetcat = 0;
#endif
char* dummy = NULL; /* Not used for anything real */
char* recv_window_arg = NULL; char* recv_window_arg = NULL;
char* keepalive_arg = NULL; char* keepalive_arg = NULL;
char* idle_timeout_arg = NULL; char* idle_timeout_arg = NULL;
char *host_arg = NULL; char *host_arg = NULL;
char *bind_arg = NULL;
char c;
/* see printhelp() for options */ /* see printhelp() for options */
cli_opts.progname = argv[0]; cli_opts.progname = argv[0];
@ -134,30 +146,38 @@ void cli_getopts(int argc, char ** argv) {
cli_opts.always_accept_key = 0; cli_opts.always_accept_key = 0;
cli_opts.no_hostkey_check = 0; cli_opts.no_hostkey_check = 0;
cli_opts.is_subsystem = 0; cli_opts.is_subsystem = 0;
#ifdef ENABLE_CLI_PUBKEY_AUTH #if DROPBEAR_CLI_PUBKEY_AUTH
cli_opts.privkeys = list_new(); cli_opts.privkeys = list_new();
#endif #endif
#ifdef ENABLE_CLI_LOCALTCPFWD #if DROPBEAR_CLI_ANYTCPFWD
cli_opts.exit_on_fwd_failure = 0;
#endif
#if DROPBEAR_CLI_LOCALTCPFWD
cli_opts.localfwds = list_new(); cli_opts.localfwds = list_new();
opts.listen_fwd_all = 0; opts.listen_fwd_all = 0;
#endif #endif
#ifdef ENABLE_CLI_REMOTETCPFWD #if DROPBEAR_CLI_REMOTETCPFWD
cli_opts.remotefwds = list_new(); cli_opts.remotefwds = list_new();
#endif #endif
#ifdef ENABLE_CLI_AGENTFWD #if DROPBEAR_CLI_AGENTFWD
cli_opts.agent_fwd = 0; cli_opts.agent_fwd = 0;
cli_opts.agent_fd = -1; cli_opts.agent_fd = -1;
cli_opts.agent_keys_loaded = 0; cli_opts.agent_keys_loaded = 0;
#endif #endif
#ifdef ENABLE_CLI_PROXYCMD #if DROPBEAR_CLI_PROXYCMD
cli_opts.proxycmd = NULL; cli_opts.proxycmd = NULL;
#endif #endif
cli_opts.bind_address = NULL;
cli_opts.bind_port = NULL;
#ifndef DISABLE_ZLIB #ifndef DISABLE_ZLIB
opts.enable_compress = 1; opts.compress_mode = DROPBEAR_COMPRESS_ON;
#endif #endif
#ifdef ENABLE_USER_ALGO_LIST #if DROPBEAR_USER_ALGO_LIST
opts.cipher_list = NULL; opts.cipher_list = NULL;
opts.mac_list = NULL; opts.mac_list = NULL;
#endif
#ifndef DISABLE_SYSLOG
opts.usingsyslog = 0;
#endif #endif
/* not yet /* not yet
opts.ipv4 = 1; opts.ipv4 = 1;
@ -169,54 +189,23 @@ void cli_getopts(int argc, char ** argv) {
fill_own_user(); fill_own_user();
/* Iterate all the arguments */
for (i = 1; i < (unsigned int)argc; i++) { for (i = 1; i < (unsigned int)argc; i++) {
#ifdef ENABLE_CLI_PUBKEY_AUTH /* Handle non-flag arguments such as hostname or commands for the remote host */
if (nextiskey) { if (argv[i][0] != '-')
/* Load a hostkey since the previous argument was "-i" */ {
loadidentityfile(argv[i]); if (host_arg == NULL) {
nextiskey = 0; host_arg = argv[i];
continue; 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");
} }
next = NULL; /* Commands to pass to the remote host. No more flag handling,
continue; commands are consumed below */
break;
} }
if (argv[i][0] == '-') { /* Begins with '-' */
/* A flag *waves* */ opt = OPT_OTHER;
for (j = 1; (c = argv[i][j]) != '\0' && !next && opt == OPT_OTHER; j++) {
switch (argv[i][1]) { switch (c) {
case 'y': /* always accept the remote hostkey */ case 'y': /* always accept the remote hostkey */
if (cli_opts.always_accept_key) { if (cli_opts.always_accept_key) {
/* twice means no checking at all */ /* twice means no checking at all */
@ -225,16 +214,11 @@ void cli_getopts(int argc, char ** argv) {
cli_opts.always_accept_key = 1; cli_opts.always_accept_key = 1;
break; break;
case 'p': /* remoteport */ case 'p': /* remoteport */
next = &cli_opts.remoteport; next = (char**)&cli_opts.remoteport;
break; break;
#ifdef ENABLE_CLI_PUBKEY_AUTH #if DROPBEAR_CLI_PUBKEY_AUTH
case 'i': /* an identityfile */ case 'i': /* an identityfile */
/* Keep scp happy when it changes "-i file" to "-ifile" */ opt = OPT_AUTHKEY;
if (strlen(argv[i]) > 2) {
loadidentityfile(&argv[i][2]);
} else {
nextiskey = 1;
}
break; break;
#endif #endif
case 't': /* we want a pty */ case 't': /* we want a pty */
@ -252,25 +236,28 @@ void cli_getopts(int argc, char ** argv) {
case 's': case 's':
cli_opts.is_subsystem = 1; cli_opts.is_subsystem = 1;
break; break;
#ifdef ENABLE_CLI_LOCALTCPFWD case 'o':
opt = OPT_EXTENDED_OPTIONS;
break;
#if DROPBEAR_CLI_LOCALTCPFWD
case 'L': case 'L':
nextislocal = 1; opt = OPT_LOCALTCPFWD;
break; break;
case 'g': case 'g':
opts.listen_fwd_all = 1; opts.listen_fwd_all = 1;
break; break;
#endif #endif
#ifdef ENABLE_CLI_REMOTETCPFWD #if DROPBEAR_CLI_REMOTETCPFWD
case 'R': case 'R':
nextisremote = 1; opt = OPT_REMOTETCPFWD;
break; break;
#endif #endif
#ifdef ENABLE_CLI_NETCAT #if DROPBEAR_CLI_NETCAT
case 'B': case 'B':
nextisnetcat = 1; opt = OPT_NETCAT;
break; break;
#endif #endif
#ifdef ENABLE_CLI_PROXYCMD #if DROPBEAR_CLI_PROXYCMD
case 'J': case 'J':
next = &cli_opts.proxycmd; next = &cli_opts.proxycmd;
break; break;
@ -294,12 +281,12 @@ void cli_getopts(int argc, char ** argv) {
case 'I': case 'I':
next = &idle_timeout_arg; next = &idle_timeout_arg;
break; break;
#ifdef ENABLE_CLI_AGENTFWD #if DROPBEAR_CLI_AGENTFWD
case 'A': case 'A':
cli_opts.agent_fwd = 1; cli_opts.agent_fwd = 1;
break; break;
#endif #endif
#ifdef ENABLE_USER_ALGO_LIST #if DROPBEAR_USER_ALGO_LIST
case 'c': case 'c':
next = &opts.cipher_list; next = &opts.cipher_list;
break; break;
@ -307,90 +294,125 @@ void cli_getopts(int argc, char ** argv) {
next = &opts.mac_list; next = &opts.mac_list;
break; break;
#endif #endif
#ifdef DEBUG_TRACE #if DEBUG_TRACE
case 'v': case 'v':
debug_trace = 1; debug_trace = 1;
break; break;
#endif #endif
case 'F': case 'F':
case 'e': case 'e':
#ifndef ENABLE_USER_ALGO_LIST #if !DROPBEAR_USER_ALGO_LIST
case 'c': case 'c':
case 'm': case 'm':
#endif #endif
case 'D': case 'D':
#ifndef ENABLE_CLI_REMOTETCPFWD #if !DROPBEAR_CLI_REMOTETCPFWD
case 'R': case 'R':
#endif #endif
#ifndef ENABLE_CLI_LOCALTCPFWD #if !DROPBEAR_CLI_LOCALTCPFWD
case 'L': case 'L':
#endif #endif
case 'V': case 'V':
print_version(); print_version();
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
break; break;
case 'o':
case 'b': case 'b':
next = &dummy; next = &bind_arg;
break;
default: default:
fprintf(stderr, fprintf(stderr,
"WARNING: Ignoring unknown argument '%s'\n", argv[i]); "WARNING: Ignoring unknown option -%c\n", c);
break; break;
} /* Switch */ } /* Switch */
/* Now we handle args where they might be "-luser" (no spaces)*/
if (next && strlen(argv[i]) > 2) {
*next = &argv[i][2];
next = NULL;
}
continue; /* next argument */
} else {
TRACE(("non-flag arg: '%s'", argv[i]))
/* Either the hostname or commands */
if (host_arg == NULL) {
host_arg = argv[i];
} else {
/* this is part of the commands to send - after this we
* don't parse any more options, and flags are sent as the
* command */
cmdlen = 0;
for (j = i; j < (unsigned int)argc; j++) {
cmdlen += strlen(argv[j]) + 1; /* +1 for spaces */
}
/* Allocate the space */
cli_opts.cmd = (char*)m_malloc(cmdlen);
cli_opts.cmd[0] = '\0';
/* Append all the bits */
for (j = i; j < (unsigned int)argc; j++) {
strlcat(cli_opts.cmd, argv[j], cmdlen);
strlcat(cli_opts.cmd, " ", cmdlen);
}
/* It'll be null-terminated here */
/* We've eaten all the options and flags */
break;
}
} }
if (!next && opt == OPT_OTHER) /* got a flag */
continue;
if (c == '\0') {
i++;
j = 0;
if (!argv[i])
dropbear_exit("Missing argument");
}
if (opt == OPT_EXTENDED_OPTIONS) {
TRACE(("opt extended"))
add_extendedopt(&argv[i][j]);
}
else
#if DROPBEAR_CLI_PUBKEY_AUTH
if (opt == OPT_AUTHKEY) {
TRACE(("opt authkey"))
loadidentityfile(&argv[i][j], 1);
}
else
#endif
#if DROPBEAR_CLI_REMOTETCPFWD
if (opt == OPT_REMOTETCPFWD) {
TRACE(("opt remotetcpfwd"))
addforward(&argv[i][j], cli_opts.remotefwds);
}
else
#endif
#if DROPBEAR_CLI_LOCALTCPFWD
if (opt == OPT_LOCALTCPFWD) {
TRACE(("opt localtcpfwd"))
addforward(&argv[i][j], cli_opts.localfwds);
}
else
#endif
#if DROPBEAR_CLI_NETCAT
if (opt == OPT_NETCAT) {
TRACE(("opt netcat"))
add_netcat(&argv[i][j]);
}
else
#endif
if (next) {
/* The previous flag set a value to assign */
*next = &argv[i][j];
if (*next == NULL)
dropbear_exit("Invalid null argument");
next = NULL;
}
}
/* Done with options/flags; now handle the hostname (which may not
* start with a hyphen) and optional command */
if (host_arg == NULL) { /* missing hostname */
printhelp();
exit(EXIT_FAILURE);
}
TRACE(("host is: %s", host_arg))
if (i < (unsigned int)argc) {
/* Build the command to send */
cmdlen = 0;
for (j = i; j < (unsigned int)argc; j++)
cmdlen += strlen(argv[j]) + 1; /* +1 for spaces */
/* Allocate the space */
cli_opts.cmd = (char*)m_malloc(cmdlen);
cli_opts.cmd[0] = '\0';
/* Append all the bits */
for (j = i; j < (unsigned int)argc; j++) {
strlcat(cli_opts.cmd, argv[j], cmdlen);
strlcat(cli_opts.cmd, " ", cmdlen);
}
/* It'll be null-terminated here */
TRACE(("cmd is: %s", cli_opts.cmd))
} }
/* And now a few sanity checks and setup */ /* And now a few sanity checks and setup */
#ifdef ENABLE_USER_ALGO_LIST #if DROPBEAR_USER_ALGO_LIST
parse_ciphers_macs(); parse_ciphers_macs();
#endif #endif
if (host_arg == NULL) { #if DROPBEAR_CLI_PROXYCMD
printhelp();
exit(EXIT_FAILURE);
}
#ifdef ENABLE_CLI_PROXYCMD
if (cli_opts.proxycmd) { if (cli_opts.proxycmd) {
/* To match the common path of m_freeing it */ /* To match the common path of m_freeing it */
cli_opts.proxycmd = m_strdup(cli_opts.proxycmd); cli_opts.proxycmd = m_strdup(cli_opts.proxycmd);
@ -401,6 +423,18 @@ void cli_getopts(int argc, char ** argv) {
cli_opts.remoteport = "22"; cli_opts.remoteport = "22";
} }
if (bind_arg) {
/* split [host][:port] */
char *port = strrchr(bind_arg, ':');
if (port) {
cli_opts.bind_port = m_strdup(port+1);
*port = '\0';
}
if (strlen(bind_arg) > 0) {
cli_opts.bind_address = m_strdup(bind_arg);
}
}
/* If not explicitly specified with -t or -T, we don't want a pty if /* If not explicitly specified with -t or -T, we don't want a pty if
* there's a command, but we do otherwise */ * there's a command, but we do otherwise */
if (cli_opts.wantpty == 9) { if (cli_opts.wantpty == 9) {
@ -438,31 +472,43 @@ void cli_getopts(int argc, char ** argv) {
opts.idle_timeout_secs = val; opts.idle_timeout_secs = val;
} }
#ifdef ENABLE_CLI_NETCAT #if DROPBEAR_CLI_NETCAT
if (cli_opts.cmd && cli_opts.netcat_host) { if (cli_opts.cmd && cli_opts.netcat_host) {
dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd); dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
} }
#endif #endif
#if (DROPBEAR_CLI_PUBKEY_AUTH)
{
char *expand_path = expand_homedir_path(DROPBEAR_DEFAULT_CLI_AUTHKEY);
loadidentityfile(expand_path, 0);
m_free(expand_path);
}
#endif
/* The hostname gets set up last, since /* The hostname gets set up last, since
* in multi-hop mode it will require knowledge * in multi-hop mode it will require knowledge
* of other flags such as -i */ * of other flags such as -i */
#ifdef ENABLE_CLI_MULTIHOP #if DROPBEAR_CLI_MULTIHOP
parse_multihop_hostname(host_arg, argv[0]); parse_multihop_hostname(host_arg, argv[0]);
#else #else
parse_hostname(host_arg); parse_hostname(host_arg);
#endif #endif
} }
#ifdef ENABLE_CLI_PUBKEY_AUTH #if DROPBEAR_CLI_PUBKEY_AUTH
static void loadidentityfile(const char* filename) { static void loadidentityfile(const char* filename, int warnfail) {
sign_key *key; sign_key *key;
enum signkey_type keytype; enum signkey_type keytype;
TRACE(("loadidentityfile %s", filename))
key = new_sign_key(); key = new_sign_key();
keytype = DROPBEAR_SIGNKEY_ANY; keytype = DROPBEAR_SIGNKEY_ANY;
if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) { if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
fprintf(stderr, "Failed loading keyfile '%s'\n", filename); if (warnfail) {
dropbear_log(LOG_WARNING, "Failed loading keyfile '%s'\n", filename);
}
sign_key_free(key); sign_key_free(key);
} else { } else {
key->type = keytype; key->type = keytype;
@ -473,7 +519,7 @@ static void loadidentityfile(const char* filename) {
} }
#endif #endif
#ifdef ENABLE_CLI_MULTIHOP #if DROPBEAR_CLI_MULTIHOP
static char* static char*
multihop_passthrough_args() { multihop_passthrough_args() {
@ -483,11 +529,14 @@ multihop_passthrough_args() {
m_list_elem *iter; m_list_elem *iter;
/* Fill out -i, -y, -W options that make sense for all /* Fill out -i, -y, -W options that make sense for all
* the intermediate processes */ * the intermediate processes */
#if DROPBEAR_CLI_PUBKEY_AUTH
for (iter = cli_opts.privkeys->first; iter; iter = iter->next) for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{ {
sign_key * key = (sign_key*)iter->item; sign_key * key = (sign_key*)iter->item;
len += 3 + strlen(key->filename); len += 3 + strlen(key->filename);
} }
#endif /* DROPBEAR_CLI_PUBKEY_AUTH */
len += 30; /* space for -W <size>, terminator. */ len += 30; /* space for -W <size>, terminator. */
ret = m_malloc(len); ret = m_malloc(len);
total = 0; total = 0;
@ -505,10 +554,11 @@ multihop_passthrough_args() {
if (opts.recv_window != DEFAULT_RECV_WINDOW) if (opts.recv_window != DEFAULT_RECV_WINDOW)
{ {
int written = snprintf(ret+total, len-total, "-W %d ", opts.recv_window); int written = snprintf(ret+total, len-total, "-W %u ", opts.recv_window);
total += written; total += written;
} }
#if DROPBEAR_CLI_PUBKEY_AUTH
for (iter = cli_opts.privkeys->first; iter; iter = iter->next) for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{ {
sign_key * key = (sign_key*)iter->item; sign_key * key = (sign_key*)iter->item;
@ -517,6 +567,7 @@ multihop_passthrough_args() {
dropbear_assert((unsigned int)written < size); dropbear_assert((unsigned int)written < size);
total += written; total += written;
} }
#endif /* DROPBEAR_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 args were passed, total will be not zero, and it will have a space at the end, so remove that */
if (total > 0) if (total > 0)
@ -594,13 +645,13 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
passthrough_args, remainder); passthrough_args, remainder);
#ifndef DISABLE_ZLIB #ifndef DISABLE_ZLIB
/* The stream will be incompressible since it's encrypted. */ /* The stream will be incompressible since it's encrypted. */
opts.enable_compress = 0; opts.compress_mode = DROPBEAR_COMPRESS_OFF;
#endif #endif
m_free(passthrough_args); m_free(passthrough_args);
} }
m_free(hostbuf); m_free(hostbuf);
} }
#endif /* !ENABLE_CLI_MULTIHOP */ #endif /* !DROPBEAR_CLI_MULTIHOP */
/* Parses a [user@]hostname[/port] argument. */ /* Parses a [user@]hostname[/port] argument. */
static void parse_hostname(const char* orighostarg) { static void parse_hostname(const char* orighostarg) {
@ -639,7 +690,7 @@ static void parse_hostname(const char* orighostarg) {
} }
} }
#ifdef ENABLE_CLI_NETCAT #if DROPBEAR_CLI_NETCAT
static void add_netcat(const char* origstr) { static void add_netcat(const char* origstr) {
char *portstr = NULL; char *portstr = NULL;
@ -692,7 +743,7 @@ static void fill_own_user() {
} }
#ifdef ENABLE_CLI_ANYTCPFWD #if DROPBEAR_CLI_ANYTCPFWD
/* Turn a "[listenaddr:]listenport:remoteaddr:remoteport" string into into a forwarding /* Turn a "[listenaddr:]listenport:remoteaddr:remoteport" string into into a forwarding
* set, and add it to the forwarding list */ * set, and add it to the forwarding list */
static void addforward(const char* origstr, m_list *fwdlist) { static void addforward(const char* origstr, m_list *fwdlist) {
@ -787,3 +838,82 @@ badport:
dropbear_exit("Bad TCP port in '%s'", origstr); dropbear_exit("Bad TCP port in '%s'", origstr);
} }
#endif #endif
static int match_extendedopt(const char** strptr, const char *optname) {
int seen_eq = 0;
int optlen = strlen(optname);
const char *str = *strptr;
while (isspace(*str)) {
++str;
}
if (strncasecmp(str, optname, optlen) != 0) {
return DROPBEAR_FAILURE;
}
str += optlen;
while (isspace(*str) || (!seen_eq && *str == '=')) {
if (*str == '=') {
seen_eq = 1;
}
++str;
}
if (str-*strptr == optlen) {
/* matched just a prefix of optname */
return DROPBEAR_FAILURE;
}
*strptr = str;
return DROPBEAR_SUCCESS;
}
static int parse_flag_value(const char *value) {
if (strcmp(value, "yes") == 0 || strcmp(value, "true") == 0) {
return 1;
} else if (strcmp(value, "no") == 0 || strcmp(value, "false") == 0) {
return 0;
}
dropbear_exit("Bad yes/no argument '%s'", value);
}
static void add_extendedopt(const char* origstr) {
const char *optstr = origstr;
if (strcmp(origstr, "help") == 0) {
dropbear_log(LOG_INFO, "Available options:\n"
#if DROPBEAR_CLI_ANYTCPFWD
"\tExitOnForwardFailure\n"
#endif
#ifndef DISABLE_SYSLOG
"\tUseSyslog\n"
#endif
"\tPort\n"
);
exit(EXIT_SUCCESS);
}
#if DROPBEAR_CLI_ANYTCPFWD
if (match_extendedopt(&optstr, "ExitOnForwardFailure") == DROPBEAR_SUCCESS) {
cli_opts.exit_on_fwd_failure = parse_flag_value(optstr);
return;
}
#endif
#ifndef DISABLE_SYSLOG
if (match_extendedopt(&optstr, "UseSyslog") == DROPBEAR_SUCCESS) {
opts.usingsyslog = parse_flag_value(optstr);
return;
}
#endif
if (match_extendedopt(&optstr, "Port") == DROPBEAR_SUCCESS) {
cli_opts.remoteport = optstr;
return;
}
dropbear_log(LOG_WARNING, "Ignoring unknown configuration option '%s'", origstr);
}

View File

@ -37,11 +37,12 @@
#include "chansession.h" #include "chansession.h"
#include "agentfwd.h" #include "agentfwd.h"
#include "crypto_desc.h" #include "crypto_desc.h"
#include "netio.h"
static void cli_remoteclosed(); static void cli_remoteclosed(void) ATTRIB_NORETURN;
static void cli_sessionloop(); static void cli_sessionloop(void);
static void cli_session_init(); static void cli_session_init(pid_t proxy_cmd_pid);
static void cli_finished(); static void cli_finished(void) ATTRIB_NORETURN;
static void recv_msg_service_accept(void); static void recv_msg_service_accept(void);
static void cli_session_cleanup(void); static void cli_session_cleanup(void);
static void recv_msg_global_request_cli(void); static void recv_msg_global_request_cli(void);
@ -72,7 +73,7 @@ static const packettype cli_packettypes[] = {
{SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_cli}, {SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_cli},
{SSH_MSG_CHANNEL_SUCCESS, ignore_recv_response}, {SSH_MSG_CHANNEL_SUCCESS, ignore_recv_response},
{SSH_MSG_CHANNEL_FAILURE, ignore_recv_response}, {SSH_MSG_CHANNEL_FAILURE, ignore_recv_response},
#ifdef ENABLE_CLI_REMOTETCPFWD #if DROPBEAR_CLI_REMOTETCPFWD
{SSH_MSG_REQUEST_SUCCESS, cli_recv_msg_request_success}, /* client */ {SSH_MSG_REQUEST_SUCCESS, cli_recv_msg_request_success}, /* client */
{SSH_MSG_REQUEST_FAILURE, cli_recv_msg_request_failure}, /* client */ {SSH_MSG_REQUEST_FAILURE, cli_recv_msg_request_failure}, /* client */
#else #else
@ -80,34 +81,50 @@ static const packettype cli_packettypes[] = {
{SSH_MSG_REQUEST_SUCCESS, ignore_recv_response}, {SSH_MSG_REQUEST_SUCCESS, ignore_recv_response},
{SSH_MSG_REQUEST_FAILURE, ignore_recv_response}, {SSH_MSG_REQUEST_FAILURE, ignore_recv_response},
#endif #endif
{0, 0} /* End */ {0, NULL} /* End */
}; };
static const struct ChanType *cli_chantypes[] = { static const struct ChanType *cli_chantypes[] = {
#ifdef ENABLE_CLI_REMOTETCPFWD #if DROPBEAR_CLI_REMOTETCPFWD
&cli_chan_tcpremote, &cli_chan_tcpremote,
#endif #endif
#ifdef ENABLE_CLI_AGENTFWD #if DROPBEAR_CLI_AGENTFWD
&cli_chan_agent, &cli_chan_agent,
#endif #endif
NULL /* Null termination */ 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, pid_t proxy_cmd_pid) {
common_session_init(sock_in, sock_out); common_session_init(sock_in, sock_out);
if (progress) {
connect_set_writequeue(progress, &ses.writequeue);
}
chaninitialise(cli_chantypes); chaninitialise(cli_chantypes);
/* Set up cli_ses vars */ /* Set up cli_ses vars */
cli_session_init(); cli_session_init(proxy_cmd_pid);
/* Ready to go */ /* Ready to go */
sessinitdone = 1; ses.init_done = 1;
/* Exchange identification */ /* Exchange identification */
send_session_identification(); send_session_identification();
kexfirstinitialise(); /* initialise the kex state */
send_msg_kexinit(); send_msg_kexinit();
session_loop(cli_sessionloop); session_loop(cli_sessionloop);
@ -116,13 +133,13 @@ void cli_session(int sock_in, int sock_out) {
} }
#ifdef USE_KEX_FIRST_FOLLOWS #if DROPBEAR_KEX_FIRST_FOLLOWS
static void cli_send_kex_first_guess() { static void cli_send_kex_first_guess() {
send_msg_kexdh_init(); send_msg_kexdh_init();
} }
#endif #endif
static void cli_session_init() { static void cli_session_init(pid_t proxy_cmd_pid) {
cli_ses.state = STATE_NOTHING; cli_ses.state = STATE_NOTHING;
cli_ses.kex_state = KEX_NOTHING; cli_ses.kex_state = KEX_NOTHING;
@ -141,18 +158,13 @@ static void cli_session_init() {
cli_ses.retval = EXIT_SUCCESS; /* Assume it's clean if we don't get a cli_ses.retval = EXIT_SUCCESS; /* Assume it's clean if we don't get a
specific exit status */ specific exit status */
cli_ses.proxy_cmd_pid = proxy_cmd_pid;
TRACE(("proxy command PID='%d'", proxy_cmd_pid));
/* Auth */ /* Auth */
cli_ses.lastprivkey = NULL; cli_ses.lastprivkey = NULL;
cli_ses.lastauthtype = 0; cli_ses.lastauthtype = 0;
#ifdef DROPBEAR_NONE_CIPHER
cli_ses.cipher_none_after_auth = get_algo_usable(sshciphers, "none");
set_algo_usable(sshciphers, "none", 0);
#else
cli_ses.cipher_none_after_auth = 0;
#endif
/* For printing "remote host closed" for the user */ /* For printing "remote host closed" for the user */
ses.remoteclosed = cli_remoteclosed; ses.remoteclosed = cli_remoteclosed;
@ -163,13 +175,13 @@ static void cli_session_init() {
ses.isserver = 0; ses.isserver = 0;
#ifdef USE_KEX_FIRST_FOLLOWS #if DROPBEAR_KEX_FIRST_FOLLOWS
ses.send_kex_first_guess = cli_send_kex_first_guess; ses.send_kex_first_guess = cli_send_kex_first_guess;
#endif #endif
} }
static void send_msg_service_request(char* servicename) { static void send_msg_service_request(const char* servicename) {
TRACE(("enter send_msg_service_request: servicename='%s'", servicename)) TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
@ -250,12 +262,9 @@ static void cli_sessionloop() {
return; return;
case USERAUTH_SUCCESS_RCVD: case USERAUTH_SUCCESS_RCVD:
#ifndef DISABLE_SYSLOG
#ifdef DROPBEAR_NONE_CIPHER if (opts.usingsyslog) {
if (cli_ses.cipher_none_after_auth) dropbear_log(LOG_INFO, "Authentication succeeded.");
{
set_algo_usable(sshciphers, "none", 1);
send_msg_kexinit();
} }
#endif #endif
@ -263,7 +272,7 @@ static void cli_sessionloop() {
int devnull; int devnull;
/* keeping stdin open steals input from the terminal and /* keeping stdin open steals input from the terminal and
is confusing, though stdout/stderr could be useful. */ is confusing, though stdout/stderr could be useful. */
devnull = open(_PATH_DEVNULL, O_RDONLY); devnull = open(DROPBEAR_PATH_DEVNULL, O_RDONLY);
if (devnull < 0) { if (devnull < 0) {
dropbear_exit("Opening /dev/null: %d %s", dropbear_exit("Opening /dev/null: %d %s",
errno, strerror(errno)); errno, strerror(errno));
@ -275,7 +284,7 @@ static void cli_sessionloop() {
} }
} }
#ifdef ENABLE_CLI_NETCAT #if DROPBEAR_CLI_NETCAT
if (cli_opts.netcat_host) { if (cli_opts.netcat_host) {
cli_send_netcat_request(); cli_send_netcat_request();
} else } else
@ -284,10 +293,10 @@ static void cli_sessionloop() {
cli_send_chansess_request(); cli_send_chansess_request();
} }
#ifdef ENABLE_CLI_LOCALTCPFWD #if DROPBEAR_CLI_LOCALTCPFWD
setup_localtcp(); setup_localtcp();
#endif #endif
#ifdef ENABLE_CLI_REMOTETCPFWD #if DROPBEAR_CLI_REMOTETCPFWD
setup_remotetcp(); setup_remotetcp();
#endif #endif
@ -316,23 +325,38 @@ static void cli_sessionloop() {
} }
void kill_proxy_command(void) {
/*
* Send SIGHUP to proxy command if used. We don't wait() in
* case it hangs and instead rely on init to reap the child
*/
if (cli_ses.proxy_cmd_pid > 1) {
TRACE(("killing proxy command with PID='%d'", cli_ses.proxy_cmd_pid));
kill(cli_ses.proxy_cmd_pid, SIGHUP);
}
}
static void cli_session_cleanup(void) { static void cli_session_cleanup(void) {
if (!sessinitdone) { if (!ses.init_done) {
return; return;
} }
kill_proxy_command();
/* Set std{in,out,err} back to non-blocking - busybox ash dies nastily if /* Set std{in,out,err} back to non-blocking - busybox ash dies nastily if
* we don't revert the flags */ * we don't revert the flags */
fcntl(cli_ses.stdincopy, F_SETFL, cli_ses.stdinflags); /* Ignore return value since there's nothing we can do */
fcntl(cli_ses.stdoutcopy, F_SETFL, cli_ses.stdoutflags); (void)fcntl(cli_ses.stdincopy, F_SETFL, cli_ses.stdinflags);
fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags); (void)fcntl(cli_ses.stdoutcopy, F_SETFL, cli_ses.stdoutflags);
(void)fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags);
cli_tty_cleanup(); cli_tty_cleanup();
} }
static void cli_finished() { static void cli_finished() {
TRACE(("cli_finised()"))
session_cleanup(); session_cleanup();
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username, fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
@ -356,10 +380,10 @@ static void cli_remoteclosed() {
/* Operates in-place turning dirty (untrusted potentially containing control /* Operates in-place turning dirty (untrusted potentially containing control
* characters) text into clean text. * characters) text into clean text.
* Note: this is safe only with ascii - other charsets could have problems. */ * 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 int i, j;
unsigned char c; char c;
j = 0; j = 0;
for (i = 0; dirtytext[i] != '\0'; i++) { for (i = 0; dirtytext[i] != '\0'; i++) {

View File

@ -23,15 +23,15 @@
* SOFTWARE. */ * SOFTWARE. */
#include "includes.h" #include "includes.h"
#include "options.h"
#include "dbutil.h" #include "dbutil.h"
#include "tcpfwd.h" #include "tcpfwd.h"
#include "channel.h" #include "channel.h"
#include "runopts.h" #include "runopts.h"
#include "session.h" #include "session.h"
#include "ssh.h" #include "ssh.h"
#include "netio.h"
#ifdef ENABLE_CLI_REMOTETCPFWD #if DROPBEAR_CLI_REMOTETCPFWD
static int newtcpforwarded(struct Channel * channel); static int newtcpforwarded(struct Channel * channel);
const struct ChanType cli_chan_tcpremote = { const struct ChanType cli_chan_tcpremote = {
@ -40,11 +40,12 @@ const struct ChanType cli_chan_tcpremote = {
newtcpforwarded, newtcpforwarded,
NULL, NULL,
NULL, NULL,
NULL,
NULL NULL
}; };
#endif #endif
#ifdef ENABLE_CLI_LOCALTCPFWD #if DROPBEAR_CLI_LOCALTCPFWD
static int cli_localtcp(const char* listenaddr, static int cli_localtcp(const char* listenaddr,
unsigned int listenport, unsigned int listenport,
const char* remoteaddr, const char* remoteaddr,
@ -55,11 +56,29 @@ static const struct ChanType cli_chan_tcplocal = {
tcp_prio_inithandler, tcp_prio_inithandler,
NULL, NULL,
NULL, NULL,
NULL,
NULL NULL
}; };
#endif #endif
#ifdef ENABLE_CLI_LOCALTCPFWD #if DROPBEAR_CLI_ANYTCPFWD
static void fwd_failed(const char* format, ...) ATTRIB_PRINTF(1,2);
static void fwd_failed(const char* format, ...)
{
va_list param;
va_start(param, format);
if (cli_opts.exit_on_fwd_failure) {
_dropbear_exit(EXIT_FAILURE, format, param);
} else {
_dropbear_log(LOG_WARNING, format, param);
}
va_end(param);
}
#endif
#if DROPBEAR_CLI_LOCALTCPFWD
void setup_localtcp() { void setup_localtcp() {
m_list_elem *iter; m_list_elem *iter;
int ret; int ret;
@ -74,7 +93,7 @@ void setup_localtcp() {
fwd->connectaddr, fwd->connectaddr,
fwd->connectport); fwd->connectport);
if (ret == DROPBEAR_FAILURE) { if (ret == DROPBEAR_FAILURE) {
dropbear_log(LOG_WARNING, "Failed local port forward %s:%d:%s:%d", fwd_failed("Failed local port forward %s:%d:%s:%d",
fwd->listenaddr, fwd->listenaddr,
fwd->listenport, fwd->listenport,
fwd->connectaddr, fwd->connectaddr,
@ -118,7 +137,7 @@ static int cli_localtcp(const char* listenaddr,
tcpinfo->chantype = &cli_chan_tcplocal; tcpinfo->chantype = &cli_chan_tcplocal;
tcpinfo->tcp_type = direct; tcpinfo->tcp_type = direct;
ret = listen_tcpfwd(tcpinfo); ret = listen_tcpfwd(tcpinfo, NULL);
if (ret == DROPBEAR_FAILURE) { if (ret == DROPBEAR_FAILURE) {
m_free(tcpinfo); m_free(tcpinfo);
@ -126,9 +145,9 @@ static int cli_localtcp(const char* listenaddr,
TRACE(("leave cli_localtcp: %d", ret)) TRACE(("leave cli_localtcp: %d", ret))
return ret; return ret;
} }
#endif /* ENABLE_CLI_LOCALTCPFWD */ #endif /* DROPBEAR_CLI_LOCALTCPFWD */
#ifdef ENABLE_CLI_REMOTETCPFWD #if DROPBEAR_CLI_REMOTETCPFWD
static void send_msg_global_request_remotetcp(const char *addr, int port) { static void send_msg_global_request_remotetcp(const char *addr, int port) {
TRACE(("enter send_msg_global_request_remotetcp")) TRACE(("enter send_msg_global_request_remotetcp"))
@ -180,7 +199,10 @@ void cli_recv_msg_request_failure() {
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item; struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
if (!fwd->have_reply) { if (!fwd->have_reply) {
fwd->have_reply = 1; fwd->have_reply = 1;
dropbear_log(LOG_WARNING, "Remote TCP forward request failed (port %d -> %s:%d)", fwd->listenport, fwd->connectaddr, fwd->connectport); fwd_failed("Remote TCP forward request failed (port %d -> %s:%d)",
fwd->listenport,
fwd->connectaddr,
fwd->connectport);
return; return;
} }
} }
@ -210,12 +232,11 @@ void setup_remotetcp() {
static int newtcpforwarded(struct Channel * channel) { static int newtcpforwarded(struct Channel * channel) {
char *origaddr = NULL; char *origaddr = NULL;
unsigned int origport; unsigned int origport;
m_list_elem * iter = NULL; m_list_elem * iter = NULL;
struct TCPFwdEntry *fwd; struct TCPFwdEntry *fwd = NULL;
char portstring[NI_MAXSERV]; char portstring[NI_MAXSERV];
int sock;
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
origaddr = buf_getstring(ses.payload, NULL); origaddr = buf_getstring(ses.payload, NULL);
@ -245,28 +266,16 @@ static int newtcpforwarded(struct Channel * channel) {
} }
if (iter == NULL) { if (iter == NULL || fwd == NULL) {
/* We didn't request forwarding on that port */ /* We didn't request forwarding on that port */
cleantext(origaddr); cleantext(origaddr);
dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"", dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"",
origaddr, origport); origaddr, origport);
goto out; goto out;
} }
snprintf(portstring, sizeof(portstring), "%d", fwd->connectport); snprintf(portstring, sizeof(portstring), "%u", fwd->connectport);
sock = connect_remote(fwd->connectaddr, portstring, 1, NULL); channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel, NULL, 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->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE; channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
@ -277,4 +286,4 @@ out:
TRACE(("leave newtcpdirect: err %d", err)) TRACE(("leave newtcpdirect: err %d", err))
return err; return err;
} }
#endif /* ENABLE_CLI_REMOTETCPFWD */ #endif /* DROPBEAR_CLI_REMOTETCPFWD */

View File

@ -27,7 +27,7 @@
#include "algo.h" #include "algo.h"
#include "session.h" #include "session.h"
#include "dbutil.h" #include "dbutil.h"
#include "kex.h" #include "dh_groups.h"
#include "ltc_prng.h" #include "ltc_prng.h"
#include "ecc.h" #include "ecc.h"
@ -53,27 +53,27 @@ static int void_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
/* Remember to add new ciphers/hashes to regciphers/reghashes too */ /* Remember to add new ciphers/hashes to regciphers/reghashes too */
#ifdef DROPBEAR_AES256 #if DROPBEAR_AES256
static const struct dropbear_cipher dropbear_aes256 = static const struct dropbear_cipher dropbear_aes256 =
{&aes_desc, 32, 16}; {&aes_desc, 32, 16};
#endif #endif
#ifdef DROPBEAR_AES128 #if DROPBEAR_AES128
static const struct dropbear_cipher dropbear_aes128 = static const struct dropbear_cipher dropbear_aes128 =
{&aes_desc, 16, 16}; {&aes_desc, 16, 16};
#endif #endif
#ifdef DROPBEAR_BLOWFISH #if DROPBEAR_BLOWFISH
static const struct dropbear_cipher dropbear_blowfish = static const struct dropbear_cipher dropbear_blowfish =
{&blowfish_desc, 16, 8}; {&blowfish_desc, 16, 8};
#endif #endif
#ifdef DROPBEAR_TWOFISH256 #if DROPBEAR_TWOFISH256
static const struct dropbear_cipher dropbear_twofish256 = static const struct dropbear_cipher dropbear_twofish256 =
{&twofish_desc, 32, 16}; {&twofish_desc, 32, 16};
#endif #endif
#ifdef DROPBEAR_TWOFISH128 #if DROPBEAR_TWOFISH128
static const struct dropbear_cipher dropbear_twofish128 = static const struct dropbear_cipher dropbear_twofish128 =
{&twofish_desc, 16, 16}; {&twofish_desc, 16, 16};
#endif #endif
#ifdef DROPBEAR_3DES #if DROPBEAR_3DES
static const struct dropbear_cipher dropbear_3des = static const struct dropbear_cipher dropbear_3des =
{&des3_desc, 24, 8}; {&des3_desc, 24, 8};
#endif #endif
@ -84,11 +84,15 @@ const struct dropbear_cipher dropbear_nocipher =
/* A few void* s are required to silence warnings /* A few void* s are required to silence warnings
* about the symmetric_CBC vs symmetric_CTR cipher_state pointer */ * about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
#if DROPBEAR_ENABLE_CBC_MODE
const struct dropbear_cipher_mode dropbear_mode_cbc = const struct dropbear_cipher_mode dropbear_mode_cbc =
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt}; {(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
#endif /* DROPBEAR_ENABLE_CBC_MODE */
const struct dropbear_cipher_mode dropbear_mode_none = const struct dropbear_cipher_mode dropbear_mode_none =
{void_start, void_cipher, void_cipher}; {void_start, void_cipher, void_cipher};
#ifdef DROPBEAR_ENABLE_CTR_MODE
#if DROPBEAR_ENABLE_CTR_MODE
/* a wrapper to make ctr_start and cbc_start look the same */ /* a wrapper to make ctr_start and cbc_start look the same */
static int dropbear_big_endian_ctr_start(int cipher, static int dropbear_big_endian_ctr_start(int cipher,
const unsigned char *IV, const unsigned char *IV,
@ -98,28 +102,28 @@ static int dropbear_big_endian_ctr_start(int cipher,
} }
const struct dropbear_cipher_mode dropbear_mode_ctr = const struct dropbear_cipher_mode dropbear_mode_ctr =
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt}; {(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
#endif #endif /* DROPBEAR_ENABLE_CTR_MODE */
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc. /* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
{&hash_desc, keysize, hashsize} */ {&hash_desc, keysize, hashsize} */
#ifdef DROPBEAR_SHA1_HMAC #if DROPBEAR_SHA1_HMAC
static const struct dropbear_hash dropbear_sha1 = static const struct dropbear_hash dropbear_sha1 =
{&sha1_desc, 20, 20}; {&sha1_desc, 20, 20};
#endif #endif
#ifdef DROPBEAR_SHA1_96_HMAC #if DROPBEAR_SHA1_96_HMAC
static const struct dropbear_hash dropbear_sha1_96 = static const struct dropbear_hash dropbear_sha1_96 =
{&sha1_desc, 20, 12}; {&sha1_desc, 20, 12};
#endif #endif
#ifdef DROPBEAR_SHA2_256_HMAC #if DROPBEAR_SHA2_256_HMAC
static const struct dropbear_hash dropbear_sha2_256 = static const struct dropbear_hash dropbear_sha2_256 =
{&sha256_desc, 32, 32}; {&sha256_desc, 32, 32};
#endif #endif
#ifdef DROPBEAR_SHA2_512_HMAC #if DROPBEAR_SHA2_512_HMAC
static const struct dropbear_hash dropbear_sha2_512 = static const struct dropbear_hash dropbear_sha2_512 =
{&sha512_desc, 64, 64}; {&sha512_desc, 64, 64};
#endif #endif
#ifdef DROPBEAR_MD5_HMAC #if DROPBEAR_MD5_HMAC
static const struct dropbear_hash dropbear_md5 = static const struct dropbear_hash dropbear_md5 =
{&md5_desc, 16, 16}; {&md5_desc, 16, 16};
#endif #endif
@ -133,69 +137,79 @@ const struct dropbear_hash dropbear_nohash =
* that is also supported by the server will get used. */ * that is also supported by the server will get used. */
algo_type sshciphers[] = { algo_type sshciphers[] = {
#ifdef DROPBEAR_ENABLE_CTR_MODE #if DROPBEAR_ENABLE_CTR_MODE
#ifdef DROPBEAR_AES128 #if DROPBEAR_AES128
{"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr}, {"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
#endif #endif
#ifdef DROPBEAR_3DES #if DROPBEAR_AES256
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_AES256
{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr}, {"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
#endif #endif
#if DROPBEAR_TWOFISH_CTR
/* twofish ctr is conditional as it hasn't been tested for interoperability, see options.h */
#if DROPBEAR_TWOFISH256
{"twofish256-ctr", 0, &dropbear_twofish256, 1, &dropbear_mode_ctr},
#endif
#if DROPBEAR_TWOFISH128
{"twofish128-ctr", 0, &dropbear_twofish128, 1, &dropbear_mode_ctr},
#endif
#endif /* DROPBEAR_TWOFISH_CTR */
#endif /* DROPBEAR_ENABLE_CTR_MODE */ #endif /* DROPBEAR_ENABLE_CTR_MODE */
/* CBC modes are always enabled */ #if DROPBEAR_ENABLE_CBC_MODE
#ifdef DROPBEAR_AES128 #if DROPBEAR_AES128
{"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc}, {"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc},
#endif #endif
#ifdef DROPBEAR_3DES #if DROPBEAR_AES256
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_AES256
{"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc}, {"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
#endif #endif
#ifdef DROPBEAR_TWOFISH256 #if DROPBEAR_TWOFISH256
{"twofish256-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc}, {"twofish256-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
{"twofish-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc}, {"twofish-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
#endif #endif
#ifdef DROPBEAR_TWOFISH128 #if DROPBEAR_TWOFISH128
{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc}, {"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
#endif #endif
#ifdef DROPBEAR_BLOWFISH #if DROPBEAR_3DES
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
#endif
#if DROPBEAR_3DES
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
#endif
#if DROPBEAR_BLOWFISH
{"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc}, {"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
#endif #endif
#ifdef DROPBEAR_NONE_CIPHER #endif /* DROPBEAR_ENABLE_CBC_MODE */
{"none", 0, (void*)&dropbear_nocipher, 1, &dropbear_mode_none},
#endif
{NULL, 0, NULL, 0, NULL} {NULL, 0, NULL, 0, NULL}
}; };
algo_type sshhashes[] = { algo_type sshhashes[] = {
#ifdef DROPBEAR_SHA2_256_HMAC #if DROPBEAR_SHA1_96_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}, {"hmac-sha1-96", 0, &dropbear_sha1_96, 1, NULL},
#endif #endif
#ifdef DROPBEAR_SHA1_HMAC #if DROPBEAR_SHA1_HMAC
{"hmac-sha1", 0, &dropbear_sha1, 1, NULL}, {"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
#endif #endif
#ifdef DROPBEAR_MD5_HMAC #if DROPBEAR_SHA2_256_HMAC
{"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL}, {"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
#endif #endif
#ifdef DROPBEAR_NONE_INTEGRITY #if DROPBEAR_SHA2_512_HMAC
{"none", 0, (void*)&dropbear_nohash, 1, NULL}, {"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
#endif
#if DROPBEAR_MD5_HMAC
{"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL},
#endif #endif
{NULL, 0, NULL, 0, NULL} {NULL, 0, NULL, 0, NULL}
}; };
#ifndef DISABLE_ZLIB #ifndef DISABLE_ZLIB
algo_type ssh_compress[] = { algo_type ssh_compress[] = {
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL}, {"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
{NULL, 0, NULL, 0, NULL}
};
algo_type ssh_delaycompress[] = {
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL}, {"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL}, {"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
{NULL, 0, NULL, 0, NULL} {NULL, 0, NULL, 0, NULL}
@ -208,66 +222,87 @@ algo_type ssh_nocompress[] = {
}; };
algo_type sshhostkey[] = { algo_type sshhostkey[] = {
#ifdef DROPBEAR_ECDSA #if DROPBEAR_ECDSA
#ifdef DROPBEAR_ECC_256 #if DROPBEAR_ECC_256
{"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL}, {"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL},
#endif #endif
#ifdef DROPBEAR_ECC_384 #if DROPBEAR_ECC_384
{"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL}, {"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL},
#endif #endif
#ifdef DROPBEAR_ECC_521 #if DROPBEAR_ECC_521
{"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL}, {"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL},
#endif #endif
#endif #endif
#ifdef DROPBEAR_RSA #if DROPBEAR_RSA
{"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL}, {"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL},
#endif #endif
#ifdef DROPBEAR_DSS #if DROPBEAR_DSS
{"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1, NULL}, {"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1, NULL},
#endif #endif
{NULL, 0, NULL, 0, NULL} {NULL, 0, NULL, 0, NULL}
}; };
#if DROPBEAR_DH_GROUP1
static const struct dropbear_kex kex_dh_group1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_1, DH_P_1_LEN, NULL, &sha1_desc }; static const struct dropbear_kex kex_dh_group1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_1, DH_P_1_LEN, NULL, &sha1_desc };
static const struct dropbear_kex kex_dh_group14 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha1_desc }; #endif
#if DROPBEAR_DH_GROUP14_SHA1
static const struct dropbear_kex kex_dh_group14_sha1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha1_desc };
#endif
#if DROPBEAR_DH_GROUP14_SHA256
static const struct dropbear_kex kex_dh_group14_sha256 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha256_desc };
#endif
#if DROPBEAR_DH_GROUP16
static const struct dropbear_kex kex_dh_group16_sha512 = {DROPBEAR_KEX_NORMAL_DH, dh_p_16, DH_P_16_LEN, NULL, &sha512_desc };
#endif
/* These can't be const since dropbear_ecc_fill_dp() fills out /* These can't be const since dropbear_ecc_fill_dp() fills out
ecc_curve at runtime */ ecc_curve at runtime */
#ifdef DROPBEAR_ECDH #if DROPBEAR_ECDH
#ifdef DROPBEAR_ECC_256 #if DROPBEAR_ECC_256
static struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc }; static const struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
#endif #endif
#ifdef DROPBEAR_ECC_384 #if DROPBEAR_ECC_384
static struct dropbear_kex kex_ecdh_nistp384 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp384, &sha384_desc }; static const struct dropbear_kex kex_ecdh_nistp384 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp384, &sha384_desc };
#endif #endif
#ifdef DROPBEAR_ECC_521 #if DROPBEAR_ECC_521
static struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp521, &sha512_desc }; static const struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp521, &sha512_desc };
#endif #endif
#endif /* DROPBEAR_ECDH */ #endif /* DROPBEAR_ECDH */
#ifdef DROPBEAR_CURVE25519 #if DROPBEAR_CURVE25519
/* Referred to directly */ /* Referred to directly */
static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc }; static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc };
#endif #endif
algo_type sshkex[] = { algo_type sshkex[] = {
#ifdef DROPBEAR_CURVE25519 #if DROPBEAR_CURVE25519
{"curve25519-sha256", 0, &kex_curve25519, 1, NULL},
{"curve25519-sha256@libssh.org", 0, &kex_curve25519, 1, NULL}, {"curve25519-sha256@libssh.org", 0, &kex_curve25519, 1, NULL},
#endif #endif
#ifdef DROPBEAR_ECDH #if DROPBEAR_ECDH
#ifdef DROPBEAR_ECC_521 #if DROPBEAR_ECC_521
{"ecdh-sha2-nistp521", 0, &kex_ecdh_nistp521, 1, NULL}, {"ecdh-sha2-nistp521", 0, &kex_ecdh_nistp521, 1, NULL},
#endif #endif
#ifdef DROPBEAR_ECC_384 #if DROPBEAR_ECC_384
{"ecdh-sha2-nistp384", 0, &kex_ecdh_nistp384, 1, NULL}, {"ecdh-sha2-nistp384", 0, &kex_ecdh_nistp384, 1, NULL},
#endif #endif
#ifdef DROPBEAR_ECC_256 #if DROPBEAR_ECC_256
{"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL}, {"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL},
#endif #endif
#endif #endif
#if DROPBEAR_DH_GROUP14_SHA256
{"diffie-hellman-group14-sha256", 0, &kex_dh_group14_sha256, 1, NULL},
#endif
#if DROPBEAR_DH_GROUP14_SHA1
{"diffie-hellman-group14-sha1", 0, &kex_dh_group14_sha1, 1, NULL},
#endif
#if DROPBEAR_DH_GROUP1
{"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL}, {"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL},
{"diffie-hellman-group14-sha1", 0, &kex_dh_group14, 1, NULL}, #endif
#ifdef USE_KEXGUESS2 #if DROPBEAR_DH_GROUP16
{"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL},
#endif
#if DROPBEAR_KEXGUESS2
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL}, {KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
#endif #endif
{NULL, 0, NULL, 0, NULL} {NULL, 0, NULL, 0, NULL}
@ -277,7 +312,7 @@ algo_type sshkex[] = {
* against. * against.
* Returns DROPBEAR_SUCCESS if we have a match for algo, DROPBEAR_FAILURE * Returns DROPBEAR_SUCCESS if we have a match for algo, DROPBEAR_FAILURE
* otherwise */ * otherwise */
int have_algo(char* algo, size_t algolen, algo_type algos[]) { int have_algo(const char* algo, size_t algolen, const algo_type algos[]) {
int i; int i;
@ -292,23 +327,24 @@ int have_algo(char* algo, size_t algolen, algo_type algos[]) {
} }
/* Output a comma separated list of algorithms to a buffer */ /* Output a comma separated list of algorithms to a buffer */
void buf_put_algolist(buffer * buf, algo_type localalgos[]) { void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
unsigned int i, len; unsigned int i, len;
unsigned int donefirst = 0; unsigned int donefirst = 0;
buffer *algolist = NULL; buffer *algolist = NULL;
algolist = buf_new(200); algolist = buf_new(300);
for (i = 0; localalgos[i].name != NULL; i++) { for (i = 0; localalgos[i].name != NULL; i++) {
if (localalgos[i].usable) { if (localalgos[i].usable) {
if (donefirst) if (donefirst)
buf_putbyte(algolist, ','); buf_putbyte(algolist, ',');
donefirst = 1; donefirst = 1;
len = strlen(localalgos[i].name); 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);
TRACE(("algolist add '%*s'", algolist->len, algolist->data))
buf_free(algolist); buf_free(algolist);
} }
@ -321,12 +357,12 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
enum kexguess2_used *kexguess2, int *goodguess) enum kexguess2_used *kexguess2, int *goodguess)
{ {
unsigned char * algolist = NULL; char * algolist = NULL;
const unsigned char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO]; const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
unsigned int len; unsigned int len;
unsigned int remotecount, localcount, clicount, servcount, i, j; unsigned int remotecount, localcount, clicount, servcount, i, j;
algo_type * ret = NULL; algo_type * ret = NULL;
const unsigned char **clinames, **servnames; const char **clinames, **servnames;
if (goodguess) { if (goodguess) {
*goodguess = 0; *goodguess = 0;
@ -428,42 +464,10 @@ out:
return ret; return ret;
} }
#ifdef DROPBEAR_NONE_CIPHER #if DROPBEAR_USER_ALGO_LIST
void
set_algo_usable(algo_type algos[], const char * algo_name, int usable)
{
algo_type *a;
for (a = algos; a->name != NULL; a++)
{
if (strcmp(a->name, algo_name) == 0)
{
a->usable = usable;
return;
}
}
}
int
get_algo_usable(algo_type algos[], const char * algo_name)
{
algo_type *a;
for (a = algos; a->name != NULL; a++)
{
if (strcmp(a->name, algo_name) == 0)
{
return a->usable;
}
}
return 0;
}
#endif /* DROPBEAR_NONE_CIPHER */
#ifdef ENABLE_USER_ALGO_LIST
char * char *
algolist_string(algo_type algos[]) algolist_string(const algo_type algos[])
{ {
char *ret_list; char *ret_list;
buffer *b = buf_new(200); buffer *b = buf_new(200);
@ -471,7 +475,7 @@ algolist_string(algo_type algos[])
buf_setpos(b, b->len); buf_setpos(b, b->len);
buf_putbyte(b, '\0'); buf_putbyte(b, '\0');
buf_setpos(b, 4); 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); buf_free(b);
return ret_list; return ret_list;
} }
@ -491,21 +495,6 @@ check_algo(const char* algo_name, algo_type *algos)
return NULL; return NULL;
} }
static void
try_add_algo(const char *algo_name, algo_type *algos,
const char *algo_desc, algo_type * new_algos, int *num_ret)
{
algo_type *match_algo = check_algo(algo_name, algos);
if (!match_algo)
{
dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", algo_name, algo_desc);
return;
}
new_algos[*num_ret] = *match_algo;
(*num_ret)++;
}
/* Checks a user provided comma-separated algorithm list for available /* Checks a user provided comma-separated algorithm list for available
* options. Any that are not acceptable are removed in-place. Returns the * options. Any that are not acceptable are removed in-place. Returns the
* number of valid algorithms. */ * number of valid algorithms. */
@ -513,30 +502,43 @@ int
check_user_algos(const char* user_algo_list, algo_type * algos, check_user_algos(const char* user_algo_list, algo_type * algos,
const char *algo_desc) const char *algo_desc)
{ {
algo_type new_algos[MAX_PROPOSED_ALGO]; algo_type new_algos[MAX_PROPOSED_ALGO+1];
/* this has two passes. first we sweep through the given list of
* algorithms and mark them as usable=2 in the algo_type[] array... */
int num_ret = 0;
char *work_list = m_strdup(user_algo_list); char *work_list = m_strdup(user_algo_list);
char *last_name = work_list; char *start = work_list;
char *c; char *c;
for (c = work_list; *c; c++) int n;
/* So we can iterate and look for null terminator */
memset(new_algos, 0x0, sizeof(new_algos));
for (c = work_list, n = 0; ; c++)
{ {
if (*c == ',') char oc = *c;
{ if (n >= MAX_PROPOSED_ALGO) {
dropbear_exit("Too many algorithms '%s'", user_algo_list);
}
if (*c == ',' || *c == '\0') {
algo_type *match_algo = NULL;
*c = '\0'; *c = '\0';
try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret); match_algo = check_algo(start, algos);
if (match_algo) {
if (check_algo(start, new_algos)) {
TRACE(("Skip repeated algorithm '%s'", start))
} else {
new_algos[n] = *match_algo;
n++;
}
} else {
dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", start, algo_desc);
}
c++; c++;
last_name = c; start = c;
}
if (oc == '\0') {
break;
} }
} }
try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret);
m_free(work_list); m_free(work_list);
/* n+1 to include a null terminator */
new_algos[num_ret].name = NULL; memcpy(algos, new_algos, sizeof(*new_algos) * (n+1));
return n;
/* Copy one more as a blank delimiter */
memcpy(algos, new_algos, sizeof(*new_algos) * (num_ret+1));
return num_ret;
} }
#endif /* ENABLE_USER_ALGO_LIST */ #endif /* DROPBEAR_USER_ALGO_LIST */

View File

@ -32,24 +32,24 @@
#include "circbuffer.h" #include "circbuffer.h"
#include "dbutil.h" #include "dbutil.h"
#include "channel.h" #include "channel.h"
#include "ssh.h"
#include "listener.h" #include "listener.h"
#include "runopts.h" #include "runopts.h"
#include "netio.h"
static void send_msg_channel_open_failure(unsigned int remotechan, int reason, 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, static void send_msg_channel_open_confirmation(const struct Channel* channel,
unsigned int recvwindow, unsigned int recvwindow,
unsigned int recvmaxpacket); unsigned int recvmaxpacket);
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf); static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
static void send_msg_channel_window_adjust(struct Channel *channel, const unsigned char *moredata, unsigned int *morelen);
static void send_msg_channel_window_adjust(const struct Channel *channel,
unsigned int incr); unsigned int incr);
static void send_msg_channel_data(struct Channel *channel, int isextended); 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_eof(struct Channel *channel);
static void send_msg_channel_close(struct Channel *channel); static void send_msg_channel_close(struct Channel *channel);
static void remove_channel(struct Channel *channel); static void remove_channel(struct Channel *channel);
static void check_in_progress(struct Channel *channel); static unsigned int write_pending(const struct Channel * channel);
static unsigned int write_pending(struct Channel * channel);
static void check_close(struct Channel *channel); static void check_close(struct Channel *channel);
static void close_chan_fd(struct Channel *channel, int fd, int how); static void close_chan_fd(struct Channel *channel, int fd, int how);
@ -77,7 +77,7 @@ void chaninitialise(const struct ChanType *chantypes[]) {
ses.chantypes = chantypes; ses.chantypes = chantypes;
#ifdef USING_LISTENERS #if DROPBEAR_LISTENERS
listeners_initialise(); listeners_initialise();
#endif #endif
@ -99,15 +99,6 @@ void chancleanup() {
TRACE(("leave 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 */ /* Create a new channel entry, send a reply confirm or failure */
/* If remotechan, transwindow and transmaxpacket are not know (for a new /* If remotechan, transwindow and transmaxpacket are not know (for a new
* outgoing connection, with them to be filled on confirmation), they should * outgoing connection, with them to be filled on confirmation), they should
@ -153,7 +144,6 @@ static struct Channel* newchannel(unsigned int remotechan,
newchan->index = i; newchan->index = i;
newchan->sent_close = newchan->recv_close = 0; newchan->sent_close = newchan->recv_close = 0;
newchan->sent_eof = newchan->recv_eof = 0; newchan->sent_eof = newchan->recv_eof = 0;
newchan->close_handler_done = 0;
newchan->remotechan = remotechan; newchan->remotechan = remotechan;
newchan->transwindow = transwindow; newchan->transwindow = transwindow;
@ -163,12 +153,11 @@ static struct Channel* newchannel(unsigned int remotechan,
newchan->writefd = FD_UNINIT; newchan->writefd = FD_UNINIT;
newchan->readfd = FD_UNINIT; newchan->readfd = FD_UNINIT;
newchan->errfd = FD_CLOSED; /* this isn't always set to start with */ newchan->errfd = FD_CLOSED; /* this isn't always set to start with */
newchan->initconn = 0;
newchan->await_open = 0; newchan->await_open = 0;
newchan->flushing = 0; newchan->flushing = 0;
newchan->writebuf = cbuf_new(0); /* resized later by chan_initwritebuf */ newchan->writebuf = cbuf_new(opts.recv_window);
newchan->recvwindow = 0; newchan->recvwindow = opts.recv_window;
newchan->extrabuf = NULL; /* The user code can set it up */ newchan->extrabuf = NULL; /* The user code can set it up */
newchan->recvdonelen = 0; newchan->recvdonelen = 0;
@ -208,7 +197,7 @@ struct Channel* getchannel() {
} }
/* Iterate through the channels, performing IO if available */ /* Iterate through the channels, performing IO if available */
void channelio(fd_set *readfds, fd_set *writefds) { void channelio(const fd_set *readfds, const fd_set *writefds) {
/* Listeners such as TCP, X11, agent-auth */ /* Listeners such as TCP, X11, agent-auth */
struct Channel *channel; struct Channel *channel;
@ -242,27 +231,20 @@ void channelio(fd_set *readfds, fd_set *writefds) {
/* write to program/pipe stdin */ /* write to program/pipe stdin */
if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) { if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) {
if (channel->initconn) { writechannel(channel, channel->writefd, channel->writebuf, NULL, NULL);
/* 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);
do_check_close = 1; do_check_close = 1;
} }
/* stderr for client mode */ /* stderr for client mode */
if (ERRFD_IS_WRITE(channel) if (ERRFD_IS_WRITE(channel)
&& channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) { && 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; do_check_close = 1;
} }
if (ses.channel_signal_pending) { if (ses.channel_signal_pending) {
/* SIGCHLD can change channel state for server sessions */ /* SIGCHLD can change channel state for server sessions */
do_check_close = 1; do_check_close = 1;
ses.channel_signal_pending = 0;
} }
/* handle any channel closing etc */ /* handle any channel closing etc */
@ -271,7 +253,7 @@ void channelio(fd_set *readfds, fd_set *writefds) {
} }
} }
#ifdef USING_LISTENERS #if DROPBEAR_LISTENERS
handle_listeners(readfds); handle_listeners(readfds);
#endif #endif
} }
@ -279,7 +261,7 @@ void channelio(fd_set *readfds, fd_set *writefds) {
/* Returns true if there is data remaining to be written to stdin or /* Returns true if there is data remaining to be written to stdin or
* stderr of a channel's endpoint. */ * stderr of a channel's endpoint. */
static unsigned int write_pending(struct Channel * channel) { static unsigned int write_pending(const struct Channel * channel) {
if (channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0) { if (channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0) {
return 1; return 1;
@ -303,7 +285,7 @@ static void check_close(struct Channel *channel) {
channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0)) channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0))
if (!channel->flushing if (!channel->flushing
&& !channel->close_handler_done && !channel->sent_close
&& channel->type->check_close && channel->type->check_close
&& channel->type->check_close(channel)) && channel->type->check_close(channel))
{ {
@ -315,7 +297,7 @@ static void check_close(struct Channel *channel) {
channel, to ensure that the shell has exited (and the exit status channel, to ensure that the shell has exited (and the exit status
retrieved) before we close things up. */ retrieved) before we close things up. */
if (!channel->type->check_close if (!channel->type->check_close
|| channel->close_handler_done || channel->sent_close
|| channel->type->check_close(channel)) { || channel->type->check_close(channel)) {
close_allowed = 1; close_allowed = 1;
} }
@ -374,27 +356,26 @@ static void check_close(struct Channel *channel) {
* if so, set up the channel properly. Otherwise, the channel is cleaned up, so * 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 * it is important that the channel reference isn't used after a call to this
* function */ * 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; struct Channel *channel = user_data;
socklen_t vallen = sizeof(val);
TRACE(("enter check_in_progress")) TRACE(("enter channel_connect_done"))
if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen) if (result == DROPBEAR_SUCCESS)
|| val != 0) { {
send_msg_channel_open_failure(channel->remotechan, channel->readfd = channel->writefd = sock;
SSH_OPEN_CONNECT_FAILED, "", ""); channel->conn_pending = NULL;
close(channel->writefd);
remove_channel(channel);
TRACE(("leave check_in_progress: fail"))
} else {
chan_initwritebuf(channel);
send_msg_channel_open_confirmation(channel, channel->recvwindow, send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket); channel->recvmaxpacket);
channel->readfd = channel->writefd; TRACE(("leave channel_connect_done: success"))
channel->initconn = 0; }
TRACE(("leave check_in_progress: success")) else
{
send_msg_channel_open_failure(channel->remotechan,
SSH_OPEN_CONNECT_FAILED, "", "");
remove_channel(channel);
TRACE(("leave check_in_progress: fail"))
} }
} }
@ -402,11 +383,9 @@ static void check_in_progress(struct Channel *channel) {
/* Send the close message and set the channel as closed */ /* Send the close message and set the channel as closed */
static void send_msg_channel_close(struct Channel *channel) { 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 if (channel->type->closehandler) {
&& !channel->close_handler_done) {
channel->type->closehandler(channel); channel->type->closehandler(channel);
channel->close_handler_done = 1;
} }
CHECKCLEARTOWRITE(); CHECKCLEARTOWRITE();
@ -440,35 +419,120 @@ static void send_msg_channel_eof(struct Channel *channel) {
TRACE(("leave send_msg_channel_eof")) TRACE(("leave send_msg_channel_eof"))
} }
/* Called to write data out to the local side of the channel. #ifndef HAVE_WRITEV
* Only called when we know we can write to a channel, writes as much as static int writechannel_fallback(struct Channel* channel, int fd, circbuffer *cbuf,
* possible */ const unsigned char *UNUSED(moredata), unsigned int *morelen) {
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
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 */
maxlen = cbuf_readlen(cbuf); *morelen = 0;
/* Write the data out */
len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
if (len <= 0) {
TRACE(("errno %d len %d", errno, len))
if (len < 0 && errno != EINTR) {
close_chan_fd(channel, fd, SHUT_WR);
}
TRACE(("leave writechannel: len <= 0"))
return;
} }
TRACE(("writechannel wrote %d", len))
cbuf_incrread(cbuf, len); /* Write the first portion of the circular buffer */
channel->recvdonelen += len; 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 */
#ifdef HAVE_WRITEV
static int writechannel_writev(struct Channel* channel, int fd, circbuffer *cbuf,
const unsigned char *moredata, unsigned int *morelen) {
struct iovec iov[3];
unsigned char *circ_p1, *circ_p2;
unsigned int circ_len1, circ_len2;
int io_count = 0;
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;
}
} 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;
}
return DROPBEAR_SUCCESS;
}
#endif /* HAVE_WRITEV */
/* Called to write data out to the local side of the channel.
Writes the circular buffer contents and also the "moredata" buffer
if not null. Will ignore EAGAIN.
Returns DROPBEAR_FAILURE if writing to fd had an error and the channel is being closed, DROPBEAR_SUCCESS otherwise */
static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
const unsigned char *moredata, unsigned int *morelen) {
int ret = DROPBEAR_SUCCESS;
TRACE(("enter writechannel fd %d", fd))
#ifdef HAVE_WRITEV
ret = writechannel_writev(channel, fd, cbuf, moredata, morelen);
#else
ret = writechannel_fallback(channel, fd, cbuf, moredata, morelen);
#endif
/* Window adjust handling */ /* Window adjust handling */
if (channel->recvdonelen >= RECV_WINDOWEXTEND) { if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
/* Set it back to max window */
send_msg_channel_window_adjust(channel, channel->recvdonelen); send_msg_channel_window_adjust(channel, channel->recvdonelen);
channel->recvwindow += channel->recvdonelen; channel->recvwindow += channel->recvdonelen;
channel->recvdonelen = 0; channel->recvdonelen = 0;
@ -480,11 +544,13 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
channel->recvwindow <= cbuf_getavail(channel->extrabuf)); channel->recvwindow <= cbuf_getavail(channel->extrabuf));
TRACE(("leave writechannel")) TRACE(("leave writechannel"))
return ret;
} }
/* Set the file descriptors for the main select in session.c /* Set the file descriptors for the main select in session.c
* This avoid channels which don't have any window available, are closed, etc*/ * 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; unsigned int i;
struct Channel * channel; struct Channel * channel;
@ -502,7 +568,7 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
FD if there's the possibility of "~."" to kill an FD if there's the possibility of "~."" to kill an
interactive session (the read_mangler) */ interactive session (the read_mangler) */
if (channel->transwindow > 0 if (channel->transwindow > 0
&& (ses.dataallowed || channel->read_mangler)) { && ((ses.dataallowed && allow_reads) || channel->read_mangler)) {
if (channel->readfd >= 0) { if (channel->readfd >= 0) {
FD_SET(channel->readfd, readfds); FD_SET(channel->readfd, readfds);
@ -514,8 +580,7 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
} }
/* Stuff from the wire */ /* Stuff from the wire */
if (channel->initconn if (channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0) {
||(channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0)) {
FD_SET(channel->writefd, writefds); FD_SET(channel->writefd, writefds);
} }
@ -526,7 +591,7 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
} /* foreach channel */ } /* foreach channel */
#ifdef USING_LISTENERS #if DROPBEAR_LISTENERS
set_listener_fds(readfds); set_listener_fds(readfds);
#endif #endif
@ -586,17 +651,19 @@ static void remove_channel(struct Channel * channel) {
/* close the FDs in case they haven't been done /* close the FDs in case they haven't been done
* yet (they might have been shutdown etc) */ * yet (they might have been shutdown etc) */
TRACE(("CLOSE writefd %d", channel->writefd)) TRACE(("CLOSE writefd %d", channel->writefd))
close(channel->writefd); m_close(channel->writefd);
TRACE(("CLOSE readfd %d", channel->readfd)) TRACE(("CLOSE readfd %d", channel->readfd))
close(channel->readfd); m_close(channel->readfd);
TRACE(("CLOSE errfd %d", channel->errfd)) TRACE(("CLOSE errfd %d", channel->errfd))
close(channel->errfd); m_close(channel->errfd);
} }
if (!channel->close_handler_done if (channel->type->cleanup) {
&& channel->type->closehandler) { channel->type->cleanup(channel);
channel->type->closehandler(channel); }
channel->close_handler_done = 1;
if (channel->conn_pending) {
cancel_connect(channel->conn_pending);
} }
ses.channels[channel->index] = NULL; ses.channels[channel->index] = NULL;
@ -616,15 +683,9 @@ void recv_msg_channel_request() {
channel = getchannel(); channel = getchannel();
TRACE(("enter recv_msg_channel_request %p", channel)) TRACE(("enter recv_msg_channel_request %p", (void*)channel))
if (channel->sent_close) { if (channel->type->reqhandler) {
TRACE(("leave recv_msg_channel_request: already closed channel"))
return;
}
if (channel->type->reqhandler
&& !channel->close_handler_done) {
channel->type->reqhandler(channel); channel->type->reqhandler(channel);
} else { } else {
int wantreply; int wantreply;
@ -749,6 +810,8 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
unsigned int maxdata; unsigned int maxdata;
unsigned int buflen; unsigned int buflen;
unsigned int len; unsigned int len;
unsigned int consumed;
int res;
TRACE(("enter recv_msg_channel_data")) TRACE(("enter recv_msg_channel_data"))
@ -775,25 +838,36 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
dropbear_exit("Oversized packet"); 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); dropbear_assert(channel->recvwindow >= datalen);
channel->recvwindow -= datalen; channel->recvwindow -= datalen;
dropbear_assert(channel->recvwindow <= opts.recv_window); 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")) TRACE(("leave recv_msg_channel_data"))
} }
@ -818,7 +892,7 @@ void recv_msg_channel_window_adjust() {
/* Increment the incoming data window for a channel, and let the remote /* Increment the incoming data window for a channel, and let the remote
* end know */ * end know */
static void send_msg_channel_window_adjust(struct Channel* channel, static void send_msg_channel_window_adjust(const struct Channel* channel,
unsigned int incr) { unsigned int incr) {
TRACE(("sending window adjust %d", incr)) TRACE(("sending window adjust %d", incr))
@ -834,7 +908,7 @@ static void send_msg_channel_window_adjust(struct Channel* channel,
/* Handle a new channel request, performing any channel-type-specific setup */ /* Handle a new channel request, performing any channel-type-specific setup */
void recv_msg_channel_open() { void recv_msg_channel_open() {
unsigned char *type; char *type;
unsigned int typelen; unsigned int typelen;
unsigned int remotechan, transwindow, transmaxpacket; unsigned int remotechan, transwindow, transmaxpacket;
struct Channel *channel; struct Channel *channel;
@ -883,6 +957,7 @@ void recv_msg_channel_open() {
if (channel == NULL) { if (channel == NULL) {
TRACE(("newchannel returned NULL")) TRACE(("newchannel returned NULL"))
errtype = SSH_OPEN_RESOURCE_SHORTAGE;
goto failure; goto failure;
} }
@ -904,8 +979,6 @@ void recv_msg_channel_open() {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK; channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
} }
chan_initwritebuf(channel);
/* success */ /* success */
send_msg_channel_open_confirmation(channel, channel->recvwindow, send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket); channel->recvmaxpacket);
@ -924,9 +997,14 @@ cleanup:
} }
/* Send a failure message */ /* Send a failure message */
void send_msg_channel_failure(struct Channel *channel) { void send_msg_channel_failure(const struct Channel *channel) {
TRACE(("enter send_msg_channel_failure")) TRACE(("enter send_msg_channel_failure"))
if (channel->sent_close) {
TRACE(("Skipping sending msg_channel_failure for closed channel"))
return;
}
CHECKCLEARTOWRITE(); CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_FAILURE); buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_FAILURE);
@ -937,9 +1015,13 @@ void send_msg_channel_failure(struct Channel *channel) {
} }
/* Send a success message */ /* Send a success message */
void send_msg_channel_success(struct Channel *channel) { void send_msg_channel_success(const struct Channel *channel) {
TRACE(("enter send_msg_channel_success")) TRACE(("enter send_msg_channel_success"))
if (channel->sent_close) {
TRACE(("Skipping sending msg_channel_success for closed channel"))
return;
}
CHECKCLEARTOWRITE(); CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_SUCCESS); buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_SUCCESS);
@ -952,7 +1034,7 @@ void send_msg_channel_success(struct Channel *channel) {
/* Send a channel open failure message, with a corresponding reason /* Send a channel open failure message, with a corresponding reason
* code (usually resource shortage or unknown chan type) */ * code (usually resource shortage or unknown chan type) */
static void send_msg_channel_open_failure(unsigned int remotechan, 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")) TRACE(("enter send_msg_channel_open_failure"))
CHECKCLEARTOWRITE(); CHECKCLEARTOWRITE();
@ -960,8 +1042,8 @@ static void send_msg_channel_open_failure(unsigned int remotechan,
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN_FAILURE); buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN_FAILURE);
buf_putint(ses.writepayload, remotechan); buf_putint(ses.writepayload, remotechan);
buf_putint(ses.writepayload, reason); buf_putint(ses.writepayload, reason);
buf_putstring(ses.writepayload, text, strlen((char*)text)); buf_putstring(ses.writepayload, text, strlen(text));
buf_putstring(ses.writepayload, lang, strlen((char*)lang)); buf_putstring(ses.writepayload, lang, strlen(lang));
encrypt_packet(); encrypt_packet();
TRACE(("leave send_msg_channel_open_failure")) TRACE(("leave send_msg_channel_open_failure"))
@ -969,7 +1051,7 @@ static void send_msg_channel_open_failure(unsigned int remotechan,
/* Confirm a channel open, and let the remote end know what number we've /* Confirm a channel open, and let the remote end know what number we've
* allocated and the receive parameters */ * allocated and the receive parameters */
static void send_msg_channel_open_confirmation(struct Channel* channel, static void send_msg_channel_open_confirmation(const struct Channel* channel,
unsigned int recvwindow, unsigned int recvwindow,
unsigned int recvmaxpacket) { unsigned int recvmaxpacket) {
@ -1001,7 +1083,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
} }
} else { } else {
TRACE(("CLOSE some fd %d", fd)) TRACE(("CLOSE some fd %d", fd))
close(fd); m_close(fd);
closein = closeout = 1; closein = closeout = 1;
} }
@ -1024,12 +1106,12 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
if (channel->type->sepfds && channel->readfd == FD_CLOSED if (channel->type->sepfds && channel->readfd == FD_CLOSED
&& channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) { && channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {
TRACE(("CLOSE (finally) of %d", fd)) TRACE(("CLOSE (finally) of %d", fd))
close(fd); m_close(fd);
} }
} }
#if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT) #if (DROPBEAR_LISTENERS) || (DROPBEAR_CLIENT)
/* Create a new channel, and start the open request. This is intended /* Create a new channel, and start the open request. This is intended
* for X11, agent, tcp forwarding, and should be filled with channel-specific * for X11, agent, tcp forwarding, and should be filled with channel-specific
* options, with the calling function calling encrypt_packet() after * options, with the calling function calling encrypt_packet() after
@ -1048,7 +1130,6 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
/* Outbound opened channels don't make use of in-progress connections, /* Outbound opened channels don't make use of in-progress connections,
* we can set it up straight away */ * we can set it up straight away */
chan_initwritebuf(chan);
/* set fd non-blocking */ /* set fd non-blocking */
setnonblocking(fd); setnonblocking(fd);
@ -1126,7 +1207,7 @@ void recv_msg_channel_open_failure() {
remove_channel(channel); remove_channel(channel);
} }
#endif /* USING_LISTENERS */ #endif /* DROPBEAR_LISTENERS */
void send_msg_request_success() { void send_msg_request_success() {
CHECKCLEARTOWRITE(); CHECKCLEARTOWRITE();
@ -1141,23 +1222,23 @@ void send_msg_request_failure() {
} }
struct Channel* get_any_ready_channel() { struct Channel* get_any_ready_channel() {
size_t i;
if (ses.chancount == 0) { if (ses.chancount == 0) {
return NULL; return NULL;
} }
size_t i;
for (i = 0; i < ses.chansize; i++) { for (i = 0; i < ses.chansize; i++) {
struct Channel *chan = ses.channels[i]; struct Channel *chan = ses.channels[i];
if (chan if (chan
&& !(chan->sent_eof || chan->recv_eof) && !(chan->sent_eof || chan->recv_eof)
&& !(chan->await_open || chan->initconn)) { && !(chan->await_open)) {
return chan; return chan;
} }
} }
return NULL; return NULL;
} }
void start_send_channel_request(struct Channel *channel, void start_send_channel_request(const struct Channel *channel,
unsigned char *type) { const char *type) {
CHECKCLEARTOWRITE(); CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST); buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);

View File

@ -29,6 +29,7 @@
#include "buffer.h" #include "buffer.h"
#include "session.h" #include "session.h"
#include "kex.h" #include "kex.h"
#include "dh_groups.h"
#include "ssh.h" #include "ssh.h"
#include "packet.h" #include "packet.h"
#include "bignum.h" #include "bignum.h"
@ -37,59 +38,16 @@
#include "ecc.h" #include "ecc.h"
#include "crypto_desc.h" #include "crypto_desc.h"
/* diffie-hellman-group1-sha1 value for p */ static void kexinitialise(void);
const unsigned char dh_p_1[DH_P_1_LEN] = { static void gen_new_keys(void);
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
/* diffie-hellman-group14-sha1 value for p */
const unsigned char dh_p_14[DH_P_14_LEN] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2,
0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C,
0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF};
/* Same for group1 and group14 */
static const int DH_G_VAL = 2;
static void kexinitialise();
static void gen_new_keys();
#ifndef DISABLE_ZLIB #ifndef DISABLE_ZLIB
static void gen_new_zstream_recv(); static void gen_new_zstream_recv(void);
static void gen_new_zstream_trans(); static void gen_new_zstream_trans(void);
#endif #endif
static void read_kex_algos(); static void read_kex_algos(void);
/* helper function for gen_new_keys */ /* helper function for gen_new_keys */
static void hashkeys(unsigned char *out, unsigned int outlen, static void hashkeys(unsigned char *out, unsigned int outlen,
const hash_state * hs, const unsigned char X); const hash_state * hs, const unsigned char X);
static void finish_kexhashbuf(void);
/* Send our list of algorithms we can use */ /* Send our list of algorithms we can use */
@ -238,14 +196,24 @@ void recv_msg_newkeys() {
void kexfirstinitialise() { void kexfirstinitialise() {
ses.kexstate.donefirstkex = 0; ses.kexstate.donefirstkex = 0;
#ifndef DISABLE_ZLIB #ifdef DISABLE_ZLIB
if (opts.enable_compress) { ses.compress_algos = ssh_nocompress;
ses.compress_algos = ssh_compress; #else
} else switch (opts.compress_mode)
#endif
{ {
ses.compress_algos = ssh_nocompress; case DROPBEAR_COMPRESS_DELAYED:
ses.compress_algos = ssh_delaycompress;
break;
case DROPBEAR_COMPRESS_ON:
ses.compress_algos = ssh_compress;
break;
case DROPBEAR_COMPRESS_OFF:
ses.compress_algos = ssh_nocompress;
break;
} }
#endif
kexinitialise(); kexinitialise();
} }
@ -303,7 +271,7 @@ static void hashkeys(unsigned char *out, unsigned int outlen,
hash_desc->done(&hs2, tmpout); hash_desc->done(&hs2, tmpout);
memcpy(&out[offset], tmpout, MIN(outlen - offset, hash_desc->hashsize)); memcpy(&out[offset], tmpout, MIN(outlen - offset, hash_desc->hashsize));
} }
m_burn(&hs2, sizeof(hash_state));
} }
/* Generate the actual encryption/integrity keys, using the results of the /* Generate the actual encryption/integrity keys, using the results of the
@ -339,17 +307,17 @@ static void gen_new_keys() {
ses.hash = NULL; ses.hash = NULL;
if (IS_DROPBEAR_CLIENT) { if (IS_DROPBEAR_CLIENT) {
trans_IV = C2S_IV; trans_IV = C2S_IV;
recv_IV = S2C_IV; recv_IV = S2C_IV;
trans_key = C2S_key; trans_key = C2S_key;
recv_key = S2C_key; recv_key = S2C_key;
mactransletter = 'E'; mactransletter = 'E';
macrecvletter = 'F'; macrecvletter = 'F';
} else { } else {
trans_IV = S2C_IV; trans_IV = S2C_IV;
recv_IV = C2S_IV; recv_IV = C2S_IV;
trans_key = S2C_key; trans_key = S2C_key;
recv_key = C2S_key; recv_key = C2S_key;
mactransletter = 'F'; mactransletter = 'F';
macrecvletter = 'E'; macrecvletter = 'E';
} }
@ -403,6 +371,7 @@ static void gen_new_keys() {
m_burn(C2S_key, sizeof(C2S_key)); m_burn(C2S_key, sizeof(C2S_key));
m_burn(S2C_IV, sizeof(S2C_IV)); m_burn(S2C_IV, sizeof(S2C_IV));
m_burn(S2C_key, sizeof(S2C_key)); m_burn(S2C_key, sizeof(S2C_key));
m_burn(&hs, sizeof(hash_state));
TRACE(("leave gen_new_keys")) TRACE(("leave gen_new_keys"))
} }
@ -421,6 +390,14 @@ int is_compress_recv() {
&& ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY); && ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
} }
static void* dropbear_zalloc(void* UNUSED(opaque), uInt items, uInt size) {
return m_calloc(items, size);
}
static void dropbear_zfree(void* UNUSED(opaque), void* ptr) {
m_free(ptr);
}
/* Set up new zlib compression streams, close the old ones. Only /* Set up new zlib compression streams, close the old ones. Only
* called from gen_new_keys() */ * called from gen_new_keys() */
static void gen_new_zstream_recv() { static void gen_new_zstream_recv() {
@ -429,8 +406,8 @@ static void gen_new_zstream_recv() {
if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) { || ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream)); ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->recv.zstream->zalloc = Z_NULL; ses.newkeys->recv.zstream->zalloc = dropbear_zalloc;
ses.newkeys->recv.zstream->zfree = Z_NULL; ses.newkeys->recv.zstream->zfree = dropbear_zfree;
if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) { if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) {
dropbear_exit("zlib error"); dropbear_exit("zlib error");
@ -453,8 +430,8 @@ static void gen_new_zstream_trans() {
if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) { || ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream)); ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->trans.zstream->zalloc = Z_NULL; ses.newkeys->trans.zstream->zalloc = dropbear_zalloc;
ses.newkeys->trans.zstream->zfree = Z_NULL; ses.newkeys->trans.zstream->zfree = dropbear_zfree;
if (deflateInit2(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION, if (deflateInit2(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, DROPBEAR_ZLIB_WINDOW_BITS, Z_DEFLATED, DROPBEAR_ZLIB_WINDOW_BITS,
@ -500,7 +477,7 @@ void recv_msg_kexinit() {
/* start the kex hash */ /* start the kex hash */
local_ident_len = strlen(LOCAL_IDENT); 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 kexhashbuf_len = local_ident_len + remote_ident_len
+ ses.transkexinit->len + ses.payload->len + ses.transkexinit->len + ses.payload->len
@ -514,17 +491,18 @@ void recv_msg_kexinit() {
read_kex_algos(); read_kex_algos();
/* V_C, the client's version string (CR and NL excluded) */ /* V_C, the client's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf, buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len);
(unsigned char*)LOCAL_IDENT, local_ident_len);
/* V_S, the server's version string (CR and NL excluded) */ /* V_S, the server's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len); buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
/* I_C, the payload of the client's SSH_MSG_KEXINIT */ /* I_C, the payload of the client's SSH_MSG_KEXINIT */
buf_putstring(ses.kexhashbuf, 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 */ /* I_S, the payload of the server's SSH_MSG_KEXINIT */
buf_setpos(ses.payload, 0); buf_setpos(ses.payload, ses.payload_beginning);
buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len); 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; ses.requirenext = SSH_MSG_KEXDH_REPLY;
} else { } else {
/* SERVER */ /* SERVER */
@ -532,18 +510,19 @@ void recv_msg_kexinit() {
/* read the peer's choice of algos */ /* read the peer's choice of algos */
read_kex_algos(); read_kex_algos();
/* V_C, the client's version string (CR and NL excluded) */ /* V_C, the client's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len); buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
/* V_S, the server's version string (CR and NL excluded) */ /* V_S, the server's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf, buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len);
(unsigned char*)LOCAL_IDENT, local_ident_len);
/* I_C, the payload of the client's SSH_MSG_KEXINIT */ /* I_C, the payload of the client's SSH_MSG_KEXINIT */
buf_setpos(ses.payload, 0); buf_setpos(ses.payload, ses.payload_beginning);
buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len); 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 */ /* I_S, the payload of the server's SSH_MSG_KEXINIT */
buf_putstring(ses.kexhashbuf, buf_putstring(ses.kexhashbuf,
ses.transkexinit->data, ses.transkexinit->len); (const char*)ses.transkexinit->data, ses.transkexinit->len);
ses.requirenext = SSH_MSG_KEXDH_INIT; ses.requirenext = SSH_MSG_KEXDH_INIT;
} }
@ -618,16 +597,20 @@ void free_kexdh_param(struct kex_dh_param *param)
void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them, void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
sign_key *hostkey) { 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; mp_int *dh_e = NULL, *dh_f = NULL;
/* read the prime and generator*/ m_mp_init_multi(&dh_p, &dh_p_min1, NULL);
m_mp_init(&dh_p);
load_dh_p(&dh_p); load_dh_p(&dh_p);
/* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */ if (mp_sub_d(&dh_p, 1, &dh_p_min1) != MP_OKAY) {
if (mp_cmp(dh_pub_them, &dh_p) != MP_LT dropbear_exit("Diffie-Hellman error");
|| mp_cmp_d(dh_pub_them, 0) != MP_GT) { }
/* 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"); dropbear_exit("Diffie-Hellman error");
} }
@ -638,7 +621,7 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
} }
/* clear no longer needed vars */ /* 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, /* From here on, the code needs to work with the _same_ vars on each side,
* not vice-versaing for client/server */ * not vice-versaing for client/server */
@ -664,7 +647,7 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
finish_kexhashbuf(); finish_kexhashbuf();
} }
#ifdef DROPBEAR_ECDH #if DROPBEAR_ECDH
struct kex_ecdh_param *gen_kexecdh_param() { struct kex_ecdh_param *gen_kexecdh_param() {
struct kex_ecdh_param *param = m_malloc(sizeof(*param)); struct kex_ecdh_param *param = m_malloc(sizeof(*param));
if (ecc_make_key_ex(NULL, dropbear_ltc_prng, if (ecc_make_key_ex(NULL, dropbear_ltc_prng,
@ -686,6 +669,9 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
ecc_key *Q_C, *Q_S, *Q_them; ecc_key *Q_C, *Q_S, *Q_them;
Q_them = buf_get_ecc_raw_pubkey(pub_them, algo_kex->ecc_curve); 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, &param->key); ses.dh_K = dropbear_ecc_shared_secret(Q_them, &param->key);
@ -708,12 +694,15 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
/* K, the shared secret */ /* K, the shared secret */
buf_putmpint(ses.kexhashbuf, ses.dh_K); buf_putmpint(ses.kexhashbuf, ses.dh_K);
ecc_free(Q_them);
m_free(Q_them);
/* calculate the hash H to sign */ /* calculate the hash H to sign */
finish_kexhashbuf(); finish_kexhashbuf();
} }
#endif /* DROPBEAR_ECDH */ #endif /* DROPBEAR_ECDH */
#ifdef DROPBEAR_CURVE25519 #if DROPBEAR_CURVE25519
struct kex_curve25519_param *gen_kexcurve25519_param () { struct kex_curve25519_param *gen_kexcurve25519_param () {
/* Per http://cr.yp.to/ecdh.html */ /* Per http://cr.yp.to/ecdh.html */
struct kex_curve25519_param *param = m_malloc(sizeof(*param)); struct kex_curve25519_param *param = m_malloc(sizeof(*param));
@ -735,11 +724,12 @@ void free_kexcurve25519_param(struct kex_curve25519_param *param)
m_free(param); m_free(param);
} }
void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_them, void kexcurve25519_comb_key(const struct kex_curve25519_param *param, const buffer *buf_pub_them,
sign_key *hostkey) { sign_key *hostkey) {
unsigned char out[CURVE25519_LEN]; unsigned char out[CURVE25519_LEN];
const unsigned char* Q_C = NULL; const unsigned char* Q_C = NULL;
const unsigned char* Q_S = NULL; const unsigned char* Q_S = NULL;
char zeroes[CURVE25519_LEN] = {0};
if (buf_pub_them->len != CURVE25519_LEN) if (buf_pub_them->len != CURVE25519_LEN)
{ {
@ -747,6 +737,11 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
} }
curve25519_donna(out, param->priv, buf_pub_them->data); 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); m_mp_alloc_init_multi(&ses.dh_K, NULL);
bytes_to_mp(ses.dh_K, out, CURVE25519_LEN); bytes_to_mp(ses.dh_K, out, CURVE25519_LEN);
m_burn(out, sizeof(out)); m_burn(out, sizeof(out));
@ -764,9 +759,9 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
/* K_S, the host key */ /* K_S, the host key */
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey); buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
/* Q_C, client's ephemeral public key octet string */ /* 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 */ /* 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 */ /* K, the shared secret */
buf_putmpint(ses.kexhashbuf, ses.dh_K); buf_putmpint(ses.kexhashbuf, ses.dh_K);
@ -776,8 +771,7 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
#endif /* DROPBEAR_CURVE25519 */ #endif /* DROPBEAR_CURVE25519 */
void finish_kexhashbuf(void) {
static void finish_kexhashbuf(void) {
hash_state hs; hash_state hs;
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc; const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
@ -789,7 +783,7 @@ static void finish_kexhashbuf(void) {
hash_desc->done(&hs, buf_getwriteptr(ses.hash, hash_desc->hashsize)); hash_desc->done(&hs, buf_getwriteptr(ses.hash, hash_desc->hashsize));
buf_setlen(ses.hash, hash_desc->hashsize); buf_setlen(ses.hash, hash_desc->hashsize);
#if defined(DEBUG_KEXHASH) && defined(DEBUG_TRACE) #if defined(DEBUG_KEXHASH) && DEBUG_TRACE
if (!debug_trace) { if (!debug_trace) {
printhex("kexhashbuf", ses.kexhashbuf->data, ses.kexhashbuf->len); printhex("kexhashbuf", ses.kexhashbuf->data, ses.kexhashbuf->len);
printhex("kexhash", ses.hash->data, ses.hash->len); printhex("kexhash", ses.hash->data, ses.hash->len);
@ -798,6 +792,7 @@ static void finish_kexhashbuf(void) {
buf_burn(ses.kexhashbuf); buf_burn(ses.kexhashbuf);
buf_free(ses.kexhashbuf); buf_free(ses.kexhashbuf);
m_burn(&hs, sizeof(hash_state));
ses.kexhashbuf = NULL; ses.kexhashbuf = NULL;
/* first time around, we set the session_id to H */ /* first time around, we set the session_id to H */
@ -805,7 +800,6 @@ static void finish_kexhashbuf(void) {
/* create the session_id, this never needs freeing */ /* create the session_id, this never needs freeing */
ses.session_id = buf_newcopy(ses.hash); ses.session_id = buf_newcopy(ses.hash);
} }
} }
/* read the other side's algo list. buf_match_algo is a callback to match /* read the other side's algo list. buf_match_algo is a callback to match
@ -829,7 +823,7 @@ static void read_kex_algos() {
int allgood = 1; /* we AND this with each goodguess and see if its still int allgood = 1; /* we AND this with each goodguess and see if its still
true after */ true after */
#ifdef USE_KEXGUESS2 #if DROPBEAR_KEXGUESS2
enum kexguess2_used kexguess2 = KEXGUESS2_LOOK; enum kexguess2_used kexguess2 = KEXGUESS2_LOOK;
#else #else
enum kexguess2_used kexguess2 = KEXGUESS2_NO; enum kexguess2_used kexguess2 = KEXGUESS2_NO;
@ -958,6 +952,12 @@ static void read_kex_algos() {
ses.newkeys->trans.algo_comp = s2c_comp_algo->val; ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
} }
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
fuzz_kex_fakealgos();
}
#endif
/* reserved for future extensions */ /* reserved for future extensions */
buf_getint(ses.payload); buf_getint(ses.payload);

View File

@ -62,7 +62,7 @@ out:
return ret; return ret;
} }
#ifdef ENABLE_USER_ALGO_LIST #if DROPBEAR_USER_ALGO_LIST
void void
parse_ciphers_macs() parse_ciphers_macs()
{ {

View File

@ -1,7 +1,7 @@
/* /*
* Dropbear - a SSH2 server * Dropbear - a SSH2 server
* *
* Copyright (c) 2002,2003 Matt Johnston * Copyright (c) Matt Johnston
* All rights reserved. * All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
@ -34,52 +34,70 @@
#include "kex.h" #include "kex.h"
#include "channel.h" #include "channel.h"
#include "runopts.h" #include "runopts.h"
#include "netio.h"
static void checktimeouts(); static void checktimeouts(void);
static long select_timeout(); static long select_timeout(void);
static int ident_readln(int fd, char* buf, int count); static int ident_readln(int fd, char* buf, int count);
static void read_session_identification(); static void read_session_identification(void);
struct sshsession ses; /* GLOBAL */ struct sshsession ses; /* GLOBAL */
/* need to know if the session struct has been initialised, this way isn't the
* cleanest, but works OK */
int sessinitdone = 0; /* GLOBAL */
/* this is set when we get SIGINT or SIGTERM, the handler is in main.c */
int exitflag = 0; /* GLOBAL */
/* called only at the start of a session, set up initial state */ /* called only at the start of a session, set up initial state */
void common_session_init(int sock_in, int sock_out) { void common_session_init(int sock_in, int sock_out) {
time_t now; time_t now;
#if DEBUG_TRACE
debug_start_net();
#endif
TRACE(("enter session_init")) TRACE(("enter session_init"))
ses.sock_in = sock_in; ses.sock_in = sock_in;
ses.sock_out = sock_out; ses.sock_out = sock_out;
ses.maxfd = MAX(sock_in, 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; ses.socket_prio = DROPBEAR_PRIO_DEFAULT;
/* Sets it to lowdelay */ /* Sets it to lowdelay */
update_channel_prio(); update_channel_prio();
#if !DROPBEAR_SVR_MULTIUSER
/* A sanity check to prevent an accidental configuration option
leaving multiuser systems exposed */
errno = 0;
getuid();
if (errno != ENOSYS) {
dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel");
}
#endif
now = monotonic_now(); now = monotonic_now();
ses.connect_time = now;
ses.last_packet_time_keepalive_recv = now; ses.last_packet_time_keepalive_recv = now;
ses.last_packet_time_idle = now; ses.last_packet_time_idle = now;
ses.last_packet_time_any_sent = 0; ses.last_packet_time_any_sent = 0;
ses.last_packet_time_keepalive_sent = 0; ses.last_packet_time_keepalive_sent = 0;
#if DROPBEAR_FUZZ
if (!fuzz.fuzzing)
#endif
{
if (pipe(ses.signal_pipe) < 0) { if (pipe(ses.signal_pipe) < 0) {
dropbear_exit("Signal pipe failed"); dropbear_exit("Signal pipe failed");
} }
setnonblocking(ses.signal_pipe[0]); setnonblocking(ses.signal_pipe[0]);
setnonblocking(ses.signal_pipe[1]); setnonblocking(ses.signal_pipe[1]);
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]); ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]); ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
}
kexfirstinitialise(); /* initialise the kex state */
ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN); ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN);
ses.transseq = 0; ses.transseq = 0;
@ -132,7 +150,7 @@ void common_session_init(int sock_in, int sock_out) {
TRACE(("leave session_init")) TRACE(("leave session_init"))
} }
void session_loop(void(*loophandler)()) { void session_loop(void(*loophandler)(void)) {
fd_set readfd, writefd; fd_set readfd, writefd;
struct timeval timeout; struct timeval timeout;
@ -140,32 +158,51 @@ void session_loop(void(*loophandler)()) {
/* main loop, select()s for all sockets in use */ /* main loop, select()s for all sockets in use */
for(;;) { for(;;) {
const int writequeue_has_space = (ses.writequeue_len <= 2*TRANS_MAX_PAYLOAD_LEN);
timeout.tv_sec = select_timeout(); timeout.tv_sec = select_timeout();
timeout.tv_usec = 0; timeout.tv_usec = 0;
FD_ZERO(&writefd); DROPBEAR_FD_ZERO(&writefd);
FD_ZERO(&readfd); DROPBEAR_FD_ZERO(&readfd);
dropbear_assert(ses.payload == NULL); dropbear_assert(ses.payload == NULL);
/* during initial setup we flush out the KEXINIT packet before /* We get woken up when signal handlers write to this pipe.
* attempting to read the remote version string, which might block */ SIGCHLD in svr-chansession is the only one currently. */
if (ses.sock_in != -1 && (ses.remoteident || isempty(&ses.writequeue))) { #if DROPBEAR_FUZZ
if (!fuzz.fuzzing)
#endif
{
FD_SET(ses.signal_pipe[0], &readfd);
}
/* set up for channels which can be read/written */
setchannelfds(&readfd, &writefd, writequeue_has_space);
/* Pending connections to test */
set_connect_fds(&writefd);
/* We delay reading from the input socket during initial setup until
after we have written out our initial KEXINIT packet (empty writequeue).
This means our initial packet can be in-flight while we're doing a blocking
read for the remote ident.
We also avoid reading from the socket if the writequeue is full, that avoids
replies backing up */
if (ses.sock_in != -1
&& (ses.remoteident || isempty(&ses.writequeue))
&& writequeue_has_space) {
FD_SET(ses.sock_in, &readfd); 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)) { if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
FD_SET(ses.sock_out, &writefd); FD_SET(ses.sock_out, &writefd);
} }
/* We get woken up when signal handlers write to this pipe.
SIGCHLD in svr-chansession is the only one currently. */
FD_SET(ses.signal_pipe[0], &readfd);
/* set up for channels which can be read/written */
setchannelfds(&readfd, &writefd);
val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout); val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
if (exitflag) { if (ses.exitflag) {
dropbear_exit("Terminated by signal"); dropbear_exit("Terminated by signal");
} }
@ -178,16 +215,19 @@ void session_loop(void(*loophandler)()) {
* want to iterate over channels etc for reading, to handle * want to iterate over channels etc for reading, to handle
* server processes exiting etc. * server processes exiting etc.
* We don't want to read/write FDs. */ * We don't want to read/write FDs. */
FD_ZERO(&writefd); DROPBEAR_FD_ZERO(&writefd);
FD_ZERO(&readfd); DROPBEAR_FD_ZERO(&readfd);
} }
/* We'll just empty out the pipe if required. We don't do /* We'll just empty out the pipe if required. We don't do
any thing with the data, since the pipe's purpose is purely to any thing with the data, since the pipe's purpose is purely to
wake up the select() above. */ wake up the select() above. */
ses.channel_signal_pending = 0;
if (FD_ISSET(ses.signal_pipe[0], &readfd)) { if (FD_ISSET(ses.signal_pipe[0], &readfd)) {
char x; char x;
TRACE(("signal pipe set"))
while (read(ses.signal_pipe[0], &x, 1) > 0) {} while (read(ses.signal_pipe[0], &x, 1) > 0) {}
ses.channel_signal_pending = 1;
} }
/* check for auth timeout, rekeying required etc */ /* check for auth timeout, rekeying required etc */
@ -210,11 +250,17 @@ void session_loop(void(*loophandler)()) {
process_packet(); process_packet();
} }
} }
/* if required, flush out any queued reply packets that /* if required, flush out any queued reply packets that
were being held up during a KEX */ were being held up during a KEX */
maybe_flush_reply_queue(); maybe_flush_reply_queue();
handle_connect_fds(&writefd);
/* loop handler prior to channelio, in case the server loophandler closes
channels on process exit */
loophandler();
/* process pipes etc for the channels, ses.dataallowed == 0 /* process pipes etc for the channels, ses.dataallowed == 0
* during rekeying ) */ * during rekeying ) */
channelio(&readfd, &writefd); channelio(&readfd, &writefd);
@ -226,45 +272,82 @@ void session_loop(void(*loophandler)()) {
} }
} }
if (loophandler) {
loophandler();
}
} /* for(;;) */ } /* for(;;) */
/* Not reached */ /* 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 */ /* clean up a session on exit */
void session_cleanup() { void session_cleanup() {
TRACE(("enter session_cleanup")) TRACE(("enter session_cleanup"))
/* we can't cleanup if we don't know the session state */ /* we can't cleanup if we don't know the session state */
if (!sessinitdone) { if (!ses.init_done) {
TRACE(("leave session_cleanup: !sessinitdone")) TRACE(("leave session_cleanup: !ses.init_done"))
return; return;
} }
/* BEWARE of changing order of functions here. */
/* Must be before extra_session_cleanup() */
chancleanup();
if (ses.extra_session_cleanup) { if (ses.extra_session_cleanup) {
ses.extra_session_cleanup(); ses.extra_session_cleanup();
} }
chancleanup(); /* After these are freed most functions will fail */
#if DROPBEAR_CLEANUP
/* Cleaning up keys must happen after other cleanup /* listeners call cleanup functions, this should occur before
functions which might queue packets */ other session state is freed. */
if (ses.session_id) { remove_all_listeners();
buf_burn(ses.session_id);
buf_free(ses.session_id); remove_connect_pending();
ses.session_id = NULL;
while (!isempty(&ses.writequeue)) {
buf_free(dequeue(&ses.writequeue));
} }
if (ses.hash) {
buf_burn(ses.hash); m_free(ses.newkeys);
buf_free(ses.hash); #ifndef DISABLE_ZLIB
ses.hash = NULL; if (ses.keys->recv.zstream != NULL) {
if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
dropbear_exit("Crypto error");
}
m_free(ses.keys->recv.zstream);
} }
#endif
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_burn(ses.keys, sizeof(struct key_context));
m_free(ses.keys); m_free(ses.keys);
@ -273,10 +356,8 @@ void session_cleanup() {
void send_session_identification() { void send_session_identification() {
buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1); buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
buf_putbytes(writebuf, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n")); buf_putbytes(writebuf, (const unsigned char *) LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
buf_putbyte(writebuf, 0x0); /* packet type */ writebuf_enqueue(writebuf);
buf_setpos(writebuf, 0);
enqueue(&ses.writequeue, writebuf);
} }
static void read_session_identification() { static void read_session_identification() {
@ -302,7 +383,7 @@ static void read_session_identification() {
} }
if (!done) { if (!done) {
TRACE(("err: %s for '%s'\n", strerror(errno), linebuf)) TRACE(("error reading remote ident: %s\n", strerror(errno)))
ses.remoteclosed(); ses.remoteclosed();
} else { } else {
/* linebuf is already null terminated */ /* linebuf is already null terminated */
@ -336,7 +417,7 @@ static int ident_readln(int fd, char* buf, int count) {
return -1; return -1;
} }
FD_ZERO(&fds); DROPBEAR_FD_ZERO(&fds);
/* select since it's a non-blocking fd */ /* select since it's a non-blocking fd */
@ -395,16 +476,16 @@ static int ident_readln(int fd, char* buf, int count) {
} }
void ignore_recv_response() { void ignore_recv_response() {
// Do nothing /* Do nothing */
TRACE(("Ignored msg_request_response")) TRACE(("Ignored msg_request_response"))
} }
static void send_msg_keepalive() { static void send_msg_keepalive() {
CHECKCLEARTOWRITE();
time_t old_time_idle = ses.last_packet_time_idle; time_t old_time_idle = ses.last_packet_time_idle;
struct Channel *chan = get_any_ready_channel(); struct Channel *chan = get_any_ready_channel();
CHECKCLEARTOWRITE();
if (chan) { if (chan) {
/* Channel requests are preferable, more implementations /* Channel requests are preferable, more implementations
handle them than SSH_MSG_GLOBAL_REQUEST */ handle them than SSH_MSG_GLOBAL_REQUEST */
@ -434,6 +515,11 @@ static void checktimeouts() {
time_t now; time_t now;
now = monotonic_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 */ /* we can't rekey if we haven't done remote ident exchange yet */
if (ses.remoteident == NULL) { if (ses.remoteident == NULL) {
return; return;
@ -474,20 +560,41 @@ 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() { static long select_timeout() {
/* determine the minimum timeout that might be required, so /* determine the minimum timeout that might be required, so
as to avoid waking when unneccessary */ as to avoid waking when unneccessary */
long ret = LONG_MAX; long timeout = KEX_REKEY_TIMEOUT;
if (KEX_REKEY_TIMEOUT > 0) long now = monotonic_now();
ret = MIN(KEX_REKEY_TIMEOUT, ret);
/* AUTH_TIMEOUT is only relevant before authdone */ if (!ses.kexstate.sentkexinit) {
if (ses.authstate.authdone != 1 && AUTH_TIMEOUT > 0) update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
ret = MIN(AUTH_TIMEOUT, ret); }
if (opts.keepalive_secs > 0)
ret = MIN(opts.keepalive_secs, ret); if (ses.authstate.authdone != 1 && IS_DROPBEAR_SERVER) {
if (opts.idle_timeout_secs > 0) /* AUTH_TIMEOUT is only relevant before authdone */
ret = MIN(opts.idle_timeout_secs, ret); update_timeout(AUTH_TIMEOUT, now, ses.connect_time, &timeout);
return ret; }
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() { const char* get_user_shell() {
@ -554,6 +661,11 @@ void update_channel_prio() {
TRACE(("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; new_prio = DROPBEAR_PRIO_BULK;
for (i = 0; i < ses.chansize; i++) { for (i = 0; i < ses.chansize; i++) {
struct Channel *channel = ses.channels[i]; struct Channel *channel = ses.channels[i];
@ -584,7 +696,7 @@ void update_channel_prio() {
} }
if (new_prio != ses.socket_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); set_sock_priority(ses.sock_out, new_prio);
ses.socket_prio = new_prio; ses.socket_prio = new_prio;
} }

View File

@ -114,8 +114,8 @@ size_t strlcpy(char *dst, const char *src, size_t size) {
#endif /* HAVE_STRLCPY */ #endif /* HAVE_STRLCPY */
#ifndef HAVE_STRLCAT #ifndef HAVE_STRLCAT
/* taken from openbsd-compat for OpenSSH 3.6.1p1 */ /* taken from openbsd-compat for OpenSSH 7.2p2 */
/* "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $" /* "$OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $"
* *
* Appends src to string dst of size siz (unlike strncat, siz is the * Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters * full size of dst, not space left). At most siz-1 characters
@ -123,15 +123,12 @@ size_t strlcpy(char *dst, const char *src, size_t size) {
* Returns strlen(src) + MIN(siz, strlen(initial dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred. * If retval >= siz, truncation occurred.
*/ */
size_t size_t
strlcat(dst, src, siz) strlcat(char *dst, const char *src, size_t siz)
char *dst;
const char *src;
size_t siz;
{ {
register char *d = dst; char *d = dst;
register const char *s = src; const char *s = src;
register size_t n = siz; size_t n = siz;
size_t dlen; size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */ /* Find the end of dst and adjust bytes left but don't go past end */
@ -177,7 +174,7 @@ int daemon(int nochdir, int noclose) {
if (!nochdir) if (!nochdir)
(void)chdir("/"); (void)chdir("/");
if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { if (!noclose && (fd = open(DROPBEAR_PATH_DEVNULL, O_RDWR, 0)) != -1) {
(void)dup2(fd, STDIN_FILENO); (void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO); (void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO); (void)dup2(fd, STDERR_FILENO);

View File

@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _COMPAT_H_ #ifndef DROPBEAR_COMPAT_H_
#define _COMPAT_H_ #define DROPBEAR_COMPAT_H_
#include "includes.h" #include "includes.h"
@ -44,13 +44,13 @@ char *basename(const char* path);
#endif #endif
#ifndef HAVE_GETUSERSHELL #ifndef HAVE_GETUSERSHELL
char *getusershell(); char *getusershell(void);
void setusershell(); void setusershell(void);
void endusershell(); void endusershell(void);
#endif #endif
#ifndef _PATH_DEVNULL #ifndef DROPBEAR_PATH_DEVNULL
#define _PATH_DEVNULL "/dev/null" #define DROPBEAR_PATH_DEVNULL "/dev/null"
#endif #endif
#endif /* _COMPAT_H_ */ #endif /* DROPBEAR_COMPAT_H_ */

939
dropbear/config.guess vendored

File diff suppressed because it is too large Load Diff

View File

@ -54,15 +54,24 @@
/* Use zlib */ /* Use zlib */
#undef DISABLE_ZLIB #undef DISABLE_ZLIB
/* Fuzzing */
#undef DROPBEAR_FUZZ
/* Define to 1 if you have the `basename' function. */ /* Define to 1 if you have the `basename' function. */
#undef HAVE_BASENAME #undef HAVE_BASENAME
/* Define to 1 if you have the `clearenv' function. */ /* Define to 1 if you have the `clearenv' function. */
#undef HAVE_CLEARENV #undef HAVE_CLEARENV
/* Define to 1 if you have the `clock_gettime' function. */
#undef HAVE_CLOCK_GETTIME
/* Define if gai_strerror() returns const char * */ /* Define if gai_strerror() returns const char * */
#undef HAVE_CONST_GAI_STRERROR_PROTO #undef HAVE_CONST_GAI_STRERROR_PROTO
/* crypt() function */
#undef HAVE_CRYPT
/* Define to 1 if you have the <crypt.h> header file. */ /* Define to 1 if you have the <crypt.h> header file. */
#undef HAVE_CRYPT_H #undef HAVE_CRYPT_H
@ -72,17 +81,14 @@
/* Use /dev/ptc & /dev/pts */ /* Use /dev/ptc & /dev/pts */
#undef HAVE_DEV_PTS_AND_PTC #undef HAVE_DEV_PTS_AND_PTC
/* Define to 1 if you have the `dup2' function. */
#undef HAVE_DUP2
/* Define to 1 if you have the `endutent' function. */ /* Define to 1 if you have the `endutent' function. */
#undef HAVE_ENDUTENT #undef HAVE_ENDUTENT
/* Define to 1 if you have the `endutxent' function. */ /* Define to 1 if you have the `endutxent' function. */
#undef HAVE_ENDUTXENT #undef HAVE_ENDUTXENT
/* Define to 1 if you have the <fcntl.h> header file. */ /* Define to 1 if you have the `explicit_bzero' function. */
#undef HAVE_FCNTL_H #undef HAVE_EXPLICIT_BZERO
/* Define to 1 if you have the `fork' function. */ /* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK #undef HAVE_FORK
@ -96,9 +102,15 @@
/* Define to 1 if you have the `getaddrinfo' function. */ /* Define to 1 if you have the `getaddrinfo' function. */
#undef HAVE_GETADDRINFO #undef HAVE_GETADDRINFO
/* Define to 1 if you have the `getgrouplist' function. */
#undef HAVE_GETGROUPLIST
/* Define to 1 if you have the `getnameinfo' function. */ /* Define to 1 if you have the `getnameinfo' function. */
#undef HAVE_GETNAMEINFO #undef HAVE_GETNAMEINFO
/* Define to 1 if you have the `getpass' function. */
#undef HAVE_GETPASS
/* Define to 1 if you have the `getspnam' function. */ /* Define to 1 if you have the `getspnam' function. */
#undef HAVE_GETSPNAM #undef HAVE_GETSPNAM
@ -126,9 +138,6 @@
/* Define to 1 if you have the <inttypes.h> header file. */ /* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H #undef HAVE_INTTYPES_H
/* Define to 1 if you have the <ioctl.h> header file. */
#undef HAVE_IOCTL_H
/* Define to 1 if you have the <lastlog.h> header file. */ /* Define to 1 if you have the <lastlog.h> header file. */
#undef HAVE_LASTLOG_H #undef HAVE_LASTLOG_H
@ -144,8 +153,8 @@
/* Define to 1 if you have the `z' library (-lz). */ /* Define to 1 if you have the `z' library (-lz). */
#undef HAVE_LIBZ #undef HAVE_LIBZ
/* Define to 1 if you have the <limits.h> header file. */ /* Define to 1 if you have the <linux/pkt_sched.h> header file. */
#undef HAVE_LIMITS_H #undef HAVE_LINUX_PKT_SCHED_H
/* Have login() function */ /* Have login() function */
#undef HAVE_LOGIN #undef HAVE_LOGIN
@ -165,8 +174,8 @@
/* Define to 1 if you have the <memory.h> header file. */ /* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H #undef HAVE_MEMORY_H
/* Define to 1 if you have the `memset' function. */ /* Define to 1 if you have the `memset_s' function. */
#undef HAVE_MEMSET #undef HAVE_MEMSET_S
/* Define to 1 if you have the <netdb.h> header file. */ /* Define to 1 if you have the <netdb.h> header file. */
#undef HAVE_NETDB_H #undef HAVE_NETDB_H
@ -207,9 +216,6 @@
/* Define to 1 if you have the <security/pam_appl.h> header file. */ /* Define to 1 if you have the <security/pam_appl.h> header file. */
#undef HAVE_SECURITY_PAM_APPL_H #undef HAVE_SECURITY_PAM_APPL_H
/* Define to 1 if you have the `select' function. */
#undef HAVE_SELECT
/* Define to 1 if you have the `setutent' function. */ /* Define to 1 if you have the `setutent' function. */
#undef HAVE_SETUTENT #undef HAVE_SETUTENT
@ -219,18 +225,12 @@
/* Define to 1 if you have the <shadow.h> header file. */ /* Define to 1 if you have the <shadow.h> header file. */
#undef HAVE_SHADOW_H #undef HAVE_SHADOW_H
/* Define to 1 if you have the `socket' function. */
#undef HAVE_SOCKET
/* Define to 1 if you have the <stdint.h> header file. */ /* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H #undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */ /* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H #undef HAVE_STDLIB_H
/* Define to 1 if you have the `strdup' function. */
#undef HAVE_STRDUP
/* Define to 1 if you have the <strings.h> header file. */ /* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H #undef HAVE_STRINGS_H
@ -321,9 +321,6 @@
/* Define to 1 if you have the <sys/stat.h> header file. */ /* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H #undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */ /* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H #undef HAVE_SYS_TYPES_H
@ -333,9 +330,6 @@
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */ /* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
#undef HAVE_SYS_WAIT_H #undef HAVE_SYS_WAIT_H
/* Define to 1 if you have the <termios.h> header file. */
#undef HAVE_TERMIOS_H
/* Define to 1 if the system has the type `uint16_t'. */ /* Define to 1 if the system has the type `uint16_t'. */
#undef HAVE_UINT16_T #undef HAVE_UINT16_T

2752
dropbear/config.sub vendored

File diff suppressed because it is too large Load Diff

962
dropbear/configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -9,19 +9,119 @@ AC_PREREQ(2.59)
AC_INIT AC_INIT
AC_CONFIG_SRCDIR(buffer.c) AC_CONFIG_SRCDIR(buffer.c)
OLDCFLAGS=$CFLAGS # Record which revision is being built
if test -s "`which hg`" && test -d "$srcdir/.hg"; then
hgrev=`hg id -i -R "$srcdir"`
AC_MSG_NOTICE([Source directory Mercurial base revision $hgrev])
fi
ORIGCFLAGS="$CFLAGS"
# Checks for programs. # Checks for programs.
AC_PROG_CC AC_PROG_CC
AC_PROG_MAKE_SET
if test -z "$LD" ; then if test -z "$LD" ; then
LD=$CC LD=$CC
fi fi
AC_SUBST(LD) AC_SUBST(LD)
if test -z "$OLDCFLAGS" && test "$GCC" = "yes"; then AC_DEFUN(DB_TRYADDCFLAGS,
[{
OLDFLAGS="$CFLAGS"
TESTFLAGS="$1"
CFLAGS="$CFLAGS $TESTFLAGS"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
[AC_MSG_NOTICE([Not setting $TESTFLAGS]); CFLAGS="$OLDFLAGS" ]
)
}])
# set compile flags prior to other tests
if test -z "$ORIGCFLAGS" && test "$GCC" = "yes"; then
AC_MSG_NOTICE(No \$CFLAGS set... using "-Os -W -Wall" for GCC) AC_MSG_NOTICE(No \$CFLAGS set... using "-Os -W -Wall" for GCC)
CFLAGS="-Os -W -Wall -Wno-pointer-sign" CFLAGS="-Os -W -Wall"
fi
AC_MSG_NOTICE([Checking if compiler '$CC' supports -Wno-pointer-sign])
DB_TRYADDCFLAGS([-Wno-pointer-sign])
AC_MSG_NOTICE([Checking if compiler '$CC' supports -fno-strict-overflow])
DB_TRYADDCFLAGS([-fno-strict-overflow])
STATIC=0
AC_ARG_ENABLE(static,
[ --enable-static Build static binaries],
[
if test "x$enableval" = "xyes"; then
STATIC=1
AC_MSG_NOTICE(Static Build)
fi
], [])
AC_SUBST(STATIC)
hardenbuild=1
AC_ARG_ENABLE(harden,
[ --disable-harden Don't set hardened build flags],
[
if test "x$enableval" = "xno"; then
hardenbuild=0
AC_MSG_NOTICE(Disabling hardened build flags)
fi
], [])
if test "$hardenbuild" -eq 1; then
AC_MSG_NOTICE(Checking for available hardened build flags:)
# relocation flags don't make sense for static builds
if test "$STATIC" -ne 1; then
# pie
DB_TRYADDCFLAGS([-fPIE])
OLDLDFLAGS="$LDFLAGS"
TESTFLAGS="-Wl,-pie"
LDFLAGS="$LDFLAGS $TESTFLAGS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
[
LDFLAGS="$OLDLDFLAGS"
TESTFLAGS="-pie"
LDFLAGS="$LDFLAGS $TESTFLAGS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
[AC_MSG_NOTICE([Not setting $TESTFLAGS]); LDFLAGS="$OLDLDFLAGS" ]
)
]
)
# readonly elf relocation sections (relro)
OLDLDFLAGS="$LDFLAGS"
TESTFLAGS="-Wl,-z,now -Wl,-z,relro"
LDFLAGS="$LDFLAGS $TESTFLAGS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
[AC_MSG_NOTICE([Not setting $TESTFLAGS]); LDFLAGS="$OLDLDFLAGS" ]
)
fi # non-static
# stack protector. -strong is good but only in gcc 4.9 or later
OLDCFLAGS="$CFLAGS"
TESTFLAGS="-fstack-protector-strong"
CFLAGS="$CFLAGS $TESTFLAGS"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
[
CFLAGS="$OLDCFLAGS"
TESTFLAGS="-fstack-protector --param=ssp-buffer-size=4"
CFLAGS="$CFLAGS $TESTFLAGS"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
[AC_MSG_NOTICE([Not setting $TESTFLAGS]); CFLAGS="$OLDCFLAGS" ]
)
]
)
# FORTIFY_SOURCE
DB_TRYADDCFLAGS([-D_FORTIFY_SOURCE=2])
# Spectre v2 mitigations
DB_TRYADDCFLAGS([-mfunction-return=thunk])
DB_TRYADDCFLAGS([-mindirect-branch=thunk])
fi fi
# large file support is useful for scp # large file support is useful for scp
@ -45,8 +145,8 @@ case "$host" in
sol2ver=`echo "$host"| sed -e 's/.*[[0-9]]\.//'` sol2ver=`echo "$host"| sed -e 's/.*[[0-9]]\.//'`
if test "$sol2ver" -ge 8; then if test "$sol2ver" -ge 8; then
AC_MSG_RESULT(yes) AC_MSG_RESULT(yes)
AC_DEFINE(DISABLE_UTMP,,Disable utmp) AC_DEFINE(DISABLE_UTMP,1,Disable utmp)
AC_DEFINE(DISABLE_WTMP,,Disable wtmp) AC_DEFINE(DISABLE_WTMP,1,Disable wtmp)
else else
AC_MSG_RESULT(no) AC_MSG_RESULT(no)
fi fi
@ -55,18 +155,18 @@ case "$host" in
;; ;;
*-*-aix*) *-*-aix*)
AC_DEFINE(AIX,,Using AIX) AC_DEFINE(AIX,1,Using AIX)
# OpenSSH thinks it's broken. If it isn't, let me know. # OpenSSH thinks it's broken. If it isn't, let me know.
AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo) AC_DEFINE(BROKEN_GETADDRINFO,1,Broken getaddrinfo)
;; ;;
*-*-hpux*) *-*-hpux*)
LIBS="$LIBS -lsec" LIBS="$LIBS -lsec"
# It's probably broken. # It's probably broken.
AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo) AC_DEFINE(BROKEN_GETADDRINFO,1,Broken getaddrinfo)
;; ;;
*-dec-osf*) *-dec-osf*)
AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo) AC_DEFINE(BROKEN_GETADDRINFO,1,Broken getaddrinfo)
;; ;;
esac esac
@ -80,11 +180,21 @@ AC_CHECK_DECL(__UCLIBC__,
[ [
no_loginfunc_check=1 no_loginfunc_check=1
AC_MSG_NOTICE([Using uClibc - login() and logout() probably don't work, so we won't use them.]) AC_MSG_NOTICE([Using uClibc - login() and logout() probably don't work, so we won't use them.])
],,,) ],,)
# Checks for libraries. dnl We test for crypt() specially. On Linux (and others?) it resides in libcrypt
AC_CHECK_LIB(crypt, crypt, CRYPTLIB="-lcrypt") 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) AC_SUBST(CRYPTLIB)
if test "t$found_crypt_func" = there; then
AC_DEFINE(HAVE_CRYPT, 1, [crypt() function])
fi
# Check if zlib is needed # Check if zlib is needed
AC_ARG_WITH(zlib, AC_ARG_WITH(zlib,
@ -108,7 +218,7 @@ AC_ARG_ENABLE(zlib,
[ --disable-zlib Don't include zlib support], [ --disable-zlib Don't include zlib support],
[ [
if test "x$enableval" = "xno"; then if test "x$enableval" = "xno"; then
AC_DEFINE(DISABLE_ZLIB,, Use zlib) AC_DEFINE(DISABLE_ZLIB,1,Use zlib)
AC_MSG_NOTICE(Disabling zlib) AC_MSG_NOTICE(Disabling zlib)
else else
AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***])) AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***]))
@ -142,20 +252,20 @@ AC_ARG_WITH(pam,
AC_ARG_ENABLE(pam, AC_ARG_ENABLE(pam,
[ --enable-pam Try to include PAM support], [ --enable-pam Try to include PAM support],
[ [
if test "x$enableval" = "xyes"; then if test "x$enableval" = "xyes"; then
AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***])) AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***]))
AC_MSG_NOTICE(Enabling PAM) AC_MSG_NOTICE(Enabling PAM)
AC_CHECK_FUNCS(pam_fail_delay) AC_CHECK_FUNCS(pam_fail_delay)
else else
AC_DEFINE(DISABLE_PAM,, Use PAM) AC_DEFINE(DISABLE_PAM,1,Use PAM)
AC_MSG_NOTICE(Disabling PAM) AC_MSG_NOTICE(Disabling PAM)
fi fi
], ],
[ [
# disable it by default # disable it by default
AC_DEFINE(DISABLE_PAM,, Use PAM) AC_DEFINE(DISABLE_PAM,1,Use PAM)
AC_MSG_NOTICE(Disabling PAM) AC_MSG_NOTICE(Disabling PAM)
] ]
) )
@ -167,21 +277,26 @@ AC_ARG_ENABLE(openpty,
AC_MSG_NOTICE(Not using openpty) AC_MSG_NOTICE(Not using openpty)
else else
AC_MSG_NOTICE(Using openpty if available) AC_MSG_NOTICE(Using openpty if available)
AC_SEARCH_LIBS(openpty, util, [AC_DEFINE(HAVE_OPENPTY,,Have openpty() function)]) AC_SEARCH_LIBS(openpty, util, [dropbear_cv_func_have_openpty=yes])
fi fi
], ],
[ [
AC_MSG_NOTICE(Using openpty if available) AC_MSG_NOTICE(Using openpty if available)
AC_SEARCH_LIBS(openpty, util, [AC_DEFINE(HAVE_OPENPTY)]) AC_SEARCH_LIBS(openpty, util, [dropbear_cv_func_have_openpty=yes])
] ]
) )
if test "x$dropbear_cv_func_have_openpty" = "xyes"; then
AC_DEFINE(HAVE_OPENPTY,,Have openpty() function)
no_ptc_check=yes
no_ptmx_check=yes
fi
AC_ARG_ENABLE(syslog, AC_ARG_ENABLE(syslog,
[ --disable-syslog Don't include syslog support], [ --disable-syslog Don't include syslog support],
[ [
if test "x$enableval" = "xno"; then if test "x$enableval" = "xno"; then
AC_DEFINE(DISABLE_SYSLOG,, Using syslog) AC_DEFINE(DISABLE_SYSLOG,1,Using syslog)
AC_MSG_NOTICE(Disabling syslog) AC_MSG_NOTICE(Disabling syslog)
else else
AC_MSG_NOTICE(Enabling syslog) AC_MSG_NOTICE(Enabling syslog)
@ -207,12 +322,33 @@ AC_ARG_ENABLE(shadow,
AC_MSG_NOTICE(Using shadow passwords if available) AC_MSG_NOTICE(Using shadow passwords if available)
] ]
) )
AC_ARG_ENABLE(fuzz,
[ --enable-fuzz Build fuzzing. Not recommended for deployment.],
[
AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing)
AC_MSG_NOTICE(Enabling fuzzing)
DROPBEAR_FUZZ=1
# libfuzzer needs linking with c++ libraries
AC_PROG_CXX
],
[
AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
DROPBEAR_FUZZ=0
]
)
AC_SUBST(DROPBEAR_FUZZ)
AC_SUBST(CXX)
# Checks for header files. # Checks for header files.
AC_HEADER_STDC AC_HEADER_STDC
AC_HEADER_SYS_WAIT AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h pam/pam_appl.h netinet/in_systm.h sys/uio.h]) AC_CHECK_HEADERS([netinet/in.h netinet/tcp.h \
crypt.h \
pty.h libutil.h libgen.h inttypes.h stropts.h utmp.h \
utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h \
pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h])
# Checks for typedefs, structures, and compiler characteristics. # Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST AC_C_CONST
@ -265,7 +401,7 @@ AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
]], ]],
[[ struct sockaddr_storage s; ]])], [[ if (sizeof(struct sockaddr_storage)) return 0 ]])],
[ ac_cv_have_struct_sockaddr_storage="yes" ], [ ac_cv_have_struct_sockaddr_storage="yes" ],
[ ac_cv_have_struct_sockaddr_storage="no" ] [ ac_cv_have_struct_sockaddr_storage="no" ]
) )
@ -279,13 +415,13 @@ AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
#include <sys/types.h> #include <sys/types.h>
#include <netinet/in.h> #include <netinet/in.h>
]], ]],
[[ struct sockaddr_in6 s; s.sin6_family = 0; ]])], [[ if (sizeof(struct sockaddr_in6)) return 0 ]])],
[ ac_cv_have_struct_sockaddr_in6="yes" ], [ ac_cv_have_struct_sockaddr_in6="yes" ],
[ ac_cv_have_struct_sockaddr_in6="no" ] [ ac_cv_have_struct_sockaddr_in6="no" ]
) )
]) ])
if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then
AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6,,Have struct sockaddr_in6) AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6,1,Have struct sockaddr_in6)
fi fi
AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [ AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
@ -293,13 +429,13 @@ AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
#include <sys/types.h> #include <sys/types.h>
#include <netinet/in.h> #include <netinet/in.h>
]], ]],
[[ struct in6_addr s; s.s6_addr[0] = 0; ]])], [[ if (sizeof(struct in6_addr)) return 0 ]])],
[ ac_cv_have_struct_in6_addr="yes" ], [ ac_cv_have_struct_in6_addr="yes" ],
[ ac_cv_have_struct_in6_addr="no" ] [ ac_cv_have_struct_in6_addr="no" ]
) )
]) ])
if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
AC_DEFINE(HAVE_STRUCT_IN6_ADDR,,Have struct in6_addr) AC_DEFINE(HAVE_STRUCT_IN6_ADDR,1,Have struct in6_addr)
fi fi
AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [ AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
@ -308,13 +444,13 @@ AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
#include <sys/socket.h> #include <sys/socket.h>
#include <netdb.h> #include <netdb.h>
]], ]],
[[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ]])], [[ if (sizeof(struct addrinfo)) return 0 ]])],
[ ac_cv_have_struct_addrinfo="yes" ], [ ac_cv_have_struct_addrinfo="yes" ],
[ ac_cv_have_struct_addrinfo="no" ] [ ac_cv_have_struct_addrinfo="no" ]
) )
]) ])
if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then
AC_DEFINE(HAVE_STRUCT_ADDRINFO,,Have struct addrinfo) AC_DEFINE(HAVE_STRUCT_ADDRINFO,1,Have struct addrinfo)
fi fi
@ -361,10 +497,15 @@ AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
AC_CHECK_FUNCS(setutxent utmpxname) AC_CHECK_FUNCS(setutxent utmpxname)
AC_CHECK_FUNCS(logout updwtmp logwtmp) AC_CHECK_FUNCS(logout updwtmp logwtmp)
# POSIX monotonic time
AC_CHECK_FUNCS(clock_gettime)
# OS X monotonic time # OS X monotonic time
AC_CHECK_HEADERS([mach/mach_time.h]) AC_CHECK_HEADERS([mach/mach_time.h])
AC_CHECK_FUNCS(mach_absolute_time) AC_CHECK_FUNCS(mach_absolute_time)
AC_CHECK_FUNCS(explicit_bzero memset_s)
AC_ARG_ENABLE(bundled-libtom, AC_ARG_ENABLE(bundled-libtom,
[ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists. [ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists.
--disable-bundled-libtom Force using system libtomcrypt/libtommath, fail if it does not exist. --disable-bundled-libtom Force using system libtomcrypt/libtommath, fail if it does not exist.
@ -375,21 +516,21 @@ AC_ARG_ENABLE(bundled-libtom,
AC_MSG_NOTICE(Forcing bundled libtom*) AC_MSG_NOTICE(Forcing bundled libtom*)
else else
BUNDLED_LIBTOM=0 BUNDLED_LIBTOM=0
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="$LIBTOM_LIBS -ltommath", AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS",
[AC_MSG_ERROR([Missing system libtommath and --disable-bundled-libtom was specified])] ) [AC_MSG_ERROR([Missing system libtommath and --disable-bundled-libtom was specified])] )
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="$LIBTOM_LIBS -ltomcrypt", AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS",
[AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] ) [AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] )
fi fi
], ],
[ [
BUNDLED_LIBTOM=0 BUNDLED_LIBTOM=0
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="$LIBTOM_LIBS -ltommath", BUNDLED_LIBTOM=1) AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="$LIBTOM_LIBS -ltomcrypt", BUNDLED_LIBTOM=1) AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
] ]
) )
if test $BUNDLED_LIBTOM = 1 ; then if test $BUNDLED_LIBTOM = 1 ; then
AC_DEFINE(BUNDLED_LIBTOM,,Use bundled libtom) AC_DEFINE(BUNDLED_LIBTOM,1,Use bundled libtom)
fi fi
AC_SUBST(LIBTOM_LIBS) AC_SUBST(LIBTOM_LIBS)
@ -400,36 +541,64 @@ dnl Added from OpenSSH 3.6.1p2's configure.ac
dnl allow user to disable some login recording features dnl allow user to disable some login recording features
AC_ARG_ENABLE(lastlog, AC_ARG_ENABLE(lastlog,
[ --disable-lastlog Disable use of lastlog even if detected [no]], [ --disable-lastlog Disable use of lastlog even if detected [no]],
[ AC_DEFINE(DISABLE_LASTLOG,,Disable use of lastlog()) ] [
if test "x$enableval" = "xno" ; then
AC_DEFINE(DISABLE_LASTLOG,1,Disable use of lastlog())
fi
]
) )
AC_ARG_ENABLE(utmp, AC_ARG_ENABLE(utmp,
[ --disable-utmp Disable use of utmp even if detected [no]], [ --disable-utmp Disable use of utmp even if detected [no]],
[ AC_DEFINE(DISABLE_UTMP,,Disable use of utmp) ] [
if test "x$enableval" = "xno" ; then
AC_DEFINE(DISABLE_UTMP,1,Disable use of utmp)
fi
]
) )
AC_ARG_ENABLE(utmpx, AC_ARG_ENABLE(utmpx,
[ --disable-utmpx Disable use of utmpx even if detected [no]], [ --disable-utmpx Disable use of utmpx even if detected [no]],
[ AC_DEFINE(DISABLE_UTMPX,,Disable use of utmpx) ] [
if test "x$enableval" = "xno" ; then
AC_DEFINE(DISABLE_UTMPX,1,Disable use of utmpx)
fi
]
) )
AC_ARG_ENABLE(wtmp, AC_ARG_ENABLE(wtmp,
[ --disable-wtmp Disable use of wtmp even if detected [no]], [ --disable-wtmp Disable use of wtmp even if detected [no]],
[ AC_DEFINE(DISABLE_WTMP,,Disable use of wtmp) ] [
if test "x$enableval" = "xno" ; then
AC_DEFINE(DISABLE_WTMP,1,Disable use of wtmp)
fi
]
) )
AC_ARG_ENABLE(wtmpx, AC_ARG_ENABLE(wtmpx,
[ --disable-wtmpx Disable use of wtmpx even if detected [no]], [ --disable-wtmpx Disable use of wtmpx even if detected [no]],
[ AC_DEFINE(DISABLE_WTMPX,,Disable use of wtmpx) ] [
if test "x$enableval" = "xno" ; then
AC_DEFINE(DISABLE_WTMPX,1,Disable use of wtmpx)
fi
]
) )
AC_ARG_ENABLE(loginfunc, AC_ARG_ENABLE(loginfunc,
[ --disable-loginfunc Disable use of login() etc. [no]], [ --disable-loginfunc Disable use of login() etc. [no]],
[ no_loginfunc_check=1 [ no_loginfunc_check=1
AC_MSG_NOTICE(Not using login() etc) ] AC_MSG_NOTICE([Not using login() etc]) ]
) )
AC_ARG_ENABLE(pututline, AC_ARG_ENABLE(pututline,
[ --disable-pututline Disable use of pututline() etc. ([uw]tmp) [no]], [ --disable-pututline Disable use of pututline() etc. ([uw]tmp) [no]],
[ AC_DEFINE(DISABLE_PUTUTLINE,,Disable use of pututline()) ] [
if test "x$enableval" = "xno" ; then
AC_DEFINE(DISABLE_PUTUTLINE,1,Disable use of pututline())
fi
]
) )
AC_ARG_ENABLE(pututxline, AC_ARG_ENABLE(pututxline,
[ --disable-pututxline Disable use of pututxline() etc. ([uw]tmpx) [no]], [ --disable-pututxline Disable use of pututxline() etc. ([uw]tmpx) [no]],
[ AC_DEFINE(DISABLE_PUTUTXLINE,,Disable use of pututxline()) ] [
if test "x$enableval" = "xno" ; then
AC_DEFINE(DISABLE_PUTUTXLINE,1,Disable use of pututxline())
fi
]
) )
AC_ARG_WITH(lastlog, AC_ARG_WITH(lastlog,
[ --with-lastlog=FILE|DIR specify lastlog location [common locations]], [ --with-lastlog=FILE|DIR specify lastlog location [common locations]],
@ -444,7 +613,7 @@ AC_ARG_WITH(lastlog,
if test -z "$no_loginfunc_check"; then if test -z "$no_loginfunc_check"; then
dnl Checks for libutil functions (login(), logout() etc, not openpty() ) dnl Checks for libutil functions (login(), logout() etc, not openpty() )
AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN,,Have login() function)]) AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN,1,[Have login() function])])
AC_CHECK_FUNCS(logout updwtmp logwtmp) AC_CHECK_FUNCS(logout updwtmp logwtmp)
fi fi
@ -632,7 +801,9 @@ fi
AC_PROG_GCC_TRADITIONAL AC_PROG_GCC_TRADITIONAL
AC_FUNC_MEMCMP AC_FUNC_MEMCMP
AC_FUNC_SELECT_ARGTYPES 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([getpass getspnam getusershell putenv])
AC_CHECK_FUNCS([clearenv strlcpy strlcat daemon basename _getpty getaddrinfo ])
AC_CHECK_FUNCS([freeaddrinfo getnameinfo fork writev getgrouplist])
AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME)) AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
@ -640,7 +811,7 @@ AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
if test -z "$no_ptmx_check" ; then if test -z "$no_ptmx_check" ; then
if test x"$cross_compiling" = x"no" ; then if test x"$cross_compiling" = x"no" ; then
if test -e /dev/ptmx ; then if test -e /dev/ptmx ; then
AC_DEFINE(USE_DEV_PTMX,,Use /dev/ptmx) AC_DEFINE(USE_DEV_PTMX,1,Use /dev/ptmx)
fi fi
else else
AC_MSG_NOTICE([Not checking for /dev/ptmx, we're cross-compiling]) AC_MSG_NOTICE([Not checking for /dev/ptmx, we're cross-compiling])
@ -650,7 +821,7 @@ fi
if test -z "$no_ptc_check" ; then if test -z "$no_ptc_check" ; then
if test x"$cross_compiling" = x"no" ; then if test x"$cross_compiling" = x"no" ; then
if test -e /dev/ptc ; then if test -e /dev/ptc ; then
AC_DEFINE(HAVE_DEV_PTS_AND_PTC,,Use /dev/ptc & /dev/pts) AC_DEFINE(HAVE_DEV_PTS_AND_PTC,1,Use /dev/ptc & /dev/pts)
fi fi
else else
AC_MSG_NOTICE([Not checking for /dev/ptc & /dev/pts since we're cross-compiling]) AC_MSG_NOTICE([Not checking for /dev/ptc & /dev/pts since we're cross-compiling])
@ -659,67 +830,32 @@ fi
AC_EXEEXT AC_EXEEXT
# XXX there must be a nicer way to do this if test $BUNDLED_LIBTOM = 1 ; then
AS_MKDIR_P(libtomcrypt/src/ciphers/aes) (cd $srcdir; find libtomcrypt -type d) | xargs mkdir -pv
AS_MKDIR_P(libtomcrypt/src/ciphers/safer) LIBTOM_FILES="libtomcrypt/Makefile libtommath/Makefile"
AS_MKDIR_P(libtomcrypt/src/ciphers/twofish) fi
AS_MKDIR_P(libtomcrypt/src/encauth/ccm)
AS_MKDIR_P(libtomcrypt/src/encauth/eax)
AS_MKDIR_P(libtomcrypt/src/encauth/gcm)
AS_MKDIR_P(libtomcrypt/src/encauth/ocb)
AS_MKDIR_P(libtomcrypt/src/hashes)
AS_MKDIR_P(libtomcrypt/src/hashes/chc)
AS_MKDIR_P(libtomcrypt/src/hashes/helper)
AS_MKDIR_P(libtomcrypt/src/hashes/sha2)
AS_MKDIR_P(libtomcrypt/src/hashes/whirl)
AS_MKDIR_P(libtomcrypt/src/mac/hmac)
AS_MKDIR_P(libtomcrypt/src/mac/omac)
AS_MKDIR_P(libtomcrypt/src/mac/pelican)
AS_MKDIR_P(libtomcrypt/src/mac/pmac)
AS_MKDIR_P(libtomcrypt/src/mac/f9)
AS_MKDIR_P(libtomcrypt/src/mac/xcbc)
AS_MKDIR_P(libtomcrypt/src/math/fp)
AS_MKDIR_P(libtomcrypt/src/misc/base64)
AS_MKDIR_P(libtomcrypt/src/misc/crypt)
AS_MKDIR_P(libtomcrypt/src/misc/mpi)
AS_MKDIR_P(libtomcrypt/src/misc/pkcs5)
AS_MKDIR_P(libtomcrypt/src/modes/cbc)
AS_MKDIR_P(libtomcrypt/src/modes/cfb)
AS_MKDIR_P(libtomcrypt/src/modes/ctr)
AS_MKDIR_P(libtomcrypt/src/modes/ecb)
AS_MKDIR_P(libtomcrypt/src/modes/ofb)
AS_MKDIR_P(libtomcrypt/src/modes/f8)
AS_MKDIR_P(libtomcrypt/src/modes/lrw)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/bit)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/boolean)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/choice)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/ia5)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/integer)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/object_identifier)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/octet)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/printable_string)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/sequence)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/set)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/short_integer)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/utctime)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/utf8)
AS_MKDIR_P(libtomcrypt/src/pk/dh)
AS_MKDIR_P(libtomcrypt/src/pk/dsa)
AS_MKDIR_P(libtomcrypt/src/pk/ecc)
AS_MKDIR_P(libtomcrypt/src/pk/katja)
AS_MKDIR_P(libtomcrypt/src/pk/pkcs1)
AS_MKDIR_P(libtomcrypt/src/pk/rsa)
AS_MKDIR_P(libtomcrypt/src/prngs)
AC_CONFIG_HEADER(config.h) AC_CONFIG_HEADER(config.h)
AC_CONFIG_FILES(Makefile libtomcrypt/Makefile libtommath/Makefile) AC_CONFIG_FILES(Makefile $LIBTOM_FILES)
AC_OUTPUT AC_OUTPUT
AC_MSG_NOTICE() AC_MSG_NOTICE()
if test $BUNDLED_LIBTOM = 1 ; then if test $BUNDLED_LIBTOM = 1 ; then
AC_MSG_NOTICE(Using bundled libtomcrypt and libtommath) AC_MSG_NOTICE([Using bundled libtomcrypt and libtommath])
else 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 fi
AC_MSG_NOTICE() AC_MSG_NOTICE()
AC_MSG_NOTICE(Now edit options.h to choose features.) AC_MSG_NOTICE([Now edit options.h to choose features.])

View File

@ -4,7 +4,7 @@
#include "ltc_prng.h" #include "ltc_prng.h"
#include "ecc.h" #include "ecc.h"
#ifdef DROPBEAR_LTC_PRNG #if DROPBEAR_LTC_PRNG
int dropbear_ltc_prng = -1; int dropbear_ltc_prng = -1;
#endif #endif
@ -14,16 +14,16 @@
void crypto_init() { void crypto_init() {
const struct ltc_cipher_descriptor *regciphers[] = { const struct ltc_cipher_descriptor *regciphers[] = {
#ifdef DROPBEAR_AES #if DROPBEAR_AES
&aes_desc, &aes_desc,
#endif #endif
#ifdef DROPBEAR_BLOWFISH #if DROPBEAR_BLOWFISH
&blowfish_desc, &blowfish_desc,
#endif #endif
#ifdef DROPBEAR_TWOFISH #if DROPBEAR_TWOFISH
&twofish_desc, &twofish_desc,
#endif #endif
#ifdef DROPBEAR_3DES #if DROPBEAR_3DES
&des3_desc, &des3_desc,
#endif #endif
NULL NULL
@ -32,16 +32,16 @@ void crypto_init() {
const struct ltc_hash_descriptor *reghashes[] = { const struct ltc_hash_descriptor *reghashes[] = {
/* we need sha1 for hostkey stuff regardless */ /* we need sha1 for hostkey stuff regardless */
&sha1_desc, &sha1_desc,
#ifdef DROPBEAR_MD5_HMAC #if DROPBEAR_MD5_HMAC
&md5_desc, &md5_desc,
#endif #endif
#ifdef DROPBEAR_SHA256 #if DROPBEAR_SHA256
&sha256_desc, &sha256_desc,
#endif #endif
#ifdef DROPBEAR_SHA384 #if DROPBEAR_SHA384
&sha384_desc, &sha384_desc,
#endif #endif
#ifdef DROPBEAR_SHA512 #if DROPBEAR_SHA512
&sha512_desc, &sha512_desc,
#endif #endif
NULL NULL
@ -60,14 +60,14 @@ void crypto_init() {
} }
} }
#ifdef DROPBEAR_LTC_PRNG #if DROPBEAR_LTC_PRNG
dropbear_ltc_prng = register_prng(&dropbear_prng_desc); dropbear_ltc_prng = register_prng(&dropbear_prng_desc);
if (dropbear_ltc_prng == -1) { if (dropbear_ltc_prng == -1) {
dropbear_exit("Error registering crypto"); dropbear_exit("Error registering crypto");
} }
#endif #endif
#ifdef DROPBEAR_ECC #if DROPBEAR_ECC
ltc_mp = ltm_desc; ltc_mp = ltm_desc;
dropbear_ecc_fill_dp(); dropbear_ecc_fill_dp();
#endif #endif

View File

@ -1,9 +1,9 @@
#ifndef _CRYPTO_DESC_H #ifndef DROPBEAR_CRYPTO_DESC_H
#define _CRYPTO_DESC_H #define DROPBEAR_CRYPTO_DESC_H
void crypto_init(); void crypto_init(void);
extern int dropbear_ltc_prng; extern int dropbear_ltc_prng;
#endif /* _CRYPTO_DESC_H */ #endif /* DROPBEAR_CRYPTO_DESC_H */

View File

@ -43,8 +43,7 @@
* *
* This is, almost, a clean room reimplementation from the curve25519 paper. It * This is, almost, a clean room reimplementation from the curve25519 paper. It
* uses many of the tricks described therein. Only the crecip function is taken * uses many of the tricks described therein. Only the crecip function is taken
* from the sample implementation. * from the sample implementation. */
*/
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
@ -63,25 +62,23 @@ typedef int64_t limb;
* significant first. The value of the field element is: * significant first. The value of the field element is:
* x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ... * x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ...
* *
* i.e. the limbs are 26, 25, 26, 25, ... bits wide. * i.e. the limbs are 26, 25, 26, 25, ... bits wide. */
*/
/* Sum two numbers: output += in */ /* Sum two numbers: output += in */
static void fsum(limb *output, const limb *in) { static void fsum(limb *output, const limb *in) {
unsigned i; unsigned i;
for (i = 0; i < 10; i += 2) { for (i = 0; i < 10; i += 2) {
output[0+i] = (output[0+i] + in[0+i]); output[0+i] = output[0+i] + in[0+i];
output[1+i] = (output[1+i] + in[1+i]); output[1+i] = output[1+i] + in[1+i];
} }
} }
/* Find the difference of two numbers: output = in - output /* Find the difference of two numbers: output = in - output
* (note the order of the arguments!) * (note the order of the arguments!). */
*/
static void fdifference(limb *output, const limb *in) { static void fdifference(limb *output, const limb *in) {
unsigned i; unsigned i;
for (i = 0; i < 10; ++i) { for (i = 0; i < 10; ++i) {
output[i] = (in[i] - output[i]); output[i] = in[i] - output[i];
} }
} }
@ -97,7 +94,8 @@ static void fscalar_product(limb *output, const limb *in, const limb scalar) {
* *
* output must be distinct to both inputs. The inputs are reduced coefficient * output must be distinct to both inputs. The inputs are reduced coefficient
* form, the output is not. * form, the output is not.
*/ *
* output[x] <= 14 * the largest product of the input limbs. */
static void fproduct(limb *output, const limb *in2, const limb *in) { static void fproduct(limb *output, const limb *in2, const limb *in) {
output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]); output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]);
output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) + output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) +
@ -201,9 +199,15 @@ static void fproduct(limb *output, const limb *in2, const limb *in) {
output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]); output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]);
} }
/* Reduce a long form to a short form by taking the input mod 2^255 - 19. */ /* Reduce a long form to a short form by taking the input mod 2^255 - 19.
*
* On entry: |output[i]| < 14*2^54
* On exit: |output[0..8]| < 280*2^54 */
static void freduce_degree(limb *output) { static void freduce_degree(limb *output) {
/* Each of these shifts and adds ends up multiplying the value by 19. */ /* Each of these shifts and adds ends up multiplying the value by 19.
*
* For output[0..8], the absolute entry value is < 14*2^54 and we add, at
* most, 19*14*2^54 thus, on exit, |output[0..8]| < 280*2^54. */
output[8] += output[18] << 4; output[8] += output[18] << 4;
output[8] += output[18] << 1; output[8] += output[18] << 1;
output[8] += output[18]; output[8] += output[18];
@ -237,11 +241,13 @@ static void freduce_degree(limb *output) {
#error "This code only works on a two's complement system" #error "This code only works on a two's complement system"
#endif #endif
/* return v / 2^26, using only shifts and adds. */ /* return v / 2^26, using only shifts and adds.
*
* On entry: v can take any value. */
static inline limb static inline limb
div_by_2_26(const limb v) div_by_2_26(const limb v)
{ {
/* High word of v; no shift needed*/ /* High word of v; no shift needed. */
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
/* Set to all 1s if v was negative; else set to 0s. */ /* Set to all 1s if v was negative; else set to 0s. */
const int32_t sign = ((int32_t) highword) >> 31; const int32_t sign = ((int32_t) highword) >> 31;
@ -251,7 +257,9 @@ div_by_2_26(const limb v)
return (v + roundoff) >> 26; return (v + roundoff) >> 26;
} }
/* return v / (2^25), using only shifts and adds. */ /* return v / (2^25), using only shifts and adds.
*
* On entry: v can take any value. */
static inline limb static inline limb
div_by_2_25(const limb v) div_by_2_25(const limb v)
{ {
@ -265,17 +273,9 @@ div_by_2_25(const limb v)
return (v + roundoff) >> 25; return (v + roundoff) >> 25;
} }
static inline s32
div_s32_by_2_25(const s32 v)
{
const s32 roundoff = ((uint32_t)(v >> 31)) >> 7;
return (v + roundoff) >> 25;
}
/* Reduce all coefficients of the short form input so that |x| < 2^26. /* Reduce all coefficients of the short form input so that |x| < 2^26.
* *
* On entry: |output[i]| < 2^62 * On entry: |output[i]| < 280*2^54 */
*/
static void freduce_coefficients(limb *output) { static void freduce_coefficients(limb *output) {
unsigned i; unsigned i;
@ -283,56 +283,65 @@ static void freduce_coefficients(limb *output) {
for (i = 0; i < 10; i += 2) { for (i = 0; i < 10; i += 2) {
limb over = div_by_2_26(output[i]); limb over = div_by_2_26(output[i]);
/* The entry condition (that |output[i]| < 280*2^54) means that over is, at
* most, 280*2^28 in the first iteration of this loop. This is added to the
* next limb and we can approximate the resulting bound of that limb by
* 281*2^54. */
output[i] -= over << 26; output[i] -= over << 26;
output[i+1] += over; output[i+1] += over;
/* For the first iteration, |output[i+1]| < 281*2^54, thus |over| <
* 281*2^29. When this is added to the next limb, the resulting bound can
* be approximated as 281*2^54.
*
* For subsequent iterations of the loop, 281*2^54 remains a conservative
* bound and no overflow occurs. */
over = div_by_2_25(output[i+1]); over = div_by_2_25(output[i+1]);
output[i+1] -= over << 25; output[i+1] -= over << 25;
output[i+2] += over; output[i+2] += over;
} }
/* Now |output[10]| < 2 ^ 38 and all other coefficients are reduced. */ /* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */
output[0] += output[10] << 4; output[0] += output[10] << 4;
output[0] += output[10] << 1; output[0] += output[10] << 1;
output[0] += output[10]; output[0] += output[10];
output[10] = 0; output[10] = 0;
/* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19 * 2^38 /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29
* So |over| will be no more than 77825 */ * So |over| will be no more than 2^16. */
{ {
limb over = div_by_2_26(output[0]); limb over = div_by_2_26(output[0]);
output[0] -= over << 26; output[0] -= over << 26;
output[1] += over; output[1] += over;
} }
/* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 77825 /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The
* So |over| will be no more than 1. */ * bound on |output[1]| is sufficient to meet our needs. */
{
/* output[1] fits in 32 bits, so we can use div_s32_by_2_25 here. */
s32 over32 = div_s32_by_2_25((s32) output[1]);
output[1] -= over32 << 25;
output[2] += over32;
}
/* Finally, output[0,1,3..9] are reduced, and output[2] is "nearly reduced":
* we have |output[2]| <= 2^26. This is good enough for all of our math,
* but it will require an extra freduce_coefficients before fcontract. */
} }
/* A helpful wrapper around fproduct: output = in * in2. /* A helpful wrapper around fproduct: output = in * in2.
* *
* output must be distinct to both inputs. The output is reduced degree and * On entry: |in[i]| < 2^27 and |in2[i]| < 2^27.
* reduced coefficient. *
*/ * output must be distinct to both inputs. The output is reduced degree
* (indeed, one need only provide storage for 10 limbs) and |output[i]| < 2^26. */
static void static void
fmul(limb *output, const limb *in, const limb *in2) { fmul(limb *output, const limb *in, const limb *in2) {
limb t[19]; limb t[19];
fproduct(t, in, in2); fproduct(t, in, in2);
/* |t[i]| < 14*2^54 */
freduce_degree(t); freduce_degree(t);
freduce_coefficients(t); freduce_coefficients(t);
/* |t[i]| < 2^26 */
memcpy(output, t, sizeof(limb) * 10); memcpy(output, t, sizeof(limb) * 10);
} }
/* Square a number: output = in**2
*
* output must be distinct from the input. The inputs are reduced coefficient
* form, the output is not.
*
* output[x] <= 14 * the largest product of the input limbs. */
static void fsquare_inner(limb *output, const limb *in) { static void fsquare_inner(limb *output, const limb *in) {
output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]); output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]);
output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]); output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]);
@ -391,12 +400,23 @@ static void fsquare_inner(limb *output, const limb *in) {
output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]); output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]);
} }
/* fsquare sets output = in^2.
*
* On entry: The |in| argument is in reduced coefficients form and |in[i]| <
* 2^27.
*
* On exit: The |output| argument is in reduced coefficients form (indeed, one
* need only provide storage for 10 limbs) and |out[i]| < 2^26. */
static void static void
fsquare(limb *output, const limb *in) { fsquare(limb *output, const limb *in) {
limb t[19]; limb t[19];
fsquare_inner(t, in); fsquare_inner(t, in);
/* |t[i]| < 14*2^54 because the largest product of two limbs will be <
* 2^(27+27) and fsquare_inner adds together, at most, 14 of those
* products. */
freduce_degree(t); freduce_degree(t);
freduce_coefficients(t); freduce_coefficients(t);
/* |t[i]| < 2^26 */
memcpy(output, t, sizeof(limb) * 10); memcpy(output, t, sizeof(limb) * 10);
} }
@ -417,7 +437,7 @@ fexpand(limb *output, const u8 *input) {
F(6, 19, 1, 0x3ffffff); F(6, 19, 1, 0x3ffffff);
F(7, 22, 3, 0x1ffffff); F(7, 22, 3, 0x1ffffff);
F(8, 25, 4, 0x3ffffff); F(8, 25, 4, 0x3ffffff);
F(9, 28, 6, 0x3ffffff); F(9, 28, 6, 0x1ffffff);
#undef F #undef F
} }
@ -425,60 +445,143 @@ fexpand(limb *output, const u8 *input) {
#error "This code only works when >> does sign-extension on negative numbers" #error "This code only works when >> does sign-extension on negative numbers"
#endif #endif
/* s32_eq returns 0xffffffff iff a == b and zero otherwise. */
static s32 s32_eq(s32 a, s32 b) {
a = ~(a ^ b);
a &= a << 16;
a &= a << 8;
a &= a << 4;
a &= a << 2;
a &= a << 1;
return a >> 31;
}
/* s32_gte returns 0xffffffff if a >= b and zero otherwise, where a and b are
* both non-negative. */
static s32 s32_gte(s32 a, s32 b) {
a -= b;
/* a >= 0 iff a >= b. */
return ~(a >> 31);
}
/* Take a fully reduced polynomial form number and contract it into a /* Take a fully reduced polynomial form number and contract it into a
* little-endian, 32-byte array * little-endian, 32-byte array.
*/ *
* On entry: |input_limbs[i]| < 2^26 */
static void static void
fcontract(u8 *output, limb *input) { fcontract(u8 *output, limb *input_limbs) {
int i; int i;
int j; int j;
s32 input[10];
s32 mask;
/* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */
for (i = 0; i < 10; i++) {
input[i] = input_limbs[i];
}
for (j = 0; j < 2; ++j) { for (j = 0; j < 2; ++j) {
for (i = 0; i < 9; ++i) { for (i = 0; i < 9; ++i) {
if ((i & 1) == 1) { if ((i & 1) == 1) {
/* This calculation is a time-invariant way to make input[i] positive /* This calculation is a time-invariant way to make input[i]
by borrowing from the next-larger limb. * non-negative by borrowing from the next-larger limb. */
*/ const s32 mask = input[i] >> 31;
const s32 mask = (s32)(input[i]) >> 31; const s32 carry = -((input[i] & mask) >> 25);
const s32 carry = -(((s32)(input[i]) & mask) >> 25); input[i] = input[i] + (carry << 25);
input[i] = (s32)(input[i]) + (carry << 25); input[i+1] = input[i+1] - carry;
input[i+1] = (s32)(input[i+1]) - carry;
} else { } else {
const s32 mask = (s32)(input[i]) >> 31; const s32 mask = input[i] >> 31;
const s32 carry = -(((s32)(input[i]) & mask) >> 26); const s32 carry = -((input[i] & mask) >> 26);
input[i] = (s32)(input[i]) + (carry << 26); input[i] = input[i] + (carry << 26);
input[i+1] = (s32)(input[i+1]) - carry; input[i+1] = input[i+1] - carry;
} }
} }
/* There's no greater limb for input[9] to borrow from, but we can multiply
* by 19 and borrow from input[0], which is valid mod 2^255-19. */
{ {
const s32 mask = (s32)(input[9]) >> 31; const s32 mask = input[9] >> 31;
const s32 carry = -(((s32)(input[9]) & mask) >> 25); const s32 carry = -((input[9] & mask) >> 25);
input[9] = (s32)(input[9]) + (carry << 25); input[9] = input[9] + (carry << 25);
input[0] = (s32)(input[0]) - (carry * 19); input[0] = input[0] - (carry * 19);
} }
/* After the first iteration, input[1..9] are non-negative and fit within
* 25 or 26 bits, depending on position. However, input[0] may be
* negative. */
} }
/* The first borrow-propagation pass above ended with every limb /* The first borrow-propagation pass above ended with every limb
except (possibly) input[0] non-negative. except (possibly) input[0] non-negative.
Since each input limb except input[0] is decreased by at most 1 If input[0] was negative after the first pass, then it was because of a
by a borrow-propagation pass, the second borrow-propagation pass carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most,
could only have wrapped around to decrease input[0] again if the one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19.
first pass left input[0] negative *and* input[1] through input[9]
were all zero. In that case, input[1] is now 2^25 - 1, and this In the second pass, each limb is decreased by at most one. Thus the second
last borrow-propagation step will leave input[1] non-negative. borrow-propagation pass could only have wrapped around to decrease
*/ input[0] again if the first pass left input[0] negative *and* input[1]
through input[9] were all zero. In that case, input[1] is now 2^25 - 1,
and this last borrow-propagation step will leave input[1] non-negative. */
{ {
const s32 mask = (s32)(input[0]) >> 31; const s32 mask = input[0] >> 31;
const s32 carry = -(((s32)(input[0]) & mask) >> 26); const s32 carry = -((input[0] & mask) >> 26);
input[0] = (s32)(input[0]) + (carry << 26); input[0] = input[0] + (carry << 26);
input[1] = (s32)(input[1]) - carry; input[1] = input[1] - carry;
} }
/* Both passes through the above loop, plus the last 0-to-1 step, are /* All input[i] are now non-negative. However, there might be values between
necessary: if input[9] is -1 and input[0] through input[8] are 0, * 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */
negative values will remain in the array until the end. for (j = 0; j < 2; j++) {
*/ for (i = 0; i < 9; i++) {
if ((i & 1) == 1) {
const s32 carry = input[i] >> 25;
input[i] &= 0x1ffffff;
input[i+1] += carry;
} else {
const s32 carry = input[i] >> 26;
input[i] &= 0x3ffffff;
input[i+1] += carry;
}
}
{
const s32 carry = input[9] >> 25;
input[9] &= 0x1ffffff;
input[0] += 19*carry;
}
}
/* If the first carry-chain pass, just above, ended up with a carry from
* input[9], and that caused input[0] to be out-of-bounds, then input[0] was
* < 2^26 + 2*19, because the carry was, at most, two.
*
* If the second pass carried from input[9] again then input[0] is < 2*19 and
* the input[9] -> input[0] carry didn't push input[0] out of bounds. */
/* It still remains the case that input might be between 2^255-19 and 2^255.
* In this case, input[1..9] must take their maximum value and input[0] must
* be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */
mask = s32_gte(input[0], 0x3ffffed);
for (i = 1; i < 10; i++) {
if ((i & 1) == 1) {
mask &= s32_eq(input[i], 0x1ffffff);
} else {
mask &= s32_eq(input[i], 0x3ffffff);
}
}
/* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus
* this conditionally subtracts 2^255-19. */
input[0] -= mask & 0x3ffffed;
for (i = 1; i < 10; i++) {
if ((i & 1) == 1) {
input[i] -= mask & 0x1ffffff;
} else {
input[i] -= mask & 0x3ffffff;
}
}
input[1] <<= 2; input[1] <<= 2;
input[2] <<= 3; input[2] <<= 3;
@ -516,7 +619,9 @@ fcontract(u8 *output, limb *input) {
* x z: short form, destroyed * x z: short form, destroyed
* xprime zprime: short form, destroyed * xprime zprime: short form, destroyed
* qmqp: short form, preserved * qmqp: short form, preserved
*/ *
* On entry and exit, the absolute value of the limbs of all inputs and outputs
* are < 2^26. */
static void fmonty(limb *x2, limb *z2, /* output 2Q */ static void fmonty(limb *x2, limb *z2, /* output 2Q */
limb *x3, limb *z3, /* output Q + Q' */ limb *x3, limb *z3, /* output Q + Q' */
limb *x, limb *z, /* input Q */ limb *x, limb *z, /* input Q */
@ -527,43 +632,69 @@ static void fmonty(limb *x2, limb *z2, /* output 2Q */
memcpy(origx, x, 10 * sizeof(limb)); memcpy(origx, x, 10 * sizeof(limb));
fsum(x, z); fsum(x, z);
fdifference(z, origx); // does x - z /* |x[i]| < 2^27 */
fdifference(z, origx); /* does x - z */
/* |z[i]| < 2^27 */
memcpy(origxprime, xprime, sizeof(limb) * 10); memcpy(origxprime, xprime, sizeof(limb) * 10);
fsum(xprime, zprime); fsum(xprime, zprime);
/* |xprime[i]| < 2^27 */
fdifference(zprime, origxprime); fdifference(zprime, origxprime);
/* |zprime[i]| < 2^27 */
fproduct(xxprime, xprime, z); fproduct(xxprime, xprime, z);
/* |xxprime[i]| < 14*2^54: the largest product of two limbs will be <
* 2^(27+27) and fproduct adds together, at most, 14 of those products.
* (Approximating that to 2^58 doesn't work out.) */
fproduct(zzprime, x, zprime); fproduct(zzprime, x, zprime);
/* |zzprime[i]| < 14*2^54 */
freduce_degree(xxprime); freduce_degree(xxprime);
freduce_coefficients(xxprime); freduce_coefficients(xxprime);
/* |xxprime[i]| < 2^26 */
freduce_degree(zzprime); freduce_degree(zzprime);
freduce_coefficients(zzprime); freduce_coefficients(zzprime);
/* |zzprime[i]| < 2^26 */
memcpy(origxprime, xxprime, sizeof(limb) * 10); memcpy(origxprime, xxprime, sizeof(limb) * 10);
fsum(xxprime, zzprime); fsum(xxprime, zzprime);
/* |xxprime[i]| < 2^27 */
fdifference(zzprime, origxprime); fdifference(zzprime, origxprime);
/* |zzprime[i]| < 2^27 */
fsquare(xxxprime, xxprime); fsquare(xxxprime, xxprime);
/* |xxxprime[i]| < 2^26 */
fsquare(zzzprime, zzprime); fsquare(zzzprime, zzprime);
/* |zzzprime[i]| < 2^26 */
fproduct(zzprime, zzzprime, qmqp); fproduct(zzprime, zzzprime, qmqp);
/* |zzprime[i]| < 14*2^52 */
freduce_degree(zzprime); freduce_degree(zzprime);
freduce_coefficients(zzprime); freduce_coefficients(zzprime);
/* |zzprime[i]| < 2^26 */
memcpy(x3, xxxprime, sizeof(limb) * 10); memcpy(x3, xxxprime, sizeof(limb) * 10);
memcpy(z3, zzprime, sizeof(limb) * 10); memcpy(z3, zzprime, sizeof(limb) * 10);
fsquare(xx, x); fsquare(xx, x);
/* |xx[i]| < 2^26 */
fsquare(zz, z); fsquare(zz, z);
/* |zz[i]| < 2^26 */
fproduct(x2, xx, zz); fproduct(x2, xx, zz);
/* |x2[i]| < 14*2^52 */
freduce_degree(x2); freduce_degree(x2);
freduce_coefficients(x2); freduce_coefficients(x2);
fdifference(zz, xx); // does zz = xx - zz /* |x2[i]| < 2^26 */
fdifference(zz, xx); /* does zz = xx - zz */
/* |zz[i]| < 2^27 */
memset(zzz + 10, 0, sizeof(limb) * 9); memset(zzz + 10, 0, sizeof(limb) * 9);
fscalar_product(zzz, zz, 121665); fscalar_product(zzz, zz, 121665);
/* |zzz[i]| < 2^(27+17) */
/* No need to call freduce_degree here: /* No need to call freduce_degree here:
fscalar_product doesn't increase the degree of its input. */ fscalar_product doesn't increase the degree of its input. */
freduce_coefficients(zzz); freduce_coefficients(zzz);
/* |zzz[i]| < 2^26 */
fsum(zzz, xx); fsum(zzz, xx);
/* |zzz[i]| < 2^27 */
fproduct(z2, zz, zzz); fproduct(z2, zz, zzz);
/* |z2[i]| < 14*2^(26+27) */
freduce_degree(z2); freduce_degree(z2);
freduce_coefficients(z2); freduce_coefficients(z2);
/* |z2|i| < 2^26 */
} }
/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave /* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave
@ -574,8 +705,7 @@ static void fmonty(limb *x2, limb *z2, /* output 2Q */
* wrong results. Also, the two limb arrays must be in reduced-coefficient, * wrong results. Also, the two limb arrays must be in reduced-coefficient,
* reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped, * reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped,
* and all all values in a[0..9],b[0..9] must have magnitude less than * and all all values in a[0..9],b[0..9] must have magnitude less than
* INT32_MAX. * INT32_MAX. */
*/
static void static void
swap_conditional(limb a[19], limb b[19], limb iswap) { swap_conditional(limb a[19], limb b[19], limb iswap) {
unsigned i; unsigned i;
@ -592,8 +722,7 @@ swap_conditional(limb a[19], limb b[19], limb iswap) {
* *
* resultx/resultz: the x coordinate of the resulting curve point (short form) * resultx/resultz: the x coordinate of the resulting curve point (short form)
* n: a little endian, 32-byte number * n: a little endian, 32-byte number
* q: a point of the curve (short form) * q: a point of the curve (short form) */
*/
static void static void
cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) { cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0}; limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0};
@ -641,9 +770,9 @@ cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
memcpy(resultz, nqz, sizeof(limb) * 10); memcpy(resultz, nqz, sizeof(limb) * 10);
} }
// ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
// Shamelessly copied from djb's code * Shamelessly copied from djb's code
// ----------------------------------------------------------------------------- * ----------------------------------------------------------------------------- */
static void static void
crecip(limb *out, const limb *z) { crecip(limb *out, const limb *z) {
limb z2[10]; limb z2[10];
@ -711,8 +840,6 @@ crecip(limb *out, const limb *z) {
/* 2^255 - 21 */ fmul(out,t1,z11); /* 2^255 - 21 */ fmul(out,t1,z11);
} }
int curve25519_donna(u8 *, const u8 *, const u8 *);
int int
curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) { curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
limb bp[10], x[10], z[11], zmone[10]; limb bp[10], x[10], z[11], zmone[10];
@ -728,7 +855,6 @@ curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
cmult(x, z, e, bp); cmult(x, z, e, bp);
crecip(zmone, z); crecip(zmone, z);
fmul(z, x, zmone); fmul(z, x, zmone);
freduce_coefficients(z);
fcontract(mypublic, z); fcontract(mypublic, z);
return 0; return 0;
} }

View File

@ -3,25 +3,32 @@
dbclient \- lightweight SSH client dbclient \- lightweight SSH client
.SH SYNOPSIS .SH SYNOPSIS
.B dbclient .B dbclient
[\-Tt] [\-p [\fIflag arguments\fR] [\-p
.I port\fR] [\-i .I port\fR] [\-i
.I id\fR] [\-L .I id\fR] [\-L
.I l\fR:\fIh\fR:\fIr\fR] [\-R .I l\fR:\fIh\fR:\fIp\fR] [\-R
.I l\fR:\fIh\fR:\fIr\fR] [\-l .I l\fR:\fIh\fR:\fIp\fR] [\-l
.IR user ] .IR user ]
.I host .I host
.RI [ \fImore\ flags\fR ]
.RI [ command ] .RI [ command ]
.B dbclient .B dbclient
[ [\fIargs\fR]
.I args ] [\fIuser1\fR]@\fIhost1\fR[^\fIport1\fR],[\fIuser2\fR]@\fIhost2\fR[^\fIport2\fR],...
.I [user1]@host1[^port1],[user2]@host2[^port2],...
.SH DESCRIPTION .SH DESCRIPTION
.B dbclient .B dbclient
is a small SSH client is a small SSH client
.SH OPTIONS .SH OPTIONS
.TP .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 .B \-p \fIport
Connect to Connect to
.I port .I port
@ -33,9 +40,9 @@ Identity file.
Read the identity key from file Read the identity key from file
.I idfile .I idfile
(multiple allowed). This file is created with dropbearkey(1) or converted (multiple allowed). This file is created with dropbearkey(1) or converted
from OpenSSH with dropbearconvert(1). from OpenSSH with dropbearconvert(1). The default path ~/.ssh/id_dropbear is used
.TP .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. Local port forwarding.
Forward the port Forward the port
.I listenport .I listenport
@ -44,7 +51,7 @@ on the local host through the SSH connection to port
on the host on the host
.IR host . .IR host .
.TP .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. Remote port forwarding.
Forward the port Forward the port
.I listenport .I listenport
@ -60,10 +67,12 @@ Login as
on the remote host. on the remote host.
.TP .TP
.B \-t .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 .TP
.B \-T .B \-T
Don't allocate a PTY. Don't allocate a PTY. This is the default a command is given. See -t.
.TP .TP
.B \-N .B \-N
Don't request a remote shell or run any commands. Any command arguments are ignored. Don't request a remote shell or run any commands. Any command arguments are ignored.
@ -102,10 +111,22 @@ if 0 disables keepalives. If no response is received for 3 consecutive keepalive
.B \-I \fIidle_timeout .B \-I \fIidle_timeout
Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds. Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
.TP .TP
.\" TODO: how to avoid a line break between these two -J arguments?
.B \-J \fIproxy_command .B \-J \fIproxy_command
.TP
.B \-J \fI&fd
.br
Use the standard input/output of the program \fIproxy_command\fR rather than using Use the standard input/output of the program \fIproxy_command\fR rather than using
a normal TCP connection. A hostname should be still be provided, as this is used for a normal TCP connection. A hostname should be still be provided, as this is used for
comparing saved hostkeys. comparing saved hostkeys. This command will be executed as "exec proxy_command ..." with the
default shell.
The second form &fd will make dbclient use the numeric file descriptor as a socket. This
can be used for more complex tunnelling scenarios. Example usage with socat is
socat EXEC:'dbclient -J &38 ev',fdin=38,fdout=38 TCP4:host.example.com:22
.TP .TP
.B \-B \fIendhost:endport .B \-B \fIendhost:endport
"Netcat-alike" mode, where Dropbear will connect to the given host, then create a "Netcat-alike" mode, where Dropbear will connect to the given host, then create a
@ -118,9 +139,29 @@ Specify a comma separated list of ciphers to enable. Use \fI-c help\fR to list p
.B \-m \fIMAClist .B \-m \fIMAClist
Specify a comma separated list of authentication MACs to enable. Use \fI-m help\fR to list possibilities. Specify a comma separated list of authentication MACs to enable. Use \fI-m help\fR to list possibilities.
.TP .TP
.B \-o \fIoption
Can be used to give options in the format used by OpenSSH config file. This is
useful for specifying options for which there is no separate command-line flag.
For full details of the options listed below, and their possible values, see
ssh_config(5).
The following options have currently been implemented:
.RS
.TP
.B ExitOnForwardFailure
Specifies whether dbclient should terminate the connection if it cannot set up all requested local and remote port forwardings. The argument must be “yes” or “no”. The default is “no”.
.TP
.B UseSyslog
Send dbclient log messages to syslog in addition to stderr.
.RE
.TP
.B \-s .B \-s
The specified command will be requested as a subsystem, used for sftp. Dropbear doesn't implement sftp itself but the OpenSSH sftp client can be used eg \fIsftp -S dbclient user@host\fR The specified command will be requested as a subsystem, used for sftp. Dropbear doesn't implement sftp itself but the OpenSSH sftp client can be used eg \fIsftp -S dbclient user@host\fR
.TP .TP
.B \-b \fI[address][:port]
Bind to a specific local address when connecting to the remote host. This can be used to choose from
multiple outgoing interfaces. Either address or port (or both) can be given.
.TP
.B \-V .B \-V
Print the version Print the version
@ -129,7 +170,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 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 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. 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 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 ssh/rsh command). A file can be "bounced" through multiple SSH hops, eg
@ -157,6 +198,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 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 standard input is not a TTY, or the environment variable SSH_ASKPASS_ALWAYS is
set. set.
.SH NOTES
If compiled with zlib support and if the server supports it, dbclient will
always use compression.
.SH AUTHOR .SH AUTHOR
Matt Johnston (matt@ucc.asn.au). Matt Johnston (matt@ucc.asn.au).
.br .br

18
dropbear/dbhelpers.c Normal file
View File

@ -0,0 +1,18 @@
#include "dbhelpers.h"
#include "includes.h"
/* Erase data */
void m_burn(void *data, unsigned int len) {
#if defined(HAVE_MEMSET_S)
memset_s(data, len, 0x0, len);
#elif defined(HAVE_EXPLICIT_BZERO)
explicit_bzero(data, len);
#else
/* This must be volatile to avoid compiler optimisation */
volatile void *p = data;
memset((void*)p, 0x0, len);
#endif
}

21
dropbear/dbhelpers.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef DROPBEAR_DBHELPERS_H_
#define DROPBEAR_DBHELPERS_H_
/* This header defines some things that are also used by libtomcrypt/math.
We avoid including normal include.h since that can result in conflicting
definitions - only include config.h */
#include "config.h"
#ifdef __GNUC__
#define ATTRIB_PRINTF(fmt,args) __attribute__((format(printf, fmt, args)))
#define ATTRIB_NORETURN __attribute__((noreturn))
#define ATTRIB_SENTINEL __attribute__((sentinel))
#else
#define ATTRIB_PRINTF(fmt,args)
#define ATTRIB_NORETURN
#define ATTRIB_SENTINEL
#endif
void m_burn(void* data, unsigned int len);
#endif /* DROPBEAR_DBHELPERS_H_ */

182
dropbear/dbmalloc.c Normal file
View File

@ -0,0 +1,182 @@
#include "dbmalloc.h"
#include "dbutil.h"
void * m_calloc(size_t nmemb, size_t size) {
if (SIZE_T_MAX / nmemb < size) {
dropbear_exit("m_calloc failed");
}
return m_malloc(nmemb*size);
}
void * m_strdup(const char * str) {
char* ret;
unsigned int len;
len = strlen(str);
ret = m_malloc(len+1);
if (ret == NULL) {
dropbear_exit("m_strdup failed");
}
memcpy(ret, str, len+1);
return ret;
}
#if !DROPBEAR_TRACKING_MALLOC
/* Simple wrappers around malloc etc */
void * m_malloc(size_t size) {
void* ret;
if (size == 0) {
dropbear_exit("m_malloc failed");
}
ret = calloc(1, size);
if (ret == NULL) {
dropbear_exit("m_malloc failed");
}
return ret;
}
void * m_realloc(void* ptr, size_t size) {
void *ret;
if (size == 0) {
dropbear_exit("m_realloc failed");
}
ret = realloc(ptr, size);
if (ret == NULL) {
dropbear_exit("m_realloc failed");
}
return ret;
}
#else
/* For fuzzing */
struct dbmalloc_header {
unsigned int epoch;
struct dbmalloc_header *prev;
struct dbmalloc_header *next;
};
static void put_alloc(struct dbmalloc_header *header);
static void remove_alloc(struct dbmalloc_header *header);
/* end of the linked list */
static struct dbmalloc_header* staple;
unsigned int current_epoch = 0;
void m_malloc_set_epoch(unsigned int epoch) {
current_epoch = epoch;
}
void m_malloc_free_epoch(unsigned int epoch, int dofree) {
struct dbmalloc_header* header;
struct dbmalloc_header* nextheader = NULL;
struct dbmalloc_header* oldstaple = staple;
staple = NULL;
/* free allocations from this epoch, create a new staple-anchored list from
the remainder */
for (header = oldstaple; header; header = nextheader)
{
nextheader = header->next;
if (header->epoch == epoch) {
if (dofree) {
free(header);
}
} else {
header->prev = NULL;
header->next = NULL;
put_alloc(header);
}
}
}
static void put_alloc(struct dbmalloc_header *header) {
assert(header->next == NULL);
assert(header->prev == NULL);
if (staple) {
staple->prev = header;
}
header->next = staple;
staple = header;
}
static void remove_alloc(struct dbmalloc_header *header) {
if (header->prev) {
header->prev->next = header->next;
}
if (header->next) {
header->next->prev = header->prev;
}
if (staple == header) {
staple = header->next;
}
header->prev = NULL;
header->next = NULL;
}
static struct dbmalloc_header* get_header(void* ptr) {
char* bptr = ptr;
return (struct dbmalloc_header*)&bptr[-sizeof(struct dbmalloc_header)];
}
void * m_malloc(size_t size) {
char* mem = NULL;
struct dbmalloc_header* header = NULL;
if (size == 0 || size > 1e9) {
dropbear_exit("m_malloc failed");
}
size = size + sizeof(struct dbmalloc_header);
mem = calloc(1, size);
if (mem == NULL) {
dropbear_exit("m_malloc failed");
}
header = (struct dbmalloc_header*)mem;
put_alloc(header);
header->epoch = current_epoch;
return &mem[sizeof(struct dbmalloc_header)];
}
void * m_realloc(void* ptr, size_t size) {
char* mem = NULL;
struct dbmalloc_header* header = NULL;
if (size == 0 || size > 1e9) {
dropbear_exit("m_realloc failed");
}
header = get_header(ptr);
remove_alloc(header);
size = size + sizeof(struct dbmalloc_header);
mem = realloc(header, size);
if (mem == NULL) {
dropbear_exit("m_realloc failed");
}
header = (struct dbmalloc_header*)mem;
put_alloc(header);
return &mem[sizeof(struct dbmalloc_header)];
}
void m_free_direct(void* ptr) {
struct dbmalloc_header* header = NULL;
if (!ptr) {
return;
}
header = get_header(ptr);
remove_alloc(header);
free(header);
}
#endif /* DROPBEAR_TRACKING_MALLOC */

27
dropbear/dbmalloc.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef DBMALLOC_H_
#define DBMALLOC_H_
#include "stdint.h"
#include "stdlib.h"
#include "options.h"
void * m_malloc(size_t size);
void * m_calloc(size_t nmemb, size_t size);
void * m_strdup(const char * str);
void * m_realloc(void* ptr, size_t size);
#if DROPBEAR_TRACKING_MALLOC
void m_free_direct(void* ptr);
void m_malloc_set_epoch(unsigned int epoch);
void m_malloc_free_epoch(unsigned int epoch, int dofree);
#else
/* plain wrapper */
#define m_free_direct free
#endif
#define m_free(X) do {m_free_direct(X); (X) = NULL;} while (0)
#endif /* DBMALLOC_H_ */

View File

@ -26,17 +26,13 @@
/* definitions are cleanest if we just put them here */ /* definitions are cleanest if we just put them here */
int dropbear_main(int argc, char ** argv); int dropbear_main(int argc, char ** argv);
int cli_main(int argc, char ** argv);
int dropbearkey_main(int argc, char ** argv); int dropbearkey_main(int argc, char ** argv);
int dropbearconvert_main(int argc, char ** argv); int dropbearconvert_main(int argc, char ** argv);
int scp_main(int argc, char ** argv); int scp_main(int argc, char ** argv);
int main(int argc, char ** argv) { static int runprog(const char *progname, int argc, char ** argv, int *match) {
*match = DROPBEAR_SUCCESS;
char * progname;
if (argc > 0) {
/* figure which form we're being called as */
progname = basename(argv[0]);
#ifdef DBMULTI_dropbear #ifdef DBMULTI_dropbear
if (strcmp(progname, "dropbear") == 0) { if (strcmp(progname, "dropbear") == 0) {
@ -64,10 +60,28 @@ int main(int argc, char ** argv) {
return scp_main(argc, argv); return scp_main(argc, argv);
} }
#endif #endif
*match = DROPBEAR_FAILURE;
return 1;
}
int main(int argc, char ** argv) {
int i;
for (i = 0; i < 2; i++) {
/* Try symlink first, then try as an argument eg "dropbearmulti dbclient host ..." */
if (argc > i) {
int match, res;
/* figure which form we're being called as */
const char* progname = basename(argv[i]);
res = runprog(progname, argc-i, &argv[i], &match);
if (match == DROPBEAR_SUCCESS) {
return res;
}
}
} }
fprintf(stderr, "Dropbear SSH multi-purpose v%s\n" fprintf(stderr, "Dropbear SSH multi-purpose v%s\n"
"Make a symlink pointing at this binary with one of the following names:\n" "Make a symlink pointing at this binary with one of the\n"
"following names or run 'dropbearmulti <command>'.\n"
#ifdef DBMULTI_dropbear #ifdef DBMULTI_dropbear
"'dropbear' - the Dropbear server\n" "'dropbear' - the Dropbear server\n"
#endif #endif

View File

@ -27,12 +27,12 @@
#include "dbutil.h" #include "dbutil.h"
#include "bignum.h" #include "bignum.h"
#include "dbrandom.h" #include "dbrandom.h"
#include "runopts.h"
/* this is used to generate unique output from the same hashpool */ /* this is used to generate unique output from the same hashpool */
static uint32_t counter = 0; static uint32_t counter = 0;
/* the max value for the counter, so it won't integer overflow */ /* the max value for the counter, so it won't integer overflow */
#define MAX_COUNTER 1<<30 #define MAX_COUNTER (1<<30)
static unsigned char hashpool[SHA1_HASH_SIZE] = {0}; static unsigned char hashpool[SHA1_HASH_SIZE] = {0};
static int donerandinit = 0; static int donerandinit = 0;
@ -59,7 +59,7 @@ process_file(hash_state *hs, const char *filename,
unsigned int readcount; unsigned int readcount;
int ret = DROPBEAR_FAILURE; int ret = DROPBEAR_FAILURE;
#ifdef DROPBEAR_PRNGD_SOCKET #if DROPBEAR_USE_PRNGD
if (prngd) if (prngd)
{ {
readfd = connect_unix(filename); readfd = connect_unix(filename);
@ -88,7 +88,7 @@ process_file(hash_state *hs, const char *filename,
timeout.tv_sec = 0; timeout.tv_sec = 0;
timeout.tv_usec = 1000; timeout.tv_usec = 1000;
FD_ZERO(&read_fds); DROPBEAR_FD_ZERO(&read_fds);
FD_SET(readfd, &read_fds); FD_SET(readfd, &read_fds);
res = select(readfd + 1, &read_fds, NULL, NULL, &timeout); res = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
if (res == 0) if (res == 0)
@ -109,7 +109,7 @@ process_file(hash_state *hs, const char *filename,
wantread = MIN(sizeof(readbuf), len-readcount); wantread = MIN(sizeof(readbuf), len-readcount);
} }
#ifdef DROPBEAR_PRNGD_SOCKET #if DROPBEAR_USE_PRNGD
if (prngd) if (prngd)
{ {
char egdcmd[2]; char egdcmd[2];
@ -143,10 +143,16 @@ out:
return ret; return ret;
} }
void addrandom(char * buf, unsigned int len) void addrandom(const unsigned char * buf, unsigned int len)
{ {
hash_state hs; hash_state hs;
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
return;
}
#endif
/* hash in the new seed data */ /* hash in the new seed data */
sha1_init(&hs); sha1_init(&hs);
/* existing state (zeroes on startup) */ /* existing state (zeroes on startup) */
@ -159,7 +165,12 @@ void addrandom(char * buf, unsigned int len)
static void write_urandom() static void write_urandom()
{ {
#ifndef DROPBEAR_PRNGD_SOCKET #if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
return;
}
#endif
#if !DROPBEAR_USE_PRNGD
/* This is opportunistic, don't worry about failure */ /* This is opportunistic, don't worry about failure */
unsigned char buf[INIT_SEED_SIZE]; unsigned char buf[INIT_SEED_SIZE];
FILE *f = fopen(DROPBEAR_URANDOM_DEV, "w"); FILE *f = fopen(DROPBEAR_URANDOM_DEV, "w");
@ -172,6 +183,18 @@ static void write_urandom()
#endif #endif
} }
#if DROPBEAR_FUZZ
void fuzz_seed(void) {
hash_state hs;
sha1_init(&hs);
sha1_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz"));
sha1_done(&hs, hashpool);
counter = 0;
donerandinit = 1;
}
#endif
/* Initialise the prng from /dev/urandom or prngd. This function can /* Initialise the prng from /dev/urandom or prngd. This function can
* be called multiple times */ * be called multiple times */
void seedrandom() { void seedrandom() {
@ -182,12 +205,19 @@ void seedrandom() {
struct timeval tv; struct timeval tv;
clock_t clockval; clock_t clockval;
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
return;
}
#endif
/* hash in the new seed data */ /* hash in the new seed data */
sha1_init(&hs); sha1_init(&hs);
/* existing state */ /* existing state */
sha1_process(&hs, (void*)hashpool, sizeof(hashpool)); sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
#ifdef DROPBEAR_PRNGD_SOCKET #if DROPBEAR_USE_PRNGD
if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1) if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1)
!= DROPBEAR_SUCCESS) { != DROPBEAR_SUCCESS) {
dropbear_exit("Failure reading random device %s", dropbear_exit("Failure reading random device %s",
@ -308,7 +338,7 @@ void gen_random_mpint(mp_int *max, mp_int *rand) {
/* keep regenerating until we get one satisfying /* keep regenerating until we get one satisfying
* 0 < rand < max */ * 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_burn(randbuf, len);
m_free(randbuf); m_free(randbuf);
} }

View File

@ -22,14 +22,14 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _RANDOM_H_ #ifndef DROPBEAR_RANDOM_H_
#define _RANDOM_H_ #define DROPBEAR_RANDOM_H_
#include "includes.h" #include "includes.h"
void seedrandom(); void seedrandom(void);
void genrandom(unsigned char* buf, unsigned int len); void genrandom(unsigned char* buf, unsigned int len);
void addrandom(char * buf, unsigned int len); void addrandom(const unsigned char * buf, unsigned int len);
void gen_random_mpint(mp_int *max, mp_int *rand); void gen_random_mpint(mp_int *max, mp_int *rand);
#endif /* _RANDOM_H_ */ #endif /* DROPBEAR_RANDOM_H_ */

View File

@ -79,14 +79,14 @@ void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_N
void (*_dropbear_log)(int priority, const char* format, va_list param) void (*_dropbear_log)(int priority, const char* format, va_list param)
= generic_dropbear_log; = generic_dropbear_log;
#ifdef DEBUG_TRACE #if DEBUG_TRACE
int debug_trace = 0; int debug_trace = 0;
#endif #endif
#ifndef DISABLE_SYSLOG #ifndef DISABLE_SYSLOG
void startsyslog() { void startsyslog(const char *ident) {
openlog(PROGNAME, LOG_PID, LOG_AUTHPRIV); openlog(ident, LOG_PID, LOG_AUTHPRIV);
} }
#endif /* DISABLE_SYSLOG */ #endif /* DISABLE_SYSLOG */
@ -120,6 +120,13 @@ static void generic_dropbear_exit(int exitcode, const char* format,
_dropbear_log(LOG_INFO, fmtbuf, param); _dropbear_log(LOG_INFO, fmtbuf, param);
#if DROPBEAR_FUZZ
/* longjmp before cleaning up svr_opts */
if (fuzz.do_jmp) {
longjmp(fuzz.jmp, 1);
}
#endif
exit(exitcode); exit(exitcode);
} }
@ -149,19 +156,45 @@ void dropbear_log(int priority, const char* format, ...) {
} }
#ifdef DEBUG_TRACE #if 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, ...) { void dropbear_trace(const char* format, ...) {
va_list param; va_list param;
struct timeval tv;
if (!debug_trace) { if (!debug_trace) {
return; return;
} }
gettimeofday(&tv, NULL);
va_start(param, format); 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); vfprintf(stderr, format, param);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
va_end(param); va_end(param);
@ -170,7 +203,6 @@ void dropbear_trace(const char* format, ...) {
void dropbear_trace2(const char* format, ...) { void dropbear_trace2(const char* format, ...) {
static int trace_env = -1; static int trace_env = -1;
va_list param; va_list param;
struct timeval tv;
if (trace_env == -1) { if (trace_env == -1) {
trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0; trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0;
@ -180,195 +212,16 @@ void dropbear_trace2(const char* format, ...) {
return; return;
} }
gettimeofday(&tv, NULL);
va_start(param, format); 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); vfprintf(stderr, format, param);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
va_end(param); va_end(param);
} }
#endif /* DEBUG_TRACE */ #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 */ /* Connect to a given unix socket. The socket is blocking */
#ifdef ENABLE_CONNECT_UNIX #if ENABLE_CONNECT_UNIX
int connect_unix(const char* path) { int connect_unix(const char* path) {
struct sockaddr_un addr; struct sockaddr_un addr;
int fd = -1; int fd = -1;
@ -390,99 +243,12 @@ int connect_unix(const char* path) {
} }
#endif #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 /* 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, * 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. * it will be run after the child has fork()ed, and is passed exec_data.
* If ret_errfd == NULL then stderr will not be captured. * If ret_errfd == NULL then stderr will not be captured.
* ret_pid can be passed as NULL to discard the pid. */ * ret_pid can be passed as NULL to discard the pid. */
int spawn_command(void(*exec_fn)(void *user_data), void *exec_data, int spawn_command(void(*exec_fn)(const void *user_data), const void *exec_data,
int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) { int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) {
int infds[2]; int infds[2];
int outfds[2]; int outfds[2];
@ -503,7 +269,7 @@ int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
return DROPBEAR_FAILURE; return DROPBEAR_FAILURE;
} }
#ifdef USE_VFORK #if DROPBEAR_VFORK
pid = vfork(); pid = vfork();
#else #else
pid = fork(); pid = fork();
@ -677,91 +443,7 @@ void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) {
execv(usershell, argv); execv(usershell, argv);
} }
void get_socket_address(int fd, char **local_host, char **local_port, #if DEBUG_TRACE
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_log(LOG_WARNING, "Failed lookup: %s", gai_strerror(ret));
sprintf(host, "unknown%u", ((struct sockaddr *)addr)->sa_family);
strcpy(serv, "unknown");
}
}
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) { void printhex(const char * label, const unsigned char * buf, int len) {
int i; int i;
@ -782,6 +464,7 @@ void printhex(const char * label, const unsigned char * buf, int len) {
void printmpint(const char *label, mp_int *mp) { void printmpint(const char *label, mp_int *mp) {
buffer *buf = buf_new(1000); buffer *buf = buf_new(1000);
buf_putmpint(buf, mp); buf_putmpint(buf, mp);
fprintf(stderr, "%d bits ", mp_count_bits(mp));
printhex(label, buf->data, buf->len); printhex(label, buf->data, buf->len);
buf_free(buf); buf_free(buf);
@ -855,7 +538,7 @@ out:
* authkeys file. * authkeys file.
* Will return DROPBEAR_SUCCESS if data is read, or DROPBEAR_FAILURE on EOF.*/ * Will return DROPBEAR_SUCCESS if data is read, or DROPBEAR_FAILURE on EOF.*/
/* Only used for ~/.ssh/known_hosts and ~/.ssh/authorized_keys */ /* Only used for ~/.ssh/known_hosts and ~/.ssh/authorized_keys */
#if defined(DROPBEAR_CLIENT) || defined(ENABLE_SVR_PUBKEY_AUTH) #if DROPBEAR_CLIENT || DROPBEAR_SVR_PUBKEY_AUTH
int buf_getline(buffer * line, FILE * authfile) { int buf_getline(buffer * line, FILE * authfile) {
int c = EOF; int c = EOF;
@ -894,12 +577,12 @@ out:
/* make sure that the socket closes */ /* make sure that the socket closes */
void m_close(int fd) { void m_close(int fd) {
int val;
if (fd == -1) { if (fd < 0) {
return; return;
} }
int val;
do { do {
val = close(fd); val = close(fd);
} while (val < 0 && errno == EINTR); } while (val < 0 && errno == EINTR);
@ -910,72 +593,26 @@ void m_close(int fd) {
} }
} }
void * m_malloc(size_t size) {
void* ret;
if (size == 0) {
dropbear_exit("m_malloc failed");
}
ret = calloc(1, size);
if (ret == NULL) {
dropbear_exit("m_malloc failed");
}
return ret;
}
void * m_strdup(const char * str) {
char* ret;
ret = strdup(str);
if (ret == NULL) {
dropbear_exit("m_strdup failed");
}
return ret;
}
void * m_realloc(void* ptr, size_t size) {
void *ret;
if (size == 0) {
dropbear_exit("m_realloc failed");
}
ret = realloc(ptr, size);
if (ret == NULL) {
dropbear_exit("m_realloc failed");
}
return ret;
}
/* Clear the data, based on the method in David Wheeler's
* "Secure Programming for Linux and Unix HOWTO" */
/* Beware of calling this from within dbutil.c - things might get
* optimised away */
void m_burn(void *data, unsigned int len) {
volatile char *p = data;
if (data == NULL)
return;
while (len--) {
*p++ = 0x0;
}
}
void setnonblocking(int fd) { void setnonblocking(int fd) {
TRACE(("setnonblocking: %d", fd)) TRACE(("setnonblocking: %d", fd))
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
return;
}
#endif
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
if (errno == ENODEV) { if (errno == ENODEV) {
/* Some devices (like /dev/null redirected in) /* Some devices (like /dev/null redirected in)
* can't be set to non-blocking */ * can't be set to non-blocking */
TRACE(("ignoring ENODEV for setnonblocking")) TRACE(("ignoring ENODEV for setnonblocking"))
} else { } else {
{
dropbear_exit("Couldn't set nonblocking"); dropbear_exit("Couldn't set nonblocking");
} }
}
} }
TRACE(("leave setnonblocking")) TRACE(("leave setnonblocking"))
} }
@ -1003,6 +640,24 @@ int m_str_to_uint(const char* str, unsigned int *val) {
} }
} }
/* Returns malloced path. inpath beginning with '/' is returned as-is,
otherwise home directory is prepended */
char * expand_homedir_path(const char *inpath) {
struct passwd *pw = NULL;
if (inpath[0] != '/') {
pw = getpwuid(getuid());
if (pw && pw->pw_dir) {
int len = strlen(inpath) + strlen(pw->pw_dir) + 2;
char *buf = m_malloc(len);
snprintf(buf, len, "%s/%s", pw->pw_dir, inpath);
return buf;
}
}
/* Fallback */
return m_strdup(inpath);
}
int constant_time_memcmp(const void* a, const void *b, size_t n) int constant_time_memcmp(const void* a, const void *b, size_t n)
{ {
const char *xa = a, *xb = b; const char *xa = a, *xb = b;
@ -1015,56 +670,84 @@ int constant_time_memcmp(const void* a, const void *b, size_t n)
return c; return c;
} }
#if defined(__linux__) && defined(SYS_clock_gettime) /* higher-resolution monotonic timestamp, falls back to gettimeofday */
/* CLOCK_MONOTONIC_COARSE was added in Linux 2.6.32 but took a while to void gettime_wrapper(struct timespec *now) {
reach userspace include headers */ struct timeval tv;
#ifndef CLOCK_MONOTONIC_COARSE #if DROPBEAR_FUZZ
#define CLOCK_MONOTONIC_COARSE 6 if (fuzz.fuzzing) {
/* time stands still when fuzzing */
now->tv_sec = 5;
now->tv_nsec = 0;
}
#endif #endif
static clockid_t get_linux_clock_source() {
struct timespec ts;
if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC_COARSE, &ts) == 0) {
return CLOCK_MONOTONIC_COARSE;
}
if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts) == 0) { #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
return CLOCK_MONOTONIC; /* POSIX monotonic clock. Newer Linux, BSD, MacOSX >10.12 */
if (clock_gettime(CLOCK_MONOTONIC, now) == 0) {
return;
} }
return -1; #endif
}
#endif
time_t monotonic_now() {
#if defined(__linux__) && defined(SYS_clock_gettime) #if defined(__linux__) && defined(SYS_clock_gettime)
static clockid_t clock_source = -2; {
/* Old linux toolchain - kernel might support it but not the build headers */
if (clock_source == -2) { /* Also glibc <2.17 requires -lrt which we neglect to add */
/* First run, find out which one works. static int linux_monotonic_failed = 0;
-1 will fall back to time() */ if (!linux_monotonic_failed) {
clock_source = get_linux_clock_source(); /* CLOCK_MONOTONIC isn't in some headers */
} int clock_source_monotonic = 1;
if (syscall(SYS_clock_gettime, clock_source_monotonic, now) == 0) {
if (clock_source >= 0) { return;
struct timespec ts; } else {
if (syscall(SYS_clock_gettime, clock_source, &ts) != 0) { /* Don't try again */
/* Intermittent clock failures should not happen */ linux_monotonic_failed = 1;
dropbear_exit("Clock broke");
} }
return ts.tv_sec;
} }
#endif /* linux clock_gettime */ }
#endif /* linux fallback clock_gettime */
#if defined(HAVE_MACH_ABSOLUTE_TIME) #if defined(HAVE_MACH_ABSOLUTE_TIME)
/* OS X, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */ {
/* OS X pre 10.12, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
static mach_timebase_info_data_t timebase_info; static mach_timebase_info_data_t timebase_info;
uint64_t scaled_time;
if (timebase_info.denom == 0) { if (timebase_info.denom == 0) {
mach_timebase_info(&timebase_info); mach_timebase_info(&timebase_info);
} }
return mach_absolute_time() * timebase_info.numer / timebase_info.denom scaled_time = mach_absolute_time() * timebase_info.numer / timebase_info.denom;
/ 1e9; now->tv_sec = scaled_time / 1000000000;
now->tv_nsec = scaled_time % 1000000000;
}
#endif /* osx mach_absolute_time */ #endif /* osx mach_absolute_time */
/* Fallback for everything else - this will sometimes go backwards */ /* Fallback for everything else - this will sometimes go backwards */
return time(NULL); gettimeofday(&tv, NULL);
now->tv_sec = tv.tv_sec;
now->tv_nsec = 1000*tv.tv_usec;
} }
/* second-resolution monotonic timestamp */
time_t monotonic_now() {
struct timespec ts;
gettime_wrapper(&ts);
return ts.tv_sec;
}
void fsync_parent_dir(const char* fn) {
#ifdef HAVE_LIBGEN_H
char *fn_dir = m_strdup(fn);
char *dir = dirname(fn_dir);
int dirfd = open(dir, O_RDONLY);
if (dirfd != -1) {
if (fsync(dirfd) != 0) {
TRACE(("fsync of directory %s failed: %s", dir, strerror(errno)))
}
m_close(dirfd);
} else {
TRACE(("error opening directory %s for fsync: %s", dir, strerror(errno)))
}
m_free(fn_dir);
#endif
}

View File

@ -22,25 +22,18 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _DBUTIL_H_ #ifndef DROPBEAR_DBUTIL_H_
#define _DBUTIL_H_ #define DROPBEAR_DBUTIL_H_
#include "includes.h" #include "includes.h"
#include "buffer.h" #include "buffer.h"
#include "queue.h"
#include "dbhelpers.h"
#include "dbmalloc.h"
#ifndef DISABLE_SYSLOG #ifndef DISABLE_SYSLOG
void startsyslog(); void startsyslog(const char *ident);
#endif
#ifdef __GNUC__
#define ATTRIB_PRINTF(fmt,args) __attribute__((format(printf, fmt, args)))
#define ATTRIB_NORETURN __attribute__((noreturn))
#define ATTRIB_SENTINEL __attribute__((sentinel))
#else
#define ATTRIB_PRINTF(fmt,args)
#define ATTRIB_NORETURN
#define ATTRIB_SENTINEL
#endif #endif
extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN; extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
@ -53,48 +46,29 @@ void dropbear_log(int priority, const char* format, ...) ATTRIB_PRINTF(2,3) ;
void fail_assert(const char* expr, const char* file, int line) ATTRIB_NORETURN; void fail_assert(const char* expr, const char* file, int line) ATTRIB_NORETURN;
#ifdef DEBUG_TRACE #if DEBUG_TRACE
void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2); void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace2(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 printhex(const char * label, const unsigned char * buf, int len);
void printmpint(const char *label, mp_int *mp); void printmpint(const char *label, mp_int *mp);
void debug_start_net(void);
extern int debug_trace; extern int debug_trace;
#endif #endif
enum dropbear_prio {
DROPBEAR_PRIO_DEFAULT = 10,
DROPBEAR_PRIO_LOWDELAY = 11,
DROPBEAR_PRIO_BULK = 12,
};
char * stripcontrol(const char * text); 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); int spawn_command(void(*exec_fn)(const void *user_data), const void *exec_data,
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); int *writefd, int *readfd, int *errfd, pid_t *pid);
void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell); void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell);
#ifdef ENABLE_CONNECT_UNIX #if ENABLE_CONNECT_UNIX
int connect_unix(const char* addr); int connect_unix(const char* addr);
#endif #endif
int connect_remote(const char* remotehost, const char* remoteport,
int nonblocking, char ** errstring);
int buf_readfile(buffer* buf, const char* filename); int buf_readfile(buffer* buf, const char* filename);
int buf_getline(buffer * line, FILE * authfile); int buf_getline(buffer * line, FILE * authfile);
void m_close(int fd); void m_close(int fd);
void * m_malloc(size_t size);
void * m_strdup(const char * str);
void * m_realloc(void* ptr, size_t size);
#define m_free(X) free(X); (X) = NULL;
void m_burn(void* data, unsigned int len);
void setnonblocking(int fd); void setnonblocking(int fd);
void disallow_core(); void disallow_core(void);
int m_str_to_uint(const char* str, unsigned int *val); int m_str_to_uint(const char* str, unsigned int *val);
/* Used to force mp_ints to be initialised */ /* Used to force mp_ints to be initialised */
@ -108,7 +82,19 @@ int constant_time_memcmp(const void* a, const void *b, size_t n);
/* Returns a time in seconds that doesn't go backwards - does not correspond to /* Returns a time in seconds that doesn't go backwards - does not correspond to
a real-world clock */ a real-world clock */
time_t monotonic_now(); time_t monotonic_now(void);
/* Higher resolution clock_gettime(CLOCK_MONOTONIC) wrapper */
void gettime_wrapper(struct timespec *now);
char * expand_homedir_path(const char *inpath);
#endif /* _DBUTIL_H_ */ void fsync_parent_dir(const char* fn);
#if DROPBEAR_MSAN
/* FD_ZERO seems to leave some memory uninitialized. clear it to avoid false positives */
#define DROPBEAR_FD_ZERO(fds) do { memset((fds), 0x0, sizeof(fd_set)); FD_ZERO(fds); } while(0)
#else
#define DROPBEAR_FD_ZERO(fds) FD_ZERO(fds)
#endif
#endif /* DROPBEAR_DBUTIL_H_ */

View File

@ -1,3 +1,69 @@
dropbear (2019.78-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 27 Mar 2019 22:51:57 +0800
dropbear (2019.77-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Sat, 23 Mar 2019 22:51:57 +0800
dropbear (2018.76-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Tue, 27 Feb 2018 22:51:57 +0800
dropbear (2017.75-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 18 May 2017 22:51:57 +0800
dropbear (2016.74-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 21 Jul 2016 22:51:57 +0800
dropbear (2016.73-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Fri, 18 Mar 2016 22:52:58 +0800
dropbear (2016.72-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 10 Mar 2016 22:52:58 +0800
dropbear (2015.70-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 26 Nov 2015 22:52:58 +0800
dropbear (2015.69-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 25 Nov 2015 22:52:58 +0800
dropbear (2015.68-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Sat, 8 Aug 2015 22:52:58 +0800
dropbear (2015.67-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 28 Jan 2015 22:53:59 +0800
dropbear (2014.66-0.1) unstable; urgency=low dropbear (2014.66-0.1) unstable; urgency=low
* New upstream release. * New upstream release.

View File

@ -1,4 +1,3 @@
README README
TODO
debian/README.runit debian/README.runit
debian/README.Debian.diet debian/README.Debian.diet

View File

@ -5,6 +5,7 @@
# Required-Stop: $remote_fs $syslog # Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5 # Default-Start: 2 3 4 5
# Default-Stop: 0 1 6 # Default-Stop: 0 1 6
# Short-Description: Dropbear SSH server
### END INIT INFO ### END INIT INFO
# #
# Do not configure this file. Edit /etc/default/dropbear instead! # Do not configure this file. Edit /etc/default/dropbear instead!

View File

@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _DEBUG_H_ #ifndef DROPBEAR_DEBUG_H_
#define _DEBUG_H_ #define DROPBEAR_DEBUG_H_
#include "includes.h" #include "includes.h"
@ -33,21 +33,15 @@
* etc. Don't use this normally, it might cause problems */ * etc. Don't use this normally, it might cause problems */
/* #define DEBUG_VALGRIND */ /* #define DEBUG_VALGRIND */
/* Define this to compile in trace debugging printf()s.
* You'll need to run programs with "-v" to turn this on.
*
* 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 */
/* All functions writing to the cleartext payload buffer call /* All functions writing to the cleartext payload buffer call
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're * CHECKCLEARTOWRITE() before writing. This is only really useful if you're
* attempting to track down a problem */ * attempting to track down a problem */
/*#define CHECKCLEARTOWRITE() assert(ses.writepayload->len == 0 && \ /*#define CHECKCLEARTOWRITE() assert(ses.writepayload->len == 0 && \
ses.writepayload->pos == 0)*/ ses.writepayload->pos == 0)*/
#ifndef CHECKCLEARTOWRITE
#define CHECKCLEARTOWRITE() #define CHECKCLEARTOWRITE()
#endif
/* Define this, compile with -pg and set GMON_OUT_PREFIX=gmon to get gmon /* Define this, compile with -pg and set GMON_OUT_PREFIX=gmon to get gmon
* output when Dropbear forks. This will allow it gprof to be used. * output when Dropbear forks. This will allow it gprof to be used.
@ -61,7 +55,8 @@
/*#define DEBUG_RSA*/ /*#define DEBUG_RSA*/
/* you don't need to touch this block */ /* you don't need to touch this block */
#ifdef DEBUG_TRACE #if DEBUG_TRACE
extern int debug_trace;
#define TRACE(X) dropbear_trace X; #define TRACE(X) dropbear_trace X;
#define TRACE2(X) dropbear_trace2 X; #define TRACE2(X) dropbear_trace2 X;
#else /*DEBUG_TRACE*/ #else /*DEBUG_TRACE*/

300
dropbear/default_options.h Normal file
View File

@ -0,0 +1,300 @@
#ifndef DROPBEAR_DEFAULT_OPTIONS_H_
#define DROPBEAR_DEFAULT_OPTIONS_H_
/*
> > > Read This < < <
default_options.h documents compile-time options, and provides default values.
Local customisation should be added to localoptions.h which is
used if it exists in the build directory. Options defined there will override
any options in this file.
Options can also be defined with -DDROPBEAR_XXX=[0,1] in Makefile CFLAGS
IMPORTANT: Some options will require "make clean" after changes */
#define DROPBEAR_DEFPORT "22"
/* Listen on all interfaces */
#define DROPBEAR_DEFADDRESS ""
/* Default hostkey paths - these can be specified on the command line */
#define DSS_PRIV_FILENAME "/etc/dropbear/dropbear_dss_host_key"
#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key"
/* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens
* on chosen ports and keeps accepting connections. This is the default.
*
* Set INETD_MODE if you want to be able to run Dropbear with inetd (or
* similar), where it will use stdin/stdout for connections, and each process
* lasts for a single connection. Dropbear should be invoked with the -i flag
* for inetd, and can only accept IPv4 connections.
*
* Both of these flags can be defined at once, don't compile without at least
* one of them. */
#define NON_INETD_MODE 1
#define INETD_MODE 1
/* Include verbose debug output, enabled with -v at runtime.
* This will add a reasonable amount to your executable size. */
#define DEBUG_TRACE 0
/* Set this if you want to use the DROPBEAR_SMALL_CODE option. This can save
* several kB in binary size however will make the symmetrical ciphers and hashes
* slower, perhaps by 50%. Recommended for small systems that aren't doing
* much traffic. */
#define DROPBEAR_SMALL_CODE 1
/* Enable X11 Forwarding - server only */
#define DROPBEAR_X11FWD 1
/* Enable TCP Fowarding */
/* 'Local' is "-L" style (client listening port forwarded via server)
* 'Remote' is "-R" style (server listening port forwarded via client) */
#define DROPBEAR_CLI_LOCALTCPFWD 1
#define DROPBEAR_CLI_REMOTETCPFWD 1
#define DROPBEAR_SVR_LOCALTCPFWD 1
#define DROPBEAR_SVR_REMOTETCPFWD 1
/* Enable Authentication Agent Forwarding */
#define DROPBEAR_SVR_AGENTFWD 1
#define DROPBEAR_CLI_AGENTFWD 1
/* Note: Both DROPBEAR_CLI_PROXYCMD and DROPBEAR_CLI_NETCAT must be set to
* allow multihop dbclient connections */
/* Allow using -J <proxycommand> to run the connection through a
pipe to a program, rather the normal TCP connection */
#define DROPBEAR_CLI_PROXYCMD 1
/* Enable "Netcat mode" option. This will forward standard input/output
* to a remote TCP-forwarded connection */
#define DROPBEAR_CLI_NETCAT 1
/* Whether to support "-c" and "-m" flags to choose ciphers/MACs at runtime */
#define DROPBEAR_USER_ALGO_LIST 1
/* Encryption - at least one required.
* AES128 should be enabled, some very old implementations might only
* support 3DES.
* Including both AES keysize variants (128 and 256) will result in
* a minimal size increase */
#define DROPBEAR_AES128 1
#define DROPBEAR_3DES 1
#define DROPBEAR_AES256 1
#define DROPBEAR_TWOFISH256 0
#define DROPBEAR_TWOFISH128 0
/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */
#define DROPBEAR_BLOWFISH 0
/* Enable CBC mode for ciphers. This has security issues though
* is the most compatible with older SSH implementations */
#define DROPBEAR_ENABLE_CBC_MODE 1
/* Enable "Counter Mode" for ciphers. This is more secure than
* CBC mode against certain attacks. It is recommended for security
* and forwards compatibility */
#define DROPBEAR_ENABLE_CTR_MODE 1
/* Message integrity. sha2-256 is recommended as a default,
sha1 for compatibility */
#define DROPBEAR_SHA1_HMAC 1
#define DROPBEAR_SHA1_96_HMAC 1
#define DROPBEAR_SHA2_256_HMAC 1
/* Hostkey/public key algorithms - at least one required, these are used
* for hostkey as well as for verifying signatures with pubkey auth.
* Removing either of these won't save very much space.
* RSA is recommended
* DSS may be necessary to connect to some systems though
is not recommended for new keys */
#define DROPBEAR_RSA 1
#define DROPBEAR_DSS 1
/* ECDSA is significantly faster than RSA or DSS. Compiling in ECC
* code (either ECDSA or ECDH) increases binary size - around 30kB
* on x86-64 */
#define DROPBEAR_ECDSA 1
/* RSA must be >=1024 */
#define DROPBEAR_DEFAULT_RSA_SIZE 2048
/* DSS is always 1024 */
/* ECDSA defaults to largest size configured, usually 521 */
/* Add runtime flag "-R" to generate hostkeys as-needed when the first
connection using that key type occurs.
This avoids the need to otherwise run "dropbearkey" and avoids some problems
with badly seeded /dev/urandom when systems first boot. */
#define DROPBEAR_DELAY_HOSTKEY 1
/* Key exchange algorithm.
* group14_sha1 - 2048 bit, sha1
* group14_sha256 - 2048 bit, sha2-256
* group16 - 4096 bit, sha2-512
* group1 - 1024 bit, sha1
* curve25519 - elliptic curve DH
* ecdh - NIST elliptic curve DH (256, 384, 521)
*
* group1 is too small for security though is necessary if you need
compatibility with some implementations such as Dropbear versions < 0.53
* group14 is supported by most implementations.
* group16 provides a greater strength level but is slower and increases binary size
* curve25519 and ecdh algorithms are faster than non-elliptic curve methods
* curve25519 increases binary size by ~8kB on x86-64
* including either ECDH or ECDSA increases binary size by ~30kB on x86-64
* Small systems should generally include either curve25519 or ecdh for performance.
* curve25519 is less widely supported but is faster
*/
#define DROPBEAR_DH_GROUP14_SHA1 1
#define DROPBEAR_DH_GROUP14_SHA256 1
#define DROPBEAR_DH_GROUP16 0
#define DROPBEAR_CURVE25519 1
#define DROPBEAR_ECDH 1
#define DROPBEAR_DH_GROUP1 1
/* When group1 is enabled it will only be allowed by Dropbear client
not as a server, due to concerns over its strength. Set to 0 to allow
group1 in Dropbear server too */
#define DROPBEAR_DH_GROUP1_CLIENTONLY 1
/* Control the memory/performance/compression tradeoff for zlib.
* Set windowBits=8 for least memory usage, see your system's
* zlib.h for full details.
* Default settings (windowBits=15) will use 256kB for compression
* windowBits=8 will use 129kB for compression.
* Both modes will use ~35kB for decompression (using windowBits=15 for
* interoperability) */
#define DROPBEAR_ZLIB_WINDOW_BITS 15
/* Whether to do reverse DNS lookups. */
#define DO_HOST_LOOKUP 0
/* Whether to print the message of the day (MOTD). */
#define DO_MOTD 0
#define MOTD_FILENAME "/etc/motd"
/* Authentication Types - at least one required.
RFC Draft requires pubkey auth, and recommends password */
#define DROPBEAR_SVR_PASSWORD_AUTH 1
/* Note: PAM auth is quite simple and only works for PAM modules which just do
* a simple "Login: " "Password: " (you can edit the strings in svr-authpam.c).
* It's useful for systems like OS X where standard password crypts don't work
* but there's an interface via a PAM module. It won't work for more complex
* PAM challenge/response.
* You can't enable both PASSWORD and PAM. */
#define DROPBEAR_SVR_PAM_AUTH 0
/* ~/.ssh/authorized_keys authentication */
#define DROPBEAR_SVR_PUBKEY_AUTH 1
/* Whether to take public key options in
* authorized_keys file into account */
#define DROPBEAR_SVR_PUBKEY_OPTIONS 1
/* Set this to 0 if your system does not have multiple user support.
(Linux kernel CONFIG_MULTIUSER option)
The resulting binary will not run on a normal system. */
#define DROPBEAR_SVR_MULTIUSER 1
/* Client authentication options */
#define DROPBEAR_CLI_PASSWORD_AUTH 1
#define DROPBEAR_CLI_PUBKEY_AUTH 1
/* A default argument for dbclient -i <privatekey>.
Homedir is prepended unless path begins with / */
#define DROPBEAR_DEFAULT_CLI_AUTHKEY ".ssh/id_dropbear"
/* Allow specifying the password for dbclient via the DROPBEAR_PASSWORD
* environment variable. */
#define DROPBEAR_USE_PASSWORD_ENV 1
/* Define this (as well as DROPBEAR_CLI_PASSWORD_AUTH) to allow the use of
* a helper program for the ssh client. The helper program should be
* specified in the SSH_ASKPASS environment variable, and dbclient
* should be run with DISPLAY set and no tty. The program should
* return the password on standard output */
#define DROPBEAR_CLI_ASKPASS_HELPER 0
/* Save a network roundtrip by sendng a real auth request immediately after
* sending a query for the available methods. This is not yet enabled by default
since it could cause problems with non-compliant servers */
#define DROPBEAR_CLI_IMMEDIATE_AUTH 0
/* Set this to use PRNGD or EGD instead of /dev/urandom */
#define DROPBEAR_USE_PRNGD 0
#define DROPBEAR_PRNGD_SOCKET "/var/run/dropbear-rng"
/* Specify the number of clients we will allow to be connected but
* not yet authenticated. After this limit, connections are rejected */
/* The first setting is per-IP, to avoid denial of service */
#define MAX_UNAUTH_PER_IP 5
/* And then a global limit to avoid chewing memory if connections
* come from many IPs */
#define MAX_UNAUTH_CLIENTS 30
/* Default maximum number of failed authentication tries (server option) */
/* -T server option overrides */
#define MAX_AUTH_TRIES 10
/* The default file to store the daemon's process ID, for shutdown
scripts etc. This can be overridden with the -P flag */
#define DROPBEAR_PIDFILE "/var/run/dropbear.pid"
/* The command to invoke for xauth when using X11 forwarding.
* "-q" for quiet */
#define XAUTH_COMMAND "/usr/bin/xauth -q"
/* if you want to enable running an sftp server (such as the one included with
* OpenSSH), set the path below and set DROPBEAR_SFTPSERVER.
* The sftp-server program is not provided by Dropbear itself */
#define DROPBEAR_SFTPSERVER 1
#define SFTPSERVER_PATH "/usr/libexec/sftp-server"
/* 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 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
* shell/sftp session etc. */
#define LOG_COMMANDS 0
/* Window size limits. These tend to be a trade-off between memory
usage and network performance: */
/* Size of the network receive window. This amount of memory is allocated
as a per-channel receive buffer. Increasing this value can make a
significant difference to network performance. 24kB was empirically
chosen for a 100mbit ethernet network. The value can be altered at
runtime with the -W argument. */
#define DEFAULT_RECV_WINDOW 24576
/* Maximum size of a received SSH data packet - this _MUST_ be >= 32768
in order to interoperate with other implementations */
#define RECV_MAX_PAYLOAD_LEN 32768
/* Maximum size of a transmitted data packet - this can be any value,
though increasing it may not make a significant difference. */
#define TRANS_MAX_PAYLOAD_LEN 16384
/* Ensure that data is transmitted every KEEPALIVE seconds. This can
be overridden at runtime with -K. 0 disables keepalives */
#define DEFAULT_KEEPALIVE 0
/* If this many KEEPALIVES are sent with no packets received from the
other side, exit. Not run-time configurable - if you have a need
for runtime configuration please mail the Dropbear list */
#define DEFAULT_KEEPALIVE_LIMIT 3
/* Ensure that data is received within IDLE_TIMEOUT seconds. This can
be overridden at runtime with -I. 0 disables idle timeouts */
#define DEFAULT_IDLE_TIMEOUT 0
/* The default path. This will often get replaced by the shell */
#define DEFAULT_PATH "/usr/bin:/bin"
#endif /* DROPBEAR_DEFAULT_OPTIONS_H_ */

94
dropbear/dh_groups.c Normal file
View File

@ -0,0 +1,94 @@
#include "options.h"
#include "dh_groups.h"
#if DROPBEAR_DH_GROUP1
/* diffie-hellman-group1-sha1 value for p */
const unsigned char dh_p_1[DH_P_1_LEN] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
#endif /* DROPBEAR_DH_GROUP1 */
#if DROPBEAR_DH_GROUP14
/* diffie-hellman-group14-sha1 value for p */
const unsigned char dh_p_14[DH_P_14_LEN] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2,
0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C,
0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF};
#endif /* DROPBEAR_DH_GROUP14 */
#if DROPBEAR_DH_GROUP16
/* diffie-hellman-group16-256 value for p */
const unsigned char dh_p_16[DH_P_16_LEN] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21,
0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02,
0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B,
0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3,
0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F,
0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E,
0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C,
0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC,
0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA,
0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF,
0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67,
0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18,
0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77,
0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95,
0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2,
0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4,
0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB,
0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A,
0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1,
0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94,
0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E,
0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1,
0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46,
0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC,
0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A,
0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA,
0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68,
0x34, 0xB6, 0x15, 0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F,
0xBE, 0xCA, 0xA6, 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2,
0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7,
0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76,
0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, 0x93,
0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6,
0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
#endif /* DROPBEAR_DH_GROUP16 */
/* Same for all groups */
const int DH_G_VAL = 2;

24
dropbear/dh_groups.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef DROPBEAR_DH_GROUPS_H
#define DROPBEAR_DH_GROUPS_H
#include "options.h"
#if DROPBEAR_DH_GROUP1
#define DH_P_1_LEN 128
extern const unsigned char dh_p_1[DH_P_1_LEN];
#endif
#if DROPBEAR_DH_GROUP14
#define DH_P_14_LEN 256
extern const unsigned char dh_p_14[DH_P_14_LEN];
#endif
#if DROPBEAR_DH_GROUP16
#define DH_P_16_LEN 512
extern const unsigned char dh_p_16[DH_P_16_LEN];
#endif
extern const int DH_G_VAL;
#endif

View File

@ -3,11 +3,10 @@
dropbear \- lightweight SSH server dropbear \- lightweight SSH server
.SH SYNOPSIS .SH SYNOPSIS
.B dropbear .B dropbear
[\-RFEmwsgjki] [\-b [\fIflag arguments\fR] [\-b
.I banner\fR] .I banner\fR]
[\-r [\-r
.I hostkeyfile\fR] [\-p .I hostkeyfile\fR] [\-p [\fIaddress\fR:]\fIport\fR]
.IR [address:]port ]
.SH DESCRIPTION .SH DESCRIPTION
.B dropbear .B dropbear
is a small SSH server is a small SSH server
@ -54,7 +53,7 @@ Disable local port forwarding.
.B \-k .B \-k
Disable remote port forwarding. Disable remote port forwarding.
.TP .TP
.B \-p \fI[address:]port .B \-p\fR [\fIaddress\fR:]\fIport
Listen on specified Listen on specified
.I address .I address
and TCP and TCP
@ -92,6 +91,13 @@ if 0 disables keepalives. If no response is received for 3 consecutive keepalive
.B \-I \fIidle_timeout .B \-I \fIidle_timeout
Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds. Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
.TP .TP
.B \-T \fImax_authentication_attempts
Set the number of authentication attempts allowed per connection. If unspecified the default is 10 (MAX_AUTH_TRIES)
.TP
.B \-c \fIforced_command
Disregard the command provided by the user and always run \fIforced_command\fR. This also
overrides any authorized_keys command= option.
.TP
.B \-V .B \-V
Print the version Print the version
@ -100,7 +106,8 @@ Print the version
.TP .TP
Authorized Keys 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 key. Each line is of the form
.TP .TP
[restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment] [restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment]
@ -127,8 +134,9 @@ Disable PTY allocation. Note that a user can still obtain most of the
same functionality with other means even if no-pty is set. same functionality with other means even if no-pty is set.
.TP .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. Disregard the command provided by the user and always run \fIforced_command\fR.
The -c command line option overrides this.
The authorized_keys file and its containing ~/.ssh directory must only be The authorized_keys file and its containing ~/.ssh directory must only be
writable by the user, otherwise Dropbear will not allow a login using public writable by the user, otherwise Dropbear will not allow a login using public
@ -139,9 +147,11 @@ Host Key Files
Host key files are read at startup from a standard location, by default 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_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 If the -r command line option is specified the default files are not loaded.
Host key files 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 in the default location - keys will be generated after startup when the first
connection is established. This had the benefit that the system /dev/urandom connection is established. This had the benefit that the system /dev/urandom
random number source has a better chance of being securely seeded. random number source has a better chance of being securely seeded.

View File

@ -21,27 +21,27 @@ from a private key by using
.P .P
Encrypted private keys are not supported, use ssh-keygen(1) to decrypt them Encrypted private keys are not supported, use ssh-keygen(1) to decrypt them
first. first.
.SH OPTIONS .SH ARGUMENTS
.TP .TP
.B input type .I input_type
Either Either
.I dropbear .I dropbear
or or
.I openssh .I openssh
.TP .TP
.B output type .I output_type
Either Either
.I dropbear .I dropbear
or or
.I openssh .I openssh
.TP .TP
.B input file .I input_file
An existing Dropbear or OpenSSH private key file An existing Dropbear or OpenSSH private key file
.TP .TP
.B output file .I output_file
The path to write the converted private key file The path to write the converted private key file. For client authentication ~/.ssh/id_dropbear is loaded by default
.SH EXAMPLE .SH EXAMPLE
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/dropbear_priv # dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_dropbear
.SH AUTHOR .SH AUTHOR
Matt Johnston (matt@ucc.asn.au). Matt Johnston (matt@ucc.asn.au).
.SH SEE ALSO .SH SEE ALSO

View File

@ -53,8 +53,8 @@ static void printhelp(char * progname) {
progname); progname);
} }
#if defined(DBMULTI_dropbearconvert) || !defined(DROPBEAR_MULTI) #if defined(DBMULTI_dropbearconvert) || !DROPBEAR_MULTI
#if defined(DBMULTI_dropbearconvert) && defined(DROPBEAR_MULTI) #if defined(DBMULTI_dropbearconvert) && DROPBEAR_MULTI
int dropbearconvert_main(int argc, char ** argv) { int dropbearconvert_main(int argc, char ** argv) {
#else #else
int main(int argc, char ** argv) { int main(int argc, char ** argv) {
@ -67,7 +67,7 @@ int main(int argc, char ** argv) {
crypto_init(); crypto_init();
seedrandom(); seedrandom();
#ifdef DEBUG_TRACE #if DEBUG_TRACE
/* It's hard for it to get in the way _too_ much */ /* It's hard for it to get in the way _too_ much */
debug_trace = 1; debug_trace = 1;
#endif #endif

View File

@ -9,13 +9,11 @@ dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
.I file .I file
[\-s [\-s
.IR bits ] .IR bits ]
[\-y]
.SH DESCRIPTION .SH DESCRIPTION
.B dropbearkey .B dropbearkey
generates a generates a
.I RSA \fIRSA\fR, \fIDSS\fR, or \fIECDSA\fR
.I DSS,
or
.I ECDSA
format SSH private key, and saves it to a file for the use with the format SSH private key, and saves it to a file for the use with the
Dropbear client or server. Dropbear client or server.
Note that Note that
@ -33,18 +31,25 @@ or
.TP .TP
.B \-f \fIfile .B \-f \fIfile
Write the secret key to the file Write the secret key to the file
.IR file . \fIfile\fR. For client authentication ~/.ssh/id_dropbear is loaded by default
.TP .TP
.B \-s \fIbits .B \-s \fIbits
Set the key size to Set the key size to
.I bits .I bits
bits, should be multiple of 8 (optional). 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 .SH NOTES
The program dropbearconvert(1) can be used to convert between Dropbear and OpenSSH key formats. The program dropbearconvert(1) can be used to convert between Dropbear and OpenSSH key formats.
.P .P
Dropbear does not support encrypted keys. Dropbear does not support encrypted keys.
.SH EXAMPLE .SH EXAMPLE
generate a host-key:
# dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_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 .SH AUTHOR
Matt Johnston (matt@ucc.asn.au). Matt Johnston (matt@ucc.asn.au).
.br .br

View File

@ -67,35 +67,36 @@ static void printhelp(char * progname) {
fprintf(stderr, "Usage: %s -t <type> -f <filename> [-s bits]\n" fprintf(stderr, "Usage: %s -t <type> -f <filename> [-s bits]\n"
"-t type Type of key to generate. One of:\n" "-t type Type of key to generate. One of:\n"
#ifdef DROPBEAR_RSA #if DROPBEAR_RSA
" rsa\n" " rsa\n"
#endif #endif
#ifdef DROPBEAR_DSS #if DROPBEAR_DSS
" dss\n" " dss\n"
#endif #endif
#ifdef DROPBEAR_ECDSA #if DROPBEAR_ECDSA
" ecdsa\n" " ecdsa\n"
#endif #endif
"-f filename Use filename for the secret key\n" "-f filename Use filename for the secret key.\n"
" ~/.ssh/id_dropbear is recommended for client keys.\n"
"-s bits Key size in bits, should be a multiple of 8 (optional)\n" "-s bits Key size in bits, should be a multiple of 8 (optional)\n"
#ifdef DROPBEAR_DSS #if DROPBEAR_DSS
" DSS has a fixed size of 1024 bits\n" " DSS has a fixed size of 1024 bits\n"
#endif #endif
#ifdef DROPBEAR_ECDSA #if DROPBEAR_ECDSA
" ECDSA has sizes " " ECDSA has sizes "
#ifdef DROPBEAR_ECC_256 #if DROPBEAR_ECC_256
"256 " "256 "
#endif #endif
#ifdef DROPBEAR_ECC_384 #if DROPBEAR_ECC_384
"384 " "384 "
#endif #endif
#ifdef DROPBEAR_ECC_521 #if DROPBEAR_ECC_521
"521 " "521 "
#endif #endif
"\n" "\n"
#endif #endif
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n" "-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
#ifdef DEBUG_TRACE #if DEBUG_TRACE
"-v verbose\n" "-v verbose\n"
#endif #endif
,progname); ,progname);
@ -104,41 +105,41 @@ static void printhelp(char * progname) {
/* fails fatally */ /* fails fatally */
static void check_signkey_bits(enum signkey_type type, int bits) static void check_signkey_bits(enum signkey_type type, int bits)
{ {
switch (type) { switch (type) {
#ifdef DROPBEAR_RSA #if DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA: case DROPBEAR_SIGNKEY_RSA:
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) { if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a" dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a"
" multiple of 8\n"); " multiple of 8\n");
} }
break; break;
#endif #endif
#ifdef DROPEAR_DSS #ifdef DROPEAR_DSS
case DROPBEAR_SIGNKEY_DSS: case DROPBEAR_SIGNKEY_DSS:
if (bits != 1024) { if (bits != 1024) {
dropbear_exit("DSS keys have a fixed size of 1024 bits\n"); dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
#endif #endif
default: default:
(void)0; /* quiet, compiler. ecdsa handles checks itself */ (void)0; /* quiet, compiler. ecdsa handles checks itself */
} }
} }
#if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI) #if defined(DBMULTI_dropbearkey) || !DROPBEAR_MULTI
#if defined(DBMULTI_dropbearkey) && defined(DROPBEAR_MULTI) #if defined(DBMULTI_dropbearkey) && DROPBEAR_MULTI
int dropbearkey_main(int argc, char ** argv) { int dropbearkey_main(int argc, char ** argv) {
#else #else
int main(int argc, char ** argv) { int main(int argc, char ** argv) {
#endif #endif
int i; int i;
char ** next = 0; char ** next = NULL;
char * filename = NULL; char * filename = NULL;
enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE; enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
char * typetext = NULL; char * typetext = NULL;
char * sizetext = NULL; char * sizetext = NULL;
unsigned int bits = 0; unsigned int bits = 0, genbits;
int printpub = 0; int printpub = 0;
crypto_init(); crypto_init();
@ -173,7 +174,7 @@ int main(int argc, char ** argv) {
printhelp(argv[0]); printhelp(argv[0]);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
break; break;
#ifdef DEBUG_TRACE #if DEBUG_TRACE
case 'v': case 'v':
debug_trace = 1; debug_trace = 1;
break; break;
@ -205,19 +206,19 @@ int main(int argc, char ** argv) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
#ifdef DROPBEAR_RSA #if DROPBEAR_RSA
if (strcmp(typetext, "rsa") == 0) if (strcmp(typetext, "rsa") == 0)
{ {
keytype = DROPBEAR_SIGNKEY_RSA; keytype = DROPBEAR_SIGNKEY_RSA;
} }
#endif #endif
#ifdef DROPBEAR_DSS #if DROPBEAR_DSS
if (strcmp(typetext, "dss") == 0) if (strcmp(typetext, "dss") == 0)
{ {
keytype = DROPBEAR_SIGNKEY_DSS; keytype = DROPBEAR_SIGNKEY_DSS;
} }
#endif #endif
#ifdef DROPBEAR_ECDSA #if DROPBEAR_ECDSA
if (strcmp(typetext, "ecdsa") == 0) if (strcmp(typetext, "ecdsa") == 0)
{ {
keytype = DROPBEAR_SIGNKEY_ECDSA_KEYGEN; keytype = DROPBEAR_SIGNKEY_ECDSA_KEYGEN;
@ -237,13 +238,14 @@ int main(int argc, char ** argv) {
} }
check_signkey_bits(keytype, bits);; check_signkey_bits(keytype, bits);;
} }
fprintf(stderr, "Generating key, this may take a while...\n"); genbits = signkey_generate_get_bits(keytype, bits);
if (signkey_generate(keytype, bits, filename) == DROPBEAR_FAILURE) fprintf(stderr, "Generating %u bit %s key, this may take a while...\n", genbits, typetext);
{ if (signkey_generate(keytype, bits, filename, 0) == DROPBEAR_FAILURE)
dropbear_exit("Failed to generate key.\n"); {
} dropbear_exit("Failed to generate key.\n");
}
printpubfile(filename); printpubfile(filename);

View File

@ -37,13 +37,14 @@
* See FIPS186 or the Handbook of Applied Cryptography for details of the * See FIPS186 or the Handbook of Applied Cryptography for details of the
* algorithm */ * algorithm */
#ifdef DROPBEAR_DSS #if DROPBEAR_DSS
/* Load a dss key from a buffer, initialising the values. /* Load a dss key from a buffer, initialising the values.
* The key will have the same format as buf_put_dss_key. * The key will have the same format as buf_put_dss_key.
* These should be freed with dss_key_free. * These should be freed with dss_key_free.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) { int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
int ret = DROPBEAR_FAILURE;
TRACE(("enter buf_get_dss_pub_key")) TRACE(("enter buf_get_dss_pub_key"))
dropbear_assert(key != NULL); dropbear_assert(key != NULL);
@ -56,17 +57,41 @@ int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
|| buf_getmpint(buf, key->g) == DROPBEAR_FAILURE || buf_getmpint(buf, key->g) == DROPBEAR_FAILURE
|| buf_getmpint(buf, key->y) == DROPBEAR_FAILURE) { || buf_getmpint(buf, key->y) == DROPBEAR_FAILURE) {
TRACE(("leave buf_get_dss_pub_key: failed reading mpints")) TRACE(("leave buf_get_dss_pub_key: failed reading mpints"))
return DROPBEAR_FAILURE; ret = DROPBEAR_FAILURE;
goto out;
} }
if (mp_count_bits(key->p) < MIN_DSS_KEYLEN) { if (mp_count_bits(key->p) != DSS_P_BITS) {
dropbear_log(LOG_WARNING, "DSS key too short"); dropbear_log(LOG_WARNING, "Bad DSS p");
TRACE(("leave buf_get_dss_pub_key: short key")) ret = DROPBEAR_FAILURE;
return DROPBEAR_FAILURE; goto out;
} }
if (mp_count_bits(key->q) != DSS_Q_BITS) {
dropbear_log(LOG_WARNING, "Bad DSS q");
ret = DROPBEAR_FAILURE;
goto out;
}
/* test 1 < g < p */
if (mp_cmp_d(key->g, 1) != MP_GT) {
dropbear_log(LOG_WARNING, "Bad DSS g");
ret = DROPBEAR_FAILURE;
goto out;
}
if (mp_cmp(key->g, key->p) != MP_LT) {
dropbear_log(LOG_WARNING, "Bad DSS g");
ret = DROPBEAR_FAILURE;
goto out;
}
ret = DROPBEAR_SUCCESS;
TRACE(("leave buf_get_dss_pub_key: success")) TRACE(("leave buf_get_dss_pub_key: success"))
return DROPBEAR_SUCCESS; out:
if (ret == DROPBEAR_FAILURE) {
m_mp_free_multi(&key->p, &key->q, &key->g, &key->y, NULL);
}
return ret;
} }
/* Same as buf_get_dss_pub_key, but reads a private "x" key at the end. /* Same as buf_get_dss_pub_key, but reads a private "x" key at the end.
@ -86,7 +111,7 @@ int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
m_mp_alloc_init_multi(&key->x, NULL); m_mp_alloc_init_multi(&key->x, NULL);
ret = buf_getmpint(buf, key->x); ret = buf_getmpint(buf, key->x);
if (ret == DROPBEAR_FAILURE) { if (ret == DROPBEAR_FAILURE) {
m_free(key->x); m_mp_free_multi(&key->x, NULL);
} }
return ret; return ret;
@ -101,26 +126,7 @@ void dss_key_free(dropbear_dss_key *key) {
TRACE2(("enter dsa_key_free: key == NULL")) TRACE2(("enter dsa_key_free: key == NULL"))
return; return;
} }
if (key->p) { m_mp_free_multi(&key->p, &key->q, &key->g, &key->y, &key->x, NULL);
mp_clear(key->p);
m_free(key->p);
}
if (key->q) {
mp_clear(key->q);
m_free(key->q);
}
if (key->g) {
mp_clear(key->g);
m_free(key->g);
}
if (key->y) {
mp_clear(key->y);
m_free(key->y);
}
if (key->x) {
mp_clear(key->x);
m_free(key->x);
}
m_free(key); m_free(key);
TRACE2(("leave dsa_key_free")) TRACE2(("leave dsa_key_free"))
} }
@ -133,7 +139,7 @@ void dss_key_free(dropbear_dss_key *key) {
* mpint g * mpint g
* mpint y * mpint y
*/ */
void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key) { void buf_put_dss_pub_key(buffer* buf, const dropbear_dss_key *key) {
dropbear_assert(key != NULL); dropbear_assert(key != NULL);
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN); buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
@ -145,7 +151,7 @@ void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
} }
/* Same as buf_put_dss_pub_key, but with the private "x" key appended */ /* Same as buf_put_dss_pub_key, but with the private "x" key appended */
void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key) { void buf_put_dss_priv_key(buffer* buf, const dropbear_dss_key *key) {
dropbear_assert(key != NULL); dropbear_assert(key != NULL);
buf_put_dss_pub_key(buf, key); buf_put_dss_pub_key(buf, key);
@ -153,10 +159,10 @@ void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
} }
#ifdef DROPBEAR_SIGNKEY_VERIFY #if DROPBEAR_SIGNKEY_VERIFY
/* Verify a DSS signature (in buf) made on data by the key given. /* Verify a DSS signature (in buf) made on data by the key given.
* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ * returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) { int buf_dss_verify(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf) {
unsigned char msghash[SHA1_HASH_SIZE]; unsigned char msghash[SHA1_HASH_SIZE];
hash_state hs; hash_state hs;
int ret = DROPBEAR_FAILURE; int ret = DROPBEAR_FAILURE;
@ -165,7 +171,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
DEF_MP_INT(val3); DEF_MP_INT(val3);
DEF_MP_INT(val4); DEF_MP_INT(val4);
char * string = NULL; char * string = NULL;
int stringlen; unsigned int stringlen;
TRACE(("enter buf_dss_verify")) TRACE(("enter buf_dss_verify"))
dropbear_assert(key != NULL); dropbear_assert(key != NULL);
@ -178,6 +184,13 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
goto out; goto out;
} }
#if DEBUG_DSS_VERIFY
printmpint("dss verify p", key->p);
printmpint("dss verify q", key->q);
printmpint("dss verify g", key->g);
printmpint("dss verify y", key->y);
#endif
/* hash the data */ /* hash the data */
sha1_init(&hs); sha1_init(&hs);
sha1_process(&hs, data_buf->data, data_buf->len); sha1_process(&hs, data_buf->data, data_buf->len);
@ -186,12 +199,19 @@ 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 */ /* create the signature - s' and r' are the received signatures in buf */
/* w = (s')-1 mod q */ /* w = (s')-1 mod q */
/* let val1 = s' */ /* 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 DEBUG_DSS_VERIFY
printmpint("dss verify s'", &val1);
#endif
if (mp_cmp(&val1, key->q) != MP_LT) { if (mp_cmp(&val1, key->q) != MP_LT) {
TRACE(("verify failed, s' >= q")) TRACE(("verify failed, s' >= q"))
goto out; goto out;
} }
if (mp_cmp_d(&val1, 0) != MP_GT) {
TRACE(("verify failed, s' <= 0"))
goto out;
}
/* let val2 = w = (s')^-1 mod q*/ /* let val2 = w = (s')^-1 mod q*/
if (mp_invmod(&val1, key->q, &val2) != MP_OKAY) { if (mp_invmod(&val1, key->q, &val2) != MP_OKAY) {
goto out; goto out;
@ -200,6 +220,9 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
/* u1 = ((SHA(M')w) mod q */ /* u1 = ((SHA(M')w) mod q */
/* let val1 = SHA(M') = msghash */ /* let val1 = SHA(M') = msghash */
bytes_to_mp(&val1, msghash, SHA1_HASH_SIZE); bytes_to_mp(&val1, msghash, SHA1_HASH_SIZE);
#if DEBUG_DSS_VERIFY
printmpint("dss verify r'", &val1);
#endif
/* let val3 = u1 = ((SHA(M')w) mod q */ /* let val3 = u1 = ((SHA(M')w) mod q */
if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) { if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {
@ -208,11 +231,15 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
/* u2 = ((r')w) mod q */ /* u2 = ((r')w) mod q */
/* let val1 = r' */ /* 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) { if (mp_cmp(&val1, key->q) != MP_LT) {
TRACE(("verify failed, r' >= q")) TRACE(("verify failed, r' >= q"))
goto out; goto out;
} }
if (mp_cmp_d(&val1, 0) != MP_GT) {
TRACE(("verify failed, r' <= 0"))
goto out;
}
/* let val4 = u2 = ((r')w) mod q */ /* let val4 = u2 = ((r')w) mod q */
if (mp_mulmod(&val1, &val2, key->q, &val4) != MP_OKAY) { if (mp_mulmod(&val1, &val2, key->q, &val4) != MP_OKAY) {
goto out; goto out;
@ -253,7 +280,7 @@ out:
/* Sign the data presented with key, writing the signature contents /* Sign the data presented with key, writing the signature contents
* to the buffer */ * to the buffer */
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf) { void buf_put_dss_sign(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf) {
unsigned char msghash[SHA1_HASH_SIZE]; unsigned char msghash[SHA1_HASH_SIZE];
unsigned int writelen; unsigned int writelen;
unsigned int i; unsigned int i;

View File

@ -22,13 +22,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _DSS_H_ #ifndef DROPBEAR_DSS_H_
#define _DSS_H_ #define DROPBEAR_DSS_H_
#include "includes.h" #include "includes.h"
#include "buffer.h" #include "buffer.h"
#ifdef DROPBEAR_DSS #if DROPBEAR_DSS
typedef struct { typedef struct {
@ -41,16 +41,19 @@ typedef struct {
} dropbear_dss_key; } dropbear_dss_key;
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf); #define DSS_P_BITS 1024
#ifdef DROPBEAR_SIGNKEY_VERIFY #define DSS_Q_BITS 160
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf);
void buf_put_dss_sign(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf);
#if DROPBEAR_SIGNKEY_VERIFY
int buf_dss_verify(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf);
#endif #endif
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key); int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key);
int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key); int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key);
void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key); void buf_put_dss_pub_key(buffer* buf, const dropbear_dss_key *key);
void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key); void buf_put_dss_priv_key(buffer* buf, const dropbear_dss_key *key);
void dss_key_free(dropbear_dss_key *key); void dss_key_free(dropbear_dss_key *key);
#endif /* DROPBEAR_DSS */ #endif /* DROPBEAR_DSS */
#endif /* _DSS_H_ */ #endif /* DROPBEAR_DSS_H_ */

View File

@ -1,13 +1,12 @@
#include "includes.h" #include "includes.h"
#include "options.h"
#include "ecc.h" #include "ecc.h"
#include "dbutil.h" #include "dbutil.h"
#include "bignum.h" #include "bignum.h"
#ifdef DROPBEAR_ECC #if DROPBEAR_ECC
/* .dp members are filled out by dropbear_ecc_fill_dp() at startup */ /* .dp members are filled out by dropbear_ecc_fill_dp() at startup */
#ifdef DROPBEAR_ECC_256 #if DROPBEAR_ECC_256
struct dropbear_ecc_curve ecc_curve_nistp256 = { struct dropbear_ecc_curve ecc_curve_nistp256 = {
32, /* .ltc_size */ 32, /* .ltc_size */
NULL, /* .dp */ NULL, /* .dp */
@ -15,7 +14,7 @@ struct dropbear_ecc_curve ecc_curve_nistp256 = {
"nistp256" /* .name */ "nistp256" /* .name */
}; };
#endif #endif
#ifdef DROPBEAR_ECC_384 #if DROPBEAR_ECC_384
struct dropbear_ecc_curve ecc_curve_nistp384 = { struct dropbear_ecc_curve ecc_curve_nistp384 = {
48, /* .ltc_size */ 48, /* .ltc_size */
NULL, /* .dp */ NULL, /* .dp */
@ -23,7 +22,7 @@ struct dropbear_ecc_curve ecc_curve_nistp384 = {
"nistp384" /* .name */ "nistp384" /* .name */
}; };
#endif #endif
#ifdef DROPBEAR_ECC_521 #if DROPBEAR_ECC_521
struct dropbear_ecc_curve ecc_curve_nistp521 = { struct dropbear_ecc_curve ecc_curve_nistp521 = {
66, /* .ltc_size */ 66, /* .ltc_size */
NULL, /* .dp */ NULL, /* .dp */
@ -33,13 +32,13 @@ struct dropbear_ecc_curve ecc_curve_nistp521 = {
#endif #endif
struct dropbear_ecc_curve *dropbear_ecc_curves[] = { struct dropbear_ecc_curve *dropbear_ecc_curves[] = {
#ifdef DROPBEAR_ECC_256 #if DROPBEAR_ECC_256
&ecc_curve_nistp256, &ecc_curve_nistp256,
#endif #endif
#ifdef DROPBEAR_ECC_384 #if DROPBEAR_ECC_384
&ecc_curve_nistp384, &ecc_curve_nistp384,
#endif #endif
#ifdef DROPBEAR_ECC_521 #if DROPBEAR_ECC_521
&ecc_curve_nistp521, &ecc_curve_nistp521,
#endif #endif
NULL NULL
@ -82,15 +81,10 @@ ecc_key * new_ecc_key(void) {
/* Copied from libtomcrypt ecc_import.c (version there is static), modified /* Copied from libtomcrypt ecc_import.c (version there is static), modified
for different mp_int pointer without LTC_SOURCE */ for different mp_int pointer without LTC_SOURCE */
static int ecc_is_point(ecc_key *key) static int ecc_is_point(const ecc_key *key)
{ {
mp_int *prime, *b, *t1, *t2; mp_int *prime, *b, *t1, *t2;
int err; 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); m_mp_alloc_init_multi(&prime, &b, &t1, &t2, NULL);
@ -218,7 +212,7 @@ ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *c
/* a modified version of libtomcrypt's "ecc_shared_secret" to output /* a modified version of libtomcrypt's "ecc_shared_secret" to output
a mp_int instead. */ a mp_int instead. */
mp_int * dropbear_ecc_shared_secret(ecc_key *public_key, ecc_key *private_key) mp_int * dropbear_ecc_shared_secret(ecc_key *public_key, const ecc_key *private_key)
{ {
ecc_point *result = NULL; ecc_point *result = NULL;
mp_int *prime = NULL, *shared_secret = NULL; mp_int *prime = NULL, *shared_secret = NULL;
@ -226,46 +220,41 @@ mp_int * dropbear_ecc_shared_secret(ecc_key *public_key, ecc_key *private_key)
/* type valid? */ /* type valid? */
if (private_key->type != PK_PRIVATE) { if (private_key->type != PK_PRIVATE) {
goto done; goto out;
} }
if (private_key->dp != public_key->dp) { if (private_key->dp != public_key->dp) {
goto done; goto out;
} }
/* make new point */ /* make new point */
result = ltc_ecc_new_point(); result = ltc_ecc_new_point();
if (result == NULL) { if (result == NULL) {
goto done; goto out;
} }
prime = m_malloc(sizeof(*prime)); prime = m_malloc(sizeof(*prime));
m_mp_init(prime); m_mp_init(prime);
if (mp_read_radix(prime, (char *)private_key->dp->prime, 16) != CRYPT_OK) { if (mp_read_radix(prime, (char *)private_key->dp->prime, 16) != CRYPT_OK) {
goto done; goto out;
} }
if (ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1) != CRYPT_OK) { if (ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1) != CRYPT_OK) {
goto done; goto out;
} }
shared_secret = m_malloc(sizeof(*shared_secret));
m_mp_init(shared_secret);
if (mp_copy(result->x, shared_secret) != CRYPT_OK) {
goto out;
}
mp_clear(prime);
m_free(prime);
ltc_ecc_del_point(result);
err = DROPBEAR_SUCCESS; err = DROPBEAR_SUCCESS;
done: out:
if (err == DROPBEAR_SUCCESS) {
shared_secret = m_malloc(sizeof(*shared_secret));
m_mp_init(shared_secret);
mp_copy(result->x, shared_secret);
}
if (prime) {
mp_clear(prime);
m_free(prime);
}
if (result)
{
ltc_ecc_del_point(result);
}
if (err == DROPBEAR_FAILURE) { if (err == DROPBEAR_FAILURE) {
dropbear_exit("ECC error"); dropbear_exit("ECC error");
} }

View File

@ -1,18 +1,17 @@
#ifndef _DROPBEAR_ECC_H #ifndef DROPBEAR_DROPBEAR_ECC_H
#define _DROPBEAR_ECC_H #define DROPBEAR_DROPBEAR_ECC_H
#include "includes.h" #include "includes.h"
#include "options.h"
#include "buffer.h" #include "buffer.h"
#ifdef DROPBEAR_ECC #if DROPBEAR_ECC
struct dropbear_ecc_curve { struct dropbear_ecc_curve {
int ltc_size; /* to match the byte sizes in ltc_ecc_sets[] */ int ltc_size; /* to match the byte sizes in ltc_ecc_sets[] */
const ltc_ecc_set_type *dp; /* curve domain parameters */ const ltc_ecc_set_type *dp; /* curve domain parameters */
const struct ltc_hash_descriptor *hash_desc; const struct ltc_hash_descriptor *hash_desc;
const unsigned char *name; const char *name;
}; };
extern struct dropbear_ecc_curve ecc_curve_nistp256; extern struct dropbear_ecc_curve ecc_curve_nistp256;
@ -20,7 +19,7 @@ extern struct dropbear_ecc_curve ecc_curve_nistp384;
extern struct dropbear_ecc_curve ecc_curve_nistp521; extern struct dropbear_ecc_curve ecc_curve_nistp521;
extern struct dropbear_ecc_curve *dropbear_ecc_curves[]; extern struct dropbear_ecc_curve *dropbear_ecc_curves[];
void dropbear_ecc_fill_dp(); void dropbear_ecc_fill_dp(void);
struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp); struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp);
/* "pubkey" refers to a point, but LTC uses ecc_key structure for both public /* "pubkey" refers to a point, but LTC uses ecc_key structure for both public
@ -29,8 +28,8 @@ void buf_put_ecc_raw_pubkey_string(buffer *buf, ecc_key *key);
ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve); ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve);
int buf_get_ecc_privkey_string(buffer *buf, ecc_key *key); int buf_get_ecc_privkey_string(buffer *buf, ecc_key *key);
mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, ecc_key *priv_key); mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, const ecc_key *priv_key);
#endif #endif
#endif /* _DROPBEAR_ECC_H */ #endif /* DROPBEAR_DROPBEAR_ECC_H */

View File

@ -1,4 +1,3 @@
#include "options.h"
#include "includes.h" #include "includes.h"
#include "dbutil.h" #include "dbutil.h"
#include "crypto_desc.h" #include "crypto_desc.h"
@ -6,7 +5,7 @@
#include "ecdsa.h" #include "ecdsa.h"
#include "signkey.h" #include "signkey.h"
#ifdef DROPBEAR_ECDSA #if DROPBEAR_ECDSA
int signkey_is_ecdsa(enum signkey_type type) int signkey_is_ecdsa(enum signkey_type type)
{ {
@ -15,18 +14,18 @@ int signkey_is_ecdsa(enum signkey_type type)
|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP521; || type == DROPBEAR_SIGNKEY_ECDSA_NISTP521;
} }
enum signkey_type ecdsa_signkey_type(ecc_key * key) { enum signkey_type ecdsa_signkey_type(const ecc_key * key) {
#ifdef DROPBEAR_ECC_256 #if DROPBEAR_ECC_256
if (key->dp == ecc_curve_nistp256.dp) { if (key->dp == ecc_curve_nistp256.dp) {
return DROPBEAR_SIGNKEY_ECDSA_NISTP256; return DROPBEAR_SIGNKEY_ECDSA_NISTP256;
} }
#endif #endif
#ifdef DROPBEAR_ECC_384 #if DROPBEAR_ECC_384
if (key->dp == ecc_curve_nistp384.dp) { if (key->dp == ecc_curve_nistp384.dp) {
return DROPBEAR_SIGNKEY_ECDSA_NISTP384; return DROPBEAR_SIGNKEY_ECDSA_NISTP384;
} }
#endif #endif
#ifdef DROPBEAR_ECC_521 #if DROPBEAR_ECC_521
if (key->dp == ecc_curve_nistp521.dp) { if (key->dp == ecc_curve_nistp521.dp) {
return DROPBEAR_SIGNKEY_ECDSA_NISTP521; return DROPBEAR_SIGNKEY_ECDSA_NISTP521;
} }
@ -38,17 +37,17 @@ ecc_key *gen_ecdsa_priv_key(unsigned int bit_size) {
const ltc_ecc_set_type *dp = NULL; /* curve domain parameters */ const ltc_ecc_set_type *dp = NULL; /* curve domain parameters */
ecc_key *new_key = NULL; ecc_key *new_key = NULL;
switch (bit_size) { switch (bit_size) {
#ifdef DROPBEAR_ECC_256 #if DROPBEAR_ECC_256
case 256: case 256:
dp = ecc_curve_nistp256.dp; dp = ecc_curve_nistp256.dp;
break; break;
#endif #endif
#ifdef DROPBEAR_ECC_384 #if DROPBEAR_ECC_384
case 384: case 384:
dp = ecc_curve_nistp384.dp; dp = ecc_curve_nistp384.dp;
break; break;
#endif #endif
#ifdef DROPBEAR_ECC_521 #if DROPBEAR_ECC_521
case 521: case 521:
dp = ecc_curve_nistp521.dp; dp = ecc_curve_nistp521.dp;
break; break;
@ -56,13 +55,13 @@ ecc_key *gen_ecdsa_priv_key(unsigned int bit_size) {
} }
if (!dp) { if (!dp) {
dropbear_exit("Key size %d isn't valid. Try " dropbear_exit("Key size %d isn't valid. Try "
#ifdef DROPBEAR_ECC_256 #if DROPBEAR_ECC_256
"256 " "256 "
#endif #endif
#ifdef DROPBEAR_ECC_384 #if DROPBEAR_ECC_384
"384 " "384 "
#endif #endif
#ifdef DROPBEAR_ECC_521 #if DROPBEAR_ECC_521
"521 " "521 "
#endif #endif
, bit_size); , bit_size);
@ -83,9 +82,9 @@ ecc_key *buf_get_ecdsa_pub_key(buffer* buf) {
ecc_key *new_key = NULL; ecc_key *new_key = NULL;
/* string "ecdsa-sha2-[identifier]" */ /* string "ecdsa-sha2-[identifier]" */
key_ident = buf_getstring(buf, &key_ident_len); key_ident = (unsigned char*)buf_getstring(buf, &key_ident_len);
/* string "[identifier]" */ /* 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-")) { if (key_ident_len != identifier_len + strlen("ecdsa-sha2-")) {
TRACE(("Bad identifier lengths")) TRACE(("Bad identifier lengths"))
@ -131,6 +130,7 @@ ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
if (buf_getmpint(buf, new_key->k) != DROPBEAR_SUCCESS) { if (buf_getmpint(buf, new_key->k) != DROPBEAR_SUCCESS) {
ecc_free(new_key); ecc_free(new_key);
m_free(new_key);
return NULL; return NULL;
} }
@ -139,10 +139,10 @@ ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) { void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) {
struct dropbear_ecc_curve *curve = NULL; struct dropbear_ecc_curve *curve = NULL;
unsigned char key_ident[30]; char key_ident[30];
curve = curve_for_dp(key->dp); 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, key_ident, strlen(key_ident));
buf_putstring(buf, curve->name, strlen(curve->name)); buf_putstring(buf, curve->name, strlen(curve->name));
buf_put_ecc_raw_pubkey_string(buf, key); buf_put_ecc_raw_pubkey_string(buf, key);
@ -153,14 +153,14 @@ void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key) {
buf_putmpint(buf, key->k); buf_putmpint(buf, key->k);
} }
void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) { void buf_put_ecdsa_sign(buffer *buf, const ecc_key *key, const buffer *data_buf) {
/* Based on libtomcrypt's ecc_sign_hash but without the asn1 */ /* Based on libtomcrypt's ecc_sign_hash but without the asn1 */
int err = DROPBEAR_FAILURE; int err = DROPBEAR_FAILURE;
struct dropbear_ecc_curve *curve = NULL; struct dropbear_ecc_curve *curve = NULL;
hash_state hs; hash_state hs;
unsigned char hash[64]; unsigned char hash[64];
void *e = NULL, *p = NULL, *s = NULL, *r; void *e = NULL, *p = NULL, *s = NULL, *r;
unsigned char key_ident[30]; char key_ident[30];
buffer *sigbuf = NULL; buffer *sigbuf = NULL;
TRACE(("buf_put_ecdsa_sign")) TRACE(("buf_put_ecdsa_sign"))
@ -221,7 +221,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)); buf_putstring(buf, key_ident, strlen(key_ident));
/* enough for nistp521 */ /* enough for nistp521 */
sigbuf = buf_new(200); sigbuf = buf_new(200);
@ -271,7 +271,7 @@ out:
} }
int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) { int buf_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf) {
/* Based on libtomcrypt's ecc_verify_hash but without the asn1 */ /* Based on libtomcrypt's ecc_verify_hash but without the asn1 */
int ret = DROPBEAR_FAILURE; int ret = DROPBEAR_FAILURE;
hash_state hs; hash_state hs;
@ -384,12 +384,12 @@ int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) {
goto out; goto out;
} }
/* reduce */ /* reduce */
if (ltc_mp.ecc_map(mG, m, mp) != CRYPT_OK) { if (ltc_mp.ecc_map(mG, m, mp) != CRYPT_OK) {
goto out; goto out;
} }
} else { } else {
/* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */ /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
if (ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m) != CRYPT_OK) { if (ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m) != CRYPT_OK) {
goto out; goto out;
} }
@ -408,7 +408,7 @@ int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) {
out: out:
ltc_ecc_del_point(mG); ltc_ecc_del_point(mG);
ltc_ecc_del_point(mQ); 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) { if (mp != NULL) {
ltc_mp.montgomery_deinit(mp); ltc_mp.montgomery_deinit(mp);
} }

View File

@ -1,21 +1,22 @@
#ifndef _ECDSA_H_ #ifndef DROPBEAR_ECDSA_H_
#define _ECDSA_H_ #define DROPBEAR_ECDSA_H_
#include "includes.h" #include "includes.h"
#include "buffer.h" #include "buffer.h"
#include "signkey.h" #include "signkey.h"
#ifdef DROPBEAR_ECDSA #if DROPBEAR_ECDSA
/* Prefer the larger size - it's fast anyway */ /* prefer 256 or 384 since those are SHOULD for
#if defined(DROPBEAR_ECC_521) draft-ietf-curdle-ssh-kex-sha2.txt */
#define ECDSA_DEFAULT_SIZE 521 #if DROPBEAR_ECC_256
#elif defined(DROPBEAR_ECC_384)
#define ECDSA_DEFAULT_SIZE 384
#elif defined(DROPBEAR_ECC_256)
#define ECDSA_DEFAULT_SIZE 256 #define ECDSA_DEFAULT_SIZE 256
#elif DROPBEAR_ECC_384
#define ECDSA_DEFAULT_SIZE 384
#elif DROPBEAR_ECC_521
#define ECDSA_DEFAULT_SIZE 521
#else #else
#define ECDSA_DEFAULT_SIZE 0 #error ECDSA cannot be enabled without enabling at least one size (256, 384, 521)
#endif #endif
ecc_key *gen_ecdsa_priv_key(unsigned int bit_size); ecc_key *gen_ecdsa_priv_key(unsigned int bit_size);
@ -23,13 +24,13 @@ ecc_key *buf_get_ecdsa_pub_key(buffer* buf);
ecc_key *buf_get_ecdsa_priv_key(buffer *buf); ecc_key *buf_get_ecdsa_priv_key(buffer *buf);
void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key); void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key);
void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key); void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key);
enum signkey_type ecdsa_signkey_type(ecc_key * key); enum signkey_type ecdsa_signkey_type(const ecc_key * key);
void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf); void buf_put_ecdsa_sign(buffer *buf, const ecc_key *key, const buffer *data_buf);
int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf); int buf_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf);
/* Returns 1 on success */ /* Returns 1 on success */
int signkey_is_ecdsa(enum signkey_type type); int signkey_is_ecdsa(enum signkey_type type);
#endif #endif
#endif /* _ECDSA_H_ */ #endif /* DROPBEAR_ECDSA_H_ */

View File

@ -39,8 +39,8 @@
* that ai_family is AF_INET. Don't use it for another purpose. * that ai_family is AF_INET. Don't use it for another purpose.
*/ */
#ifndef _FAKE_RFC2553_H #ifndef DROPBEAR_FAKE_RFC2553_H
#define _FAKE_RFC2553_H #define DROPBEAR_FAKE_RFC2553_H
#include "includes.h" #include "includes.h"
#include <sys/types.h> #include <sys/types.h>

201
dropbear/fuzz-common.c Normal file
View File

@ -0,0 +1,201 @@
#include "includes.h"
#include "includes.h"
#include "fuzz.h"
#include "dbutil.h"
#include "runopts.h"
#include "crypto_desc.h"
#include "session.h"
#include "dbrandom.h"
#include "bignum.h"
#include "fuzz-wrapfd.h"
struct dropbear_fuzz_options fuzz;
static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param);
static void load_fixed_hostkeys(void);
void fuzz_common_setup(void) {
fuzz.fuzzing = 1;
fuzz.wrapfds = 1;
fuzz.do_jmp = 1;
fuzz.input = m_malloc(sizeof(buffer));
_dropbear_log = fuzz_dropbear_log;
crypto_init();
fuzz_seed();
/* let any messages get flushed */
setlinebuf(stdout);
}
int fuzz_set_input(const uint8_t *Data, size_t Size) {
fuzz.input->data = (unsigned char*)Data;
fuzz.input->size = Size;
fuzz.input->len = Size;
fuzz.input->pos = 0;
memset(&ses, 0x0, sizeof(ses));
memset(&svr_ses, 0x0, sizeof(svr_ses));
wrapfd_setup();
fuzz_seed();
return DROPBEAR_SUCCESS;
}
#if DEBUG_TRACE
static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param) {
if (debug_trace) {
char printbuf[1024];
vsnprintf(printbuf, sizeof(printbuf), format, param);
fprintf(stderr, "%s\n", printbuf);
}
}
#else
static void fuzz_dropbear_log(int UNUSED(priority), const char* UNUSED(format), va_list UNUSED(param)) {
/* No print */
}
#endif /* DEBUG_TRACE */
void fuzz_svr_setup(void) {
fuzz_common_setup();
_dropbear_exit = svr_dropbear_exit;
char *argv[] = {
"-E",
};
int argc = sizeof(argv) / sizeof(*argv);
svr_getopts(argc, argv);
/* user lookups might be slow, cache it */
fuzz.pw_name = m_strdup("person");
fuzz.pw_dir = m_strdup("/tmp");
fuzz.pw_shell = m_strdup("/bin/zsh");
fuzz.pw_passwd = m_strdup("!!zzznope");
load_fixed_hostkeys();
}
static void load_fixed_hostkeys(void) {
#include "fuzz-hostkeys.c"
buffer *b = buf_new(3000);
enum signkey_type type;
TRACE(("load fixed hostkeys"))
svr_opts.hostkey = new_sign_key();
buf_setlen(b, 0);
buf_putbytes(b, keyr, keyr_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_RSA;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed rsa hostkey");
}
buf_setlen(b, 0);
buf_putbytes(b, keyd, keyd_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_DSS;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed dss hostkey");
}
buf_setlen(b, 0);
buf_putbytes(b, keye, keye_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed ecdsa hostkey");
}
buf_free(b);
}
void fuzz_kex_fakealgos(void) {
ses.newkeys->recv.crypt_mode = &dropbear_mode_none;
}
void fuzz_get_socket_address(int UNUSED(fd), char **local_host, char **local_port,
char **remote_host, char **remote_port, int UNUSED(host_lookup)) {
if (local_host) {
*local_host = m_strdup("fuzzlocalhost");
}
if (local_port) {
*local_port = m_strdup("1234");
}
if (remote_host) {
*remote_host = m_strdup("fuzzremotehost");
}
if (remote_port) {
*remote_port = m_strdup("9876");
}
}
/* cut down version of svr_send_msg_kexdh_reply() that skips slow maths. Still populates structures */
void fuzz_fake_send_kexdh_reply(void) {
assert(!ses.dh_K);
m_mp_alloc_init_multi(&ses.dh_K, NULL);
mp_set_int(ses.dh_K, 12345678);
finish_kexhashbuf();
}
int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
static int once = 0;
if (!once) {
fuzz_svr_setup();
fuzz.skip_kexmaths = skip_kexmaths;
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}
/*
get prefix. input format is
string prefix
uint32 wrapfd seed
... to be extended later
[bytes] ssh input stream
*/
/* be careful to avoid triggering buffer.c assertions */
if (fuzz.input->len < 8) {
return 0;
}
size_t prefix_size = buf_getint(fuzz.input);
if (prefix_size != 4) {
return 0;
}
uint32_t wrapseed = buf_getint(fuzz.input);
wrapfd_setseed(wrapseed);
int fakesock = 20;
wrapfd_add(fakesock, fuzz.input, PLAIN);
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
svr_session(fakesock, fakesock);
m_malloc_free_epoch(1, 0);
} else {
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}
return 0;
}
const void* fuzz_get_algo(const algo_type *algos, const char* name) {
const algo_type *t;
for (t = algos; t->name; t++) {
if (strcmp(t->name, name) == 0) {
return t->data;
}
}
assert(0);
}

48
dropbear/fuzz-harness.c Normal file
View File

@ -0,0 +1,48 @@
#include "includes.h"
#include "buffer.h"
#include "dbutil.h"
extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
int main(int argc, char ** argv) {
int i;
buffer *input = buf_new(100000);
for (i = 1; i < argc; i++) {
printf("arg %s\n", argv[i]);
#if DEBUG_TRACE
if (strcmp(argv[i], "-v") == 0) {
debug_trace = 1;
TRACE(("debug printing on"))
}
#endif
}
int old_fuzz_wrapfds = 0;
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
/* ignore arguments */
continue;
}
char* fn = argv[i];
buf_setlen(input, 0);
buf_readfile(input, fn);
buf_setpos(input, 0);
fuzz.wrapfds = old_fuzz_wrapfds;
printf("Running %s once \n", fn);
LLVMFuzzerTestOneInput(input->data, input->len);
printf("Running %s twice \n", fn);
LLVMFuzzerTestOneInput(input->data, input->len);
printf("Done %s\n", fn);
/* Disable wrapfd so it won't interfere with buf_readfile() above */
old_fuzz_wrapfds = fuzz.wrapfds;
fuzz.wrapfds = 0;
}
printf("Finished\n");
return 0;
}

129
dropbear/fuzz-hostkeys.c Normal file
View File

@ -0,0 +1,129 @@
unsigned char keyr[] = {
0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x00,
0x00, 0x00, 0x03, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0xb1,
0x06, 0x95, 0xc9, 0xa8, 0x38, 0xb9, 0x99, 0x91, 0xb5, 0x17, 0x39, 0xb9,
0xfa, 0xa4, 0x49, 0xf8, 0x2a, 0x4c, 0x14, 0xbd, 0xb6, 0x85, 0xdb, 0x38,
0x99, 0x44, 0xfa, 0xd6, 0xaa, 0x67, 0xef, 0x00, 0x75, 0x2b, 0x6a, 0x5c,
0x1b, 0x50, 0xa8, 0x52, 0xf9, 0xa7, 0xee, 0xe2, 0xb3, 0x80, 0x38, 0x92,
0x20, 0x86, 0x7c, 0xe5, 0x89, 0xb3, 0x06, 0xe4, 0x3b, 0xd1, 0xe2, 0x45,
0xea, 0xc1, 0xd5, 0x8e, 0x05, 0xfb, 0x90, 0x29, 0xd9, 0x41, 0xb3, 0x05,
0x31, 0x1e, 0xcc, 0xeb, 0x89, 0xdc, 0xd2, 0x6a, 0x99, 0x23, 0xbd, 0x7a,
0xbe, 0x8c, 0xe3, 0x3f, 0xa1, 0xe8, 0xf5, 0xb4, 0x51, 0x40, 0xb4, 0xb1,
0xc1, 0x16, 0x9f, 0x07, 0xbb, 0x99, 0xaa, 0x4b, 0x8f, 0x11, 0x19, 0x3c,
0x18, 0xbd, 0x6e, 0xce, 0x14, 0x54, 0x2c, 0x16, 0x4a, 0x5f, 0x89, 0xe4,
0x6b, 0x9f, 0x55, 0x68, 0xcc, 0x09, 0x8e, 0x4b, 0x92, 0xc8, 0x87, 0xfe,
0x09, 0xed, 0x53, 0x6e, 0xff, 0x5f, 0x15, 0x0d, 0x19, 0x9d, 0xa6, 0x54,
0xd2, 0xea, 0x59, 0x4f, 0xa1, 0x7c, 0xf6, 0xf5, 0x7f, 0x32, 0x23, 0xed,
0x72, 0xa8, 0x96, 0x17, 0x87, 0x06, 0xf2, 0xc7, 0xcd, 0xda, 0x4a, 0x10,
0xd1, 0xfd, 0xb8, 0xf1, 0xaf, 0x25, 0x55, 0x32, 0x45, 0x39, 0x95, 0xec,
0x0c, 0xa9, 0xf0, 0x47, 0x8b, 0x66, 0xe0, 0xb7, 0xa2, 0xf6, 0x35, 0x50,
0x27, 0xe7, 0x2f, 0x90, 0x35, 0x5b, 0xd5, 0x62, 0x19, 0xb4, 0x41, 0xd4,
0x52, 0xe7, 0x7f, 0x97, 0xfc, 0x5b, 0x4a, 0x5b, 0x19, 0x06, 0x65, 0x2d,
0x23, 0x29, 0x15, 0x8b, 0x05, 0xaf, 0xbe, 0xd3, 0x4a, 0x27, 0x5b, 0xc9,
0xc0, 0xd0, 0xd2, 0xba, 0x8b, 0x00, 0x7a, 0x2f, 0x39, 0xa0, 0x13, 0xb9,
0xe6, 0xf5, 0x4b, 0x21, 0x54, 0x57, 0xb3, 0xf9, 0x6c, 0x6f, 0xd0, 0x17,
0xf4, 0x50, 0x9d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xf2, 0xda, 0x5f, 0xfb,
0xe2, 0xda, 0xfc, 0xe0, 0xdf, 0x3a, 0x0e, 0x14, 0x18, 0xc1, 0xd9, 0x1f,
0x43, 0xe3, 0x65, 0x3e, 0x07, 0xe7, 0x8d, 0xdc, 0x1d, 0x11, 0xc1, 0xd6,
0xc0, 0xd8, 0xda, 0x53, 0xf5, 0x04, 0x73, 0x51, 0x1b, 0x26, 0xef, 0x4e,
0xf5, 0xce, 0x3d, 0x77, 0x21, 0x94, 0xd0, 0xc7, 0xc1, 0xda, 0x19, 0x7d,
0xf8, 0xc5, 0x4c, 0xc8, 0xee, 0x7d, 0xd1, 0xbb, 0x02, 0x90, 0x2b, 0xff,
0x4e, 0x4d, 0xd7, 0x9d, 0x72, 0x0c, 0x60, 0x0f, 0x4b, 0x83, 0xf5, 0xc2,
0x26, 0xd6, 0x22, 0xb8, 0x60, 0x3a, 0xf9, 0x2f, 0x92, 0x2a, 0x2e, 0x14,
0xa7, 0x56, 0x1c, 0x56, 0x05, 0x41, 0x92, 0xac, 0xb1, 0x4e, 0x44, 0x1e,
0x70, 0x42, 0xda, 0xc7, 0xc8, 0x9c, 0xae, 0x29, 0x2d, 0x0c, 0x3a, 0xff,
0x9b, 0xb6, 0xad, 0xb4, 0xfb, 0x49, 0x28, 0x96, 0x74, 0xf5, 0x94, 0x74,
0xb7, 0x40, 0x93, 0x2b, 0x34, 0x29, 0xd2, 0x8a, 0xf3, 0x99, 0xf9, 0xe9,
0xd8, 0xcc, 0x48, 0x1d, 0x3e, 0xc1, 0x82, 0x35, 0x4f, 0xef, 0xb1, 0x81,
0x3c, 0xe1, 0xa1, 0x03, 0x65, 0xac, 0x21, 0x21, 0x40, 0x61, 0xfb, 0xd3,
0x54, 0xac, 0xa1, 0xf2, 0xf0, 0x61, 0xd9, 0x01, 0x4e, 0xc2, 0x28, 0xb1,
0x7c, 0x27, 0x6e, 0x56, 0x68, 0x69, 0x8f, 0xc5, 0xfd, 0xca, 0x39, 0x6e,
0x22, 0x09, 0xf1, 0xb4, 0xd5, 0xac, 0xb8, 0xe0, 0x1b, 0x21, 0x86, 0xf4,
0xc8, 0x15, 0xc6, 0x1f, 0x21, 0xae, 0xcb, 0xab, 0x5a, 0x09, 0x30, 0x9e,
0xdd, 0x6c, 0x38, 0x59, 0xec, 0x59, 0x3a, 0x08, 0xee, 0x46, 0x7b, 0x78,
0x23, 0xbc, 0xfc, 0xe2, 0xda, 0xe8, 0x1a, 0x65, 0xe6, 0xe0, 0x78, 0xd3,
0xb0, 0x03, 0x2e, 0xf1, 0xb8, 0xca, 0x8e, 0x90, 0x75, 0xaf, 0xf7, 0xa8,
0x48, 0xed, 0x82, 0xc9, 0xcf, 0x44, 0x56, 0xfc, 0x05, 0xfd, 0x6b, 0x00,
0x00, 0x00, 0x81, 0x00, 0xfc, 0x94, 0xdf, 0x42, 0xc7, 0x9a, 0xa2, 0xff,
0x32, 0xdf, 0x06, 0xb6, 0x4d, 0x90, 0x31, 0x28, 0x28, 0xdb, 0x03, 0xf9,
0xa6, 0xb3, 0xa2, 0x91, 0x4c, 0xdf, 0x6e, 0xf6, 0xb9, 0x44, 0x3b, 0xdd,
0x17, 0xc1, 0xc8, 0x1d, 0xd1, 0xc0, 0xc0, 0x30, 0x22, 0xbe, 0x24, 0x2e,
0x0e, 0xdf, 0xe0, 0x18, 0x37, 0x3e, 0xb8, 0x7f, 0xb2, 0x50, 0x34, 0xc4,
0x08, 0x5e, 0x69, 0x1f, 0xd5, 0xc9, 0xce, 0x47, 0x7d, 0x75, 0x5e, 0x3b,
0x87, 0xdd, 0x46, 0x35, 0x01, 0x0f, 0x17, 0x8a, 0xf1, 0xf1, 0xc4, 0xa9,
0x94, 0xa7, 0x6e, 0xce, 0x80, 0xe3, 0x17, 0x2e, 0xb0, 0xef, 0x63, 0xa7,
0x11, 0x86, 0x96, 0x4a, 0x63, 0x2d, 0x9e, 0x92, 0x62, 0x43, 0x43, 0x72,
0xa5, 0xdc, 0xa0, 0xcd, 0x19, 0x93, 0xd7, 0xe0, 0x80, 0x41, 0x27, 0xea,
0xe4, 0xe8, 0xc1, 0x91, 0x9e, 0x13, 0xb3, 0x9c, 0xd1, 0xed, 0xcb, 0xbf,
0x00, 0x00, 0x00, 0x81, 0x00, 0xb3, 0x6b, 0xee, 0xa4, 0x70, 0x4e, 0xfb,
0xf9, 0x7e, 0x2e, 0x74, 0x5d, 0x3e, 0x8b, 0x3f, 0xff, 0x8c, 0xde, 0x68,
0x38, 0xda, 0xce, 0xc0, 0x66, 0x4b, 0xca, 0x35, 0xc3, 0x97, 0xa8, 0xf0,
0x00, 0x8e, 0xb3, 0x46, 0x60, 0xd0, 0x4d, 0x7e, 0x7b, 0xdf, 0x17, 0x7b,
0x2f, 0xc4, 0x16, 0xee, 0x45, 0xdb, 0xa5, 0x5d, 0xc0, 0x72, 0xe9, 0xc6,
0x91, 0x0f, 0xd9, 0x30, 0x74, 0x6c, 0xde, 0x93, 0xb5, 0xb6, 0xaf, 0x52,
0x53, 0x3c, 0x08, 0x55, 0xea, 0xb8, 0x66, 0x07, 0xbe, 0xce, 0xf9, 0x80,
0x8d, 0xe0, 0xca, 0xdc, 0x63, 0xe8, 0x58, 0x94, 0x22, 0x4f, 0x08, 0x66,
0x13, 0x9e, 0x63, 0x2e, 0x92, 0x7a, 0xb6, 0x66, 0x94, 0x9b, 0x71, 0x66,
0xd3, 0x08, 0xc9, 0x89, 0xea, 0x78, 0x35, 0x0d, 0xf2, 0x25, 0x55, 0xd4,
0xb0, 0x9b, 0xea, 0x18, 0x77, 0xf6, 0x25, 0x02, 0xb4, 0x5e, 0x71, 0xea,
0xa3
};
unsigned int keyr_len = 805;
unsigned char keye[] = {
0x00, 0x00, 0x00, 0x13, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2d, 0x73, 0x68,
0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x00,
0x00, 0x00, 0x08, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x00,
0x00, 0x00, 0x41, 0x04, 0x0a, 0x00, 0x6c, 0x7c, 0x1c, 0xc4, 0x03, 0x44,
0x46, 0x70, 0xba, 0x00, 0x7c, 0x79, 0x89, 0x7b, 0xc3, 0xd6, 0x32, 0x98,
0x34, 0xe7, 0x1c, 0x60, 0x04, 0x73, 0xd9, 0xb5, 0x7e, 0x94, 0x04, 0x04,
0xea, 0xc8, 0xb8, 0xfb, 0xd4, 0x70, 0x9f, 0x29, 0xa7, 0x8d, 0x9a, 0x64,
0x3a, 0x8c, 0x45, 0x23, 0x37, 0x5a, 0x2b, 0x4f, 0x54, 0x91, 0x80, 0xf1,
0xac, 0x3a, 0xf5, 0x6d, 0xfa, 0xe8, 0x76, 0x20, 0x00, 0x00, 0x00, 0x21,
0x00, 0xc2, 0xaf, 0xbe, 0xdc, 0x06, 0xff, 0x3d, 0x08, 0x9b, 0x73, 0xe0,
0x3c, 0x58, 0x28, 0x70, 0x9b, 0x23, 0x39, 0x51, 0xd7, 0xbc, 0xa7, 0x1a,
0xf5, 0xb4, 0x23, 0xd3, 0xf6, 0x17, 0xa6, 0x9c, 0x02
};
unsigned int keye_len = 141;
unsigned char keyd[] = {
0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x64, 0x73, 0x73, 0x00,
0x00, 0x00, 0x81, 0x00, 0xb0, 0x02, 0x19, 0x8b, 0xf3, 0x46, 0xf9, 0xc5,
0x47, 0x78, 0x3d, 0x7f, 0x04, 0x10, 0x0a, 0x43, 0x8e, 0x00, 0x9e, 0xa4,
0x30, 0xfd, 0x47, 0xb9, 0x05, 0x9e, 0x95, 0xaa, 0x37, 0x9a, 0x91, 0xbf,
0xf8, 0xb9, 0xe0, 0x8d, 0x97, 0x49, 0x87, 0xe2, 0xe6, 0x90, 0xc1, 0xe4,
0x61, 0x57, 0x77, 0xfd, 0x91, 0x1d, 0xe1, 0x4b, 0xa0, 0xb2, 0xbc, 0xa1,
0x6a, 0x6a, 0xdd, 0x31, 0xda, 0xe7, 0x54, 0x03, 0xfd, 0x48, 0x62, 0x8a,
0x1d, 0x1d, 0xe2, 0x26, 0x76, 0x29, 0x08, 0xab, 0x65, 0x88, 0x74, 0x02,
0x1e, 0xa9, 0x29, 0x1b, 0x69, 0x3b, 0xb4, 0x5f, 0x62, 0x80, 0xa3, 0xa6,
0x4b, 0xc3, 0x0e, 0x89, 0x24, 0xe4, 0x8a, 0x31, 0xae, 0x89, 0x7a, 0x7a,
0x58, 0x44, 0x46, 0x77, 0x62, 0x33, 0xa2, 0x5d, 0x17, 0x0e, 0x0b, 0x64,
0xee, 0x1a, 0x02, 0xbd, 0xf8, 0x27, 0x86, 0xe1, 0x87, 0x92, 0x84, 0xc7,
0x00, 0x00, 0x00, 0x15, 0x00, 0xb3, 0x8b, 0x81, 0x39, 0x9c, 0xba, 0xe1,
0x1d, 0x9a, 0x8b, 0x89, 0xb3, 0x08, 0x9b, 0x12, 0xa8, 0x7b, 0xea, 0x25,
0x8d, 0x00, 0x00, 0x00, 0x80, 0x76, 0x3f, 0x72, 0xb2, 0xef, 0xc3, 0x16,
0xd8, 0x09, 0x36, 0x23, 0x03, 0xf9, 0x5c, 0xac, 0x8b, 0x51, 0x35, 0x2e,
0x36, 0xba, 0x39, 0xd0, 0x57, 0x19, 0x4f, 0x14, 0x8b, 0xea, 0x32, 0xfc,
0x86, 0x41, 0xea, 0x85, 0x71, 0x4d, 0x52, 0x0c, 0xff, 0xc1, 0xd3, 0xd5,
0xcd, 0x2e, 0x37, 0xcc, 0xe1, 0xcc, 0x22, 0x38, 0xa8, 0x47, 0x16, 0x34,
0x3b, 0x32, 0x9c, 0x2f, 0x0f, 0xcd, 0x5f, 0x7f, 0x06, 0x64, 0x89, 0xc5,
0x02, 0x4f, 0x9a, 0x70, 0x11, 0xf0, 0xaa, 0xe1, 0x7a, 0x75, 0x49, 0x8d,
0x0f, 0x8d, 0x5b, 0x54, 0xe2, 0xe7, 0x10, 0x6e, 0xe5, 0xbd, 0xb7, 0x62,
0xf7, 0x40, 0x59, 0x39, 0x31, 0xd9, 0x13, 0x7b, 0xa3, 0xdf, 0x0d, 0x31,
0x52, 0x43, 0xe0, 0xaf, 0x19, 0x12, 0x15, 0x12, 0x34, 0x01, 0x6f, 0xcf,
0x62, 0x21, 0xe4, 0xc8, 0x34, 0x69, 0xc9, 0x85, 0xe3, 0xde, 0xd7, 0x0c,
0xac, 0x00, 0x00, 0x00, 0x80, 0x41, 0xa3, 0xc5, 0xa4, 0x89, 0x86, 0xc8,
0x17, 0xf3, 0x8e, 0x68, 0x72, 0xbe, 0x13, 0x8b, 0x63, 0xe3, 0x07, 0xe3,
0xd5, 0xa4, 0xa2, 0xd3, 0x2c, 0x2f, 0xbe, 0x16, 0x71, 0xc9, 0x79, 0x64,
0x5a, 0x1e, 0x19, 0x82, 0x07, 0xe2, 0x93, 0xda, 0x22, 0xcf, 0x6d, 0xdd,
0x38, 0xcb, 0x6e, 0x6b, 0x0f, 0x95, 0x8d, 0xfa, 0x3f, 0xbb, 0xb8, 0x6a,
0x7d, 0xc3, 0x22, 0x1e, 0x49, 0xcf, 0x98, 0x73, 0x05, 0x5d, 0x97, 0xfa,
0x4c, 0xf2, 0x82, 0x3d, 0x98, 0x61, 0x4e, 0x96, 0x80, 0x26, 0x79, 0xda,
0x24, 0xf8, 0xa1, 0x9c, 0x71, 0x82, 0xe6, 0xc7, 0xdc, 0xc2, 0xa5, 0xd0,
0xf4, 0x36, 0xba, 0xaa, 0xee, 0xd3, 0x43, 0x46, 0x1d, 0xaa, 0x53, 0xea,
0x85, 0x2c, 0x1b, 0xc8, 0x7c, 0x3c, 0xe7, 0x06, 0x44, 0xab, 0x16, 0xad,
0xc6, 0x54, 0x91, 0x9a, 0xb9, 0xc0, 0xeb, 0x93, 0x8c, 0xca, 0x39, 0xcf,
0x6f, 0x00, 0x00, 0x00, 0x15, 0x00, 0x90, 0x26, 0x0a, 0xfc, 0x15, 0x99,
0x7b, 0xac, 0xaa, 0x0c, 0xa2, 0xca, 0x7b, 0xa8, 0xd4, 0xdf, 0x68, 0x56,
0xf9, 0x39
};
unsigned int keyd_len = 458;

246
dropbear/fuzz-wrapfd.c Normal file
View File

@ -0,0 +1,246 @@
#define FUZZ_SKIP_WRAP 1
#include "includes.h"
#include "fuzz-wrapfd.h"
#include "dbutil.h"
#include "fuzz.h"
#define IOWRAP_MAXFD (FD_SETSIZE-1)
static const int MAX_RANDOM_IN = 50000;
static const double CHANCE_CLOSE = 1.0 / 600;
static const double CHANCE_INTR = 1.0 / 900;
static const double CHANCE_READ1 = 0.96;
static const double CHANCE_READ2 = 0.5;
static const double CHANCE_WRITE1 = 0.96;
static const double CHANCE_WRITE2 = 0.5;
struct fdwrap {
enum wrapfd_mode mode;
buffer *buf;
int closein;
int closeout;
};
static struct fdwrap wrap_fds[IOWRAP_MAXFD+1];
/* for quick selection of in-use descriptors */
static int wrap_used[IOWRAP_MAXFD+1];
static unsigned int nused;
static unsigned short rand_state[3];
void wrapfd_setup(void) {
TRACE(("wrapfd_setup"))
nused = 0;
memset(wrap_fds, 0x0, sizeof(wrap_fds));
memset(wrap_used, 0x0, sizeof(wrap_used));
memset(rand_state, 0x0, sizeof(rand_state));
wrapfd_setseed(50);
}
void wrapfd_setseed(uint32_t seed) {
memcpy(rand_state, &seed, sizeof(seed));
nrand48(rand_state);
}
void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode) {
TRACE(("wrapfd_add %d buf %p mode %d", fd, buf, mode))
assert(fd >= 0);
assert(fd <= IOWRAP_MAXFD);
assert(wrap_fds[fd].mode == UNUSED);
assert(buf || mode == RANDOMIN);
wrap_fds[fd].mode = mode;
wrap_fds[fd].buf = buf;
wrap_fds[fd].closein = 0;
wrap_fds[fd].closeout = 0;
wrap_used[nused] = fd;
nused++;
}
void wrapfd_remove(int fd) {
unsigned int i, j;
TRACE(("wrapfd_remove %d", fd))
assert(fd >= 0);
assert(fd <= IOWRAP_MAXFD);
assert(wrap_fds[fd].mode != UNUSED);
wrap_fds[fd].mode = UNUSED;
/* remove from used list */
for (i = 0, j = 0; i < nused; i++) {
if (wrap_used[i] != fd) {
wrap_used[j] = wrap_used[i];
j++;
}
}
nused--;
}
int wrapfd_close(int fd) {
if (fd >= 0 && fd <= IOWRAP_MAXFD && wrap_fds[fd].mode != UNUSED) {
wrapfd_remove(fd);
return 0;
} else {
return close(fd);
}
}
int wrapfd_read(int fd, void *out, size_t count) {
size_t maxread;
buffer *buf;
if (!fuzz.wrapfds) {
return read(fd, out, count);
}
if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
/* XXX - assertion failure? */
TRACE(("Bad read descriptor %d\n", fd))
errno = EBADF;
return -1;
}
assert(count != 0);
if (wrap_fds[fd].closein || erand48(rand_state) < CHANCE_CLOSE) {
wrap_fds[fd].closein = 1;
errno = ECONNRESET;
return -1;
}
if (erand48(rand_state) < CHANCE_INTR) {
errno = EINTR;
return -1;
}
buf = wrap_fds[fd].buf;
if (buf) {
maxread = MIN(buf->len - buf->pos, count);
/* returns 0 if buf is EOF, as intended */
if (maxread > 0) {
maxread = nrand48(rand_state) % maxread + 1;
}
memcpy(out, buf_getptr(buf, maxread), maxread);
buf_incrpos(buf, maxread);
return maxread;
}
maxread = MIN(MAX_RANDOM_IN, count);
maxread = nrand48(rand_state) % maxread + 1;
memset(out, 0xef, maxread);
return maxread;
}
int wrapfd_write(int fd, const void* in, size_t count) {
unsigned const volatile char* volin = in;
unsigned int i;
if (!fuzz.wrapfds) {
return write(fd, in, count);
}
if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
/* XXX - assertion failure? */
TRACE(("Bad read descriptor %d\n", fd))
errno = EBADF;
return -1;
}
assert(count != 0);
/* force read to exercise sanitisers */
for (i = 0; i < count; i++) {
(void)volin[i];
}
if (wrap_fds[fd].closeout || erand48(rand_state) < CHANCE_CLOSE) {
wrap_fds[fd].closeout = 1;
errno = ECONNRESET;
return -1;
}
if (erand48(rand_state) < CHANCE_INTR) {
errno = EINTR;
return -1;
}
return nrand48(rand_state) % (count+1);
}
int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout) {
int i, nset, sel;
int ret = 0;
int fdlist[IOWRAP_MAXFD+1];
memset(fdlist, 0x0, sizeof(fdlist));
if (!fuzz.wrapfds) {
return select(nfds, readfds, writefds, exceptfds, timeout);
}
assert(nfds <= IOWRAP_MAXFD+1);
if (erand48(rand_state) < CHANCE_INTR) {
errno = EINTR;
return -1;
}
/* read */
if (readfds != NULL && erand48(rand_state) < CHANCE_READ1) {
for (i = 0, nset = 0; i < nfds; i++) {
if (FD_ISSET(i, readfds)) {
assert(wrap_fds[i].mode != UNUSED);
fdlist[nset] = i;
nset++;
}
}
DROPBEAR_FD_ZERO(readfds);
if (nset > 0) {
/* set one */
sel = fdlist[nrand48(rand_state) % nset];
FD_SET(sel, readfds);
ret++;
if (erand48(rand_state) < CHANCE_READ2) {
sel = fdlist[nrand48(rand_state) % nset];
if (!FD_ISSET(sel, readfds)) {
FD_SET(sel, readfds);
ret++;
}
}
}
}
/* write */
if (writefds != NULL && erand48(rand_state) < CHANCE_WRITE1) {
for (i = 0, nset = 0; i < nfds; i++) {
if (FD_ISSET(i, writefds)) {
assert(wrap_fds[i].mode != UNUSED);
fdlist[nset] = i;
nset++;
}
}
DROPBEAR_FD_ZERO(writefds);
/* set one */
if (nset > 0) {
sel = fdlist[nrand48(rand_state) % nset];
FD_SET(sel, writefds);
ret++;
if (erand48(rand_state) < CHANCE_WRITE2) {
sel = fdlist[nrand48(rand_state) % nset];
if (!FD_ISSET(sel, writefds)) {
FD_SET(sel, writefds);
ret++;
}
}
}
}
return ret;
}

25
dropbear/fuzz-wrapfd.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef FUZZ_WRAPFD_H
#define FUZZ_WRAPFD_H
#include "buffer.h"
enum wrapfd_mode {
UNUSED = 0,
PLAIN,
INPROGRESS,
RANDOMIN
};
void wrapfd_setup(void);
void wrapfd_setseed(uint32_t seed);
// doesn't take ownership of buf. buf is optional.
void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode);
// called via #defines for read/write/select
int wrapfd_read(int fd, void *out, size_t count);
int wrapfd_write(int fd, const void* in, size_t count);
int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
int wrapfd_close(int fd);
#endif // FUZZ_WRAPFD_H

72
dropbear/fuzz.h Normal file
View File

@ -0,0 +1,72 @@
#ifndef DROPBEAR_FUZZ_H
#define DROPBEAR_FUZZ_H
#include "config.h"
#if DROPBEAR_FUZZ
#include "includes.h"
#include "buffer.h"
#include "algo.h"
#include "fuzz-wrapfd.h"
// once per process
void fuzz_common_setup(void);
void fuzz_svr_setup(void);
// must be called once per fuzz iteration.
// returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE
int fuzz_set_input(const uint8_t *Data, size_t Size);
int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths);
const void* fuzz_get_algo(const algo_type *algos, const char* name);
// fuzzer functions that intrude into general code
void fuzz_kex_fakealgos(void);
int fuzz_checkpubkey_line(buffer* line, int line_num, char* filename,
const char* algo, unsigned int algolen,
const unsigned char* keyblob, unsigned int keybloblen);
extern const char * const * fuzz_signkey_names;
void fuzz_seed(void);
void fuzz_get_socket_address(int fd, char **local_host, char **local_port,
char **remote_host, char **remote_port, int host_lookup);
void fuzz_fake_send_kexdh_reply(void);
// fake IO wrappers
#ifndef FUZZ_SKIP_WRAP
#define select(nfds, readfds, writefds, exceptfds, timeout) \
wrapfd_select(nfds, readfds, writefds, exceptfds, timeout)
#define write(fd, buf, count) wrapfd_write(fd, buf, count)
#define read(fd, buf, count) wrapfd_read(fd, buf, count)
#define close(fd) wrapfd_close(fd)
#endif // FUZZ_SKIP_WRAP
struct dropbear_fuzz_options {
int fuzzing;
// fuzzing input
buffer *input;
struct dropbear_cipher recv_cipher;
struct dropbear_hash recv_mac;
int wrapfds;
// whether to skip slow bignum maths
int skip_kexmaths;
// dropbear_exit() jumps back
int do_jmp;
sigjmp_buf jmp;
uid_t pw_uid;
gid_t pw_gid;
char* pw_name;
char* pw_dir;
char* pw_shell;
char* pw_passwd;
};
extern struct dropbear_fuzz_options fuzz;
#endif // DROPBEAR_FUZZ
#endif /* DROPBEAR_FUZZ_H */

76
dropbear/fuzzer-kexdh.c Normal file
View File

@ -0,0 +1,76 @@
#include "fuzz.h"
#include "session.h"
#include "fuzz-wrapfd.h"
#include "debug.h"
#include "runopts.h"
#include "algo.h"
#include "bignum.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static int once = 0;
static struct key_context* keep_newkeys = NULL;
/* number of generated parameters is limited by the timeout for the first run.
TODO move this to the libfuzzer initialiser function instead if the timeout
doesn't apply there */
#define NUM_PARAMS 20
static struct kex_dh_param *dh_params[NUM_PARAMS];
if (!once) {
fuzz_common_setup();
fuzz_svr_setup();
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "diffie-hellman-group14-sha256");
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
ses.newkeys = keep_newkeys;
/* Pre-generate parameters */
int i;
for (i = 0; i < NUM_PARAMS; i++) {
dh_params[i] = gen_kexdh_param();
}
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
with DROPBEAR_KEX_NORMAL_DH */
ses.newkeys = keep_newkeys;
/* Choose from the collection of ecdh params */
unsigned int e = buf_getint(fuzz.input);
struct kex_dh_param * dh_param = dh_params[e % NUM_PARAMS];
DEF_MP_INT(dh_e);
m_mp_init(&dh_e);
if (buf_getmpint(fuzz.input, &dh_e) != DROPBEAR_SUCCESS) {
dropbear_exit("Bad kex value");
}
ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
kexdh_comb_key(dh_param, &dh_e, svr_opts.hostkey);
mp_clear(ses.dh_K);
m_free(ses.dh_K);
mp_clear(&dh_e);
buf_free(ses.hash);
buf_free(ses.session_id);
/* kexhashbuf is freed in kexdh_comb_key */
m_malloc_free_epoch(1, 0);
} else {
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}
return 0;
}

82
dropbear/fuzzer-kexecdh.c Normal file
View File

@ -0,0 +1,82 @@
#include "fuzz.h"
#include "session.h"
#include "fuzz-wrapfd.h"
#include "debug.h"
#include "runopts.h"
#include "algo.h"
#include "bignum.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static int once = 0;
static const struct dropbear_kex *ecdh[3]; /* 256, 384, 521 */
static struct key_context* keep_newkeys = NULL;
/* number of generated parameters is limited by the timeout for the first run */
#define NUM_PARAMS 80
static struct kex_ecdh_param *ecdh_params[NUM_PARAMS];
if (!once) {
fuzz_common_setup();
fuzz_svr_setup();
/* ses gets zeroed by fuzz_set_input */
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
ecdh[0] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp256");
ecdh[1] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp384");
ecdh[2] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp521");
assert(ecdh[0]);
assert(ecdh[1]);
assert(ecdh[2]);
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
ses.newkeys = keep_newkeys;
/* Pre-generate parameters */
int i;
for (i = 0; i < NUM_PARAMS; i++) {
ses.newkeys->algo_kex = ecdh[i % 3];
ecdh_params[i] = gen_kexecdh_param();
}
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
with DROPBEAR_KEX_ECDH */
ses.newkeys = keep_newkeys;
/* random choice of ecdh 256, 384, 521 */
unsigned char b = buf_getbyte(fuzz.input);
ses.newkeys->algo_kex = ecdh[b % 3];
/* Choose from the collection of ecdh params */
unsigned int e = buf_getint(fuzz.input);
struct kex_ecdh_param *ecdh_param = ecdh_params[e % NUM_PARAMS];
buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
kexecdh_comb_key(ecdh_param, ecdh_qs, svr_opts.hostkey);
mp_clear(ses.dh_K);
m_free(ses.dh_K);
buf_free(ecdh_qs);
buf_free(ses.hash);
buf_free(ses.session_id);
/* kexhashbuf is freed in kexdh_comb_key */
m_malloc_free_epoch(1, 0);
} else {
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}
return 0;
}

View File

@ -0,0 +1,6 @@
#include "fuzz.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
return fuzz_run_preauth(Data, Size, 0);
}

View File

@ -0,0 +1,6 @@
#include "fuzz.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
return fuzz_run_preauth(Data, Size, 1);
}

54
dropbear/fuzzer-pubkey.c Normal file
View File

@ -0,0 +1,54 @@
#include "fuzz.h"
#include "session.h"
#include "fuzz-wrapfd.h"
#include "debug.h"
static void setup_fuzzer(void) {
fuzz_common_setup();
}
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static int once = 0;
if (!once) {
setup_fuzzer();
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
buffer *line = buf_getstringbuf(fuzz.input);
buffer *keyblob = buf_getstringbuf(fuzz.input);
unsigned int algolen;
char* algoname = buf_getstring(keyblob, &algolen);
if (have_algo(algoname, algolen, sshhostkey) == DROPBEAR_FAILURE) {
dropbear_exit("fuzzer imagined a bogus algorithm");
}
int ret = fuzz_checkpubkey_line(line, 5, "/home/me/authorized_keys",
algoname, algolen,
keyblob->data, keyblob->len);
if (ret == DROPBEAR_SUCCESS) {
/* fuzz_checkpubkey_line() should have cleaned up for failure */
svr_pubkey_options_cleanup();
}
buf_free(line);
buf_free(keyblob);
m_free(algoname);
m_malloc_free_epoch(1, 0);
} else {
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}
return 0;
}

64
dropbear/fuzzer-verify.c Normal file
View File

@ -0,0 +1,64 @@
#include "fuzz.h"
#include "session.h"
#include "fuzz-wrapfd.h"
#include "debug.h"
static void setup_fuzzer(void) {
fuzz_common_setup();
}
static buffer *verifydata;
/* Tests reading a public key and verifying a signature */
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static int once = 0;
if (!once) {
setup_fuzzer();
verifydata = buf_new(30);
buf_putstring(verifydata, "x", 1);
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
sign_key *key = new_sign_key();
enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
if (buf_get_pub_key(fuzz.input, key, &type) == DROPBEAR_SUCCESS) {
if (buf_verify(fuzz.input, key, verifydata) == DROPBEAR_SUCCESS) {
/* The fuzzer is capable of generating keys with a signature to match.
We don't want false positives if the key is bogus, since a client/server
wouldn't be trusting a bogus key anyway */
int boguskey = 0;
if (type == DROPBEAR_SIGNKEY_DSS) {
/* So far have seen dss keys with bad p/q/g domain parameters */
int pprime, qprime;
assert(mp_prime_is_prime(key->dsskey->p, 5, &pprime) == MP_OKAY);
assert(mp_prime_is_prime(key->dsskey->q, 18, &qprime) == MP_OKAY);
boguskey = !(pprime && qprime);
/* Could also check g**q mod p == 1 */
}
if (!boguskey) {
printf("Random key/signature managed to verify!\n");
abort();
}
}
}
sign_key_free(key);
m_malloc_free_epoch(1, 0);
} else {
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}
return 0;
}

12
dropbear/fuzzers_test.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
# runs fuzz corpus with standalone fuzzers
result=0
hg clone https://secure.ucc.asn.au/hg/dropbear-fuzzcorpus fuzzcorpus || exit 1
for f in `make list-fuzz-targets`; do
./$f fuzzcorpus/$f/* || result=1
done
exit $result

View File

@ -35,13 +35,13 @@
/* This is just a test */ /* This is just a test */
#ifdef DROPBEAR_DSS #if DROPBEAR_DSS
static void getq(dropbear_dss_key *key); static void getq(const dropbear_dss_key *key);
static void getp(dropbear_dss_key *key, unsigned int size); static void getp(const dropbear_dss_key *key, unsigned int size);
static void getg(dropbear_dss_key *key); static void getg(const dropbear_dss_key *key);
static void getx(dropbear_dss_key *key); static void getx(const dropbear_dss_key *key);
static void gety(dropbear_dss_key *key); static void gety(const dropbear_dss_key *key);
dropbear_dss_key * gen_dss_priv_key(unsigned int size) { dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
@ -65,9 +65,9 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
} }
static void getq(dropbear_dss_key *key) { static void getq(const dropbear_dss_key *key) {
char buf[QSIZE]; unsigned char buf[QSIZE];
/* 160 bit prime */ /* 160 bit prime */
genrandom(buf, QSIZE); genrandom(buf, QSIZE);
@ -83,7 +83,7 @@ static void getq(dropbear_dss_key *key) {
} }
} }
static void getp(dropbear_dss_key *key, unsigned int size) { static void getp(const dropbear_dss_key *key, unsigned int size) {
DEF_MP_INT(tempX); DEF_MP_INT(tempX);
DEF_MP_INT(tempC); DEF_MP_INT(tempC);
@ -142,7 +142,7 @@ static void getp(dropbear_dss_key *key, unsigned int size) {
m_free(buf); m_free(buf);
} }
static void getg(dropbear_dss_key * key) { static void getg(const dropbear_dss_key * key) {
DEF_MP_INT(div); DEF_MP_INT(div);
DEF_MP_INT(h); DEF_MP_INT(h);
@ -179,12 +179,12 @@ static void getg(dropbear_dss_key * key) {
mp_clear_multi(&div, &h, &val, NULL); mp_clear_multi(&div, &h, &val, NULL);
} }
static void getx(dropbear_dss_key *key) { static void getx(const dropbear_dss_key *key) {
gen_random_mpint(key->q, key->x); gen_random_mpint(key->q, key->x);
} }
static void gety(dropbear_dss_key *key) { static void gety(const dropbear_dss_key *key) {
if (mp_exptmod(key->g, key->x, key->p, key->y) != MP_OKAY) { if (mp_exptmod(key->g, key->x, key->p, key->y) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n"); fprintf(stderr, "DSS key generation failed\n");

View File

@ -22,15 +22,15 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _GENDSS_H_ #ifndef DROPBEAR_GENDSS_H_
#define _GENDSS_H_ #define DROPBEAR_GENDSS_H_
#include "dss.h" #include "dss.h"
#ifdef DROPBEAR_DSS #if DROPBEAR_DSS
dropbear_dss_key * gen_dss_priv_key(unsigned int size); dropbear_dss_key * gen_dss_priv_key(unsigned int size);
#endif /* DROPBEAR_DSS */ #endif /* DROPBEAR_DSS */
#endif /* _GENDSS_H_ */ #endif /* DROPBEAR_GENDSS_H_ */

View File

@ -31,7 +31,7 @@
#define RSA_E 65537 #define RSA_E 65537
#ifdef DROPBEAR_RSA #if DROPBEAR_RSA
static void getrsaprime(mp_int* prime, mp_int *primeminus, static void getrsaprime(mp_int* prime, mp_int *primeminus,
mp_int* rsa_e, unsigned int size_bytes); mp_int* rsa_e, unsigned int size_bytes);

View File

@ -22,15 +22,15 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _GENRSA_H_ #ifndef DROPBEAR_GENRSA_H_
#define _GENRSA_H_ #define DROPBEAR_GENRSA_H_
#include "rsa.h" #include "rsa.h"
#ifdef DROPBEAR_RSA #if DROPBEAR_RSA
dropbear_rsa_key * gen_rsa_priv_key(unsigned int size); dropbear_rsa_key * gen_rsa_priv_key(unsigned int size);
#endif /* DROPBEAR_RSA */ #endif /* DROPBEAR_RSA */
#endif /* _GENRSA_H_ */ #endif /* DROPBEAR_GENRSA_H_ */

View File

@ -7,9 +7,6 @@
#include "signkey.h" #include "signkey.h"
#include "dbrandom.h" #include "dbrandom.h"
#define RSA_DEFAULT_SIZE 2048
#define DSS_DEFAULT_SIZE 1024
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static int buf_writefile(buffer * buf, const char * filename) { static int buf_writefile(buffer * buf, const char * filename) {
int ret = DROPBEAR_FAILURE; int ret = DROPBEAR_FAILURE;
@ -41,6 +38,9 @@ static int buf_writefile(buffer * buf, const char * filename) {
out: out:
if (fd >= 0) { if (fd >= 0) {
if (fsync(fd) != 0) {
dropbear_log(LOG_ERR, "fsync of %s failed: %s", filename, strerror(errno));
}
m_close(fd); m_close(fd);
} }
return ret; return ret;
@ -49,39 +49,47 @@ out:
/* returns 0 on failure */ /* returns 0 on failure */
static int get_default_bits(enum signkey_type keytype) static int get_default_bits(enum signkey_type keytype)
{ {
switch (keytype) { switch (keytype) {
#ifdef DROPBEAR_RSA #if DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA: case DROPBEAR_SIGNKEY_RSA:
return RSA_DEFAULT_SIZE; return DROPBEAR_DEFAULT_RSA_SIZE;
#endif #endif
#ifdef DROPBEAR_DSS #if DROPBEAR_DSS
case DROPBEAR_SIGNKEY_DSS: case DROPBEAR_SIGNKEY_DSS:
return DSS_DEFAULT_SIZE; /* DSS for SSH only defines 1024 bits */
return 1024;
#endif #endif
#ifdef DROPBEAR_ECDSA #if DROPBEAR_ECDSA
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN: case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
return ECDSA_DEFAULT_SIZE; return ECDSA_DEFAULT_SIZE;
case DROPBEAR_SIGNKEY_ECDSA_NISTP521: case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
return 521; return 521;
case DROPBEAR_SIGNKEY_ECDSA_NISTP384: case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
return 384; return 384;
case DROPBEAR_SIGNKEY_ECDSA_NISTP256: case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
return 256; return 256;
#endif #endif
default: default:
return 0; return 0;
} }
} }
int signkey_generate(enum signkey_type keytype, int bits, const char* filename) int signkey_generate_get_bits(enum signkey_type keytype, int bits) {
{
sign_key * key = NULL;
buffer *buf = NULL;
int ret = DROPBEAR_FAILURE;
if (bits == 0) if (bits == 0)
{ {
bits = get_default_bits(keytype); bits = get_default_bits(keytype);
} }
return bits;
}
/* if skip_exist is set it will silently return if the key file exists */
int signkey_generate(enum signkey_type keytype, int bits, const char* filename, int skip_exist)
{
sign_key * key = NULL;
buffer *buf = NULL;
char *fn_temp = NULL;
int ret = DROPBEAR_FAILURE;
bits = signkey_generate_get_bits(keytype, bits);
/* now we can generate the key */ /* now we can generate the key */
key = new_sign_key(); key = new_sign_key();
@ -89,17 +97,17 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename)
seedrandom(); seedrandom();
switch(keytype) { switch(keytype) {
#ifdef DROPBEAR_RSA #if DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA: case DROPBEAR_SIGNKEY_RSA:
key->rsakey = gen_rsa_priv_key(bits); key->rsakey = gen_rsa_priv_key(bits);
break; break;
#endif #endif
#ifdef DROPBEAR_DSS #if DROPBEAR_DSS
case DROPBEAR_SIGNKEY_DSS: case DROPBEAR_SIGNKEY_DSS:
key->dsskey = gen_dss_priv_key(bits); key->dsskey = gen_dss_priv_key(bits);
break; break;
#endif #endif
#ifdef DROPBEAR_ECDSA #if DROPBEAR_ECDSA
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN: case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
case DROPBEAR_SIGNKEY_ECDSA_NISTP521: case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
case DROPBEAR_SIGNKEY_ECDSA_NISTP384: case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
@ -123,10 +131,37 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename)
sign_key_free(key); sign_key_free(key);
key = NULL; key = NULL;
buf_setpos(buf, 0); buf_setpos(buf, 0);
ret = buf_writefile(buf, filename);
buf_burn(buf); fn_temp = m_malloc(strlen(filename) + 30);
buf_free(buf); snprintf(fn_temp, strlen(filename)+30, "%s.tmp%d", filename, getpid());
buf = NULL; ret = buf_writefile(buf, fn_temp);
if (ret == DROPBEAR_FAILURE) {
goto out;
}
if (link(fn_temp, filename) < 0) {
/* If generating keys on connection (skipexist) it's OK to get EEXIST
- we probably just lost a race with another connection to generate the key */
if (!(skip_exist && errno == EEXIST)) {
dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename,
strerror(errno));
/* XXX fallback to non-atomic copy for some filesystems? */
ret = DROPBEAR_FAILURE;
goto out;
}
}
out:
if (buf) {
buf_burn(buf);
buf_free(buf);
}
if (fn_temp) {
unlink(fn_temp);
m_free(fn_temp);
}
return ret; return ret;
} }

View File

@ -1,8 +1,9 @@
#ifndef _GENSIGNKEY_H #ifndef DROPBEAR_GENSIGNKEY_H
#define _GENSIGNKEY_H #define DROPBEAR_GENSIGNKEY_H
#include "signkey.h" #include "signkey.h"
int signkey_generate(enum signkey_type type, int bits, const char* filename); int signkey_generate(enum signkey_type type, int bits, const char* filename, int skip_exist);
int signkey_generate_get_bits(enum signkey_type keytype, int bits);
#endif #endif

7
dropbear/ifndef_wrapper.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
# Wrap all "#define X Y" with a #ifndef X...#endif"
sed 's/^\( *#define \([^ ][^ ]*\) .*\)/#ifndef \2\
\1\
#endif/'

View File

@ -22,11 +22,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */ * SOFTWARE. */
#ifndef _INCLUDES_H_ #ifndef DROPBEAR_INCLUDES_H_
#define _INCLUDES_H_ #define DROPBEAR_INCLUDES_H_
#include "config.h"
#include "options.h" #include "options.h"
#include "debug.h" #include "debug.h"
@ -57,6 +56,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <dirent.h> #include <dirent.h>
#include <time.h> #include <time.h>
#include <setjmp.h>
#ifdef HAVE_UTMP_H #ifdef HAVE_UTMP_H
#include <utmp.h> #include <utmp.h>
@ -132,7 +132,6 @@
#include <tommath.h> #include <tommath.h>
#endif #endif
#include "compat.h" #include "compat.h"
#ifndef HAVE_U_INT8_T #ifndef HAVE_U_INT8_T
@ -156,13 +155,19 @@ typedef unsigned int u_int32_t;
typedef u_int32_t uint32_t; typedef u_int32_t uint32_t;
#endif /* HAVE_UINT32_T */ #endif /* HAVE_UINT32_T */
#ifdef SO_PRIORITY #ifndef SIZE_T_MAX
#define SIZE_T_MAX ULONG_MAX
#endif /* SIZE_T_MAX */
#ifdef HAVE_LINUX_PKT_SCHED_H
#include <linux/types.h> #include <linux/types.h>
#include <linux/pkt_sched.h> #include <linux/pkt_sched.h>
#endif #endif
#include "fake-rfc2553.h" #include "fake-rfc2553.h"
#include "fuzz.h"
#ifndef LOG_AUTHPRIV #ifndef LOG_AUTHPRIV
#define LOG_AUTHPRIV LOG_AUTH #define LOG_AUTHPRIV LOG_AUTH
#endif #endif
@ -177,4 +182,4 @@ typedef u_int32_t uint32_t;
# define UNUSED(x) x # define UNUSED(x) x
#endif #endif
#endif /* _INCLUDES_H_ */ #endif /* DROPBEAR_INCLUDES_H_ */

Some files were not shown because too many files have changed in this diff Show More