mirror of
https://github.com/clearml/dropbear
synced 2025-06-26 18:17:32 +00:00
Compare commits
1557 Commits
DROPBEAR_0
...
coverity
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ea2e3463d | ||
|
|
ddb6751ab4 | ||
|
|
3727b099c5 | ||
|
|
45294b458a | ||
|
|
d51e4a75cd | ||
|
|
e9f2815144 | ||
|
|
2771fab0fa | ||
|
|
a7a67585cb | ||
|
|
366f01252e | ||
|
|
1490c0c3a6 | ||
|
|
3f5c106a88 | ||
|
|
10e119f638 | ||
|
|
5b68d117c2 | ||
|
|
58106b1615 | ||
|
|
1e10af850b | ||
|
|
ee4b4db816 | ||
|
|
ab9cfce00d | ||
|
|
2b8106b14e | ||
|
|
78c5daee52 | ||
|
|
2301b6ac0b | ||
|
|
a27e8b053e | ||
|
|
6145289e0d | ||
|
|
d14ebdbf0e | ||
|
|
4b305c5721 | ||
|
|
615885be01 | ||
|
|
6b823d617c | ||
|
|
ec993dbdbc | ||
|
|
ad1e9b7e3c | ||
|
|
846b8cdbf7 | ||
|
|
b0243b0e7b | ||
|
|
4faf06aae7 | ||
|
|
07d46f9907 | ||
|
|
413eaf1ba1 | ||
|
|
3b359050b4 | ||
|
|
a015cc7594 | ||
|
|
dc12be0cfe | ||
|
|
89e98a2f83 | ||
|
|
5027bc4db1 | ||
|
|
630f6aa6b9 | ||
|
|
8048473eb9 | ||
|
|
4216c984ae | ||
|
|
6abf756e51 | ||
|
|
b4bd23b4d2 | ||
|
|
724e61f8ae | ||
|
|
49667a82de | ||
|
|
a57114e7fa | ||
|
|
cfe90bc6bd | ||
|
|
0aefec6c89 | ||
|
|
6a3bc73a78 | ||
|
|
73aa4f0de9 | ||
|
|
9e25854b41 | ||
|
|
d277f140ba | ||
|
|
61267f8503 | ||
|
|
d3d0d60076 | ||
|
|
91e537e427 | ||
|
|
fb9a78c3ee | ||
|
|
8f8a3dff70 | ||
|
|
c917807b1c | ||
|
|
701d43b859 | ||
|
|
79bedc90a1 | ||
|
|
545cc62671 | ||
|
|
331d4a714f | ||
|
|
2a81289ed3 | ||
|
|
5acee497bf | ||
|
|
972d723484 | ||
|
|
7dc2f36c3e | ||
|
|
90cfbe1f7a | ||
|
|
b681570899 | ||
|
|
201e359363 | ||
|
|
fa4c4646d8 | ||
|
|
6f6aa9db5a | ||
|
|
e35d0784a8 | ||
|
|
cc6fa57a41 | ||
|
|
a26ad21c0a | ||
|
|
002b79e2f9 | ||
|
|
3d12521735 | ||
|
|
b2007beeb0 | ||
|
|
8f123fb618 | ||
|
|
c71258625d | ||
|
|
615ed4e46a | ||
|
|
fa116e983b | ||
|
|
8c6aaf8d36 | ||
|
|
cae6e6af10 | ||
|
|
f89c5b0390 | ||
|
|
4318631dd6 | ||
|
|
7bc6280613 | ||
|
|
e9231f73c2 | ||
|
|
4fd40e61f7 | ||
|
|
71f818262c | ||
|
|
07f790db5a | ||
|
|
78a3388b98 | ||
|
|
6e3c3c8c51 | ||
|
|
6fecc91d10 | ||
|
|
ef080502f8 | ||
|
|
8b4f60a7a1 | ||
|
|
01cd1bd11f | ||
|
|
f6df3e1fec | ||
|
|
553087b7a6 | ||
|
|
16fb0b0d53 | ||
|
|
493ab8fd81 | ||
|
|
0afcfafbb9 | ||
|
|
0af22aa8e4 | ||
|
|
2fd3b9f560 | ||
|
|
2de3bc9353 | ||
|
|
28b6111db0 | ||
|
|
a0aa274981 | ||
|
|
b016ebedfd | ||
|
|
cb945f9f67 | ||
|
|
df0f1297eb | ||
|
|
fe992bf4ea | ||
|
|
ffde4a524f | ||
|
|
7e03e4d443 | ||
|
|
02ffdd09dc | ||
|
|
6f6ef4834c | ||
|
|
d2e71ade72 | ||
|
|
892c5fc1c8 | ||
|
|
e7504b3311 | ||
|
|
ad3eacf3d6 | ||
|
|
52adbb34c3 | ||
|
|
90f04384ee | ||
|
|
195934be96 | ||
|
|
fdbdbe5703 | ||
|
|
d740dc5489 | ||
|
|
76933e6c0a | ||
|
|
38c9408cf8 | ||
|
|
397af3e6a6 | ||
|
|
933bc5f8a7 | ||
|
|
ba94bcd2e8 | ||
|
|
56855744b8 | ||
|
|
b4b11c8155 | ||
|
|
f82933108d | ||
|
|
27828c742c | ||
|
|
ed4c38ba46 | ||
|
|
e9edbe8bb2 | ||
|
|
4fd3160179 | ||
|
|
a60725740b | ||
|
|
5d065258da | ||
|
|
149b21d7cf | ||
|
|
145fb96989 | ||
|
|
084ff9b4c8 | ||
|
|
6b05aa4275 | ||
|
|
366fc8f335 | ||
|
|
35f479bd87 | ||
|
|
9d11cad5dc | ||
|
|
0233dcebb4 | ||
|
|
f7dedab4a7 | ||
|
|
129c440362 | ||
|
|
abee8093b3 | ||
|
|
2583b180c9 | ||
|
|
1e1e477d85 | ||
|
|
85eda7d943 | ||
|
|
4b36e24735 | ||
|
|
921592d37e | ||
|
|
a5eac0a065 | ||
|
|
7f15910541 | ||
|
|
625b38d7af | ||
|
|
b9edf939f4 | ||
|
|
257bba00ac | ||
|
|
8d0b48f165 | ||
|
|
ce1f9cdf7c | ||
|
|
e612aec5d9 | ||
|
|
5bd0c0d25a | ||
|
|
26ad6853d2 | ||
|
|
8a4f7fe4f8 | ||
|
|
294e98c397 | ||
|
|
c1a2dcb25d | ||
|
|
a0972e0ac6 | ||
|
|
8062a4e8d6 | ||
|
|
a0ab5e86b5 | ||
|
|
a1dcaf82a0 | ||
|
|
78e17f6ee9 | ||
|
|
5ebc48b3f2 | ||
|
|
1ae4237920 | ||
|
|
5ca12d8332 | ||
|
|
7f8702d3d6 | ||
|
|
5f2447edbb | ||
|
|
c658b275fd | ||
|
|
9bbce01e1b | ||
|
|
bbe02dc3cf | ||
|
|
3d76aecaa6 | ||
|
|
64bd345a5d | ||
|
|
152c507499 | ||
|
|
e2ae628b17 | ||
|
|
6eabc0fe87 | ||
|
|
bf6f04cbe6 | ||
|
|
e0c86670e2 | ||
|
|
7840691420 | ||
|
|
96e1a7e6da | ||
|
|
5df73215f8 | ||
|
|
04a02730bc | ||
|
|
3996e93a20 | ||
|
|
246f24eda8 | ||
|
|
4aa72b96c1 | ||
|
|
0fc20c70af | ||
|
|
ebc915baae | ||
|
|
7435369615 | ||
|
|
2e836bb553 | ||
|
|
36ccfd21e7 | ||
|
|
44c323872a | ||
|
|
094972ea84 | ||
|
|
2707f054a5 | ||
|
|
4c95d595c0 | ||
|
|
573838a027 | ||
|
|
05f4e29a52 | ||
|
|
dbc0520992 | ||
|
|
7efe873d73 | ||
|
|
4058574cfa | ||
|
|
d17dedfa4f | ||
|
|
dcce2cfd8d | ||
|
|
4768351e89 | ||
|
|
3f3f399231 | ||
|
|
316c923188 | ||
|
|
8fdaf0268d | ||
|
|
f2d86ae7d3 | ||
|
|
34ee326075 | ||
|
|
1656db9e58 | ||
|
|
802dace05e | ||
|
|
c2f2f2b817 | ||
|
|
dcb41e91eb | ||
|
|
67111efdad | ||
|
|
5fd677af76 | ||
|
|
b080f5a047 | ||
|
|
7e8094d53a | ||
|
|
c8d852caf6 | ||
|
|
00a1290173 | ||
|
|
f042eb41ab | ||
|
|
017e2f07a7 | ||
|
|
3a923b72a4 | ||
|
|
5bf1214859 | ||
|
|
2ef1ab0753 | ||
|
|
c218af6ea7 | ||
|
|
e0748b1970 | ||
|
|
3ee685ad1c | ||
|
|
17be46e229 | ||
|
|
370d4c7cd5 | ||
|
|
1700987bfc | ||
|
|
a1aa161527 | ||
|
|
9a7972dcb8 | ||
|
|
191f22e11a | ||
|
|
93632660bb | ||
|
|
84d415fb66 | ||
|
|
ad9db51434 | ||
|
|
1a37d7aa48 | ||
|
|
22eb197d6c | ||
|
|
3953018c2d | ||
|
|
cfe99a79bd | ||
|
|
a3a0b26581 | ||
|
|
276197b404 | ||
|
|
ee812daf69 | ||
|
|
df66daa26a | ||
|
|
484d1e9b81 | ||
|
|
8013009880 | ||
|
|
95b99cc86a | ||
|
|
6a713ad834 | ||
|
|
278a3e43e5 | ||
|
|
c81e530d3c | ||
|
|
2df2117388 | ||
|
|
4b021ae6f0 | ||
|
|
a36f182b36 | ||
|
|
d8bb6a7816 | ||
|
|
57d474e183 | ||
|
|
d7e12aadbe | ||
|
|
c0df3902b7 | ||
|
|
4f2eb1914b | ||
|
|
d72f50ff32 | ||
|
|
debb208553 | ||
|
|
f581ef9453 | ||
|
|
b65354d237 | ||
|
|
e4ac7ea1ca | ||
|
|
9c7ecf6d14 | ||
|
|
917722257d | ||
|
|
3d61b6eab6 | ||
|
|
e64e25e4d6 | ||
|
|
f7a664f127 | ||
|
|
89bdf3b0b9 | ||
|
|
597f7eb5e9 | ||
|
|
ba23b823dc | ||
|
|
fa3b0dd3ca | ||
|
|
dd8988220e | ||
|
|
cc803ee802 | ||
|
|
598056d168 | ||
|
|
89e64c631e | ||
|
|
5cd003d9e6 | ||
|
|
468656b4aa | ||
|
|
22037d5fba | ||
|
|
4b7105dfea | ||
|
|
a5ec3aca7d | ||
|
|
785459d31b | ||
|
|
a9a3746d09 | ||
|
|
74ace058a6 | ||
|
|
96382d52ab | ||
|
|
ddbc8113a9 | ||
|
|
65115b9159 | ||
|
|
e255101299 | ||
|
|
187fc95deb | ||
|
|
a94338dc67 | ||
|
|
6ac5ea2a9f | ||
|
|
364fb6019c | ||
|
|
a79b61517b | ||
|
|
99361f54ca | ||
|
|
82c06dd76b | ||
|
|
17a9b8802f | ||
|
|
9b6f7fc9af | ||
|
|
57690891ce | ||
|
|
5896a4941d | ||
|
|
5ac4a71000 | ||
|
|
521e63529c | ||
|
|
24b446705b | ||
|
|
3c5ed47804 | ||
|
|
b967dc1fa5 | ||
|
|
af2caaab72 | ||
|
|
2cbe70ba34 | ||
|
|
8e1ea0f27b | ||
|
|
e3246ceb7e | ||
|
|
169f41a43c | ||
|
|
88ce30beb6 | ||
|
|
d260d5148e | ||
|
|
723ec19eed | ||
|
|
44f36d57e6 | ||
|
|
7ab8f61974 | ||
|
|
4bba3268d5 | ||
|
|
5f76e4c1ed | ||
|
|
b75a033787 | ||
|
|
92c4f20089 | ||
|
|
acfd372808 | ||
|
|
6054483dc7 | ||
|
|
25931bc1e6 | ||
|
|
9250c58013 | ||
|
|
4f226ab36a | ||
|
|
33e28fb96b | ||
|
|
206b9cea0d | ||
|
|
9dcb04a1e0 | ||
|
|
08543d0c76 | ||
|
|
937e6cb91e | ||
|
|
6c43be767c | ||
|
|
81b64ea0b5 | ||
|
|
ea0e23c172 | ||
|
|
4d07aa315b | ||
|
|
2e298b25e4 | ||
|
|
c38927da47 | ||
|
|
25607c04a7 | ||
|
|
cbd5be1b82 | ||
|
|
924b8469cb | ||
|
|
f24d93d4e4 | ||
|
|
65baa71b58 | ||
|
|
b8fa712847 | ||
|
|
095b067857 | ||
|
|
87c4586d61 | ||
|
|
b17254925d | ||
|
|
cf2c4f44a2 | ||
|
|
2bc55ff428 | ||
|
|
ee5769f31f | ||
|
|
3a8517b06f | ||
|
|
0363d3c32e | ||
|
|
a582c4cdb6 | ||
|
|
a43b6b0323 | ||
|
|
84a143a605 | ||
|
|
114438e669 | ||
|
|
50bde9976b | ||
|
|
18ea116827 | ||
|
|
0ab0687a3a | ||
|
|
72f85ad90f | ||
|
|
fb4e07f7a8 | ||
|
|
6e0b539e9c | ||
|
|
83b2c899f5 | ||
|
|
eb7ca20379 | ||
|
|
30d3ccd419 | ||
|
|
fb8fb7fed0 | ||
|
|
1abd239b9d | ||
|
|
9f1c8b2f8f | ||
|
|
c169423051 | ||
|
|
fdc6f32392 | ||
|
|
ea984cfb95 | ||
|
|
e7cdb2ebe5 | ||
|
|
4dae8edb76 | ||
|
|
a3e01b8884 | ||
|
|
6d33a2b0bb | ||
|
|
423be0d5e6 | ||
|
|
f7d38a1b9c | ||
|
|
45b27b0194 | ||
|
|
2a921c2c25 | ||
|
|
4c759cde1f | ||
|
|
c3984c89f7 | ||
|
|
96dfbc882d | ||
|
|
d3883e54b8 | ||
|
|
beaff53a79 | ||
|
|
b9b308f2fe | ||
|
|
a7bfd792f7 | ||
|
|
06fd9e3771 | ||
|
|
fb719e3d0b | ||
|
|
9f24cdf74c | ||
|
|
d7471c4f87 | ||
|
|
5d2cb48f46 | ||
|
|
597f12c44a | ||
|
|
9f674382d5 | ||
|
|
6830a65923 | ||
|
|
0d9c3fe70b | ||
|
|
2e38ac7504 | ||
|
|
f208d7920c | ||
|
|
ecb4a6173d | ||
|
|
37a66fa5b6 | ||
|
|
f9e6bc2aec | ||
|
|
81a0240491 | ||
|
|
b4d31b492c | ||
|
|
32df924d02 | ||
|
|
c60a65bc93 | ||
|
|
68b3ef0734 | ||
|
|
4222251d6f | ||
|
|
c6e912f9e2 | ||
|
|
1df5c97144 | ||
|
|
b840a0f500 | ||
|
|
9f40bbba29 | ||
|
|
0086e1d7ca | ||
|
|
4732de71c6 | ||
|
|
8db9415f2a | ||
|
|
dd19d73db4 | ||
|
|
91450c7a95 | ||
|
|
1d20df627d | ||
|
|
4a10b1961c | ||
|
|
100cbc5f3f | ||
|
|
e0c6e819c2 | ||
|
|
9025cd9b72 | ||
|
|
2b891f5eb3 | ||
|
|
01bde8ff94 | ||
|
|
eed0e2e431 | ||
|
|
bda3bc4c8d | ||
|
|
93f3c31807 | ||
|
|
3aeb557196 | ||
|
|
8c7ebc02a0 | ||
|
|
1152e47b52 | ||
|
|
32a28d0d9c | ||
|
|
d6daad29fc | ||
|
|
4664ce2c35 | ||
|
|
171456c683 | ||
|
|
2c73fd6fbf | ||
|
|
0ee860a011 | ||
|
|
5127943673 | ||
|
|
3ee9656250 | ||
|
|
c0f63ee100 | ||
|
|
8fd720c3e3 | ||
|
|
4f5d0756c2 | ||
|
|
64e6e3aca9 | ||
|
|
8174300429 | ||
|
|
a453b06168 | ||
|
|
103036c546 | ||
|
|
ac9a4c839f | ||
|
|
3d2ddd15f8 | ||
|
|
ea4ab22017 | ||
|
|
d58e0497cc | ||
|
|
8c53621c24 | ||
|
|
514baf3bf7 | ||
|
|
420151dbd9 | ||
|
|
156b28c771 | ||
|
|
ad801851a2 | ||
|
|
b647b753e0 | ||
|
|
48b855c581 | ||
|
|
c830d30553 | ||
|
|
0650182289 | ||
|
|
3e20c442de | ||
|
|
af87369cb3 | ||
|
|
edea73b1f8 | ||
|
|
893d7be5bf | ||
|
|
c5b77e1b49 | ||
|
|
a5e5bab74b | ||
|
|
8f96b8908e | ||
|
|
f3a6dd139c | ||
|
|
1dba0d4830 | ||
|
|
da85400e57 | ||
|
|
7f38caefd0 | ||
|
|
937594c130 | ||
|
|
3e7672edca | ||
|
|
af10eb8346 | ||
|
|
098aba47c3 | ||
|
|
c67fc5693a | ||
|
|
6b5c6af613 | ||
|
|
3ccc36b3b7 | ||
|
|
8e93ac9925 | ||
|
|
e7828bb911 | ||
|
|
e255f0590b | ||
|
|
4615631d83 | ||
|
|
e708f9542f | ||
|
|
6bfbcdbfdb | ||
|
|
645b254173 | ||
|
|
fdc61f3ab2 | ||
|
|
a991d3b56b | ||
|
|
26a1a0a3bc | ||
|
|
73bc3a9853 | ||
|
|
9cb325ee6f | ||
|
|
9e1d038a65 | ||
|
|
7e5fe1d813 | ||
|
|
97dff151ae | ||
|
|
18681875e3 | ||
|
|
9b0a2714f0 | ||
|
|
a84ce21aec | ||
|
|
1fc1559d15 | ||
|
|
de70b02c2f | ||
|
|
6453b5b70e | ||
|
|
61b49ea2e3 | ||
|
|
21ed9480d7 | ||
|
|
09e83ad742 | ||
|
|
3360072f84 | ||
|
|
0ba59d80b6 | ||
|
|
d416a9b818 | ||
|
|
de1993a1fd | ||
|
|
307c71b66a | ||
|
|
b41ae80399 | ||
|
|
bbf9ba6d8d | ||
|
|
9bcd5f3c0a | ||
|
|
533aebe336 | ||
|
|
5f8fcef688 | ||
|
|
f37d67ff5e | ||
|
|
9bda22e702 | ||
|
|
23ac7f56fa | ||
|
|
4c4aa502d4 | ||
|
|
20bdf3a5b1 | ||
|
|
6d5b27715a | ||
|
|
da108a9327 | ||
|
|
e6432b1262 | ||
|
|
99bc4f451a | ||
|
|
79b43270a7 | ||
|
|
3d33e65a35 | ||
|
|
5ab562f695 | ||
|
|
3cb278c35c | ||
|
|
c59827334c | ||
|
|
2d6bbf341d | ||
|
|
2f62128297 | ||
|
|
ed21e75235 | ||
|
|
87d2c9c05c | ||
|
|
df999ed1e1 | ||
|
|
154de2aee3 | ||
|
|
f808b8e930 | ||
|
|
5b2e57aa2f | ||
|
|
960364d953 | ||
|
|
0b9793ccd0 | ||
|
|
fff298523d | ||
|
|
f295fbe0b2 | ||
|
|
e81b6fbc6e | ||
|
|
4dc1388ac7 | ||
|
|
1b69d6d658 | ||
|
|
f64a50f319 | ||
|
|
f299caf612 | ||
|
|
f76141a704 | ||
|
|
a3049d6433 | ||
|
|
ee353847be | ||
|
|
33b2fbb5ef | ||
|
|
7d84615545 | ||
|
|
b42113119a | ||
|
|
722944f307 | ||
|
|
e038c26963 | ||
|
|
56b9388702 | ||
|
|
0e438f6d5c | ||
|
|
9f1eb695b4 | ||
|
|
9fef5d1050 | ||
|
|
0bb7f77a8f | ||
|
|
9e4e562cfb | ||
|
|
92ec446cb9 | ||
|
|
9097da0284 | ||
|
|
eedeb009ec | ||
|
|
d8bc6abcf0 | ||
|
|
2293e3d105 | ||
|
|
550b3056fd | ||
|
|
575f0e5f92 | ||
|
|
1ba5e8052e | ||
|
|
6f5abeff2e | ||
|
|
7cbf6b131b | ||
|
|
a461298109 | ||
|
|
90c3a74b2a | ||
|
|
87373be960 | ||
|
|
85d9672e47 | ||
|
|
e0ae527190 | ||
|
|
7fb1bec84a | ||
|
|
1f308fb2b4 | ||
|
|
e2d36d493f | ||
|
|
7c43594075 | ||
|
|
e4827025be | ||
|
|
00798ca8cc | ||
|
|
e84cb3c3c2 | ||
|
|
78b9cecb52 | ||
|
|
93c54fe6f6 | ||
|
|
5f97d0fbbc | ||
|
|
dc01a8edd4 | ||
|
|
23cc2bfb8c | ||
|
|
9e379835c4 | ||
|
|
8ccbd216c6 | ||
|
|
90f4da29d7 | ||
|
|
54dbd5bbc8 | ||
|
|
849b8ec469 | ||
|
|
84e18f72ae | ||
|
|
633b98ef28 | ||
|
|
2a34a72bff | ||
|
|
85374c5ba2 | ||
|
|
24bae46e42 | ||
|
|
7585d4606e | ||
|
|
94bff1df66 | ||
|
|
2e60d20a76 | ||
|
|
ce59260ee9 | ||
|
|
387ebccf36 | ||
|
|
2f618af086 | ||
|
|
0ac33d22f7 | ||
|
|
c7bd5ac77d | ||
|
|
941c067765 | ||
|
|
83f3f55280 | ||
|
|
839e023ed8 | ||
|
|
b2beb2c2da | ||
|
|
48ad370a19 | ||
|
|
c36f94a322 | ||
|
|
6493bbb7e7 | ||
|
|
2e05a2b8c4 | ||
|
|
fc2c67e61c | ||
|
|
9c3e9fcdad | ||
|
|
1a4db21fe4 | ||
|
|
d96a52541f | ||
|
|
e7ac4c1ab3 | ||
|
|
ecd8505218 | ||
|
|
1fa1c3f9db | ||
|
|
91df741926 | ||
|
|
2a431cab03 | ||
|
|
9fdab3ced8 | ||
|
|
6e15e75391 | ||
|
|
1c2a1838fc | ||
|
|
bfd730aa4c | ||
|
|
e3c6a86b1e | ||
|
|
bbaeb917ff | ||
|
|
20f1e49b73 | ||
|
|
292656d899 | ||
|
|
05b36b484e | ||
|
|
be3016b8d5 | ||
|
|
5cf43d76bf | ||
|
|
6f05e810d9 | ||
|
|
947d2697cf | ||
|
|
449ddae628 | ||
|
|
6b90885d4f | ||
|
|
bd6c37adb6 | ||
|
|
59235276ac | ||
|
|
e5ce3fc51b | ||
|
|
9f97511356 | ||
|
|
ef0aac432c | ||
|
|
7928d83b02 | ||
|
|
3e91ec07e4 | ||
|
|
d680a9e3fb | ||
|
|
6086851fc1 | ||
|
|
61726df20c | ||
|
|
1601a657d4 | ||
|
|
50b14f696c | ||
|
|
c239baf801 | ||
|
|
18638859e6 | ||
|
|
224b16b247 | ||
|
|
d9d97969a3 | ||
|
|
897da4ee36 | ||
|
|
90f9f43335 | ||
|
|
0e1dee828a | ||
|
|
cbdc1f0753 | ||
|
|
7e306336d0 | ||
|
|
e7def4c211 | ||
|
|
19e1afbd1c | ||
|
|
fee32054e6 | ||
|
|
3ec2737d54 | ||
|
|
9754fdd995 | ||
|
|
ef20b9ff7a | ||
|
|
275611fbaa | ||
|
|
a070159cc5 | ||
|
|
20f9683ae0 | ||
|
|
dce384668b | ||
|
|
fdcd21e74b | ||
|
|
67b4fa313e | ||
|
|
5dff74109e | ||
|
|
20d970a0e2 | ||
|
|
94734ad377 | ||
|
|
72ccfda5b2 | ||
|
|
14ad6a5972 | ||
|
|
9e66b5a9b1 | ||
|
|
f782cf375a | ||
|
|
3317916111 | ||
|
|
f367273549 | ||
|
|
91ef9b2fa9 | ||
|
|
579463933b | ||
|
|
989c5c1436 | ||
|
|
3113932151 | ||
|
|
003ec5d356 | ||
|
|
125a970d71 | ||
|
|
89c0b2a6d8 | ||
|
|
31e379c300 | ||
|
|
843953379c | ||
|
|
2a90c1ca7e | ||
|
|
f91d66448a | ||
|
|
59bb1777be | ||
|
|
c5f3c550a6 | ||
|
|
1809f741cb | ||
|
|
9adfff5c1a | ||
|
|
8008b595d3 | ||
|
|
21bed0d21a | ||
|
|
4b1f5ec7c2 | ||
|
|
ab9439519a | ||
|
|
abeb9d64a3 | ||
|
|
fdb7ffa864 | ||
|
|
46845fd3e8 | ||
|
|
c53ca6ebc0 | ||
|
|
f04a3a2cfa | ||
|
|
364a53577e | ||
|
|
1b1997bf2d | ||
|
|
34f9adb1c9 | ||
|
|
2e7d468b90 | ||
|
|
86a717c80c | ||
|
|
76a3eb393c | ||
|
|
5f0cc969a0 | ||
|
|
755c1458f0 | ||
|
|
8795d733ec | ||
|
|
28f61c8b3a | ||
|
|
9abcc7b909 | ||
|
|
2c35f1c8fd | ||
|
|
136188259e | ||
|
|
02179b1218 | ||
|
|
1e350de136 | ||
|
|
9aeda4c5bd | ||
|
|
8eb30c353a | ||
|
|
ccfdf7e039 | ||
|
|
c44a78a2e6 | ||
|
|
b6685bf806 | ||
|
|
269d690e71 | ||
|
|
4df268f10e | ||
|
|
19b3f01477 | ||
|
|
86811f4765 | ||
|
|
dd0352d93b | ||
|
|
95ce05da40 | ||
|
|
30ec18d938 | ||
|
|
9d495ab2b5 | ||
|
|
9174de47a9 | ||
|
|
d857faf18e | ||
|
|
d5c8ba1690 | ||
|
|
9bb9b4829d | ||
|
|
e25c297c3c | ||
|
|
4de876f259 | ||
|
|
b9073961f7 | ||
|
|
c5d53cf81c | ||
|
|
a7a79d569a | ||
|
|
6165f53fcd | ||
|
|
4122cac66b | ||
|
|
a1dcebe4f4 | ||
|
|
6cbb23a819 | ||
|
|
5c57a31184 | ||
|
|
7b2c42aa75 | ||
|
|
1ed8d3938e | ||
|
|
b24984deb3 | ||
|
|
5574460d25 | ||
|
|
eabd9f5e60 | ||
|
|
d4609682af | ||
|
|
634415f79e | ||
|
|
4ba830fc31 | ||
|
|
3022a46039 | ||
|
|
d9a868ff60 | ||
|
|
c890a0c133 | ||
|
|
9ec934a94a | ||
|
|
5e606a964b | ||
|
|
d88034434c | ||
|
|
233fd96994 | ||
|
|
776d908703 | ||
|
|
444b15889f | ||
|
|
957450582f | ||
|
|
d1b29336b1 | ||
|
|
6d2d3669f3 | ||
|
|
1387654cc8 | ||
|
|
10eb218fb0 | ||
|
|
bfb2b30de6 | ||
|
|
426d4d72c6 | ||
|
|
cce29ba38c | ||
|
|
fa5eb62464 | ||
|
|
ed2e276b3a | ||
|
|
12a020aa62 | ||
|
|
b969101b33 | ||
|
|
86a742f635 | ||
|
|
9468f7f6d6 | ||
|
|
628a3f5cca | ||
|
|
e815e97440 | ||
|
|
0b48a4f879 | ||
|
|
0e7409c7ff | ||
|
|
393ca2a290 | ||
|
|
00ef081fcf | ||
|
|
ad1d48e07b | ||
|
|
ac98aae160 | ||
|
|
c1267398a2 | ||
|
|
8c3a2bb63e | ||
|
|
923fc9087c | ||
|
|
83511fecc0 | ||
|
|
ed0552f214 | ||
|
|
dabeaec461 | ||
|
|
5cf83a7212 | ||
|
|
d4ed2fffe4 | ||
|
|
7808eff0a9 | ||
|
|
da57dd13c5 | ||
|
|
f1826ea389 | ||
|
|
c884e5000e | ||
|
|
1ccac01cee | ||
|
|
50a5d3756f | ||
|
|
ca86726f9f | ||
|
|
6b5317e7cc | ||
|
|
2a1d28ea3a | ||
|
|
0e0ff51582 | ||
|
|
cd700aaf6e | ||
|
|
188ec1e258 | ||
|
|
d01fb265d6 | ||
|
|
db688e3ec1 | ||
|
|
e767bbb41f | ||
|
|
2b599df57a | ||
|
|
5baa10a6b6 | ||
|
|
0533b87b1a | ||
|
|
3e1a389629 | ||
|
|
7504cd1a1a | ||
|
|
482dc0eff4 | ||
|
|
fc34d02427 | ||
|
|
5ce5fbcba0 | ||
|
|
31d2311537 | ||
|
|
37e6207396 | ||
|
|
927a2dc849 | ||
|
|
ce9f9594da | ||
|
|
f0bf37b6cb | ||
|
|
2f0b35a105 | ||
|
|
7a9ed81f5f | ||
|
|
12e7d570a2 | ||
|
|
bb7934bf04 | ||
|
|
fb3c718963 | ||
|
|
231fc607f9 | ||
|
|
9594a3aa45 | ||
|
|
162fcab347 | ||
|
|
0c8bdfd7cd | ||
|
|
5e4dc71907 | ||
|
|
3e4433f715 | ||
|
|
29062e629f | ||
|
|
47f7272ba1 | ||
|
|
bf6f3f613d | ||
|
|
0c9a643216 | ||
|
|
fa2d843403 | ||
|
|
1dc5312f00 | ||
|
|
73444f2957 | ||
|
|
a18a6b8db8 | ||
|
|
bf56591fb8 | ||
|
|
5ea428a30d | ||
|
|
af524c4d65 | ||
|
|
2bc9f35052 | ||
|
|
55a0c5068f | ||
|
|
8128b15e41 | ||
|
|
8081b0e033 | ||
|
|
61cecbb337 | ||
|
|
aee1309c91 | ||
|
|
710c1df413 | ||
|
|
0f165a95a8 | ||
|
|
581f04c80b | ||
|
|
511be4acc6 | ||
|
|
d77b29f1d7 | ||
|
|
092a4d9a7e | ||
|
|
b3cab3ce31 | ||
|
|
e5279b0e2e | ||
|
|
9ff337aa3b | ||
|
|
441facc6e0 | ||
|
|
998d6cdfc4 | ||
|
|
ddc10b2d0c | ||
|
|
4f6f651b7d | ||
|
|
68c7667a20 | ||
|
|
0b62d71e70 | ||
|
|
be5780ef90 | ||
|
|
e5c52796c3 | ||
|
|
c5e36f8e3c | ||
|
|
5a85c4b91b | ||
|
|
0201072c1b | ||
|
|
aa029ed991 | ||
|
|
0777e896f1 | ||
|
|
7f90231b8f | ||
|
|
cbe63bbabe | ||
|
|
de1deaf0bd | ||
|
|
e00a97944a | ||
|
|
a65f84db38 | ||
|
|
8c8ecec3e9 | ||
|
|
b77864931b | ||
|
|
e60a84d0ed | ||
|
|
f025277147 | ||
|
|
1e00d0b926 | ||
|
|
29b1455f36 | ||
|
|
0162c116da | ||
|
|
58fe1c2d2a | ||
|
|
4363b8b32d | ||
|
|
cfac8435a7 | ||
|
|
35f26ff855 | ||
|
|
f66fc01620 | ||
|
|
082a2dde35 | ||
|
|
814ab77538 | ||
|
|
8eefb092c8 | ||
|
|
55e7f0486a | ||
|
|
88ac2da7c2 | ||
|
|
27510a6e9e | ||
|
|
7fda6418e1 | ||
|
|
45bd0edae5 | ||
|
|
3d733a16e9 | ||
|
|
fe623afaad | ||
|
|
b840a980e3 | ||
|
|
2ec98eb048 | ||
|
|
253cd3b66b | ||
|
|
920120d05a | ||
|
|
4ba058986e | ||
|
|
03b7255ddd | ||
|
|
2de7f8b224 | ||
|
|
bbf2f1d571 | ||
|
|
9cdd5e99a4 | ||
|
|
897ed7125b | ||
|
|
459d259185 | ||
|
|
aac6336e49 | ||
|
|
fc1155f974 | ||
|
|
6a09fa23d0 | ||
|
|
142a0f8a83 | ||
|
|
d1dec41f76 | ||
|
|
69a165db86 | ||
|
|
dffb33cecf | ||
|
|
e7917c16c9 | ||
|
|
e05b7f0b76 | ||
|
|
aeea70f95f | ||
|
|
ded40babb5 | ||
|
|
e355f69401 | ||
|
|
c2b1327deb | ||
|
|
f7ba7444e8 | ||
|
|
aafeebd0c8 | ||
|
|
6b0d47b364 | ||
|
|
d9e790e7dc | ||
|
|
51b5cdd430 | ||
|
|
aced7b5b00 | ||
|
|
0475594cb2 | ||
|
|
04518e9e80 | ||
|
|
a57947c513 | ||
|
|
372e81a842 | ||
|
|
41f531ceaf | ||
|
|
b46d46667f | ||
|
|
226671b550 | ||
|
|
916cfa6b83 | ||
|
|
49263b5314 | ||
|
|
95a21c8fd7 | ||
|
|
57166b400c | ||
|
|
79660f2eb1 | ||
|
|
3ea9068e18 | ||
|
|
e4c672bdbb | ||
|
|
791a78ad1f | ||
|
|
6da90b34fe | ||
|
|
43769b5bb3 | ||
|
|
f98eb5808b | ||
|
|
3525cabf48 | ||
|
|
54a76342f5 | ||
|
|
154a65fc31 | ||
|
|
bd7a46f514 | ||
|
|
79a307bca2 | ||
|
|
38f42a0fa2 | ||
|
|
b4cdfcb506 | ||
|
|
d3cef72f26 | ||
|
|
ef151888fb | ||
|
|
ba15bbfe33 | ||
|
|
3bdfae61a2 | ||
|
|
4404126501 | ||
|
|
5c87c6a435 | ||
|
|
adeb372a66 | ||
|
|
c0d7c6693f | ||
|
|
3ec4670478 | ||
|
|
f842712551 | ||
|
|
9f01625e23 | ||
|
|
7f091e7019 | ||
|
|
4f07805d0a | ||
|
|
a7d1a9cfcb | ||
|
|
48c83aa9d0 | ||
|
|
c797c1750c | ||
|
|
c6bdc810ab | ||
|
|
a8135dec1e | ||
|
|
2fdb5fd6ce | ||
|
|
7f42096d0f | ||
|
|
e2c813df4d | ||
|
|
a2f70a3751 | ||
|
|
286fa93a8d | ||
|
|
557d86aa79 | ||
|
|
8e68d5e2d5 | ||
|
|
1a16da38d5 | ||
|
|
cbd3d5e3a5 | ||
|
|
78fbed8c3e | ||
|
|
f267ca1f3a | ||
|
|
a6eb824950 | ||
|
|
dcd1527a11 | ||
|
|
f8a92d1eed | ||
|
|
e55e468754 | ||
|
|
ff2aa20565 | ||
|
|
90b5691183 | ||
|
|
5af0d33164 | ||
|
|
e5072c6b12 | ||
|
|
90cf7f012c | ||
|
|
484516da51 | ||
|
|
5abe22d1a5 | ||
|
|
f6b304250b | ||
|
|
36526700a9 | ||
|
|
32294978a3 | ||
|
|
a0e931005b | ||
|
|
9c7485331a | ||
|
|
99d9cf500b | ||
|
|
4f62da0f0d | ||
|
|
b4bcc60657 | ||
|
|
5139bd42f6 | ||
|
|
cf7a271f90 | ||
|
|
74cad1612f | ||
|
|
73e22c115c | ||
|
|
9be0d6b53d | ||
|
|
bbf6d5f2f5 | ||
|
|
c4861340e9 | ||
|
|
5996c3824c | ||
|
|
c172fb3b32 | ||
|
|
03a0d11c4d | ||
|
|
156e0187bf | ||
|
|
fcaaa7b4c2 | ||
|
|
2f098325f8 | ||
|
|
9dc30fbd2a | ||
|
|
024d268d8c | ||
|
|
eaa737fecd | ||
|
|
845ad0be39 | ||
|
|
2259ce4cdf | ||
|
|
34f9b2a8f7 | ||
|
|
d37dcc636f | ||
|
|
804a1e69f2 | ||
|
|
f7b1222073 | ||
|
|
4fd4fbc255 | ||
|
|
8393c5f016 | ||
|
|
5ff341206e | ||
|
|
da59afe798 | ||
|
|
6270ed2f8a | ||
|
|
80e77b5e6d | ||
|
|
58c7d4474c | ||
|
|
3af964304f | ||
|
|
4289324c4b | ||
|
|
9f3c817491 | ||
|
|
a9cf0ca25f | ||
|
|
72a5612a29 | ||
|
|
d7f2153631 | ||
|
|
26b07ccafc | ||
|
|
1205fa68df | ||
|
|
f5be0fb218 | ||
|
|
88fc38c8f0 | ||
|
|
545de7a3a1 | ||
|
|
6ba2b2b384 | ||
|
|
d5ccc32b4d | ||
|
|
e719a9ef6f | ||
|
|
a02d38072a | ||
|
|
f2cd610750 | ||
|
|
db34044c7f | ||
|
|
036edd6206 | ||
|
|
f40ed8bad7 | ||
|
|
41f50057f1 | ||
|
|
c62e53807f | ||
|
|
10d7a35841 | ||
|
|
6b4105ffe6 | ||
|
|
2713445e91 | ||
|
|
1984aabc95 | ||
|
|
f4c4ca64a8 | ||
|
|
2a02c4084a | ||
|
|
e242b2820c | ||
|
|
6467b8d903 | ||
|
|
3e2b6a1821 | ||
|
|
4d009daaa0 | ||
|
|
d4a14fcb3d | ||
|
|
49b79fa02d | ||
|
|
c957edbe75 | ||
|
|
33ae2be52e | ||
|
|
496c1db974 | ||
|
|
f381274278 | ||
|
|
398339218e | ||
|
|
4dda424f74 | ||
|
|
f403c1f18b | ||
|
|
ff5d94a7a4 | ||
|
|
a15fc009da | ||
|
|
6c4390c848 | ||
|
|
a3188b44f0 | ||
|
|
aaa72ddbfc | ||
|
|
bcf3a3ab93 | ||
|
|
5feebd300e | ||
|
|
aec23e5f79 | ||
|
|
52a466b8af | ||
|
|
baa32218b0 | ||
|
|
fd0b05943d | ||
|
|
2e0145fb95 | ||
|
|
c894ea4ea2 | ||
|
|
88278dee74 | ||
|
|
d0fadd992f | ||
|
|
eb45ce0e8a | ||
|
|
194b700592 | ||
|
|
5454c2a7f1 | ||
|
|
a6568626a5 | ||
|
|
59943acffe | ||
|
|
d4e7654ed0 | ||
|
|
68b458ece9 | ||
|
|
1119ad3a2f | ||
|
|
29e68e9d79 | ||
|
|
c1fe2ec5ae | ||
|
|
81cacd9f15 | ||
|
|
6def0ab5f1 | ||
|
|
d20627585a | ||
|
|
2bcb60fe56 | ||
|
|
0f83379dc0 | ||
|
|
ca6d5fd05c | ||
|
|
b9e21e2367 | ||
|
|
665b768cef | ||
|
|
b272b967e2 | ||
|
|
22c16a8b71 | ||
|
|
f924aa18f2 | ||
|
|
72c446f160 | ||
|
|
2028b1b517 | ||
|
|
72a82cc0ac | ||
|
|
eef35883b7 | ||
|
|
8028e07815 | ||
|
|
3fc6569d46 | ||
|
|
2303d0fd09 | ||
|
|
9a007c30d4 | ||
|
|
8a545a0d04 | ||
|
|
0993e44b4f | ||
|
|
d634b502cf | ||
|
|
53fc7eaf03 | ||
|
|
3c42c5407c | ||
|
|
9d9a8ff735 | ||
|
|
abed230cdb | ||
|
|
e9879cd07b | ||
|
|
84c51f933c | ||
|
|
977c43fffb | ||
|
|
f99a19b6ca | ||
|
|
5a7a88b843 | ||
|
|
0ffdf2bba9 | ||
|
|
38ed870ffe | ||
|
|
1e4ed404c5 | ||
|
|
642920585f | ||
|
|
af07eb115a | ||
|
|
66371f9920 | ||
|
|
aabe0677c0 | ||
|
|
0fa65ebd4d | ||
|
|
27fddd2c35 | ||
|
|
fced1113d3 | ||
|
|
4d050c34cb | ||
|
|
a8c28714cd | ||
|
|
eabfd803c9 | ||
|
|
07b764ead6 | ||
|
|
8bad5d61fd | ||
|
|
9f42a75ef6 | ||
|
|
ddbfdb0799 | ||
|
|
3b07844548 | ||
|
|
85288d7b61 | ||
|
|
8174a2f27b | ||
|
|
e3ca0513a0 | ||
|
|
95a01f9002 | ||
|
|
52551cb771 | ||
|
|
4dfb834f7c | ||
|
|
c35e38c5e9 | ||
|
|
48734bb3b5 | ||
|
|
4e9f22c602 | ||
|
|
f88bed7a30 | ||
|
|
ccd02552dd | ||
|
|
4b1f9e50f2 | ||
|
|
0b50010436 | ||
|
|
d773103730 | ||
|
|
c7e3eb9b3f | ||
|
|
f15feb2ac6 | ||
|
|
2f1ed9a34b | ||
|
|
bb8234c2f1 | ||
|
|
bacd2a8c79 | ||
|
|
103a829eac | ||
|
|
0dcecfa526 | ||
|
|
bcd541d65f | ||
|
|
3608775306 | ||
|
|
8181d41bb5 | ||
|
|
a996e61a2e | ||
|
|
8a19a049b2 | ||
|
|
c742137dc8 | ||
|
|
9dc9aff016 | ||
|
|
c6582dbe37 | ||
|
|
709a3e75cf | ||
|
|
cb82c6e3e0 | ||
|
|
d6441f4397 | ||
|
|
08893f03a5 | ||
|
|
4be3826dd5 | ||
|
|
a21cf67a6c | ||
|
|
fe03c39241 | ||
|
|
6e78eca7c8 | ||
|
|
5d3dae1492 | ||
|
|
061565865c | ||
|
|
b639e18d39 | ||
|
|
2b54d3397c | ||
|
|
ff763e4005 | ||
|
|
8e72bbaa9d | ||
|
|
4b37932ba1 | ||
|
|
d1bfb6bfb7 | ||
|
|
35f3d2ff90 | ||
|
|
a60cb7dbaa | ||
|
|
cca4e1a080 | ||
|
|
c04cc62ebf | ||
|
|
8158e952b9 | ||
|
|
b717efb577 | ||
|
|
3dbc707820 | ||
|
|
5a2dde814d | ||
|
|
4fc5a52850 | ||
|
|
d005aa139e | ||
|
|
5efdd391eb | ||
|
|
adc4d0194f | ||
|
|
1912439526 | ||
|
|
800810a181 | ||
|
|
e80f8e8c09 | ||
|
|
1fdfa2ecfd | ||
|
|
51dcfc06dc | ||
|
|
8edc0c2afc | ||
|
|
ebc3a3ac74 | ||
|
|
5cd6995fb5 | ||
|
|
ed79abed76 | ||
|
|
c2bd79131a | ||
|
|
511f6555c9 | ||
|
|
049fcf1ac5 | ||
|
|
e674c73ee6 | ||
|
|
90f8c1fd51 | ||
|
|
729aa017d3 | ||
|
|
efe45cddbe | ||
|
|
6fe6393acb | ||
|
|
b98d13effb | ||
|
|
299d26dab7 | ||
|
|
643626d546 | ||
|
|
e1a8bf0240 | ||
|
|
d54f38caf2 | ||
|
|
d981ff2c8d | ||
|
|
bece6ddcc2 | ||
|
|
f4aacaa74c | ||
|
|
66e2f59c7b | ||
|
|
af00c78e21 | ||
|
|
c7bd9ccd85 | ||
|
|
e44aa503f0 | ||
|
|
12929e8cf0 | ||
|
|
7ac24b10b9 | ||
|
|
d7c1e58217 | ||
|
|
b619e88f54 | ||
|
|
1c72a35ddb | ||
|
|
460bf43822 | ||
|
|
31fa5e605b | ||
|
|
c0ce2a6a97 | ||
|
|
f90f64b5c1 | ||
|
|
96bda2af8e | ||
|
|
a97603d003 | ||
|
|
77892be79c | ||
|
|
3e29368cbc | ||
|
|
b91874cedc | ||
|
|
acd18ce243 | ||
|
|
6c9d2abc75 | ||
|
|
e277059339 | ||
|
|
a3b5d3c8b3 | ||
|
|
bb0548b3b0 | ||
|
|
bb84e33d99 | ||
|
|
b2ac4eb29b | ||
|
|
25554bc331 | ||
|
|
a018260fe9 | ||
|
|
9a2cdc299f | ||
|
|
e41452afeb | ||
|
|
58296a95f1 | ||
|
|
ddb61adcc9 | ||
|
|
790cdadace | ||
|
|
75ec4d6510 | ||
|
|
a7649c250f | ||
|
|
57ae0bfedf | ||
|
|
993f58900d | ||
|
|
876e7b99d4 | ||
|
|
e3e4445dc1 | ||
|
|
2d4d9627a2 | ||
|
|
762e9973ff | ||
|
|
b04e2d14ef | ||
|
|
456b500902 | ||
|
|
0b72cf1ed2 | ||
|
|
4639844208 | ||
|
|
77c33e7750 | ||
|
|
a4130263bd | ||
|
|
0ffc17e481 | ||
|
|
62d792fbdc | ||
|
|
7aefd496f1 | ||
|
|
70a2281823 | ||
|
|
c077f22fb4 | ||
|
|
b01a74a9d7 | ||
|
|
66643fa5c7 | ||
|
|
7f12251fbb | ||
|
|
41fd735d4b | ||
|
|
4941c43429 | ||
|
|
f5e9b12b60 | ||
|
|
6c081b4e7c | ||
|
|
769076f2ae | ||
|
|
7c1d4d1903 | ||
|
|
c3941698cd | ||
|
|
47e76de56a | ||
|
|
519ff96bcd | ||
|
|
22440a6fb2 | ||
|
|
164ea75fa6 | ||
|
|
4c8797c9ac | ||
|
|
433d5511e1 | ||
|
|
674b4d013d | ||
|
|
cd0a08896c | ||
|
|
fc0e723805 | ||
|
|
f5ad5c1553 | ||
|
|
cda7af7ca2 | ||
|
|
d199e0b119 | ||
|
|
b121787336 | ||
|
|
e9bc9e6bd7 | ||
|
|
55ed5531b5 | ||
|
|
fd304d763a | ||
|
|
60d4cd5996 | ||
|
|
16517e6760 | ||
|
|
d2f292b3ad | ||
|
|
d4bc0aec5d | ||
|
|
d0533106a8 | ||
|
|
28f1026de8 | ||
|
|
85f22c9f09 | ||
|
|
0f707bad11 | ||
|
|
ede9a990f4 | ||
|
|
4eb0f51e42 | ||
|
|
d9aeb2773e | ||
|
|
c5fd7dd554 | ||
|
|
5acf7a6aaa | ||
|
|
5092e30605 | ||
|
|
41bfa93058 | ||
|
|
056b92bd4c | ||
|
|
4a5208512b | ||
|
|
c88f3eb2a4 | ||
|
|
943636c3e1 | ||
|
|
0a60ef26bd | ||
|
|
9d5ed350a7 | ||
|
|
ca52f070ae | ||
|
|
9e9858b81c | ||
|
|
ea8cd283eb | ||
|
|
058b2bec22 | ||
|
|
5ea605d8de | ||
|
|
7f0dd15bab | ||
|
|
a938f4cfe1 | ||
|
|
28ad393b00 | ||
|
|
f3b834d536 | ||
|
|
692d737a82 | ||
|
|
d5897b9a5d | ||
|
|
7b780efb42 | ||
|
|
4e09d27c6f | ||
|
|
e1d3a8a6e9 | ||
|
|
235ac72a06 | ||
|
|
dd06653e53 | ||
|
|
7eee3ceb70 | ||
|
|
19b89a0e19 | ||
|
|
a0aefb3d3f | ||
|
|
20fb9ea351 | ||
|
|
ee6f01918c | ||
|
|
71e25058c1 | ||
|
|
35bcc463e5 | ||
|
|
5b8a26f1d1 | ||
|
|
cc340d9cdc | ||
|
|
786ea39ac4 | ||
|
|
df57eb3824 | ||
|
|
3301bad391 | ||
|
|
f5d75b099b | ||
|
|
7e04c5e277 | ||
|
|
33a182674a | ||
|
|
14a790891f | ||
|
|
d1daf6531a | ||
|
|
e89b40e9c9 | ||
|
|
afb651821b | ||
|
|
92cf98c77b | ||
|
|
60797cb25f | ||
|
|
c9319fbef5 | ||
|
|
4cb673b644 | ||
|
|
cee2ec1680 | ||
|
|
934a6d417d | ||
|
|
d6ee29f5ae | ||
|
|
c5e5dc832c | ||
|
|
ac2b546a13 | ||
|
|
d0537c7506 | ||
|
|
a0ed2ca71b | ||
|
|
4313157666 | ||
|
|
e8fa3ce478 | ||
|
|
c9d3c0bc90 | ||
|
|
94d86427ff | ||
|
|
3b0e6a2969 | ||
|
|
64bdc502ad | ||
|
|
c81e058bb0 | ||
|
|
be2b7d9725 | ||
|
|
1428c01a5f | ||
|
|
4aafeb0da2 | ||
|
|
32af5c267e | ||
|
|
ba7513fdf3 | ||
|
|
1e26b86f15 | ||
|
|
b6b96f8841 | ||
|
|
c1b602145f | ||
|
|
719b47e3aa | ||
|
|
d57a56407b | ||
|
|
3cee7b6378 | ||
|
|
1e03393b68 | ||
|
|
dde673f8d7 | ||
|
|
f7caf6f5c6 | ||
|
|
cdbe853595 | ||
|
|
3f49fc5f2c | ||
|
|
c517ff57ca | ||
|
|
ba869e5601 | ||
|
|
46d53c37fa | ||
|
|
94b28e420c | ||
|
|
9368e4db33 | ||
|
|
ae15e644b1 | ||
|
|
3a5c4b68bb | ||
|
|
a7a5365af2 | ||
|
|
6ae3a09ef3 | ||
|
|
8608a8e64c | ||
|
|
2481693cf2 | ||
|
|
1c5fda515f | ||
|
|
33defd1f9b | ||
|
|
c57e1d8def | ||
|
|
882a9ced90 | ||
|
|
e4697de175 | ||
|
|
422f4f2b41 | ||
|
|
1dc0652444 | ||
|
|
b598996497 | ||
|
|
a5a56874af | ||
|
|
af485f89cd | ||
|
|
1eb9209afe | ||
|
|
fcba907998 | ||
|
|
096ac021a9 | ||
|
|
b05ab854ae | ||
|
|
fd0f873a36 | ||
|
|
d8e61e51de | ||
|
|
bf045a0564 | ||
|
|
cec27b5bb4 | ||
|
|
a75c71299b | ||
|
|
187a7dcfdc | ||
|
|
9a07b93cb3 | ||
|
|
a4bf09e7b9 | ||
|
|
6c56271e8c | ||
|
|
a673d60963 | ||
|
|
736f370dce | ||
|
|
4a4e1b49ec | ||
|
|
0314b2cf45 | ||
|
|
f1d36b1970 | ||
|
|
b131f74533 | ||
|
|
1632bd4a18 | ||
|
|
a2d343b108 | ||
|
|
a43af44e9c | ||
|
|
876b7081d8 | ||
|
|
cb2cb15916 | ||
|
|
3510531683 | ||
|
|
744268f388 | ||
|
|
18b082955b | ||
|
|
70438b7715 | ||
|
|
53681cbdb6 | ||
|
|
e7f579b75d | ||
|
|
21c4cd7cb2 | ||
|
|
5a6404712c | ||
|
|
b332e4aaf9 | ||
|
|
cff00f43c2 | ||
|
|
1cf8d6b631 | ||
|
|
f724ece386 | ||
|
|
aba295323e | ||
|
|
c804883350 | ||
|
|
cebbc4e2b7 | ||
|
|
77f4520207 | ||
|
|
ca77392bd1 | ||
|
|
71c07ed930 | ||
|
|
20ceb493b6 | ||
|
|
e444f0cfe6 | ||
|
|
b8e28df43a | ||
|
|
2ed6c25c80 | ||
|
|
5002c95048 | ||
|
|
9888ffd8d1 | ||
|
|
aaa0b1ec3c | ||
|
|
03731c723b | ||
|
|
215a369c2b | ||
|
|
8f75480ebc | ||
|
|
fb1fd7f6f4 | ||
|
|
109b87d2a3 | ||
|
|
975b94c5f2 | ||
|
|
d92ca4d9d1 | ||
|
|
83f6c8cddb | ||
|
|
3d58025805 | ||
|
|
a8785cf719 | ||
|
|
0f0a8472d7 | ||
|
|
e48e25a548 | ||
|
|
7b403dc57f | ||
|
|
eb741b9cc9 | ||
|
|
68445e1e34 | ||
|
|
cf585ba1de | ||
|
|
298a5717bc | ||
|
|
347e8bd839 | ||
|
|
b952231df1 | ||
|
|
51be125ff9 | ||
|
|
8bc7b0ff5a | ||
|
|
4ef72ddc16 | ||
|
|
a1fd2da0f9 | ||
|
|
269ee62cd4 | ||
|
|
f45eafe342 | ||
|
|
a68755af2b | ||
|
|
e903109d9f | ||
|
|
a3bb3137ac | ||
|
|
074d8f0a26 | ||
|
|
2d28663f53 | ||
|
|
4127be0a95 | ||
|
|
03d78bbb31 | ||
|
|
6013d993b9 | ||
|
|
b7dbb29e68 | ||
|
|
37da919b7d | ||
|
|
9d4ef36e09 | ||
|
|
c0ddf3df0c | ||
|
|
74055a3884 | ||
|
|
8c1a429c44 | ||
|
|
b5bd8591e7 | ||
|
|
e6c957caaa | ||
|
|
6d75298284 | ||
|
|
9d43183704 | ||
|
|
e7677a5e8d | ||
|
|
7dfb2bfcda | ||
|
|
34445aa819 | ||
|
|
42c691a051 | ||
|
|
8b32e8a08c | ||
|
|
37ff2eaf2a | ||
|
|
27aa148e02 | ||
|
|
8f14a1cc38 | ||
|
|
3e53f28f6e | ||
|
|
96823c424d | ||
|
|
08cb903731 | ||
|
|
5c6e8b833e | ||
|
|
028e79ddda | ||
|
|
5ebfa4aaed | ||
|
|
c2af67efd3 | ||
|
|
6766dfae26 | ||
|
|
199b67a68c | ||
|
|
644488a5f3 | ||
|
|
1ace08645a | ||
|
|
636b041b9b | ||
|
|
a41f9dc036 | ||
|
|
448a05ae2c | ||
|
|
099c9a3232 | ||
|
|
2575e227a5 | ||
|
|
fa26b59b0c | ||
|
|
c23ffe4bc1 | ||
|
|
7ed5870ed9 | ||
|
|
8559be015a | ||
|
|
cb0657bdf3 | ||
|
|
15fb479e94 | ||
|
|
0378cffafc | ||
|
|
51fb224ef8 | ||
|
|
a4516b4261 | ||
|
|
a952d23781 | ||
|
|
69282617fd | ||
|
|
51a74b4799 | ||
|
|
2dcd6b22d9 | ||
|
|
857dfdeb9e | ||
|
|
70b7c24cb0 | ||
|
|
e089ee4d85 | ||
|
|
d254e0191d | ||
|
|
0ab18bd14c | ||
|
|
aaac206345 | ||
|
|
f3761a3eda | ||
|
|
aba8a3e2d4 | ||
|
|
545ce7d8bf | ||
|
|
3840a482c7 | ||
|
|
4dd70c433e | ||
|
|
abf66aa7a1 | ||
|
|
1e94425015 | ||
|
|
a69e355a06 | ||
|
|
e17d27d91d | ||
|
|
cc1860bc86 | ||
|
|
5a053fb6fc | ||
|
|
41f5e21044 | ||
|
|
3238bed9c9 | ||
|
|
4936c9a3f3 |
27
.gitignore
vendored
Normal file
27
.gitignore
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
*~
|
||||
*.o
|
||||
*.a
|
||||
*.da
|
||||
*.bb
|
||||
*.bbg
|
||||
*.prof
|
||||
.*.swp
|
||||
/autom4te.cache
|
||||
/config.log
|
||||
/config.status
|
||||
/dbclient
|
||||
/dropbear
|
||||
/dropbearconvert
|
||||
/dropbearkey
|
||||
/dropbearmulti
|
||||
/fuzzcorpus
|
||||
/fuzzer-*
|
||||
/fuzzer-*.options
|
||||
/scp
|
||||
/scp-progress
|
||||
Makefile
|
||||
config.h
|
||||
config.h.in
|
||||
configure
|
||||
default_options_guard.h
|
||||
tags
|
||||
29
.hgsigs
Normal file
29
.hgsigs
Normal file
@@ -0,0 +1,29 @@
|
||||
aa2f51a6b81d33de5e9898a7f27c792a173d9b26 0 iD8DBQBOuADmjPn4sExkf7wRAv/fAJ9FJFvjDoF+wd1ipDx1wkzdeBQNqgCgykUrSbXv76FBbxKntVbk9oS3GjI=
|
||||
3f12086c2ef2b9ffe36a822fdb3ff647fcec1831 0 iD8DBQBOuSlQjPn4sExkf7wRAvkbAKCgE1e8xEMQ16CGeoywhIQ0QR4eNgCfZdYYlzjb/+521Uvh5/7FRYEmrho=
|
||||
85f835f2fe0ac2c503c50a414de127222fb0a57c 0 iD8DBQBPRkMUjPn4sExkf7wRAvM4AJ9mw2OAkyjhSbamM1MizlEJUX18HACgoFKQkYf6BnYxN34Nv2HhM0cmzUc=
|
||||
9b80981212fe6c01b7c16b3ca7c4e66af56f12f1 0 iEYEABECAAYFAlFLKKcACgkQjPn4sExkf7xK7wCfcioCmJPsysSbQO6+4qZMVe0mmLwAn2/o+wRf4MrUXlohrr7aXEF9vdSB
|
||||
095b46180bbc412b029420587736a6185afc17e1 0 iEYEABECAAYFAlFsCnkACgkQjPn4sExkf7xLrwCfeMWjUaSmfU/fvseT5TdrYRqBEVQAoLz5SFLEA40C5f8zE8Ma/vgVJVIC
|
||||
f168962bab857ca030829e4cd73d9b32c868c874 0 iEYEABECAAYFAlFwDNwACgkQjPn4sExkf7wJ6QCePVovn/avKXUyNwNBYCcov6JLYqkAnRCPQdkXgv20N3t10r6PRMBBo1/S
|
||||
deb211f75ca194e2fcf0d2e5f71c60474e42ec95 0 iEYEABECAAYFAlJO01cACgkQjPn4sExkf7yDqACaA/P+Yl/K2Cv3OC5G0b7ck2Kb75EAoIeW7qpCyclzJLWwk95koED+4lxD
|
||||
025237c9f0a1a60a616f984d82fb2a9270d3b0ea 0 iEYEABECAAYFAlJeqDYACgkQjPn4sExkf7y5nQCfW6t+TJySBTTo+gCfDUBPRVxvNe8AoIn/15aWfqH/A2G9uikfoVtWK3pd
|
||||
a50a1dc743317fad9b3737bc68fbca640659bb6d 0 iEYEABECAAYFAlJeqL0ACgkQjPn4sExkf7yVqACg6IP0fU29+Feh/TDeemDA+2XAzrIAoIdZfMDvVYlDoWotZD8ACFnf5H1P
|
||||
9ec083a21adfcb099f21eb03704b66d14a4ba800 0 iEYEABECAAYFAlKE4JoACgkQjPn4sExkf7wLDgCghkVGwMjI138bEv+ORVzN7zIH7cEAoLckaxZc1k1aXlmlSCRlP8cuKH3o
|
||||
3d1d7d151c0ce3a79da62e86463f5632fa2b144a 0 iEYEABECAAYFAlKd5AEACgkQjPn4sExkf7wzWgCfdvPEEIdlMPqcbOQMJ7b+eAyy164An2ip1lPh1eS5g26/gSfruvWBVym4
|
||||
277429102f1337bd10c89107d3e01de509cc1a7e 0 iEYEABECAAYFAlMEvF4ACgkQjPn4sExkf7xeVQCgtbxJ4G3hsFwUOM0K1WGr1J2vsbEAoMM8dEyr1mdrbgO1tzNLfD1nxbyn
|
||||
96584b934d04ebab443f603e78d38fe692d36313 0 iEYEABECAAYFAlPVFrQACgkQjPn4sExkf7xr6ACglRiLE21vRrS1rJ809o2yMADIKtwAn1f5SyZUngSde8eE55JxCMwtMC5m
|
||||
caac692b366c153cea0e9cd59aa2d79a7d843d4e 0 iEYEABECAAYFAlPk1mcACgkQjPn4sExkf7wLpgCeOqMYqpkf4lYUuyrn9VYThNpc7PkAn3JOSNgIqkKUcmSy6FstrI8jwJzq
|
||||
2d421bc0545d1be6d59a4ebfe61606d94b124b0c 0 iEYEABECAAYFAlRJDCQACgkQjPn4sExkf7xUYACcCwVJkYWXJn5x/D5A+qMupy778lEAn0rg1oNiq96YU/4jOPsS5IMItihu
|
||||
1d2d81b1b7c1b100e9c369e40b9fa5b2d491eea9 0 iEYEABECAAYFAlTKOKUACgkQjPn4sExkf7xWMACfYFozyHiRk5GaocTa5z6Ws1uyB4kAoLubxoxcnM3E7AA9mHAzc3OB5M0Y
|
||||
a687f835236c7025b5cb2968fe9c4ebc4a49f0ea 0 iQIcBAABCgAGBQJVxg62AAoJEPSYMBLCC7qsC+EQAKw8YWogrVHhIFct2fx/nqybSPVrhFyKFKHhq7K/lZeVm0MGIWdSyVcQgP+Hs2jWNBWzG4AJ1BtifHWQH6IDh7W5RuwOXu5KobgPW9BsN3EVE9KIR+xe9jCAmFl9rIw0tNpy1q6R0TpYXx/sWlMilxecyEGyr2Ias2Sm19aY2mOEv8PLfh9BLfrJEKtt2NxL7TX8ScPwJXJMmVIQjN9WK4Ptx3tjcGNRivEVR/dftP5sJx2DBJx9avyDqrfloMW7Q7sPgJ88MPruCDxedOkbzH7JdHe3Humr2G4LsI0KPU7pNN6EBDjhJ+SVXuOyAgu5j/C0R+0ggGfjSrjDu8WjHyclFlwwu2MSGuHf111I1qkLtaRY3H1FZO5Y2gbLwBLQ82svA4klcBIxtP5jKAZDTh1jQMYsfKotvZdawOWrPDkNmKoUg2JXLHAtj9Dd0uGIhqfspZY3qlpzxw9uCkljWclUBD097ygotwAb2XdLoAWZ3KdvoPM+k448vIAQ7Q/aqcnm/dLQJr3Le029gpkOKoWKaQTlk0itrRGpgETHAhE2LnmWxYSKp6NYSKMgEONbfDiVNLyDTOlvpPiEb20RsOP64xA4wVDGmPenCURmMYoepQK6oJdtkNtCdth2S49KxPQAC+Dem4YZ7b+5b+cXrK5Nz7elBxZzRQWdjmZ4JDQK
|
||||
ef4b26364b0cdda1084751d7de3d76c589e2d9cb 0 iQIcBAABCgAGBQJVxg7BAAoJEESTFJTynGdz9Q4P/A0Kq4H52rQqxq42PoEMFbVQIUfkFzyWjAz8eEGLmP5x5/sdpyxZDEyBSUG55uyNvOPTHE+Sd3t2h2Iieq749qwYgqggXC0P+C0zGzW3hB5Rv6dTUrKN1yCyaWE2tY488RsyVlcAs4vrp1Cum5Gv8/BUVKjzZmkZ1iq/3RyrvbLEiLoMrcLnQ+sUdaYHvfEwxDbzpOEvepg8iDJBitTrfG9xHp9otX6ucahwn1EumFvC5mvUxbiQ9jv76t4FJztjMoB24hPCH9T1FjB8uNsoM+j2Z67r81eJrGgNpJzjX0S3lY/AADZGhfGnfybTM9gFuQayIJuCJqduQibVwYkAAnPi17NmbdwPu0Rdz55oU+ft09XLVm/qkQcD1EP5bxYWnLIEMkkZQnFx7WdMpjKK9oGxZHeFYAKEgPgePCkk4TQ4PxNa+3854H19AUssQlaueGcbDLyPIRiSyqhleXawGfaJi+1jBt0DM7CNbAHAUWUE07VhQzNGWjabdEk4eXKTmDL+mZJFdHGBhyCve8sPmZBYJvM2PRgcXe8fwFh+R7gVj6kFbZJvgM9kG7EeF+4ZMEXG4yKpV/SKfMMeEPBCZjFxZhlJJ0fsZbB1Y/iLw8LXnJ0fa/5xFYv6k+iytfom/rqS4iUD7NWTjcEYHjd4EO4QlPD2Ef/AWOO8YBUBv8kA
|
||||
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=
|
||||
4877afd51e041eca7749cc46b57fd80aa23815b4 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAl7nmREACgkQRJMUlPKcZ3PG1BAAnUl0/nTnQ3CMM3S72DT1JQ1eDxZa14r6r1xEPngU83hNNzmPcnfiMDts+Vz1M3PLxNNOXVVt/MTw04+V9joPhhSWEe8O1pd3lAqTPswL7hhIEbVwZwyFCuAV4iAm+tHKzKLjtjgZfMgij6XylOmw18VBw5R+suoOMclJqeHlJ5m0Mq2wRLDE+RdVCAkulTqhGYjJNQUXMMNPx/cxUo3NHsto9pWL3d1285vBByP6BQSaeYlO012InvJRlQuEkK3lnIyzq6voIc6+tMli0q9iyBz+2GIloBQNAnb6EGaXxqAOBW5NRc+/Oauiu8Yf/6JoFlkAIcPXmGRtxiAiynJImhiTaCFdgdxaXLFzjBvq+tcwVXvvNM52fOZ4Z3QgMDu6EgNWfma0lsg4T3ar2ml2/evuWeLVut5ZmYFHarTFX+/pTVy9nAZK/F5ROJM1prTNYI18PZV4qvULta8spGV2Be0rCkQQubp9RWdKHNGZE70lrX5OnNIwE/D3g2QE04243i0IGBwhlDEpYjqujLyHk8W6XE1CORx0hQ0fUjzKZsRvOB7XyMAFpQUVOhoMFcnk5XHDW6B/U7NAxzqNqO+gbHO/UIeuy/KOVlMNJCmtRL/HYNGZ6SCZbRpyX3d8Ow0sasNfJkZrT6a0Tf6lZktWOxtPkoEDLfuCzudzn4JxGQM=
|
||||
61
.hgtags
Normal file
61
.hgtags
Normal file
@@ -0,0 +1,61 @@
|
||||
03f65e461915a940939e4cc689fc89721ffc40de DROPBEAR_0.48.1
|
||||
0f967bfef5cd0056b7ec60e2305d917e51cbf30d DROPBEAR_0.44
|
||||
170329dc8ce5dfcf6298e1ad6699f109bf78e73d DROPBEAR_0.51
|
||||
1dbd2473482f320ea59f76ce961385cb3a0150a9 DROPBEAR_0.46
|
||||
2098857ab826dd42ae05a9a22c3ce2cc835b9844 DROPBEAR_0.45
|
||||
36160290a1b27451178be36752ed038840f59cdd LTC_DB_0.46
|
||||
39d5d58461d6e93337636e69d4cdf184a09c8d24 LTC_1.05
|
||||
55a99934db873be2e63b5968fb6532e5d9bd02e4 DROPBEAR_0.48
|
||||
59400faa4b44708c5d0b595e81193bc621e752d3 libtomcrypt-1.05
|
||||
66087d87c3555c78b47cf01f32bb5a32054c3ceb DROPBEAR_0.44test4
|
||||
677843bfa734238a67636b461a02c110c462ffaf DROPBEAR_0.44test1
|
||||
7faae8f46238e23975430876547b8950b4e75481 t:ltc-0.95-orig
|
||||
8220862baae829ebc762587b99c662480d57bb23 DROPBEAR_0.53
|
||||
86e0b50a9b588239c3fc9cc9cfe255ef586df17b ltm-0.30-orig
|
||||
88e0a1ad951add46b795511dc2698e36b4aee922 DROPBEAR_0.44test3
|
||||
8e94663164c6e106ccc5c9e997dedf6e04d77dd2 LTM_DB_0.44
|
||||
91fbc376f01084037cd5f6a5bf2e2db4903e8e99 libtommath-0.35
|
||||
97db060d0ef5f8cf8e67eb602ef037055a185ca9 libtommath-0.40
|
||||
aa2f51a6b81d33de5e9898a7f27c792a173d9b26 DROPBEAR_0.53.1
|
||||
ab370c629d363f8c9a3eca512bfa86e362034654 DROPBEAR_0.49
|
||||
c2ac796b130eeb6fa840873d8c230544c8ec7e4b DROPBEAR_0.44test2
|
||||
cd1143579f00b0248c79f63ca70efee4a35a57e8 LTC_DB_0.44
|
||||
ce104c8b0be1ff3f2c2590b7cdc3fd6870c865cd DROPBEAR_0.52
|
||||
d5faf4814ddbc5abd9e209409bb9e7a4686c8cd7 libtomcrypt-1.16
|
||||
d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1
|
||||
d8254fc979e99560c93ca2cece77a6df31927ea5 LTM_0.35
|
||||
e109027b9edfb02f0bdf96ec45bb1cd9ad41e7da LTM_DB_0.46
|
||||
e109027b9edfb02f0bdf96ec45bb1cd9ad41e7da LTM_DB_0.47
|
||||
e37b160c414cab6466622f63b0c4dcbf6ebc47a9 DROPBEAR_0.47
|
||||
e430a26064ee86ab79aef372118d6d03b2441996 DROPBEAR_0.50
|
||||
e5d119ea4c63656bc54ecfd865d04591ac2ed225 LTC_DB_0.47
|
||||
3f12086c2ef2b9ffe36a822fdb3ff647fcec1831 DROPBEAR_2011.54
|
||||
d354464b2aa6f6ba0bf44d43bcae5aa798435393 DROPBEAR_2012.55
|
||||
7faae8f46238e23975430876547b8950b4e75481 t:ltc-0.95-orig
|
||||
0000000000000000000000000000000000000000 t:ltc-0.95-orig
|
||||
d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1
|
||||
0000000000000000000000000000000000000000 t:ltc-0.95-db-merge1
|
||||
1b8b2b9d6e94bc3cc5e61b620476ea36cc466e1b DROPBEAR_2013.56
|
||||
96b8bcb88017815040949a417caa55686271e8a9 DROPBEAR_2013.57
|
||||
e76614145aea67f66e4a4257685c771efba21aa1 DROPBEAR_2013.58
|
||||
7b68e581985fd4ea50869f8608ab95cda5d17876 DROPBEAR_2013.59
|
||||
a50a1dc743317fad9b3737bc68fbca640659bb6d DROPBEAR_2013.60
|
||||
e894dbc015ba7ff4c3bf897ee20e28ca90c55a16 DROPBEAR_2013.61test
|
||||
3d1d7d151c0ce3a79da62e86463f5632fa2b144a DROPBEAR_2013.62
|
||||
2351b2da8e0d08dcc6e64fcc328b53b9630bda68 DROPBEAR_2014.63
|
||||
0d2d39957c029adb7f4327d37fe6b4900f0736d9 DROPBEAR_2014.64
|
||||
e9579816f20ea85affc6135e87f8477992808948 DROPBEAR_2014.65
|
||||
735511a4c761141416ad0e6728989d2dafa55bc2 DROPBEAR_2014.66
|
||||
cbd674d63cd4f3781464a8d4056a5506c8ae926f DROPBEAR_2015.67
|
||||
809feaa9408f036734129c77f2b3c7e779d4f099 DROPBEAR_2015.68
|
||||
1637dbd262124d113e52967df46afd6c715e4fad DROPBEAR_2015.69
|
||||
79a6ef02307d05cb9dda10465cb5b807baa8f62e DROPBEAR_2015.70
|
||||
9a944a243f08be6b22d32f166a0690eb4872462b DROPBEAR_2015.71
|
||||
78b12b6549be08b0bea3da329b2578060a76ca31 DROPBEAR_2016.72
|
||||
309e1c4a87682b6ca7d80b8555a1db416c3cb7ac DROPBEAR_2016.73
|
||||
0ed3d2bbf956cb8a9bf0f4b5a86b7dd9688205cb DROPBEAR_2016.74
|
||||
c31276613181c5cff7854e7ef586ace03424e55e DROPBEAR_2017.75
|
||||
1c66ca4f3791c82501c88e7637312182c7294978 DROPBEAR_2018.76
|
||||
6d1bbe7d5fa5827c7eae28bca044d691f7efa785 DROPBEAR_2019.77
|
||||
009d52ae26d35f3381c801e02318fa9be34be93c DROPBEAR_2019.78
|
||||
e2e4929d057b09422f2ea4556fb64209aff58161 DROPBEAR_2020.79
|
||||
36
.travis.yml
Normal file
36
.travis.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
language: c
|
||||
|
||||
git:
|
||||
depth: 3
|
||||
|
||||
env:
|
||||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
- secure: "F4rKQrHK/u58vPo3F9+x0WYXAeMFJvvtH9BIGZqx9yw8bUnL+gk0Ge9wnHHTXRcgCTqoc7B35uMS5njpH+Su/esVjrLAq85f/AmQctlRpmApwGK9LyxkIvx3UJN0nqfeeDXA90/8FUZ+n/qnCydXmYCEgqSaBCNydDxW1oqYUIc="
|
||||
- BUNDLEDLIBTOM=--enable-bundled-libtom
|
||||
- MULTI=1
|
||||
|
||||
before_install:
|
||||
- echo -n | openssl s_client -connect https://scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
# packages list: https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
|
||||
- zlib1g-dev
|
||||
- libtomcrypt-dev
|
||||
- libtommath-dev
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "mkj/dropbear"
|
||||
description: "Dropbear SSH"
|
||||
notification_email: matt@ucc.asn.au
|
||||
build_command_prepend: autoconf && autoheader && ./configure --enable-bundled-libtom CFLAGS='-O2 -Wall -Wno-pointer-sign' --prefix=$HOME/inst
|
||||
build_command: make MULTI=1
|
||||
branch_pattern: coverity
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- coverity
|
||||
75
DEVELOPING.md
Normal file
75
DEVELOPING.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Developer Notes
|
||||
|
||||
## Building
|
||||
|
||||
See [INSTALL](INSTALL) for build instructions.
|
||||
[SMALL](SMALL) has hints for building smaller binaries, also see comments
|
||||
in default_options.h.
|
||||
|
||||
## Debug printing
|
||||
|
||||
Set `#define DEBUG_TRACE 1` in localoptions.h to enable a `-v` option
|
||||
for dropbear and dbclient. That prints various details of the session. For
|
||||
development running `dropbear -F -E` is useful to run in the foreground. You
|
||||
can set `#define DEBUG_NOFORK 1` to make dropbear a one-shot server, easy to
|
||||
run under a debugger.
|
||||
|
||||
## Random sources
|
||||
|
||||
Most cryptography requires a good random entropy source, both to generate secret
|
||||
keys and in the course of a session. Dropbear uses the Linux kernel's
|
||||
`getrandom()` syscall to ensure that the system RNG has been initialised before
|
||||
using it. On some systems there is insufficient entropy gathered during early
|
||||
boot - generating hostkeys then will block for some amount of time.
|
||||
Dropbear has a `-R` option to generate hostkeys upon the first connection
|
||||
as required - that will allow the system more time to gather entropy.
|
||||
|
||||
## Algorithms
|
||||
|
||||
Default algorithm lists are specified in [common-algo.c](common-algo.c).
|
||||
They are in priority order, the client's first matching choice is used
|
||||
(see rfc4253).
|
||||
Dropbear client has `-c` and `-m` arguments to choose which are enabled at
|
||||
runtime (doesn't work for server as of June 2020).
|
||||
|
||||
Enabling/disabling algorithms is done in [localoptions.h](localoptions.h),
|
||||
see [default_options.h](default_options.h).
|
||||
|
||||
## Style
|
||||
|
||||
Source code is indented with tabs, width set to 4 (though width shouldn't
|
||||
matter much). Braces are on the same line as functions/loops/if - try
|
||||
to keep consistency with existing code.
|
||||
|
||||
All `if` statements should have braces, no exceptions.
|
||||
|
||||
Avoid using pointer arithmetic, instead the functions in
|
||||
[buffer.h](buffer.h) should be used.
|
||||
|
||||
Some Dropbear platforms have old compilers.
|
||||
Variable declarations must be at the top of a scope and
|
||||
comments must be `/* */` rather than `//`.
|
||||
|
||||
Pointer variables should be initialised to NULL - it can reduce the
|
||||
severity of bugs.
|
||||
|
||||
## Third party code
|
||||
|
||||
Libtomcrypt and libtommath are periodically synced from upstream, so
|
||||
avoid making changes to that code which will need to be maintained.
|
||||
Improvements can be sent upstream to the libtom project.
|
||||
|
||||
## Non-root user
|
||||
|
||||
Dropbear server will run fine as a non-root user, allowing logins only for
|
||||
that user. Password authentication probably won't work (can't read shadow
|
||||
passwords). You will need to create hostkeys that are readable.
|
||||
|
||||
## Connection setup
|
||||
|
||||
Dropbear implements first_kex_packet_follows to reduce
|
||||
handshake latency (rfc 4253 7.1). Some less common implementations don't
|
||||
handle that, it can be a cause of problems connecting. Note also that
|
||||
Dropbear may send several ssh packets within a single TCP packet - it's just a
|
||||
stream.
|
||||
|
||||
77
FUZZER-NOTES.md
Normal file
77
FUZZER-NOTES.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# 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.
|
||||
|
||||
- [fuzzer-kexcurve25519](fuzzer-kexcurve25519.c) - test Curve25519 Elliptic Curve Diffie-Hellman key exchange
|
||||
like fuzzer-kexecdh. This is testing `dropbear_curve25519_scalarmult()` and other libtommath routines.
|
||||
41
INSTALL
41
INSTALL
@@ -1,30 +1,49 @@
|
||||
Basic Dropbear build instructions:
|
||||
|
||||
- Edit options.h to set which features you want.
|
||||
- Edit debug.h if you want any debug options (not usually required).
|
||||
- Edit localoptions.h to set which features you want. Available options
|
||||
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)
|
||||
|
||||
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
|
||||
recompile after changing the PROGRAMS list, you *MUST* "make clean" before
|
||||
recompiling - bad things will happen otherwise)
|
||||
|
||||
DEVELOPING.md has some notes on other developer topics, including debugging.
|
||||
|
||||
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
|
||||
|
||||
Binaries can be strippd with "make strip"
|
||||
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"
|
||||
|
||||
============================================================================
|
||||
|
||||
If you're compiling for a 386-class CPU, you will probably need to add
|
||||
CFLAGS=-DLTC_NO_BSWAP so that libtomcrypt doesn't use 486+ instructions.
|
||||
|
||||
============================================================================
|
||||
|
||||
@@ -39,7 +58,7 @@ Compiling for uClibc should be the same as normal, just set CC to the magic
|
||||
uClibc toolchain compiler (ie export CC=i386-uclibc-gcc or whatever).
|
||||
You can use "make STATIC=1" to make statically linked binaries, and it is
|
||||
advisable to strip the binaries too. If you're looking to make a small binary,
|
||||
you should remove unneeded ciphers and MD5, by editing options.h
|
||||
you should remove unneeded ciphers and MD5, by editing localoptions.h
|
||||
|
||||
It is possible to compile zlib in, by copying zlib.h and zconf.h into a
|
||||
subdirectory (ie zlibincludes), and
|
||||
|
||||
29
LICENSE
29
LICENSE
@@ -8,7 +8,7 @@ The majority of code is written by Matt Johnston, under the license below.
|
||||
Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the
|
||||
same license:
|
||||
|
||||
Copyright (c) 2002-2004 Matt Johnston
|
||||
Copyright (c) 2002-2020 Matt Johnston
|
||||
Portions copyright (c) 2004 Mihnea Stoenescu
|
||||
All rights reserved.
|
||||
|
||||
@@ -32,7 +32,8 @@ SOFTWARE.
|
||||
|
||||
=====
|
||||
|
||||
LibTomCrypt and LibTomMath are written by Tom St Denis, and are Public Domain.
|
||||
LibTomCrypt and LibTomMath are written by Tom St Denis and others, see
|
||||
libtomcrypt/LICENSE and libtommath/LICENSE.
|
||||
|
||||
=====
|
||||
|
||||
@@ -87,3 +88,27 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
|
||||
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
=====
|
||||
|
||||
curve25519.c:
|
||||
|
||||
Modified TweetNaCl version 20140427, a self-contained public-domain C library.
|
||||
https://tweetnacl.cr.yp.to/
|
||||
|
||||
Contributors (alphabetical order)
|
||||
Daniel J. Bernstein, University of Illinois at Chicago and Technische
|
||||
Universiteit Eindhoven
|
||||
Bernard van Gastel, Radboud Universiteit Nijmegen
|
||||
Wesley Janssen, Radboud Universiteit Nijmegen
|
||||
Tanja Lange, Technische Universiteit Eindhoven
|
||||
Peter Schwabe, Radboud Universiteit Nijmegen
|
||||
Sjaak Smetsers, Radboud Universiteit Nijmegen
|
||||
|
||||
Acknowledgments
|
||||
This work was supported by the U.S. National Science Foundation under grant
|
||||
1018836. "Any opinions, findings, and conclusions or recommendations expressed
|
||||
in this material are those of the author(s) and do not necessarily reflect the
|
||||
views of the National Science Foundation."
|
||||
This work was supported by the Netherlands Organisation for Scientific
|
||||
Research (NWO) under grant 639.073.005 and Veni 2013 project 13114.
|
||||
|
||||
4
MULTI
4
MULTI
@@ -20,7 +20,3 @@ etc
|
||||
then execute as normal:
|
||||
|
||||
./dropbear <options here>
|
||||
|
||||
"make install" doesn't currently work for multi-binary configuration, though
|
||||
in most situations where it is being used, the target and build systems will
|
||||
differ.
|
||||
|
||||
307
Makefile.in
307
Makefile.in
@@ -1,79 +1,123 @@
|
||||
# This Makefile is for Dropbear SSH Server and Client
|
||||
# @configure_input@
|
||||
|
||||
# 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
|
||||
# dbclient functionality, and includes the progress-bar functionality in scp.
|
||||
# Hopefully that seems intuitive.
|
||||
|
||||
ifndef PROGRAMS
|
||||
PROGRAMS=dropbear dbclient dropbearkey dropbearconvert
|
||||
endif
|
||||
|
||||
LTC=libtomcrypt/libtomcrypt.a
|
||||
LTM=libtommath/libtommath.a
|
||||
STATIC_LTC=libtomcrypt/libtomcrypt.a
|
||||
STATIC_LTM=libtommath/libtommath.a
|
||||
|
||||
COMMONOBJS=dbutil.o buffer.o \
|
||||
LIBTOM_LIBS=@LIBTOM_LIBS@
|
||||
|
||||
ifeq (@BUNDLED_LIBTOM@, 1)
|
||||
LIBTOM_DEPS=$(STATIC_LTC) $(STATIC_LTM)
|
||||
LIBTOM_CLEAN=ltc-clean ltm-clean
|
||||
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
|
||||
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
|
||||
endif
|
||||
|
||||
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 \
|
||||
signkey.o rsa.o random.o \
|
||||
signkey.o rsa.o dbrandom.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 \
|
||||
curve25519.o ed25519.o \
|
||||
dbmalloc.o \
|
||||
gensignkey.o gendss.o genrsa.o gened25519.o
|
||||
|
||||
SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \
|
||||
svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \
|
||||
SVROBJS=svr-kex.o svr-auth.o sshpty.o \
|
||||
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
|
||||
svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
|
||||
svr-tcpfwd.o
|
||||
svr-tcpfwd.o svr-authpam.o
|
||||
|
||||
CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
|
||||
cli-session.o cli-service.o cli-runopts.o cli-chansession.o \
|
||||
cli-authpubkey.o cli-tcpfwd.o
|
||||
CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
|
||||
cli-session.o cli-runopts.o cli-chansession.o \
|
||||
cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o \
|
||||
cli-agentfwd.o
|
||||
|
||||
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
|
||||
common-channel.o common-chansession.o termcodes.o loginrec.o \
|
||||
tcp-accept.o listener.o process-packet.o \
|
||||
common-runopts.o
|
||||
tcp-accept.o listener.o process-packet.o dh_groups.o \
|
||||
common-runopts.o circbuffer.o list.o netio.o chachapoly.o gcm.o
|
||||
|
||||
KEYOBJS=dropbearkey.o gendss.o genrsa.o
|
||||
KEYOBJS=dropbearkey.o
|
||||
|
||||
CONVERTOBJS=dropbearconvert.o keyimport.o
|
||||
|
||||
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.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 \
|
||||
dss.h bignum.h signkey.h rsa.h random.h service.h auth.h \
|
||||
debug.h channel.h chansession.h config.h queue.h sshpty.h \
|
||||
termcodes.h gendss.h genrsa.h runopts.h includes.h \
|
||||
loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \
|
||||
listener.h fake-rfc2553.h
|
||||
ifeq (@DROPBEAR_FUZZ@, 1)
|
||||
allobjs = $(COMMONOBJS) fuzz-common.o fuzz-wrapfd.o $(CLISVROBJS) $(CLIOBJS) $(SVROBJS) @CRYPTLIB@
|
||||
allobjs:=$(subst svr-main.o, ,$(allobjs))
|
||||
allobjs:=$(subst cli-main.o, ,$(allobjs))
|
||||
allobjs:=$(sort $(allobjs))
|
||||
|
||||
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
|
||||
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
|
||||
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
|
||||
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
|
||||
scpobjs=$(SCPOBJS)
|
||||
dropbearobjs=$(allobjs) svr-main.o
|
||||
dbclientobjs=$(allobjs) cli-main.o
|
||||
dropbearkeyobjs=$(allobjs) $(KEYOBJS)
|
||||
dropbearconvertobjs=$(allobjs) $(CONVERTOBJS)
|
||||
# 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
|
||||
|
||||
ifeq (@DROPBEAR_PLUGIN@, 1)
|
||||
# rdynamic makes all the global symbols of dropbear available to all the loaded shared libraries
|
||||
# this allow a plugin to reuse existing crypto/utilities like base64_decode/base64_encode without
|
||||
# the need to rewrite them.
|
||||
PLUGIN_LIBS=-ldl -rdynamic
|
||||
else
|
||||
PLUGIN_LIBS=
|
||||
endif
|
||||
|
||||
VPATH=@srcdir@
|
||||
srcdir=@srcdir@
|
||||
|
||||
prefix=@prefix@
|
||||
exec_prefix=${prefix}
|
||||
bindir=${exec_prefix}/bin
|
||||
sbindir=${exec_prefix}/sbin
|
||||
exec_prefix=@exec_prefix@
|
||||
datarootdir = @datarootdir@
|
||||
bindir=@bindir@
|
||||
sbindir=@sbindir@
|
||||
mandir=@mandir@
|
||||
|
||||
.DELETE_ON_ERROR:
|
||||
|
||||
CC=@CC@
|
||||
LD=@LD@
|
||||
AR=@AR@
|
||||
RANLIB=@RANLIB@
|
||||
STRIP=@STRIP@
|
||||
INSTALL=@INSTALL@
|
||||
CFLAGS=-Ilibtomcrypt @CFLAGS@
|
||||
LIBS=$(LTC) $(LTM) @LIBS@
|
||||
CPPFLAGS=@CPPFLAGS@
|
||||
CFLAGS+=-I. -I$(srcdir) $(CPPFLAGS) @CFLAGS@
|
||||
LIBS+=@LIBS@
|
||||
LDFLAGS=@LDFLAGS@
|
||||
|
||||
EXEEXT=@EXEEXT@
|
||||
|
||||
STATIC=@STATIC@
|
||||
|
||||
# whether we're building client, server, or both for the common objects.
|
||||
# evilness so we detect 'dropbear' by itself as a word
|
||||
space:= $(empty) $(empty)
|
||||
ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdropbearZ, Z$(prog)Z))))
|
||||
CFLAGS+= -DDROPBEAR_SERVER
|
||||
endif
|
||||
@@ -81,7 +125,6 @@ ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdbclientZ, Z$(prog)Z)
|
||||
CFLAGS+= -DDROPBEAR_CLIENT
|
||||
endif
|
||||
|
||||
|
||||
# these are exported so that libtomcrypt's makefile will use them
|
||||
export CC
|
||||
export CFLAGS
|
||||
@@ -89,13 +132,10 @@ export RANLIB AR STRIP
|
||||
|
||||
ifeq ($(STATIC), 1)
|
||||
LDFLAGS+=-static
|
||||
SPREFIX=static
|
||||
else
|
||||
SPREFIX=
|
||||
endif
|
||||
|
||||
ifeq ($(MULTI), 1)
|
||||
TARGETS=dropbearmulti
|
||||
TARGETS=dropbearmulti$(EXEEXT)
|
||||
else
|
||||
TARGETS=$(PROGRAMS)
|
||||
endif
|
||||
@@ -105,46 +145,52 @@ ifeq ($(SCPPROGRESS), 1)
|
||||
CFLAGS+=-DPROGRESS_METER
|
||||
endif
|
||||
|
||||
#%: $(HEADERS)
|
||||
#%: $(HEADERS) Makefile
|
||||
# TODO
|
||||
|
||||
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) $(addsuffix $(EXEEXT), $(addprefix $(SPREFIX), $(TARGETS)))
|
||||
$(STRIP) $(addsuffix $(EXEEXT), $(TARGETS))
|
||||
|
||||
install: $(addprefix inst, $(TARGETS))
|
||||
install: $(addprefix inst_, $(TARGETS))
|
||||
|
||||
installdropbearmulti: insdbmulti $(addprefix insmulti, $(PROGRAMS))
|
||||
insmultidropbear: dropbearmulti$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(sbindir)
|
||||
-rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
|
||||
$(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
|
||||
|
||||
insdbmulti: dropbearmulti
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -m 755 $(SPREFIX)dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)
|
||||
-chown root $(DESTDIR)$(bindir)/$(SPREFIX)dropbearmulti$(EXEEXT)
|
||||
-chgrp 0 $(DESTDIR)$(bindir)/$(SPREFIX)dropbearmulti$(EXEEXT)
|
||||
insmulti%: dropbearmulti$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
-rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
|
||||
if test -e $(srcdir)/$*.1; then $(INSTALL) -m 644 $(srcdir)/$*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
|
||||
insmultidropbear: dropbearmulti
|
||||
-rm -f $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT)
|
||||
-ln -s $(DESTDIR)$(bindir)/$(SPREFIX)dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT)
|
||||
# dropbear should go in sbin, so it needs a separate rule
|
||||
inst_dropbear: dropbear
|
||||
$(INSTALL) -d $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
|
||||
$(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
|
||||
|
||||
insmulti%: dropbearmulti
|
||||
-rm -f $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT)
|
||||
-ln -s $(DESTDIR)$(bindir)/$(SPREFIX)dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT)
|
||||
|
||||
# dropbear should go in sbin, so it needs a seperate rule
|
||||
instdropbear: dropbear
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -m 755 $(SPREFIX)dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
|
||||
-chown root $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT)
|
||||
-chgrp 0 $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT)
|
||||
|
||||
inst%: $*
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -m 755 $(SPREFIX)$*$(EXEEXT) $(DESTDIR)$(bindir)
|
||||
-chown root $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT)
|
||||
-chgrp 0 $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT)
|
||||
inst_%: %
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
$(INSTALL) $*$(EXEEXT) $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
|
||||
if test -e $(srcdir)/$*.1; then $(INSTALL) -m 644 $(srcdir)/$*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
|
||||
inst_dropbearmulti: $(addprefix insmulti, $(PROGRAMS))
|
||||
|
||||
# for some reason the rule further down doesn't like $($@objs) as a prereq.
|
||||
dropbear: $(dropbearobjs)
|
||||
@@ -152,13 +198,18 @@ dbclient: $(dbclientobjs)
|
||||
dropbearkey: $(dropbearkeyobjs)
|
||||
dropbearconvert: $(dropbearconvertobjs)
|
||||
|
||||
dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LTC) $(LTM) \
|
||||
Makefile
|
||||
$(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $($@objs) $(LIBS)
|
||||
dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@ $(PLUGIN_LIBS)
|
||||
|
||||
dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
|
||||
|
||||
dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
|
||||
|
||||
# scp doesn't use the libs so is special.
|
||||
scp: $(SCPOBJS) $(HEADERS) Makefile
|
||||
$(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(SCPOBJS)
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $(SCPOBJS)
|
||||
|
||||
|
||||
# multi-binary compilation.
|
||||
@@ -168,43 +219,115 @@ ifeq ($(MULTI),1)
|
||||
CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
|
||||
endif
|
||||
|
||||
dropbearmulti: multilink
|
||||
dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@ $(MULTIOBJS) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
|
||||
|
||||
multibinary: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) Makefile
|
||||
$(LD) $(LDFLAGS) -o $(SPREFIX)dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS)
|
||||
multibinary: dropbearmulti$(EXEEXT)
|
||||
|
||||
multilink: multibinary $(addprefix link, $(PROGRAMS))
|
||||
|
||||
link%:
|
||||
-rm -f $(SPREFIX)$*$(EXEEXT)
|
||||
-ln -s $(SPREFIX)dropbearmulti$(EXEEXT) $(SPREFIX)$*$(EXEEXT)
|
||||
-rm -f $*$(EXEEXT)
|
||||
-ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT)
|
||||
|
||||
$(LTC): options.h
|
||||
cd libtomcrypt && $(MAKE) clean && $(MAKE)
|
||||
$(STATIC_LTC): $(OPTION_HEADERS)
|
||||
$(MAKE) -C libtomcrypt
|
||||
|
||||
$(LTM): options.h
|
||||
cd libtommath && $(MAKE)
|
||||
$(STATIC_LTM): $(OPTION_HEADERS)
|
||||
$(MAKE) -C libtommath
|
||||
|
||||
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean lint
|
||||
|
||||
ltc-clean:
|
||||
cd libtomcrypt && $(MAKE) clean
|
||||
$(MAKE) -C libtomcrypt clean
|
||||
|
||||
ltm-clean:
|
||||
cd libtommath && $(MAKE) clean
|
||||
$(MAKE) -C libtommath clean
|
||||
|
||||
sizes: dropbear
|
||||
objdump -t dropbear|grep ".text"|cut -d "." -f 2|sort -rn
|
||||
|
||||
clean: ltc-clean ltm-clean thisclean
|
||||
clean: $(LIBTOM_CLEAN) thisclean
|
||||
|
||||
thisclean:
|
||||
-rm -f dropbear dbclient dropbearkey dropbearconvert scp scp-progress
|
||||
-rm -f staticdropbear staticdropbearkey staticdropbearconvert staticscp
|
||||
-rm -f dropbearmulti staticdropbearmulti
|
||||
-rm -f *.o *.da *.bb *.bbg *.prof
|
||||
-rm -f dropbear$(EXEEXT) dbclient$(EXEEXT) dropbearkey$(EXEEXT) \
|
||||
dropbearconvert$(EXEEXT) scp$(EXEEXT) scp-progress$(EXEEXT) \
|
||||
dropbearmulti$(EXEEXT) *.o *.da *.bb *.bbg *.prof
|
||||
|
||||
distclean: clean tidy
|
||||
-rm -f config.h
|
||||
-rm -f Makefile
|
||||
-rm -f default_options_guard.h
|
||||
|
||||
tidy:
|
||||
-rm -f *~ *.gcov */*~
|
||||
|
||||
lint:
|
||||
cd $(srcdir); ./dropbear_lint.sh
|
||||
|
||||
## Fuzzing targets
|
||||
|
||||
# list of fuzz targets
|
||||
FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519
|
||||
|
||||
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))
|
||||
|
||||
fuzz-harness.o: $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs) fuzz-common.o
|
||||
|
||||
# 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 fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-pubkey: fuzzer-pubkey.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-verify: fuzzer-verify.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-kexdh: fuzzer-kexdh.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-kexecdh: fuzzer-kexecdh.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-kexcurve25519: fuzzer-kexcurve25519.o fuzz-harness.o
|
||||
$(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
|
||||
dropbearkey -t ed25519 -f keyed25519
|
||||
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
|
||||
/usr/bin/xxd -i -a keyed25519 >> hostkeys.c
|
||||
|
||||
# to make coverity happy?
|
||||
test:
|
||||
true
|
||||
|
||||
|
||||
23
README
23
README
@@ -1,4 +1,5 @@
|
||||
This is Dropbear, a smallish SSH 2 server and client.
|
||||
This is Dropbear, a smallish SSH server and client.
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
|
||||
INSTALL has compilation instructions.
|
||||
|
||||
@@ -7,8 +8,8 @@ which performs multiple tasks, to save disk space)
|
||||
|
||||
SMALL has some tips on creating small binaries.
|
||||
|
||||
See TODO for a few of the things I know need looking at, and please contact
|
||||
me if you have any questions/bugs found/features/ideas/comments etc :)
|
||||
Please contact 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@ucc.asn.au
|
||||
@@ -25,10 +26,9 @@ the key entries in that file. They should be of the form:
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAwVa6M6cGVmUcLl2cFzkxEoJd06Ub4bVDsYrWvXhvUV+ZAM9uGuewZBDoAqNKJxoIn0Hyd0Nk/yU99UVv6NWV/5YSHtnf35LKds56j7cuzoQpFIdjNwdxAN0PCET/MG8qyskG/2IE2DPNIaJ3Wy+Ws4IZEgdJgPlTYUBWWtCWOGc= someone@hostname
|
||||
|
||||
You must make sure that ~/.ssh, and the key file, are only writable by the
|
||||
user.
|
||||
user. Beware of editors that split the key into multiple lines.
|
||||
|
||||
NOTE: Dropbear ignores authorized_keys options such as those described in the
|
||||
OpenSSH sshd manpage, and will not allow a login for these keys.
|
||||
Dropbear supports some options for authorized_keys entries, see the manpage.
|
||||
|
||||
============================================================================
|
||||
|
||||
@@ -42,8 +42,7 @@ If you have an OpenSSH-style private key ~/.ssh/id_rsa, you need to do:
|
||||
dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_rsa.db
|
||||
dbclient -i ~/.ssh/id_rsa.db <hostname>
|
||||
|
||||
Currently encrypted keys aren't supported, neither is agent forwarding. At some
|
||||
stage both hopefully will be.
|
||||
Dropbear does not support encrypted hostkeys though can connect to ssh-agent.
|
||||
|
||||
============================================================================
|
||||
|
||||
@@ -55,10 +54,16 @@ dropbearkey's '-y' option.
|
||||
To run the server, you need to generate server keys, this is one-off:
|
||||
./dropbearkey -t rsa -f dropbear_rsa_host_key
|
||||
./dropbearkey -t dss -f dropbear_dss_host_key
|
||||
./dropbearkey -t ecdsa -f dropbear_ecdsa_host_key
|
||||
./dropbearkey -t ed25519 -f dropbear_ed25519_host_key
|
||||
|
||||
or alternatively convert OpenSSH keys to Dropbear:
|
||||
./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
|
||||
|
||||
You can also get Dropbear to create keys when the first connection is made -
|
||||
this is preferable to generating keys when the system boots. Make sure
|
||||
/etc/dropbear/ exists and then pass '-R' to the dropbear server.
|
||||
|
||||
============================================================================
|
||||
|
||||
If the server is run as non-root, you most likely won't be able to allocate a
|
||||
@@ -69,6 +74,6 @@ pty, and you cannot login as any user other than that running the daemon
|
||||
|
||||
The Dropbear distribution includes a standalone version of OpenSSH's scp
|
||||
program. You can compile it with "make scp", you may want to change the path
|
||||
of the ssh binary, specified near the top of the scp.c file. By default
|
||||
of the ssh binary, specified by _PATH_SSH_PROGRAM in options.h . By default
|
||||
the progress meter isn't compiled in to save space, you can enable it by
|
||||
adding 'SCPPROGRESS=1' to the make commandline.
|
||||
|
||||
39
SMALL
39
SMALL
@@ -1,25 +1,36 @@
|
||||
Tips for a small system:
|
||||
|
||||
The following are set in options.h
|
||||
If you only want server functionality (for example), compile with
|
||||
make PROGRAMS=dropbear
|
||||
rather than just
|
||||
make dropbear
|
||||
so that client functionality in shared portions of Dropbear won't be included.
|
||||
The same applies if you are compiling just a client.
|
||||
|
||||
- You can safely disable blowfish and twofish ciphers, and MD5 hmac, without
|
||||
affecting interoperability
|
||||
---
|
||||
|
||||
- If you're compiling statically, you can turn off host lookups
|
||||
The following are set in options.h:
|
||||
|
||||
- You can disable either password or public-key authentication, though note
|
||||
that the IETF draft states that pubkey authentication is required.
|
||||
- You can safely disable blowfish and twofish ciphers, and MD5 hmac, without
|
||||
affecting interoperability
|
||||
|
||||
- Similarly with DSS and RSA, you can disable one of these if you know that
|
||||
all clients will be able to support a particular one. The IETF draft
|
||||
states that DSS is required, however you may prefer to use RSA.
|
||||
DON'T disable either of these on systems where you aren't 100% sure about
|
||||
who will be connecting and what clients they will be using.
|
||||
- If you're compiling statically, you can turn off host lookups
|
||||
|
||||
- Disabling the MOTD code and SFTP-SERVER may save a small amount of codesize
|
||||
- You can disable either password or public-key authentication, though note
|
||||
that the IETF draft states that pubkey authentication is required.
|
||||
|
||||
- You can disable x11, tcp and agent forwarding as desired. None of these are
|
||||
essential, although agent-forwarding is often useful even on firewall boxes.
|
||||
- Similarly with DSS and RSA, you can disable one of these if you know that
|
||||
all clients will be able to support a particular one. The IETF draft
|
||||
states that DSS is required, however you may prefer to use RSA.
|
||||
DON'T disable either of these on systems where you aren't 100% sure about
|
||||
who will be connecting and what clients they will be using.
|
||||
|
||||
- Disabling the MOTD code and SFTP-SERVER may save a small amount of codesize
|
||||
|
||||
- You can disable x11, tcp and agent forwarding as desired. None of these are
|
||||
essential, although agent-forwarding is often useful even on firewall boxes.
|
||||
|
||||
---
|
||||
|
||||
If you are compiling statically, you may want to disable zlib, as it will use
|
||||
a few tens of kB of binary-size (./configure --disable-zlib).
|
||||
|
||||
31
TODO
31
TODO
@@ -1,31 +0,0 @@
|
||||
Current:
|
||||
|
||||
Things which might need doing:
|
||||
|
||||
- Make options.h generated from configure perhaps?
|
||||
|
||||
- Improved queueing of unauthed connections
|
||||
|
||||
- fix agent fwd problems
|
||||
|
||||
- handle /etc/environment in AIX
|
||||
|
||||
- improve channel window adjustment algorithm (circular buffering)
|
||||
|
||||
- check that there aren't timing issues with valid/invalid user authentication
|
||||
feedback.
|
||||
|
||||
- Binding to different interfaces
|
||||
|
||||
- possible RSA blinding? need to check whether this is vuln to timing attacks
|
||||
- check PRNG
|
||||
- CTR mode, SSH_MSG_IGNORE sending to improve CBC security
|
||||
- DH Group Exchange possibly, or just add group14 (whatever it's called today)
|
||||
|
||||
- Use m_burn for clearing sensitive items in LTM/LTC
|
||||
|
||||
- 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
|
||||
41
agentfwd.h
41
agentfwd.h
@@ -21,23 +21,46 @@
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
#ifndef _AGENTFWD_H_
|
||||
#define _AGENTFWD_H_
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
#ifndef DROPBEAR_AGENTFWD_H_
|
||||
#define DROPBEAR_AGENTFWD_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "chansession.h"
|
||||
#include "channel.h"
|
||||
#include "auth.h"
|
||||
#include "list.h"
|
||||
|
||||
int agentreq(struct ChanSess * chansess);
|
||||
void agentsetauth(struct ChanSess *chansess);
|
||||
void agentcleanup(struct ChanSess * chansess);
|
||||
void agentset(struct ChanSess *chansess);
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
|
||||
/* From OpenSSH authfd.h */
|
||||
#define SSH_AGENT_RSA_SHA2_256 0x02
|
||||
|
||||
/* An agent reply can be reasonably large, as it can
|
||||
* contain a list of all public keys held by the agent.
|
||||
* 10000 is arbitrary */
|
||||
#define MAX_AGENT_REPLY 10000
|
||||
|
||||
/* client functions */
|
||||
void cli_load_agent_keys(m_list * ret_list);
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const buffer *data_buf, enum signature_type type);
|
||||
void cli_setup_agent(const struct Channel *channel);
|
||||
|
||||
#ifdef __hpux
|
||||
#define seteuid(a) setresuid(-1, (a), -1)
|
||||
#define setegid(a) setresgid(-1, (a), -1)
|
||||
#endif
|
||||
|
||||
#endif /* DROPBEAR_AGENTFWD */
|
||||
#endif /* _AGENTFWD_H_ */
|
||||
extern const struct ChanType cli_chan_agent;
|
||||
|
||||
#endif /* DROPBEAR_CLI_AGENTFWD */
|
||||
|
||||
#if DROPBEAR_SVR_AGENTFWD
|
||||
|
||||
int svr_agentreq(struct ChanSess * chansess);
|
||||
void svr_agentcleanup(struct ChanSess * chansess);
|
||||
void svr_agentset(const struct ChanSess *chansess);
|
||||
|
||||
#endif /* DROPBEAR_SVR_AGENTFWD */
|
||||
|
||||
#endif /* DROPBEAR_AGENTFWD_H_ */
|
||||
|
||||
117
algo.h
117
algo.h
@@ -22,53 +22,126 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _ALGO_H_
|
||||
#ifndef DROPBEAR_ALGO_H_
|
||||
|
||||
#define _ALGO_H_
|
||||
#define DROPBEAR_ALGO_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#define DROPBEAR_MODE_UNUSED 0
|
||||
#define DROPBEAR_MODE_CBC 1
|
||||
#define DROPBEAR_MODE_CTR 2
|
||||
|
||||
struct Algo_Type {
|
||||
|
||||
unsigned char *name; /* identifying name */
|
||||
const char *name; /* identifying name */
|
||||
char val; /* a value for this cipher, or -1 for invalid */
|
||||
void *data; /* algorithm specific data */
|
||||
unsigned usable : 1; /* whether we can use this algorithm */
|
||||
|
||||
const void *data; /* algorithm specific data */
|
||||
char usable; /* whether we can use this algorithm */
|
||||
const void *mode; /* the mode, currently only used for ciphers,
|
||||
points to a 'struct dropbear_cipher_mode' */
|
||||
};
|
||||
|
||||
typedef struct Algo_Type algo_type;
|
||||
|
||||
/* lists mapping ssh types of algorithms to internal values */
|
||||
extern algo_type sshkex[];
|
||||
extern algo_type sshhostkey[];
|
||||
extern algo_type sigalgs[];
|
||||
extern algo_type sshciphers[];
|
||||
extern algo_type sshhashes[];
|
||||
extern algo_type sshcompress[];
|
||||
extern algo_type ssh_compress[];
|
||||
extern algo_type ssh_delaycompress[];
|
||||
extern algo_type ssh_nocompress[];
|
||||
|
||||
extern const struct dropbear_cipher dropbear_nocipher;
|
||||
extern const struct dropbear_cipher_mode dropbear_mode_none;
|
||||
extern const struct dropbear_hash dropbear_nohash;
|
||||
|
||||
struct dropbear_cipher {
|
||||
const struct _cipher_descriptor *cipherdesc;
|
||||
unsigned long keysize;
|
||||
unsigned char blocksize;
|
||||
const struct ltc_cipher_descriptor *cipherdesc;
|
||||
const unsigned long keysize;
|
||||
const unsigned char blocksize;
|
||||
};
|
||||
|
||||
struct dropbear_cipher_mode {
|
||||
int (*start)(int cipher, const unsigned char *IV,
|
||||
const unsigned char *key,
|
||||
int keylen, int num_rounds, void *cipher_state);
|
||||
int (*encrypt)(const unsigned char *pt, unsigned char *ct,
|
||||
unsigned long len, void *cipher_state);
|
||||
int (*decrypt)(const unsigned char *ct, unsigned char *pt,
|
||||
unsigned long len, void *cipher_state);
|
||||
int (*aead_crypt)(unsigned int seq,
|
||||
const unsigned char *in, unsigned char *out,
|
||||
unsigned long len, unsigned long taglen,
|
||||
void *cipher_state, int direction);
|
||||
int (*aead_getlength)(unsigned int seq,
|
||||
const unsigned char *in, unsigned int *outlen,
|
||||
unsigned long len, void *cipher_state);
|
||||
const struct dropbear_hash *aead_mac;
|
||||
};
|
||||
|
||||
struct dropbear_hash {
|
||||
const struct _hash_descriptor *hashdesc;
|
||||
unsigned long keysize;
|
||||
unsigned char hashsize;
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
const unsigned long keysize;
|
||||
/* hashsize may be truncated from the size returned by hash_desc,
|
||||
eg sha1-96 */
|
||||
const unsigned char hashsize;
|
||||
};
|
||||
|
||||
void crypto_init();
|
||||
int have_algo(char* algo, size_t algolen, algo_type algos[]);
|
||||
void buf_put_algolist(buffer * buf, algo_type localalgos[]);
|
||||
enum dropbear_kex_mode {
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
DROPBEAR_KEX_NORMAL_DH,
|
||||
#endif
|
||||
#if DROPBEAR_ECDH
|
||||
DROPBEAR_KEX_ECDH,
|
||||
#endif
|
||||
#if DROPBEAR_CURVE25519
|
||||
DROPBEAR_KEX_CURVE25519,
|
||||
#endif
|
||||
};
|
||||
|
||||
algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int *goodguess);
|
||||
algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int *goodguess);
|
||||
struct dropbear_kex {
|
||||
enum dropbear_kex_mode mode;
|
||||
|
||||
/* "normal" DH KEX */
|
||||
const unsigned char *dh_p_bytes;
|
||||
const int dh_p_len;
|
||||
|
||||
#endif /* _ALGO_H_ */
|
||||
/* elliptic curve DH KEX */
|
||||
#if DROPBEAR_ECDH
|
||||
const struct dropbear_ecc_curve *ecc_curve;
|
||||
#else
|
||||
const void* dummy;
|
||||
#endif
|
||||
|
||||
/* both */
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
};
|
||||
|
||||
/* Includes all algorithms is useall is set */
|
||||
void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall);
|
||||
/* Includes "usable" algorithms */
|
||||
void buf_put_algolist(buffer * buf, const algo_type localalgos[]);
|
||||
|
||||
#define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au"
|
||||
|
||||
int buf_has_algo(buffer *buf, const char *algo);
|
||||
algo_type * first_usable_algo(algo_type algos[]);
|
||||
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int kexguess2, int *goodguess);
|
||||
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
int check_user_algos(const char* user_algo_list, algo_type * algos,
|
||||
const char *algo_desc);
|
||||
char * algolist_string(const algo_type algos[]);
|
||||
#endif
|
||||
|
||||
enum {
|
||||
DROPBEAR_COMP_NONE,
|
||||
DROPBEAR_COMP_ZLIB,
|
||||
DROPBEAR_COMP_ZLIB_DELAY,
|
||||
};
|
||||
|
||||
#endif /* DROPBEAR_ALGO_H_ */
|
||||
|
||||
31
atomicio.c
31
atomicio.c
@@ -1,6 +1,8 @@
|
||||
/* $OpenBSD: atomicio.c,v 1.17 2006/04/01 05:51:34 djm Exp $ */
|
||||
/*
|
||||
* Copied from OpenSSH 3.6.1p2, required for loginrec.c
|
||||
* Copied from OpenSSH/OpenBSD.
|
||||
*
|
||||
* Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
|
||||
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -25,39 +27,32 @@
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Taken from OpenSSH for use with the loginrec code */
|
||||
|
||||
/* RCSID("OpenBSD: atomicio.c,v 1.10 2001/05/08 22:48:07 markus Exp "); */
|
||||
#include "includes.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
|
||||
atomicio(f, fd, _s, n)
|
||||
ssize_t (*f) ();
|
||||
int fd;
|
||||
void *_s;
|
||||
size_t n;
|
||||
size_t
|
||||
atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
|
||||
{
|
||||
char *s = _s;
|
||||
ssize_t res, pos = 0;
|
||||
size_t pos = 0;
|
||||
ssize_t res;
|
||||
|
||||
while (n > pos) {
|
||||
res = (f) (fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
#ifdef EWOULDBLOCK
|
||||
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
#else
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
#endif
|
||||
continue;
|
||||
return 0;
|
||||
case 0:
|
||||
return (res);
|
||||
errno = EPIPE;
|
||||
return pos;
|
||||
default:
|
||||
pos += res;
|
||||
pos += (size_t)res;
|
||||
}
|
||||
}
|
||||
return (pos);
|
||||
|
||||
13
atomicio.h
13
atomicio.h
@@ -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
|
||||
*
|
||||
* $OpenBSD: atomicio.h,v 1.4 2001/06/26 06:32:46 itojun Exp $
|
||||
* Copied from OpenSSH/OpenBSD, required for loginrec.c
|
||||
*
|
||||
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
|
||||
* All rights reserved.
|
||||
@@ -28,9 +27,9 @@
|
||||
* 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
|
||||
|
||||
127
auth.h
127
auth.h
@@ -22,77 +22,124 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _AUTH_H_
|
||||
#define _AUTH_H_
|
||||
#ifndef DROPBEAR_AUTH_H_
|
||||
#define DROPBEAR_AUTH_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
#include "chansession.h"
|
||||
|
||||
void svr_authinitialise();
|
||||
void cli_authinitialise();
|
||||
void svr_authinitialise(void);
|
||||
void cli_authinitialise(void);
|
||||
|
||||
/* 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_success();
|
||||
void svr_auth_password();
|
||||
void svr_auth_pubkey();
|
||||
void send_msg_userauth_success(void);
|
||||
void send_msg_userauth_banner(const buffer *msg);
|
||||
void svr_auth_password(int valid_user);
|
||||
void svr_auth_pubkey(int valid_user);
|
||||
void svr_auth_pam(int valid_user);
|
||||
|
||||
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
|
||||
int svr_pubkey_allows_agentfwd(void);
|
||||
int svr_pubkey_allows_tcpfwd(void);
|
||||
int svr_pubkey_allows_x11fwd(void);
|
||||
int svr_pubkey_allows_pty(void);
|
||||
void svr_pubkey_set_forced_command(struct ChanSess *chansess);
|
||||
void svr_pubkey_options_cleanup(void);
|
||||
int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filename);
|
||||
#else
|
||||
/* no option : success */
|
||||
#define svr_pubkey_allows_agentfwd() 1
|
||||
#define svr_pubkey_allows_tcpfwd() 1
|
||||
#define svr_pubkey_allows_x11fwd() 1
|
||||
#define svr_pubkey_allows_pty() 1
|
||||
static inline void svr_pubkey_set_forced_command(struct ChanSess *chansess) { }
|
||||
static inline void svr_pubkey_options_cleanup(void) { }
|
||||
#define svr_add_pubkey_options(x,y,z) DROPBEAR_SUCCESS
|
||||
#endif
|
||||
|
||||
/* Client functions */
|
||||
void recv_msg_userauth_failure();
|
||||
void recv_msg_userauth_success();
|
||||
void recv_msg_userauth_pk_ok();
|
||||
void cli_get_user();
|
||||
void cli_auth_getmethods();
|
||||
void cli_auth_try();
|
||||
void recv_msg_userauth_banner();
|
||||
void cli_pubkeyfail();
|
||||
int cli_auth_password();
|
||||
int cli_auth_pubkey();
|
||||
void recv_msg_userauth_failure(void);
|
||||
void recv_msg_userauth_success(void);
|
||||
void recv_msg_userauth_specific_60(void);
|
||||
void recv_msg_userauth_pk_ok(void);
|
||||
void recv_msg_userauth_info_request(void);
|
||||
void cli_get_user(void);
|
||||
void cli_auth_getmethods(void);
|
||||
int cli_auth_try(void);
|
||||
void recv_msg_userauth_banner(void);
|
||||
void cli_pubkeyfail(void);
|
||||
void cli_auth_password(void);
|
||||
int cli_auth_pubkey(void);
|
||||
void cli_auth_interactive(void);
|
||||
char* getpass_or_cancel(const char* prompt);
|
||||
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_PUBKEY 1 << 0
|
||||
#define AUTH_TYPE_PASSWORD 1 << 1
|
||||
#define AUTH_TYPE_NONE 1
|
||||
#define AUTH_TYPE_PUBKEY (1 << 1)
|
||||
#define AUTH_TYPE_PASSWORD (1 << 2)
|
||||
#define AUTH_TYPE_INTERACT (1 << 3)
|
||||
|
||||
/* auth types, "none" means we should return list of acceptable types */
|
||||
#define AUTH_METHOD_NONE "none"
|
||||
#define AUTH_METHOD_NONE "none"
|
||||
#define AUTH_METHOD_NONE_LEN 4
|
||||
#define AUTH_METHOD_PUBKEY "publickey"
|
||||
#define AUTH_METHOD_PUBKEY_LEN 9
|
||||
#define AUTH_METHOD_PASSWORD "password"
|
||||
#define AUTH_METHOD_PASSWORD_LEN 8
|
||||
#define AUTH_METHOD_INTERACT "keyboard-interactive"
|
||||
#define AUTH_METHOD_INTERACT_LEN 20
|
||||
|
||||
|
||||
|
||||
/* This structure is shared between server and client - it contains
|
||||
* relatively little extraneous bits when used for the client rather than the
|
||||
* server */
|
||||
struct AuthState {
|
||||
|
||||
char *username; /* This is the username the client presents to check. It
|
||||
is updated each run through, used for auth checking */
|
||||
unsigned char authtypes; /* Flags indicating which auth types are still
|
||||
valid */
|
||||
unsigned int failcount; /* Number of (failed) authentication attempts.*/
|
||||
unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have. Applies for
|
||||
client and server (though has differing [obvious]
|
||||
unsigned int authdone; /* 0 if we haven't authed, 1 if we have. Applies for
|
||||
client and server (though has differing
|
||||
meanings). */
|
||||
|
||||
unsigned int perm_warn; /* Server only, set if bad permissions on
|
||||
~/.ssh/authorized_keys have already been
|
||||
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 */
|
||||
char *printableuser; /* stripped of control chars, used for logs etc */
|
||||
struct passwd * pw;
|
||||
|
||||
uid_t pw_uid;
|
||||
gid_t pw_gid;
|
||||
char *pw_dir;
|
||||
char *pw_shell;
|
||||
char *pw_name;
|
||||
char *pw_passwd;
|
||||
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
|
||||
struct PubKeyOptions* pubkey_options;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct PubkeyList;
|
||||
/* A singly linked list of pubkeys */
|
||||
struct PubkeyList {
|
||||
|
||||
sign_key *key;
|
||||
int type; /* The type of key */
|
||||
struct PubkeyList *next;
|
||||
/* filename? or the buffer? for encrypted keys, so we can later get
|
||||
* the private key portion */
|
||||
|
||||
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
|
||||
struct PubKeyOptions;
|
||||
struct PubKeyOptions {
|
||||
/* Flags */
|
||||
int no_port_forwarding_flag;
|
||||
int no_agent_forwarding_flag;
|
||||
int no_x11_forwarding_flag;
|
||||
int no_pty_flag;
|
||||
/* "command=" option. */
|
||||
char * forced_command;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* _AUTH_H_ */
|
||||
#endif /* DROPBEAR_AUTH_H_ */
|
||||
|
||||
80
bignum.c
80
bignum.c
@@ -31,7 +31,7 @@
|
||||
void m_mp_init(mp_int *mp) {
|
||||
|
||||
if (mp_init(mp) != MP_OKAY) {
|
||||
dropbear_exit("mem alloc error");
|
||||
dropbear_exit("Mem alloc error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,56 +39,66 @@ void m_mp_init(mp_int *mp) {
|
||||
* on error */
|
||||
void m_mp_init_multi(mp_int *mp, ...)
|
||||
{
|
||||
mp_int* cur_arg = mp;
|
||||
va_list args;
|
||||
mp_int* cur_arg = mp;
|
||||
va_list args;
|
||||
|
||||
va_start(args, mp); /* init args to next argument from caller */
|
||||
while (cur_arg != NULL) {
|
||||
if (mp_init(cur_arg) != MP_OKAY) {
|
||||
dropbear_exit("mem alloc error");
|
||||
}
|
||||
cur_arg = va_arg(args, mp_int*);
|
||||
}
|
||||
va_end(args);
|
||||
va_start(args, mp); /* init args to next argument from caller */
|
||||
while (cur_arg != NULL) {
|
||||
if (mp_init(cur_arg) != MP_OKAY) {
|
||||
dropbear_exit("Mem alloc error");
|
||||
}
|
||||
cur_arg = va_arg(args, mp_int*);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* convert an unsigned mp into an array of bytes, malloced.
|
||||
* This array must be freed after use, len contains the length of the array,
|
||||
* if len != NULL */
|
||||
unsigned char* mptobytes(mp_int *mp, int *len) {
|
||||
|
||||
unsigned char* ret;
|
||||
int size;
|
||||
void m_mp_alloc_init_multi(mp_int **mp, ...)
|
||||
{
|
||||
mp_int** cur_arg = mp;
|
||||
va_list args;
|
||||
|
||||
size = mp_unsigned_bin_size(mp);
|
||||
ret = m_malloc(size);
|
||||
if (mp_to_unsigned_bin(mp, ret) != MP_OKAY) {
|
||||
dropbear_exit("mem alloc error");
|
||||
va_start(args, mp); /* init args to next argument from caller */
|
||||
while (cur_arg != NULL) {
|
||||
*cur_arg = m_malloc(sizeof(mp_int));
|
||||
if (mp_init(*cur_arg) != MP_OKAY) {
|
||||
dropbear_exit("Mem alloc error");
|
||||
}
|
||||
cur_arg = va_arg(args, mp_int**);
|
||||
}
|
||||
if (len != NULL) {
|
||||
*len = size;
|
||||
}
|
||||
return ret;
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void bytestomp(mp_int *mp, unsigned char* bytes, unsigned int len) {
|
||||
void m_mp_free_multi(mp_int **mp, ...)
|
||||
{
|
||||
mp_int** cur_arg = mp;
|
||||
va_list args;
|
||||
|
||||
if (mp_read_unsigned_bin(mp, bytes, len) != MP_OKAY) {
|
||||
dropbear_exit("mem alloc error");
|
||||
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) {
|
||||
|
||||
if (mp_from_ubin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
|
||||
dropbear_exit("Mem alloc error");
|
||||
}
|
||||
}
|
||||
|
||||
/* hash the ssh representation of the mp_int mp */
|
||||
void sha1_process_mp(hash_state *hs, mp_int *mp) {
|
||||
|
||||
int i;
|
||||
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
|
||||
hash_state *hs, mp_int *mp) {
|
||||
buffer * buf;
|
||||
|
||||
buf = buf_new(512 + 20); /* max buffer is a 4096 bit key,
|
||||
plus header + some leeway*/
|
||||
buf_putmpint(buf, mp);
|
||||
i = buf->pos;
|
||||
buf_setpos(buf, 0);
|
||||
sha1_process(hs, buf_getptr(buf, i), i);
|
||||
hash_desc->process(hs, buf->data, buf->len);
|
||||
buf_free(buf);
|
||||
}
|
||||
|
||||
18
bignum.h
18
bignum.h
@@ -22,15 +22,17 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _BIGNUM_H_
|
||||
#define _BIGNUM_H_
|
||||
#ifndef DROPBEAR_BIGNUM_H_
|
||||
#define DROPBEAR_BIGNUM_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbhelpers.h"
|
||||
|
||||
void m_mp_init(mp_int *mp);
|
||||
void m_mp_init_multi(mp_int *mp, ...);
|
||||
unsigned char* mptobytes(mp_int *mp, int *len);
|
||||
void bytestomp(mp_int *mp, unsigned char* bytes, unsigned int len);
|
||||
void sha1_process_mp(hash_state *hs, mp_int *mp);
|
||||
void m_mp_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 hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
|
||||
hash_state *hs, mp_int *mp);
|
||||
|
||||
#endif /* _BIGNUM_H_ */
|
||||
#endif /* DROPBEAR_BIGNUM_H_ */
|
||||
|
||||
139
buffer.c
139
buffer.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
@@ -46,17 +46,15 @@ buffer* buf_new(unsigned int size) {
|
||||
dropbear_exit("buf->size too big");
|
||||
}
|
||||
|
||||
buf = (buffer*)m_malloc(sizeof(buffer));
|
||||
buf = (buffer*)m_malloc(sizeof(buffer)+size);
|
||||
|
||||
if (size > 0) {
|
||||
buf->data = (unsigned char*)m_malloc(size);
|
||||
buf->data = (unsigned char*)buf + sizeof(buffer);
|
||||
} else {
|
||||
buf->data = NULL;
|
||||
}
|
||||
|
||||
buf->size = size;
|
||||
buf->pos = 0;
|
||||
buf->len = 0;
|
||||
|
||||
return buf;
|
||||
|
||||
@@ -65,12 +63,11 @@ buffer* buf_new(unsigned int size) {
|
||||
/* free the buffer's data and the buffer itself */
|
||||
void buf_free(buffer* buf) {
|
||||
|
||||
m_free(buf->data)
|
||||
m_free(buf);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
@@ -78,43 +75,47 @@ void buf_burn(buffer* buf) {
|
||||
|
||||
/* resize a buffer, pos and len will be repositioned if required when
|
||||
* downsizing */
|
||||
void buf_resize(buffer *buf, unsigned int newsize) {
|
||||
buffer* buf_resize(buffer *buf, unsigned int newsize) {
|
||||
|
||||
if (newsize > BUF_MAX_SIZE) {
|
||||
dropbear_exit("buf->size too big");
|
||||
}
|
||||
|
||||
buf->data = m_realloc(buf->data, newsize);
|
||||
buf = m_realloc(buf, sizeof(buffer)+newsize);
|
||||
buf->data = (unsigned char*)buf + sizeof(buffer);
|
||||
buf->size = newsize;
|
||||
buf->len = MIN(newsize, buf->len);
|
||||
buf->pos = MIN(newsize, buf->pos);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Create a copy of buf, allocating required memory etc. */
|
||||
/* 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;
|
||||
|
||||
ret = buf_new(buf->len);
|
||||
ret->len = buf->len;
|
||||
memcpy(ret->data, buf->data, buf->len);
|
||||
if (buf->len > 0) {
|
||||
memcpy(ret->data, buf->data, buf->len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set the length of the buffer */
|
||||
void buf_setlen(buffer* buf, unsigned int len) {
|
||||
if (len > buf->size) {
|
||||
dropbear_exit("bad buf_setlen");
|
||||
dropbear_exit("Bad buf_setlen");
|
||||
}
|
||||
buf->len = len;
|
||||
buf->pos = MIN(buf->pos, buf->len);
|
||||
}
|
||||
|
||||
/* Increment the length of the buffer */
|
||||
void buf_incrlen(buffer* buf, unsigned int incr) {
|
||||
if (incr > BUF_MAX_INCR || buf->len + incr > buf->size) {
|
||||
dropbear_exit("bad buf_incrlen");
|
||||
dropbear_exit("Bad buf_incrlen");
|
||||
}
|
||||
buf->len += incr;
|
||||
}
|
||||
@@ -122,15 +123,15 @@ void buf_incrlen(buffer* buf, unsigned int incr) {
|
||||
void buf_setpos(buffer* buf, unsigned int pos) {
|
||||
|
||||
if (pos > buf->len) {
|
||||
dropbear_exit("bad buf_setpos");
|
||||
dropbear_exit("Bad buf_setpos");
|
||||
}
|
||||
buf->pos = pos;
|
||||
}
|
||||
|
||||
/* increment the postion by incr, increasing the buffer length if required */
|
||||
/* increment the position by incr, increasing the buffer length if required */
|
||||
void buf_incrwritepos(buffer* buf, unsigned int incr) {
|
||||
if (incr > BUF_MAX_INCR || buf->pos + incr > buf->size) {
|
||||
dropbear_exit("bad buf_incrwritepos");
|
||||
dropbear_exit("Bad buf_incrwritepos");
|
||||
}
|
||||
buf->pos += incr;
|
||||
if (buf->pos > buf->len) {
|
||||
@@ -141,10 +142,11 @@ void buf_incrwritepos(buffer* buf, unsigned int incr) {
|
||||
/* increment the position by incr, negative values are allowed, to
|
||||
* decrement the pos*/
|
||||
void buf_incrpos(buffer* buf, int incr) {
|
||||
if (incr > BUF_MAX_INCR ||
|
||||
(unsigned int)((int)buf->pos + incr) > buf->len
|
||||
|| ((int)buf->pos + incr) < 0) {
|
||||
dropbear_exit("bad buf_incrpos");
|
||||
if (incr > BUF_MAX_INCR
|
||||
|| incr < -BUF_MAX_INCR
|
||||
|| (unsigned int)((int)buf->pos + incr) > buf->len
|
||||
|| ((int)buf->pos + incr) < 0) {
|
||||
dropbear_exit("Bad buf_incrpos");
|
||||
}
|
||||
buf->pos += incr;
|
||||
}
|
||||
@@ -153,13 +155,23 @@ void buf_incrpos(buffer* buf, int incr) {
|
||||
unsigned char buf_getbyte(buffer* buf) {
|
||||
|
||||
/* This check is really just ==, but the >= allows us to check for the
|
||||
* assert()able case of pos > len, which should _never_ happen. */
|
||||
* bad case of pos > len, which should _never_ happen. */
|
||||
if (buf->pos >= buf->len) {
|
||||
dropbear_exit("bad buf_getbyte");
|
||||
dropbear_exit("Bad buf_getbyte");
|
||||
}
|
||||
return buf->data[buf->pos++];
|
||||
}
|
||||
|
||||
/* Get a bool from the buffer and increment the pos */
|
||||
unsigned char buf_getbool(buffer* buf) {
|
||||
|
||||
unsigned char b;
|
||||
b = buf_getbyte(buf);
|
||||
if (b != 0)
|
||||
b = 1;
|
||||
return b;
|
||||
}
|
||||
|
||||
/* put a byte, incrementing the length if required */
|
||||
void buf_putbyte(buffer* buf, unsigned char val) {
|
||||
|
||||
@@ -172,20 +184,20 @@ void buf_putbyte(buffer* buf, unsigned char val) {
|
||||
|
||||
/* returns an in-place pointer to the buffer, checking that
|
||||
* 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) {
|
||||
dropbear_exit("bad buf_getptr");
|
||||
if (len > BUF_MAX_INCR || buf->pos + len > buf->len) {
|
||||
dropbear_exit("Bad buf_getptr");
|
||||
}
|
||||
return &buf->data[buf->pos];
|
||||
}
|
||||
|
||||
/* like buf_getptr, but checks against total size, not used length.
|
||||
* 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) {
|
||||
dropbear_exit("bad buf_getwriteptr");
|
||||
if (len > BUF_MAX_INCR || buf->pos + len > buf->size) {
|
||||
dropbear_exit("Bad buf_getwriteptr");
|
||||
}
|
||||
return &buf->data[buf->pos];
|
||||
}
|
||||
@@ -193,26 +205,60 @@ unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) {
|
||||
/* Return a null-terminated string, it is malloced, so must be free()ed
|
||||
* Note that the string isn't checked for null bytes, hence the retlen
|
||||
* may be longer than what is returned by strlen */
|
||||
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
|
||||
unsigned int len;
|
||||
unsigned char* ret;
|
||||
char* ret;
|
||||
void* src = NULL;
|
||||
len = buf_getint(buf);
|
||||
if (len > MAX_STRING_LEN) {
|
||||
dropbear_exit("string too long");
|
||||
dropbear_exit("String too long");
|
||||
}
|
||||
|
||||
if (retlen != NULL) {
|
||||
*retlen = len;
|
||||
}
|
||||
src = buf_getptr(buf, len);
|
||||
ret = m_malloc(len+1);
|
||||
memcpy(ret, buf_getptr(buf, len), len);
|
||||
memcpy(ret, src, len);
|
||||
buf_incrpos(buf, len);
|
||||
ret[len] = '\0';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return a string as a newly allocated buffer */
|
||||
static buffer * buf_getstringbuf_int(buffer *buf, int incllen) {
|
||||
buffer *ret = NULL;
|
||||
unsigned int len = buf_getint(buf);
|
||||
int extra = 0;
|
||||
if (len > MAX_STRING_LEN) {
|
||||
dropbear_exit("String too long");
|
||||
}
|
||||
if (incllen) {
|
||||
extra = 4;
|
||||
}
|
||||
ret = buf_new(len+extra);
|
||||
if (incllen) {
|
||||
buf_putint(ret, len);
|
||||
}
|
||||
memcpy(buf_getwriteptr(ret, len), buf_getptr(buf, len), len);
|
||||
buf_incrpos(buf, len);
|
||||
buf_incrlen(ret, len);
|
||||
buf_setpos(ret, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return a string as a newly allocated buffer */
|
||||
buffer * buf_getstringbuf(buffer *buf) {
|
||||
return buf_getstringbuf_int(buf, 0);
|
||||
}
|
||||
|
||||
/* Returns a string in a new buffer, including the length */
|
||||
buffer * buf_getbuf(buffer *buf) {
|
||||
return buf_getstringbuf_int(buf, 1);
|
||||
}
|
||||
|
||||
/* Just increment the buffer position the same as if we'd used buf_getstring,
|
||||
* but don't bother copying/malloc()ing for it */
|
||||
void buf_eatstring(buffer *buf) {
|
||||
@@ -238,13 +284,18 @@ void buf_putint(buffer* buf, int unsigned val) {
|
||||
}
|
||||
|
||||
/* put a SSH style string into the buffer, increasing buffer len if required */
|
||||
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len) {
|
||||
void buf_putstring(buffer* buf, const char* str, unsigned int len) {
|
||||
|
||||
buf_putint(buf, len);
|
||||
buf_putbytes(buf, str, len);
|
||||
buf_putbytes(buf, (const unsigned char*)str, len);
|
||||
|
||||
}
|
||||
|
||||
/* puts an entire buffer as a SSH string. ignore pos of buf_str. */
|
||||
void buf_putbufstring(buffer *buf, const buffer* buf_str) {
|
||||
buf_putstring(buf, (const char*)buf_str->data, buf_str->len);
|
||||
}
|
||||
|
||||
/* put the set of len bytes into the buffer, incrementing the pos, increasing
|
||||
* len if required */
|
||||
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
|
||||
@@ -256,18 +307,18 @@ void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
|
||||
/* for our purposes we only need positive (or 0) numbers, so will
|
||||
* fail if we get negative numbers */
|
||||
void buf_putmpint(buffer* buf, mp_int * mp) {
|
||||
|
||||
size_t written;
|
||||
unsigned int len, pad = 0;
|
||||
TRACE(("enter buf_putmpint"));
|
||||
TRACE2(("enter buf_putmpint"))
|
||||
|
||||
assert(mp != NULL);
|
||||
dropbear_assert(mp != NULL);
|
||||
|
||||
if (SIGN(mp) == MP_NEG) {
|
||||
if (mp_isneg(mp)) {
|
||||
dropbear_exit("negative bignum");
|
||||
}
|
||||
|
||||
/* zero check */
|
||||
if (USED(mp) == 1 && DIGIT(mp, 0) == 0) {
|
||||
if (mp_iszero(mp)) {
|
||||
len = 0;
|
||||
} else {
|
||||
/* SSH spec requires padding for mpints with the MSB set, this code
|
||||
@@ -288,13 +339,13 @@ void buf_putmpint(buffer* buf, mp_int * mp) {
|
||||
if (pad) {
|
||||
buf_putbyte(buf, 0x00);
|
||||
}
|
||||
if (mp_to_unsigned_bin(mp, buf_getwriteptr(buf, len-pad)) != MP_OKAY) {
|
||||
if (mp_to_ubin(mp, buf_getwriteptr(buf, len-pad), len-pad, &written) != MP_OKAY) {
|
||||
dropbear_exit("mpint error");
|
||||
}
|
||||
buf_incrwritepos(buf, len-pad);
|
||||
buf_incrwritepos(buf, written);
|
||||
}
|
||||
|
||||
TRACE(("leave buf_putmpint"));
|
||||
TRACE2(("leave buf_putmpint"))
|
||||
}
|
||||
|
||||
/* Retrieve an mp_int from the buffer.
|
||||
@@ -319,7 +370,7 @@ int buf_getmpint(buffer* buf, mp_int* mp) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
if (mp_read_unsigned_bin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
|
||||
if (mp_from_ubin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
28
buffer.h
28
buffer.h
@@ -22,14 +22,15 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _BUFFER_H_
|
||||
#ifndef DROPBEAR_BUFFER_H_
|
||||
|
||||
#define _BUFFER_H_
|
||||
#define DROPBEAR_BUFFER_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
struct buf {
|
||||
|
||||
/* don't manipulate data member outside of buffer.c - it
|
||||
is a pointer into the malloc holding buffer itself */
|
||||
unsigned char * data;
|
||||
unsigned int len; /* the used size */
|
||||
unsigned int pos;
|
||||
@@ -40,26 +41,31 @@ struct buf {
|
||||
typedef struct buf buffer;
|
||||
|
||||
buffer * buf_new(unsigned int size);
|
||||
void buf_resize(buffer *buf, unsigned int newsize);
|
||||
/* Possibly returns a new buffer*, like realloc() */
|
||||
buffer * buf_resize(buffer *buf, unsigned int newsize);
|
||||
void buf_free(buffer* buf);
|
||||
void buf_burn(buffer* buf);
|
||||
buffer* buf_newcopy(buffer* buf);
|
||||
void buf_burn(const buffer* buf);
|
||||
buffer* buf_newcopy(const buffer* buf);
|
||||
void buf_setlen(buffer* buf, unsigned int len);
|
||||
void buf_incrlen(buffer* buf, unsigned int incr);
|
||||
void buf_setpos(buffer* buf, unsigned int pos);
|
||||
void buf_incrpos(buffer* buf, int incr); /* -ve is ok, to go backwards */
|
||||
void buf_incrwritepos(buffer* buf, unsigned int incr);
|
||||
unsigned char buf_getbyte(buffer* buf);
|
||||
unsigned char buf_getbool(buffer* buf);
|
||||
void buf_putbyte(buffer* buf, unsigned char val);
|
||||
unsigned char* buf_getptr(buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen);
|
||||
unsigned char* buf_getptr(const buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getwriteptr(const buffer* buf, unsigned int len);
|
||||
char* buf_getstring(buffer* buf, unsigned int *retlen);
|
||||
buffer * buf_getstringbuf(buffer *buf);
|
||||
buffer * buf_getbuf(buffer *buf);
|
||||
void buf_eatstring(buffer *buf);
|
||||
void buf_putint(buffer* buf, unsigned int val);
|
||||
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len);
|
||||
void buf_putstring(buffer* buf, const char* str, unsigned int len);
|
||||
void buf_putbufstring(buffer *buf, const buffer* buf_str);
|
||||
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
|
||||
void buf_putmpint(buffer* buf, mp_int * mp);
|
||||
int buf_getmpint(buffer* buf, mp_int* mp);
|
||||
unsigned int buf_getint(buffer* buf);
|
||||
|
||||
#endif /* _BUFFER_H_ */
|
||||
#endif /* DROPBEAR_BUFFER_H_ */
|
||||
|
||||
148
chachapoly.c
Normal file
148
chachapoly.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2020 by Vladislav Grishenko
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
#include "dbutil.h"
|
||||
#include "chachapoly.h"
|
||||
|
||||
#if DROPBEAR_CHACHA20POLY1305
|
||||
|
||||
#define CHACHA20_KEY_LEN 32
|
||||
#define CHACHA20_BLOCKSIZE 8
|
||||
#define POLY1305_KEY_LEN 32
|
||||
#define POLY1305_TAG_LEN 16
|
||||
|
||||
static const struct ltc_cipher_descriptor dummy = {.name = NULL};
|
||||
|
||||
static const struct dropbear_hash dropbear_chachapoly_mac =
|
||||
{NULL, POLY1305_KEY_LEN, POLY1305_TAG_LEN};
|
||||
|
||||
const struct dropbear_cipher dropbear_chachapoly =
|
||||
{&dummy, CHACHA20_KEY_LEN*2, CHACHA20_BLOCKSIZE};
|
||||
|
||||
static int dropbear_chachapoly_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
|
||||
const unsigned char *key, int keylen,
|
||||
int UNUSED(num_rounds), dropbear_chachapoly_state *state) {
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_chachapoly_start"))
|
||||
|
||||
if (keylen != CHACHA20_KEY_LEN*2) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
if ((err = chacha_setup(&state->chacha, key,
|
||||
CHACHA20_KEY_LEN, 20)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = chacha_setup(&state->header, key + CHACHA20_KEY_LEN,
|
||||
CHACHA20_KEY_LEN, 20) != CRYPT_OK)) {
|
||||
return err;
|
||||
}
|
||||
|
||||
TRACE2(("leave dropbear_chachapoly_start"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int dropbear_chachapoly_crypt(unsigned int seq,
|
||||
const unsigned char *in, unsigned char *out,
|
||||
unsigned long len, unsigned long taglen,
|
||||
dropbear_chachapoly_state *state, int direction) {
|
||||
poly1305_state poly;
|
||||
unsigned char seqbuf[8], key[POLY1305_KEY_LEN], tag[POLY1305_TAG_LEN];
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_chachapoly_crypt"))
|
||||
|
||||
if (len < 4 || taglen != POLY1305_TAG_LEN) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
STORE64H((uint64_t)seq, seqbuf);
|
||||
chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 0);
|
||||
if ((err = chacha_keystream(&state->chacha, key, sizeof(key))) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
poly1305_init(&poly, key, sizeof(key));
|
||||
if (direction == LTC_DECRYPT) {
|
||||
poly1305_process(&poly, in, len);
|
||||
poly1305_done(&poly, tag, &taglen);
|
||||
if (constant_time_memcmp(in + len, tag, taglen) != 0) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0);
|
||||
if ((err = chacha_crypt(&state->header, in, 4, out)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 1);
|
||||
if ((err = chacha_crypt(&state->chacha, in + 4, len - 4, out + 4)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (direction == LTC_ENCRYPT) {
|
||||
poly1305_process(&poly, out, len);
|
||||
poly1305_done(&poly, out + len, &taglen);
|
||||
}
|
||||
|
||||
TRACE2(("leave dropbear_chachapoly_crypt"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int dropbear_chachapoly_getlength(unsigned int seq,
|
||||
const unsigned char *in, unsigned int *outlen,
|
||||
unsigned long len, dropbear_chachapoly_state *state) {
|
||||
unsigned char seqbuf[8], buf[4];
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_chachapoly_getlength"))
|
||||
|
||||
if (len < sizeof(buf)) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
STORE64H((uint64_t)seq, seqbuf);
|
||||
chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0);
|
||||
if ((err = chacha_crypt(&state->header, in, sizeof(buf), buf)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
LOAD32H(*outlen, buf);
|
||||
|
||||
TRACE2(("leave dropbear_chachapoly_getlength"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
const struct dropbear_cipher_mode dropbear_mode_chachapoly =
|
||||
{(void *)dropbear_chachapoly_start, NULL, NULL,
|
||||
(void *)dropbear_chachapoly_crypt,
|
||||
(void *)dropbear_chachapoly_getlength, &dropbear_chachapoly_mac};
|
||||
|
||||
#endif /* DROPBEAR_CHACHA20POLY1305 */
|
||||
44
chachapoly.h
Normal file
44
chachapoly.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2020 by Vladislav Grishenko
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef DROPBEAR_DROPBEAR_CHACHAPOLY_H_
|
||||
#define DROPBEAR_DROPBEAR_CHACHAPOLY_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
|
||||
#if DROPBEAR_CHACHA20POLY1305
|
||||
|
||||
typedef struct {
|
||||
chacha_state chacha;
|
||||
chacha_state header;
|
||||
} dropbear_chachapoly_state;
|
||||
|
||||
extern const struct dropbear_cipher dropbear_chachapoly;
|
||||
extern const struct dropbear_cipher_mode dropbear_mode_chachapoly;
|
||||
|
||||
#endif /* DROPBEAR_CHACHA20POLY1305 */
|
||||
|
||||
#endif /* DROPBEAR_DROPBEAR_CHACHAPOLY_H_ */
|
||||
134
channel.h
134
channel.h
@@ -22,19 +22,12 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _CHANNEL_H_
|
||||
#define _CHANNEL_H_
|
||||
#ifndef DROPBEAR_CHANNEL_H_
|
||||
#define DROPBEAR_CHANNEL_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/* channel->type values */
|
||||
#define CHANNEL_ID_NONE 0
|
||||
#define CHANNEL_ID_SESSION 1
|
||||
#define CHANNEL_ID_X11 2
|
||||
#define CHANNEL_ID_AGENT 3
|
||||
#define CHANNEL_ID_TCPDIRECT 4
|
||||
#define CHANNEL_ID_TCPFORWARDED 5
|
||||
#include "circbuffer.h"
|
||||
|
||||
#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1
|
||||
#define SSH_OPEN_CONNECT_FAILED 2
|
||||
@@ -44,76 +37,111 @@
|
||||
/* Not a real type */
|
||||
#define SSH_OPEN_IN_PROGRESS 99
|
||||
|
||||
#define MAX_CHANNELS 60 /* simple mem restriction, includes each tcp/x11
|
||||
connection, so can't be _too_ small */
|
||||
|
||||
#define CHAN_EXTEND_SIZE 3 /* how many extra slots to add when we need more */
|
||||
|
||||
#define RECV_MAXWINDOW 6000 /* tweak */
|
||||
#define RECV_MAXPACKET 1400 /* tweak */
|
||||
#define RECV_MINWINDOW 19000 /* when we get below this, we send a windowadjust */
|
||||
|
||||
struct ChanType;
|
||||
|
||||
enum dropbear_channel_prio {
|
||||
DROPBEAR_CHANNEL_PRIO_INTERACTIVE, /* pty shell, x11 */
|
||||
DROPBEAR_CHANNEL_PRIO_UNKNOWABLE, /* tcp - can't know what's being forwarded */
|
||||
DROPBEAR_CHANNEL_PRIO_BULK, /* the rest - probably scp or something */
|
||||
DROPBEAR_CHANNEL_PRIO_EARLY, /* channel is still being set up */
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
|
||||
unsigned int index; /* the local channel index */
|
||||
unsigned int remotechan;
|
||||
unsigned int recvwindow, transwindow;
|
||||
unsigned int recvdonelen;
|
||||
unsigned int recvmaxpacket, transmaxpacket;
|
||||
void* typedata; /* a pointer to type specific data */
|
||||
int infd; /* stdin for the program, we write to this */
|
||||
int outfd; /* stdout for the program, we read from this */
|
||||
int errfd; /* stdout for a program. This doesn't really fit here,
|
||||
but makes the code a lot tidyer without being too bad. This
|
||||
is -1 for channels which don't requre it. Currently only
|
||||
a 'session' without a pty will use it */
|
||||
buffer *writebuf; /* data for the program */
|
||||
int writefd; /* read from wire, written to insecure side */
|
||||
int readfd; /* read from insecure side, written to wire */
|
||||
int errfd; /* used like writefd or readfd, depending if it's client or server.
|
||||
Doesn't exactly belong here, but is cleaner here */
|
||||
circbuffer *writebuf; /* data from the wire, for local consumption. Can be
|
||||
initially NULL */
|
||||
circbuffer *extrabuf; /* extended-data for the program - used like writebuf
|
||||
but for stderr */
|
||||
|
||||
int sentclosed, recvclosed;
|
||||
|
||||
/* this is set when we receive/send a channel eof packet */
|
||||
int recveof, senteof;
|
||||
/* whether close/eof messages have been exchanged */
|
||||
int sent_close, recv_close;
|
||||
int recv_eof, sent_eof;
|
||||
|
||||
struct dropbear_progress_connection *conn_pending;
|
||||
int initconn; /* used for TCP forwarding, whether the channel has been
|
||||
fully initialised */
|
||||
|
||||
int await_open; /* flag indicating whether we've sent an open request
|
||||
for this channel (and are awaiting a confirmation
|
||||
or failure). */
|
||||
|
||||
int flushing;
|
||||
|
||||
/* Used by client chansession to handle ~ escaping, NULL ignored otherwise */
|
||||
void (*read_mangler)(const struct Channel*, const unsigned char* bytes, int *len);
|
||||
|
||||
const struct ChanType* type;
|
||||
|
||||
enum dropbear_channel_prio prio;
|
||||
};
|
||||
|
||||
struct ChanType {
|
||||
|
||||
int sepfds; /* Whether this channel has seperate pipes for in/out or not */
|
||||
char *name;
|
||||
int sepfds; /* Whether this channel has separate pipes for in/out or not */
|
||||
const char *name;
|
||||
/* Sets up the channel */
|
||||
int (*inithandler)(struct Channel*);
|
||||
int (*checkclose)(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 (*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*);
|
||||
};
|
||||
|
||||
void chaninitialise();
|
||||
void chancleanup();
|
||||
void setchannelfds(fd_set *readfd, fd_set *writefd);
|
||||
void channelio(fd_set *readfd, fd_set *writefd);
|
||||
struct Channel* newchannel(unsigned int remotechan,
|
||||
const struct ChanType *type,
|
||||
unsigned int transwindow, unsigned int transmaxpacket);
|
||||
/* Callback for connect_remote */
|
||||
void channel_connect_done(int result, int sock, void* user_data, const char* errstring);
|
||||
|
||||
void recv_msg_channel_open();
|
||||
void recv_msg_channel_request();
|
||||
void send_msg_channel_failure(struct Channel *channel);
|
||||
void send_msg_channel_success(struct Channel *channel);
|
||||
void recv_msg_channel_data();
|
||||
void recv_msg_channel_window_adjust();
|
||||
void recv_msg_channel_close();
|
||||
void recv_msg_channel_eof();
|
||||
void chaninitialise(const struct ChanType *chantypes[]);
|
||||
void chancleanup(void);
|
||||
void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads);
|
||||
void channelio(const fd_set *readfd, const fd_set *writefd);
|
||||
struct Channel* getchannel(void);
|
||||
/* Returns an arbitrary channel that is in a ready state - not
|
||||
being initialised and no EOF in either direction. NULL if none. */
|
||||
struct Channel* get_any_ready_channel(void);
|
||||
|
||||
#ifdef USING_LISTENERS
|
||||
int send_msg_channel_open_init(int fd, const struct ChanType *type);
|
||||
void recv_msg_channel_open_confirmation();
|
||||
void recv_msg_channel_open_failure();
|
||||
void recv_msg_channel_open(void);
|
||||
void recv_msg_channel_request(void);
|
||||
void send_msg_channel_failure(const struct Channel *channel);
|
||||
void send_msg_channel_success(const struct Channel *channel);
|
||||
void recv_msg_channel_data(void);
|
||||
void recv_msg_channel_extended_data(void);
|
||||
void recv_msg_channel_window_adjust(void);
|
||||
void recv_msg_channel_close(void);
|
||||
void recv_msg_channel_eof(void);
|
||||
|
||||
void common_recv_msg_channel_data(struct Channel *channel, int fd,
|
||||
circbuffer * buf);
|
||||
|
||||
#if DROPBEAR_CLIENT
|
||||
extern const struct ChanType clichansess;
|
||||
#endif
|
||||
|
||||
#endif /* _CHANNEL_H_ */
|
||||
#if DROPBEAR_LISTENERS || DROPBEAR_CLIENT
|
||||
int send_msg_channel_open_init(int fd, const struct ChanType *type);
|
||||
void recv_msg_channel_open_confirmation(void);
|
||||
void recv_msg_channel_open_failure(void);
|
||||
#endif
|
||||
void start_send_channel_request(const struct Channel *channel, const char *type);
|
||||
|
||||
void send_msg_request_success(void);
|
||||
void send_msg_request_failure(void);
|
||||
|
||||
|
||||
#endif /* DROPBEAR_CHANNEL_H_ */
|
||||
|
||||
@@ -22,31 +22,46 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _CHANSESSION_H_
|
||||
#define _CHANSESSION_H_
|
||||
#ifndef DROPBEAR_CHANSESSION_H_
|
||||
#define DROPBEAR_CHANSESSION_H_
|
||||
|
||||
#include "loginrec.h"
|
||||
#include "channel.h"
|
||||
#include "listener.h"
|
||||
|
||||
struct exitinfo {
|
||||
|
||||
int exitpid; /* -1 if not exited */
|
||||
int exitstatus;
|
||||
int exitsignal;
|
||||
int exitcore;
|
||||
};
|
||||
|
||||
struct ChanSess {
|
||||
|
||||
unsigned char * cmd; /* command to exec */
|
||||
char * cmd; /* command to exec */
|
||||
pid_t pid; /* child process pid */
|
||||
/* command that was sent by the client, if authorized_keys command= or
|
||||
dropbear -c was used */
|
||||
char *original_command;
|
||||
|
||||
/* pty details */
|
||||
int master; /* the master terminal fd*/
|
||||
int slave;
|
||||
unsigned char * tty;
|
||||
unsigned char * term;
|
||||
char * tty;
|
||||
char * term;
|
||||
|
||||
/* exit details */
|
||||
int exited;
|
||||
int exitstatus;
|
||||
int exitsignal;
|
||||
unsigned char exitcore;
|
||||
struct exitinfo exit;
|
||||
|
||||
|
||||
/* These are only set temporarily before forking */
|
||||
/* Used to set $SSH_CONNECTION in the child session. */
|
||||
char *connection_string;
|
||||
/* Used to set $SSH_CLIENT in the child session. */
|
||||
char *client_string;
|
||||
|
||||
#ifndef DISABLE_X11FWD
|
||||
#if DROPBEAR_X11FWD
|
||||
struct Listener * x11listener;
|
||||
int x11port;
|
||||
char * x11authprot;
|
||||
@@ -55,7 +70,7 @@ struct ChanSess {
|
||||
unsigned char x11singleconn;
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
#if DROPBEAR_SVR_AGENTFWD
|
||||
struct Listener * agentlistener;
|
||||
char * agentfile;
|
||||
char * agentdir;
|
||||
@@ -68,18 +83,17 @@ struct ChildPid {
|
||||
};
|
||||
|
||||
|
||||
void chansessionrequest(struct Channel * channel);
|
||||
void send_msg_chansess_exitstatus(struct Channel * channel,
|
||||
struct ChanSess * chansess);
|
||||
void send_msg_chansess_exitsignal(struct Channel * channel,
|
||||
struct ChanSess * chansess);
|
||||
void addnewvar(const char* param, const char* var);
|
||||
|
||||
void cli_send_chansess_request();
|
||||
void cli_tty_cleanup();
|
||||
void cli_chansess_winchange();
|
||||
void cli_send_chansess_request(void);
|
||||
void cli_tty_cleanup(void);
|
||||
void cli_chansess_winchange(void);
|
||||
#if DROPBEAR_CLI_NETCAT
|
||||
void cli_send_netcat_request(void);
|
||||
#endif
|
||||
|
||||
void svr_chansessinitialise();
|
||||
void svr_chansessinitialise(void);
|
||||
void svr_chansess_checksignal(void);
|
||||
extern const struct ChanType svrchansess;
|
||||
|
||||
struct SigMap {
|
||||
@@ -89,4 +103,4 @@ struct SigMap {
|
||||
|
||||
extern const struct SigMap signames[];
|
||||
|
||||
#endif /* _CHANSESSION_H_ */
|
||||
#endif /* DROPBEAR_CHANSESSION_H_ */
|
||||
|
||||
133
circbuffer.c
Normal file
133
circbuffer.c
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002-2004 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "circbuffer.h"
|
||||
|
||||
#define MAX_CBUF_SIZE 100000000
|
||||
|
||||
circbuffer * cbuf_new(unsigned int size) {
|
||||
|
||||
circbuffer *cbuf = NULL;
|
||||
|
||||
if (size > MAX_CBUF_SIZE) {
|
||||
dropbear_exit("Bad cbuf size");
|
||||
}
|
||||
|
||||
cbuf = (circbuffer*)m_malloc(sizeof(circbuffer));
|
||||
/* data is malloced on first write */
|
||||
cbuf->data = NULL;
|
||||
cbuf->used = 0;
|
||||
cbuf->readpos = 0;
|
||||
cbuf->writepos = 0;
|
||||
cbuf->size = size;
|
||||
|
||||
return cbuf;
|
||||
}
|
||||
|
||||
void cbuf_free(circbuffer * cbuf) {
|
||||
|
||||
if (cbuf->data) {
|
||||
m_burn(cbuf->data, cbuf->size);
|
||||
m_free(cbuf->data);
|
||||
}
|
||||
m_free(cbuf);
|
||||
}
|
||||
|
||||
unsigned int cbuf_getused(const circbuffer * cbuf) {
|
||||
|
||||
return cbuf->used;
|
||||
|
||||
}
|
||||
|
||||
unsigned int cbuf_getavail(const circbuffer * cbuf) {
|
||||
|
||||
return cbuf->size - cbuf->used;
|
||||
|
||||
}
|
||||
|
||||
unsigned int cbuf_writelen(const circbuffer *cbuf) {
|
||||
|
||||
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->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
|
||||
|
||||
if (cbuf->used == cbuf->size) {
|
||||
TRACE(("cbuf_writelen: full buffer"))
|
||||
return 0; /* full */
|
||||
}
|
||||
|
||||
if (cbuf->writepos < cbuf->readpos) {
|
||||
return cbuf->readpos - cbuf->writepos;
|
||||
}
|
||||
|
||||
return cbuf->size - cbuf->writepos;
|
||||
}
|
||||
|
||||
void cbuf_readptrs(const circbuffer *cbuf,
|
||||
unsigned char **p1, unsigned int *len1,
|
||||
unsigned char **p2, unsigned int *len2) {
|
||||
*p1 = &cbuf->data[cbuf->readpos];
|
||||
*len1 = MIN(cbuf->used, cbuf->size - cbuf->readpos);
|
||||
|
||||
if (*len1 < cbuf->used) {
|
||||
*p2 = cbuf->data;
|
||||
*len2 = cbuf->used - *len1;
|
||||
} else {
|
||||
*p2 = NULL;
|
||||
*len2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
|
||||
|
||||
if (len > cbuf_writelen(cbuf)) {
|
||||
dropbear_exit("Bad cbuf write");
|
||||
}
|
||||
|
||||
if (!cbuf->data) {
|
||||
/* lazy allocation */
|
||||
cbuf->data = (unsigned char*)m_malloc(cbuf->size);
|
||||
}
|
||||
|
||||
return &cbuf->data[cbuf->writepos];
|
||||
}
|
||||
|
||||
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len) {
|
||||
if (len > cbuf_writelen(cbuf)) {
|
||||
dropbear_exit("Bad cbuf write");
|
||||
}
|
||||
|
||||
cbuf->used += len;
|
||||
dropbear_assert(cbuf->used <= cbuf->size);
|
||||
cbuf->writepos = (cbuf->writepos + len) % cbuf->size;
|
||||
}
|
||||
|
||||
|
||||
void cbuf_incrread(circbuffer *cbuf, unsigned int len) {
|
||||
dropbear_assert(cbuf->used >= len);
|
||||
cbuf->used -= len;
|
||||
cbuf->readpos = (cbuf->readpos + len) % cbuf->size;
|
||||
}
|
||||
52
circbuffer.h
Normal file
52
circbuffer.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002-2004 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef DROPBEAR_CIRCBUFFER_H_
|
||||
#define DROPBEAR_CIRCBUFFER_H_
|
||||
struct circbuf {
|
||||
|
||||
unsigned int size;
|
||||
unsigned int readpos;
|
||||
unsigned int writepos;
|
||||
unsigned int used;
|
||||
unsigned char* data;
|
||||
};
|
||||
|
||||
typedef struct circbuf circbuffer;
|
||||
|
||||
circbuffer * cbuf_new(unsigned int size);
|
||||
void cbuf_free(circbuffer * cbuf);
|
||||
|
||||
unsigned int cbuf_getused(const circbuffer * cbuf); /* how much data stored */
|
||||
unsigned int cbuf_getavail(const circbuffer * cbuf); /* how much we can write */
|
||||
unsigned int cbuf_writelen(const circbuffer *cbuf); /* max linear write 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);
|
||||
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len);
|
||||
void cbuf_incrread(circbuffer *cbuf, unsigned int len);
|
||||
#endif
|
||||
316
cli-agentfwd.c
Normal file
316
cli-agentfwd.c
Normal file
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2005 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
|
||||
#include "agentfwd.h"
|
||||
#include "session.h"
|
||||
#include "ssh.h"
|
||||
#include "dbutil.h"
|
||||
#include "chansession.h"
|
||||
#include "channel.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "dbrandom.h"
|
||||
#include "listener.h"
|
||||
#include "runopts.h"
|
||||
#include "atomicio.h"
|
||||
#include "signkey.h"
|
||||
#include "auth.h"
|
||||
|
||||
/* The protocol implemented to talk to OpenSSH's SSH2 agent is documented in
|
||||
PROTOCOL.agent in recent OpenSSH source distributions (5.1p1 has it). */
|
||||
|
||||
static int new_agent_chan(struct Channel * channel);
|
||||
|
||||
const struct ChanType cli_chan_agent = {
|
||||
0, /* sepfds */
|
||||
"auth-agent@openssh.com",
|
||||
new_agent_chan,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int connect_agent() {
|
||||
|
||||
int fd = -1;
|
||||
char* agent_sock = NULL;
|
||||
|
||||
agent_sock = getenv("SSH_AUTH_SOCK");
|
||||
if (agent_sock == NULL)
|
||||
return -1;
|
||||
|
||||
fd = connect_unix(agent_sock);
|
||||
|
||||
if (fd < 0) {
|
||||
dropbear_log(LOG_INFO, "Failed to connect to agent");
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* handle a request for a connection to the locally running ssh-agent
|
||||
or forward. */
|
||||
static int new_agent_chan(struct Channel * channel) {
|
||||
|
||||
int fd = -1;
|
||||
|
||||
if (!cli_opts.agent_fwd)
|
||||
return SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
|
||||
|
||||
fd = connect_agent();
|
||||
if (fd < 0) {
|
||||
return SSH_OPEN_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
setnonblocking(fd);
|
||||
|
||||
ses.maxfd = MAX(ses.maxfd, fd);
|
||||
|
||||
channel->readfd = fd;
|
||||
channel->writefd = fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sends a request to the agent, returning a newly allocated buffer
|
||||
* with the response */
|
||||
/* This function will block waiting for a response - it will
|
||||
* only be used by client authentication (not for forwarded requests)
|
||||
* won't cause problems for interactivity. */
|
||||
/* Packet format (from draft-ylonen)
|
||||
4 bytes Length, msb first. Does not include length itself.
|
||||
1 byte Packet type. The value 255 is reserved for future extensions.
|
||||
data Any data, depending on packet type. Encoding as in the ssh packet
|
||||
protocol.
|
||||
*/
|
||||
static buffer * agent_request(unsigned char type, const buffer *data) {
|
||||
|
||||
buffer * payload = NULL;
|
||||
buffer * inbuf = NULL;
|
||||
size_t readlen = 0;
|
||||
ssize_t ret;
|
||||
const int fd = cli_opts.agent_fd;
|
||||
unsigned int data_len = 0;
|
||||
if (data)
|
||||
{
|
||||
data_len = data->len;
|
||||
}
|
||||
|
||||
payload = buf_new(4 + 1 + data_len);
|
||||
|
||||
buf_putint(payload, 1 + data_len);
|
||||
buf_putbyte(payload, type);
|
||||
if (data) {
|
||||
buf_putbytes(payload, data->data, data->len);
|
||||
}
|
||||
buf_setpos(payload, 0);
|
||||
|
||||
ret = atomicio(vwrite, fd, buf_getptr(payload, payload->len), payload->len);
|
||||
if ((size_t)ret != payload->len) {
|
||||
TRACE(("write failed fd %d for agent_request, %s", fd, strerror(errno)))
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf_free(payload);
|
||||
payload = NULL;
|
||||
TRACE(("Wrote out bytes for agent_request"))
|
||||
/* Now we read the response */
|
||||
inbuf = buf_new(4);
|
||||
ret = atomicio(read, fd, buf_getwriteptr(inbuf, 4), 4);
|
||||
if (ret != 4) {
|
||||
TRACE(("read of length failed for agent_request"))
|
||||
goto out;
|
||||
}
|
||||
buf_setpos(inbuf, 0);
|
||||
buf_setlen(inbuf, ret);
|
||||
|
||||
readlen = buf_getint(inbuf);
|
||||
if (readlen > MAX_AGENT_REPLY) {
|
||||
TRACE(("agent reply is too big"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
inbuf = buf_resize(inbuf, readlen);
|
||||
buf_setpos(inbuf, 0);
|
||||
ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
|
||||
if ((size_t)ret != readlen) {
|
||||
TRACE(("read of data failed for agent_request"))
|
||||
goto out;
|
||||
}
|
||||
buf_incrwritepos(inbuf, readlen);
|
||||
buf_setpos(inbuf, 0);
|
||||
|
||||
out:
|
||||
if (payload)
|
||||
buf_free(payload);
|
||||
|
||||
return inbuf;
|
||||
}
|
||||
|
||||
static void agent_get_key_list(m_list * ret_list)
|
||||
{
|
||||
buffer * inbuf = NULL;
|
||||
unsigned int num = 0;
|
||||
unsigned char packet_type;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
inbuf = agent_request(SSH2_AGENTC_REQUEST_IDENTITIES, NULL);
|
||||
if (!inbuf) {
|
||||
TRACE(("agent_request failed returning identities"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The reply has a format of:
|
||||
byte SSH2_AGENT_IDENTITIES_ANSWER
|
||||
uint32 num_keys
|
||||
Followed by zero or more consecutive keys, encoded as:
|
||||
string key_blob
|
||||
string key_comment
|
||||
*/
|
||||
packet_type = buf_getbyte(inbuf);
|
||||
if (packet_type != SSH2_AGENT_IDENTITIES_ANSWER) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
num = buf_getint(inbuf);
|
||||
for (i = 0; i < num; i++) {
|
||||
sign_key * pubkey = NULL;
|
||||
enum signkey_type key_type = DROPBEAR_SIGNKEY_ANY;
|
||||
buffer * key_buf;
|
||||
|
||||
/* each public key is encoded as a string */
|
||||
key_buf = buf_getstringbuf(inbuf);
|
||||
pubkey = new_sign_key();
|
||||
ret = buf_get_pub_key(key_buf, pubkey, &key_type);
|
||||
buf_free(key_buf);
|
||||
if (ret != DROPBEAR_SUCCESS) {
|
||||
TRACE(("Skipping bad/unknown type pubkey from agent"));
|
||||
sign_key_free(pubkey);
|
||||
} else {
|
||||
pubkey->type = key_type;
|
||||
pubkey->source = SIGNKEY_SOURCE_AGENT;
|
||||
|
||||
list_append(ret_list, pubkey);
|
||||
}
|
||||
|
||||
/* We'll ignore the comment for now. might want it later.*/
|
||||
buf_eatstring(inbuf);
|
||||
}
|
||||
|
||||
out:
|
||||
if (inbuf) {
|
||||
buf_free(inbuf);
|
||||
inbuf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void cli_setup_agent(const struct Channel *channel) {
|
||||
if (!getenv("SSH_AUTH_SOCK")) {
|
||||
return;
|
||||
}
|
||||
|
||||
start_send_channel_request(channel, "auth-agent-req@openssh.com");
|
||||
/* Don't want replies */
|
||||
buf_putbyte(ses.writepayload, 0);
|
||||
encrypt_packet();
|
||||
}
|
||||
|
||||
/* Returned keys are prepended to ret_list, which will
|
||||
be updated. */
|
||||
void cli_load_agent_keys(m_list *ret_list) {
|
||||
/* agent_fd will be closed after successful auth */
|
||||
cli_opts.agent_fd = connect_agent();
|
||||
if (cli_opts.agent_fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
agent_get_key_list(ret_list);
|
||||
}
|
||||
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const buffer *data_buf, enum signature_type sigtype) {
|
||||
buffer *request_data = NULL;
|
||||
buffer *response = NULL;
|
||||
unsigned int siglen;
|
||||
int packet_type;
|
||||
int flags = 0;
|
||||
|
||||
/* Request format
|
||||
byte SSH2_AGENTC_SIGN_REQUEST
|
||||
string key_blob
|
||||
string data
|
||||
uint32 flags
|
||||
*/
|
||||
request_data = buf_new(MAX_PUBKEY_SIZE + data_buf->len + 12);
|
||||
buf_put_pub_key(request_data, key, key->type);
|
||||
|
||||
buf_putbufstring(request_data, data_buf);
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) {
|
||||
flags |= SSH_AGENT_RSA_SHA2_256;
|
||||
}
|
||||
#endif
|
||||
buf_putint(request_data, flags);
|
||||
|
||||
response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
|
||||
|
||||
if (!response) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
packet_type = buf_getbyte(response);
|
||||
if (packet_type != SSH2_AGENT_SIGN_RESPONSE) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Response format
|
||||
byte SSH2_AGENT_SIGN_RESPONSE
|
||||
string signature_blob
|
||||
*/
|
||||
siglen = buf_getint(response);
|
||||
buf_putbytes(sigblob, buf_getptr(response, siglen), siglen);
|
||||
goto cleanup;
|
||||
|
||||
fail:
|
||||
/* XXX don't fail badly here. instead propagate a failure code back up to
|
||||
the cli auth pubkey code, and just remove this key from the list of
|
||||
ones to try. */
|
||||
dropbear_exit("Agent failed signing key");
|
||||
|
||||
cleanup:
|
||||
if (request_data) {
|
||||
buf_free(request_data);
|
||||
}
|
||||
if (response) {
|
||||
buf_free(response);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
99
cli-algo.c
99
cli-algo.c
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
* SSH client implementation
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2004 by Mihnea Stoenescu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "algo.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
|
||||
/*
|
||||
* The chosen [encryption | MAC | compression] algorithm to each
|
||||
* direction MUST be the first algorithm on the client's list
|
||||
* that is also on the server's list.
|
||||
*/
|
||||
algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int *goodguess) {
|
||||
|
||||
unsigned char * algolist = NULL;
|
||||
unsigned char * remotealgos[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
unsigned int count, i, j;
|
||||
algo_type * ret = NULL;
|
||||
|
||||
*goodguess = 0;
|
||||
|
||||
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
|
||||
algolist = buf_getstring(buf, &len);
|
||||
TRACE(("cli_buf_match_algo: %s", algolist));
|
||||
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
goto out; /* just a sanity check, no other use */
|
||||
}
|
||||
|
||||
/* remotealgos will contain a list of the strings parsed out */
|
||||
/* We will have at least one string (even if it's just "") */
|
||||
remotealgos[0] = algolist;
|
||||
count = 1;
|
||||
/* Iterate through, replacing ','s with NULs, to split it into
|
||||
* words. */
|
||||
for (i = 0; i < len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
goto out;
|
||||
}
|
||||
if (algolist[i] == ',') {
|
||||
algolist[i] = '\0';
|
||||
remotealgos[count] = &algolist[i+1];
|
||||
count++;
|
||||
}
|
||||
if (count == MAX_PROPOSED_ALGO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* iterate and find the first match */
|
||||
|
||||
for (j = 0; localalgos[j].name != NULL; j++) {
|
||||
if (localalgos[j].usable) {
|
||||
len = strlen(localalgos[j].name);
|
||||
for (i = 0; i < count; i++) {
|
||||
if (len == strlen(remotealgos[i])
|
||||
&& strncmp(localalgos[j].name,
|
||||
remotealgos[i], len) == 0) {
|
||||
if (i == 0 && j == 0) {
|
||||
/* was a good guess */
|
||||
*goodguess = 1;
|
||||
}
|
||||
ret = &localalgos[j];
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(algolist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
263
cli-auth.c
263
cli-auth.c
@@ -32,7 +32,6 @@
|
||||
#include "packet.h"
|
||||
#include "runopts.h"
|
||||
|
||||
|
||||
void cli_authinitialise() {
|
||||
|
||||
memset(&ses.authstate, 0, sizeof(ses.authstate));
|
||||
@@ -41,32 +40,51 @@ void cli_authinitialise() {
|
||||
|
||||
/* Send a "none" auth request to get available methods */
|
||||
void cli_auth_getmethods() {
|
||||
|
||||
TRACE(("enter cli_auth_getmethods"));
|
||||
|
||||
TRACE(("enter cli_auth_getmethods"))
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
strlen(cli_opts.username));
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
SSH_SERVICE_CONNECTION_LEN);
|
||||
buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave cli_auth_getmethods"));
|
||||
|
||||
#if DROPBEAR_CLI_IMMEDIATE_AUTH
|
||||
/* We can't haven't two auth requests in-flight with delayed zlib mode
|
||||
since if the first one succeeds then the remote side will
|
||||
expect the second one to be compressed.
|
||||
Race described at
|
||||
http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/zlib-openssh.html
|
||||
*/
|
||||
if (ses.keys->trans.algo_comp != DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.authstate.authtypes = AUTH_TYPE_PUBKEY;
|
||||
#if DROPBEAR_USE_PASSWORD_ENV
|
||||
if (getenv(DROPBEAR_PASSWORD_ENV)) {
|
||||
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT;
|
||||
}
|
||||
#endif
|
||||
if (cli_auth_try() == DROPBEAR_SUCCESS) {
|
||||
TRACE(("skipped initial none auth query"))
|
||||
/* Note that there will be two auth responses in-flight */
|
||||
cli_ses.ignore_next_auth_response = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
TRACE(("leave cli_auth_getmethods"))
|
||||
}
|
||||
|
||||
void recv_msg_userauth_banner() {
|
||||
|
||||
unsigned char* banner = NULL;
|
||||
char* banner = NULL;
|
||||
unsigned int bannerlen;
|
||||
unsigned int i, linecount;
|
||||
int truncated = 0;
|
||||
|
||||
TRACE(("enter recv_msg_userauth_banner"));
|
||||
TRACE(("enter recv_msg_userauth_banner"))
|
||||
if (ses.authstate.authdone) {
|
||||
TRACE(("leave recv_msg_userauth_banner: banner after auth done"));
|
||||
TRACE(("leave recv_msg_userauth_banner: banner after auth done"))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -74,60 +92,124 @@ void recv_msg_userauth_banner() {
|
||||
buf_eatstring(ses.payload); /* The language string */
|
||||
|
||||
if (bannerlen > MAX_BANNER_SIZE) {
|
||||
TRACE(("recv_msg_userauth_banner: bannerlen too long: %d", bannerlen));
|
||||
goto out;
|
||||
}
|
||||
TRACE(("recv_msg_userauth_banner: bannerlen too long: %d", bannerlen))
|
||||
truncated = 1;
|
||||
} else {
|
||||
cleantext(banner);
|
||||
|
||||
cleantext(banner);
|
||||
|
||||
/* Limit to 25 lines */
|
||||
linecount = 1;
|
||||
for (i = 0; i < bannerlen; i++) {
|
||||
if (banner[i] == '\n') {
|
||||
if (linecount >= MAX_BANNER_LINES) {
|
||||
banner[i] = '\0';
|
||||
break;
|
||||
/* Limit to 24 lines */
|
||||
linecount = 1;
|
||||
for (i = 0; i < bannerlen; i++) {
|
||||
if (banner[i] == '\n') {
|
||||
if (linecount >= MAX_BANNER_LINES) {
|
||||
banner[i] = '\0';
|
||||
truncated = 1;
|
||||
break;
|
||||
}
|
||||
linecount++;
|
||||
}
|
||||
linecount++;
|
||||
}
|
||||
fprintf(stderr, "%s\n", banner);
|
||||
}
|
||||
|
||||
printf("%s\n", banner);
|
||||
if (truncated) {
|
||||
fprintf(stderr, "[Banner from the server is too long]\n");
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(banner);
|
||||
TRACE(("leave recv_msg_userauth_banner"));
|
||||
TRACE(("leave recv_msg_userauth_banner"))
|
||||
}
|
||||
|
||||
/* This handles the message-specific types which
|
||||
* all have a value of 60. These are
|
||||
* SSH_MSG_USERAUTH_PASSWD_CHANGEREQ,
|
||||
* SSH_MSG_USERAUTH_PK_OK, &
|
||||
* SSH_MSG_USERAUTH_INFO_REQUEST. */
|
||||
void recv_msg_userauth_specific_60() {
|
||||
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
|
||||
recv_msg_userauth_pk_ok();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_CLI_INTERACT_AUTH
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT) {
|
||||
recv_msg_userauth_info_request();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_CLI_PASSWORD_AUTH
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_PASSWORD) {
|
||||
/* Eventually there could be proper password-changing
|
||||
* support. However currently few servers seem to
|
||||
* implement it, and password auth is last-resort
|
||||
* regardless - keyboard-interactive is more likely
|
||||
* to be used anyway. */
|
||||
dropbear_close("Your password has expired.");
|
||||
}
|
||||
#endif
|
||||
|
||||
dropbear_exit("Unexpected userauth packet");
|
||||
}
|
||||
|
||||
void recv_msg_userauth_failure() {
|
||||
|
||||
unsigned char * methods = NULL;
|
||||
unsigned char * tok = NULL;
|
||||
char * methods = NULL;
|
||||
char * tok = NULL;
|
||||
unsigned int methlen = 0;
|
||||
unsigned int partial = 0;
|
||||
unsigned int i = 0;
|
||||
|
||||
TRACE(("<- MSG_USERAUTH_FAILURE"));
|
||||
TRACE(("enter recv_msg_userauth_failure"));
|
||||
TRACE(("<- MSG_USERAUTH_FAILURE"))
|
||||
TRACE(("enter recv_msg_userauth_failure"))
|
||||
|
||||
if (cli_ses.state != USERAUTH_REQ_SENT) {
|
||||
/* Perhaps we should be more fatal? */
|
||||
TRACE(("But we didn't send a userauth request!!!!!!"));
|
||||
if (ses.authstate.authdone) {
|
||||
TRACE(("leave recv_msg_userauth_failure, already authdone."))
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
/* If it was a pubkey auth request, we should cross that key
|
||||
* off the list. */
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
|
||||
cli_pubkeyfail();
|
||||
if (cli_ses.state != USERAUTH_REQ_SENT) {
|
||||
/* Perhaps we should be more fatal? */
|
||||
dropbear_exit("Unexpected userauth failure");
|
||||
}
|
||||
|
||||
/* When DROPBEAR_CLI_IMMEDIATE_AUTH is set there will be an initial response for
|
||||
the "none" auth request, and then a response to the immediate auth request.
|
||||
We need to be careful handling them. */
|
||||
if (cli_ses.ignore_next_auth_response) {
|
||||
cli_ses.state = USERAUTH_REQ_SENT;
|
||||
cli_ses.ignore_next_auth_response = 0;
|
||||
TRACE(("leave recv_msg_userauth_failure, ignored response, state set to USERAUTH_REQ_SENT"));
|
||||
return;
|
||||
} else {
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
/* If it was a pubkey auth request, we should cross that key
|
||||
* off the list. */
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
|
||||
cli_pubkeyfail();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_CLI_INTERACT_AUTH
|
||||
/* If we get a failure message for keyboard interactive without
|
||||
* receiving any request info packet, then we don't bother trying
|
||||
* keyboard interactive again */
|
||||
if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT
|
||||
&& !cli_ses.interact_request_received) {
|
||||
TRACE(("setting auth_interact_failed = 1"))
|
||||
cli_ses.auth_interact_failed = 1;
|
||||
}
|
||||
#endif
|
||||
cli_ses.state = USERAUTH_FAIL_RCVD;
|
||||
cli_ses.lastauthtype = AUTH_TYPE_NONE;
|
||||
}
|
||||
|
||||
methods = buf_getstring(ses.payload, &methlen);
|
||||
|
||||
partial = buf_getbyte(ses.payload);
|
||||
partial = buf_getbool(ses.payload);
|
||||
|
||||
if (partial) {
|
||||
dropbear_log(LOG_INFO, "Authentication partially succeeded, more attempts required");
|
||||
@@ -135,7 +217,7 @@ void recv_msg_userauth_failure() {
|
||||
ses.authstate.failcount++;
|
||||
}
|
||||
|
||||
TRACE(("Methods (len %d): '%s'", methlen, methods));
|
||||
TRACE(("Methods (len %d): '%s'", methlen, methods))
|
||||
|
||||
ses.authstate.authdone=0;
|
||||
ses.authstate.authtypes=0;
|
||||
@@ -150,14 +232,20 @@ void recv_msg_userauth_failure() {
|
||||
tok = methods; /* tok stores the next method we'll compare */
|
||||
for (i = 0; i <= methlen; i++) {
|
||||
if (methods[i] == '\0') {
|
||||
TRACE(("auth method '%s'", tok));
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
TRACE(("auth method '%s'", tok))
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
if (strncmp(AUTH_METHOD_PUBKEY, tok,
|
||||
AUTH_METHOD_PUBKEY_LEN) == 0) {
|
||||
ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_PASSWORD_AUTH
|
||||
#if DROPBEAR_CLI_INTERACT_AUTH
|
||||
if (strncmp(AUTH_METHOD_INTERACT, tok,
|
||||
AUTH_METHOD_INTERACT_LEN) == 0) {
|
||||
ses.authstate.authtypes |= AUTH_TYPE_INTERACT;
|
||||
}
|
||||
#endif
|
||||
#if DROPBEAR_CLI_PASSWORD_AUTH
|
||||
if (strncmp(AUTH_METHOD_PASSWORD, tok,
|
||||
AUTH_METHOD_PASSWORD_LEN) == 0) {
|
||||
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
|
||||
@@ -169,42 +257,101 @@ void recv_msg_userauth_failure() {
|
||||
}
|
||||
}
|
||||
|
||||
cli_ses.state = USERAUTH_FAIL_RCVD;
|
||||
m_free(methods);
|
||||
|
||||
TRACE(("leave recv_msg_userauth_failure"));
|
||||
TRACE(("leave recv_msg_userauth_failure"))
|
||||
}
|
||||
|
||||
void recv_msg_userauth_success() {
|
||||
TRACE(("received msg_userauth_success"));
|
||||
/* This function can validly get called multiple times
|
||||
if DROPBEAR_CLI_IMMEDIATE_AUTH is set */
|
||||
|
||||
TRACE(("received msg_userauth_success"))
|
||||
/* Note: in delayed-zlib mode, setting authdone here
|
||||
* will enable compression in the transport layer */
|
||||
ses.authstate.authdone = 1;
|
||||
cli_ses.state = USERAUTH_SUCCESS_RCVD;
|
||||
cli_ses.lastauthtype = AUTH_TYPE_NONE;
|
||||
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
cli_auth_pubkey_cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void cli_auth_try() {
|
||||
int cli_auth_try() {
|
||||
|
||||
TRACE(("enter cli_auth_try"));
|
||||
int finished = 0;
|
||||
TRACE(("enter cli_auth_try"))
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
/* XXX We hardcode that we try a pubkey first */
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
/* Order to try is pubkey, interactive, password.
|
||||
* As soon as "finished" is set for one, we don't do any more. */
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
|
||||
finished = cli_auth_pubkey();
|
||||
cli_ses.lastauthtype = AUTH_TYPE_PUBKEY;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_PASSWORD_AUTH
|
||||
if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
|
||||
finished = cli_auth_password();
|
||||
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
|
||||
#if DROPBEAR_CLI_PASSWORD_AUTH
|
||||
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_PASSWORD)) {
|
||||
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
|
||||
fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n");
|
||||
} else {
|
||||
cli_auth_password();
|
||||
finished = 1;
|
||||
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!finished) {
|
||||
dropbear_exit("No auth methods could be used.");
|
||||
#if DROPBEAR_CLI_INTERACT_AUTH
|
||||
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) {
|
||||
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
|
||||
fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n");
|
||||
} else {
|
||||
if (!cli_ses.auth_interact_failed) {
|
||||
cli_auth_interactive();
|
||||
cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
|
||||
finished = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE(("leave cli_auth_try"));
|
||||
TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype))
|
||||
|
||||
if (finished) {
|
||||
TRACE(("leave cli_auth_try success"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
TRACE(("leave cli_auth_try 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
|
||||
* password is statically allocated by getpass() */
|
||||
char* getpass_or_cancel(const char* prompt)
|
||||
{
|
||||
char* password = NULL;
|
||||
|
||||
#if DROPBEAR_USE_PASSWORD_ENV
|
||||
/* Password provided in an environment var */
|
||||
password = getenv(DROPBEAR_PASSWORD_ENV);
|
||||
if (password)
|
||||
{
|
||||
return password;
|
||||
}
|
||||
#endif
|
||||
|
||||
password = getpass(prompt);
|
||||
|
||||
/* 0x03 is a ctrl-c character in the buffer. */
|
||||
if (password == NULL || strchr(password, '\3') != NULL) {
|
||||
dropbear_close("Interrupted.");
|
||||
}
|
||||
return password;
|
||||
}
|
||||
#endif
|
||||
|
||||
175
cli-authinteract.c
Normal file
175
cli-authinteract.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2005 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "session.h"
|
||||
#include "ssh.h"
|
||||
#include "runopts.h"
|
||||
|
||||
#if DROPBEAR_CLI_INTERACT_AUTH
|
||||
|
||||
static char* get_response(char* prompt)
|
||||
{
|
||||
FILE* tty = NULL;
|
||||
char* response = NULL;
|
||||
/* not a password, but a reasonable limit */
|
||||
char buf[DROPBEAR_MAX_CLI_PASS];
|
||||
char* ret = NULL;
|
||||
|
||||
fprintf(stderr, "%s", prompt);
|
||||
|
||||
tty = fopen(_PATH_TTY, "r");
|
||||
if (tty) {
|
||||
ret = fgets(buf, sizeof(buf), tty);
|
||||
fclose(tty);
|
||||
} else {
|
||||
ret = fgets(buf, sizeof(buf), stdin);
|
||||
}
|
||||
|
||||
if (ret == NULL) {
|
||||
response = m_strdup("");
|
||||
} else {
|
||||
unsigned int buflen = strlen(buf);
|
||||
/* fgets includes newlines */
|
||||
if (buflen > 0 && buf[buflen-1] == '\n')
|
||||
buf[buflen-1] = '\0';
|
||||
response = m_strdup(buf);
|
||||
}
|
||||
|
||||
m_burn(buf, sizeof(buf));
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
void recv_msg_userauth_info_request() {
|
||||
|
||||
char *name = NULL;
|
||||
char *instruction = NULL;
|
||||
unsigned int num_prompts = 0;
|
||||
unsigned int i;
|
||||
|
||||
char *prompt = NULL;
|
||||
unsigned int echo = 0;
|
||||
char *response = NULL;
|
||||
|
||||
TRACE(("enter recv_msg_recv_userauth_info_request"))
|
||||
|
||||
/* Let the user know what password/host they are authing for */
|
||||
if (!cli_ses.interact_request_received) {
|
||||
fprintf(stderr, "Login for %s@%s\n", cli_opts.username,
|
||||
cli_opts.remotehost);
|
||||
}
|
||||
cli_ses.interact_request_received = 1;
|
||||
|
||||
name = buf_getstring(ses.payload, NULL);
|
||||
instruction = buf_getstring(ses.payload, NULL);
|
||||
|
||||
/* language tag */
|
||||
buf_eatstring(ses.payload);
|
||||
|
||||
num_prompts = buf_getint(ses.payload);
|
||||
|
||||
if (num_prompts >= DROPBEAR_MAX_CLI_INTERACT_PROMPTS) {
|
||||
dropbear_exit("Too many prompts received for keyboard-interactive");
|
||||
}
|
||||
|
||||
/* we'll build the response as we go */
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_INFO_RESPONSE);
|
||||
buf_putint(ses.writepayload, num_prompts);
|
||||
|
||||
if (strlen(name) > 0) {
|
||||
cleantext(name);
|
||||
fprintf(stderr, "%s", name);
|
||||
}
|
||||
m_free(name);
|
||||
|
||||
if (strlen(instruction) > 0) {
|
||||
cleantext(instruction);
|
||||
fprintf(stderr, "%s", instruction);
|
||||
}
|
||||
m_free(instruction);
|
||||
|
||||
for (i = 0; i < num_prompts; i++) {
|
||||
unsigned int response_len = 0;
|
||||
prompt = buf_getstring(ses.payload, NULL);
|
||||
cleantext(prompt);
|
||||
|
||||
echo = buf_getbool(ses.payload);
|
||||
|
||||
if (!echo) {
|
||||
char* p = getpass_or_cancel(prompt);
|
||||
response = m_strdup(p);
|
||||
m_burn(p, strlen(p));
|
||||
} else {
|
||||
response = get_response(prompt);
|
||||
}
|
||||
|
||||
response_len = strlen(response);
|
||||
buf_putstring(ses.writepayload, response, response_len);
|
||||
m_burn(response, response_len);
|
||||
m_free(prompt);
|
||||
m_free(response);
|
||||
}
|
||||
|
||||
encrypt_packet();
|
||||
|
||||
|
||||
TRACE(("leave recv_msg_recv_userauth_info_request"))
|
||||
}
|
||||
|
||||
void cli_auth_interactive() {
|
||||
|
||||
TRACE(("enter cli_auth_interactive"))
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
|
||||
|
||||
/* username */
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
strlen(cli_opts.username));
|
||||
|
||||
/* service name */
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
SSH_SERVICE_CONNECTION_LEN);
|
||||
|
||||
/* method */
|
||||
buf_putstring(ses.writepayload, AUTH_METHOD_INTERACT,
|
||||
AUTH_METHOD_INTERACT_LEN);
|
||||
|
||||
/* empty language tag */
|
||||
buf_putstring(ses.writepayload, "", 0);
|
||||
|
||||
/* empty submethods */
|
||||
buf_putstring(ses.writepayload, "", 0);
|
||||
|
||||
encrypt_packet();
|
||||
cli_ses.interact_request_received = 0;
|
||||
|
||||
TRACE(("leave cli_auth_interactive"))
|
||||
|
||||
}
|
||||
#endif /* DROPBEAR_CLI_INTERACT_AUTH */
|
||||
118
cli-authpasswd.c
118
cli-authpasswd.c
@@ -29,24 +29,124 @@
|
||||
#include "ssh.h"
|
||||
#include "runopts.h"
|
||||
|
||||
#ifdef ENABLE_CLI_PASSWORD_AUTH
|
||||
int cli_auth_password() {
|
||||
#if DROPBEAR_CLI_PASSWORD_AUTH
|
||||
|
||||
#if DROPBEAR_CLI_ASKPASS_HELPER
|
||||
/* Returns 1 if we want to use the askpass program, 0 otherwise */
|
||||
static int want_askpass()
|
||||
{
|
||||
char* askpass_prog = NULL;
|
||||
|
||||
askpass_prog = getenv("SSH_ASKPASS");
|
||||
return askpass_prog &&
|
||||
((!isatty(STDIN_FILENO) && getenv("DISPLAY") )
|
||||
|| getenv("SSH_ASKPASS_ALWAYS"));
|
||||
}
|
||||
|
||||
/* returns a statically allocated password from a helper app, or NULL
|
||||
* on failure */
|
||||
static char *gui_getpass(const char *prompt) {
|
||||
|
||||
pid_t pid;
|
||||
int p[2], maxlen, len, status;
|
||||
static char buf[DROPBEAR_MAX_CLI_PASS + 1];
|
||||
char* helper = NULL;
|
||||
|
||||
TRACE(("enter gui_getpass"))
|
||||
|
||||
helper = getenv("SSH_ASKPASS");
|
||||
if (!helper)
|
||||
{
|
||||
TRACE(("leave gui_getpass: no askpass program"))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pipe(p) < 0) {
|
||||
TRACE(("error creating child pipe"))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
TRACE(("fork error"))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!pid) {
|
||||
/* child */
|
||||
close(p[0]);
|
||||
if (dup2(p[1], STDOUT_FILENO) < 0) {
|
||||
TRACE(("error redirecting stdout"))
|
||||
exit(1);
|
||||
}
|
||||
close(p[1]);
|
||||
execlp(helper, helper, prompt, (char *)0);
|
||||
TRACE(("execlp error"))
|
||||
exit(1);
|
||||
}
|
||||
|
||||
close(p[1]);
|
||||
maxlen = sizeof(buf);
|
||||
while (maxlen > 0) {
|
||||
len = read(p[0], buf + sizeof(buf) - maxlen, maxlen);
|
||||
if (len > 0) {
|
||||
maxlen -= len;
|
||||
} else {
|
||||
if (errno != EINTR)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close(p[0]);
|
||||
|
||||
while (waitpid(pid, &status, 0) < 0 && errno == EINTR)
|
||||
;
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||
return(NULL);
|
||||
|
||||
len = sizeof(buf) - maxlen;
|
||||
buf[len] = '\0';
|
||||
if (len > 0 && buf[len - 1] == '\n')
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
TRACE(("leave gui_getpass"))
|
||||
return(buf);
|
||||
}
|
||||
#endif /* DROPBEAR_CLI_ASKPASS_HELPER */
|
||||
|
||||
void cli_auth_password() {
|
||||
|
||||
char* password = NULL;
|
||||
TRACE(("enter cli_auth_password"));
|
||||
char prompt[80];
|
||||
|
||||
TRACE(("enter cli_auth_password"))
|
||||
CHECKCLEARTOWRITE();
|
||||
password = getpass("Password: ");
|
||||
|
||||
snprintf(prompt, sizeof(prompt), "%s@%s's password: ",
|
||||
cli_opts.username, cli_opts.remotehost);
|
||||
#if DROPBEAR_CLI_ASKPASS_HELPER
|
||||
if (want_askpass())
|
||||
{
|
||||
password = gui_getpass(prompt);
|
||||
if (!password) {
|
||||
dropbear_exit("No password");
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
password = getpass_or_cancel(prompt);
|
||||
}
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
|
||||
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
strlen(cli_opts.username));
|
||||
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
SSH_SERVICE_CONNECTION_LEN);
|
||||
|
||||
buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD,
|
||||
buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD,
|
||||
AUTH_METHOD_PASSWORD_LEN);
|
||||
|
||||
buf_putbyte(ses.writepayload, 0); /* FALSE - so says the spec */
|
||||
@@ -56,8 +156,6 @@ int cli_auth_password() {
|
||||
encrypt_packet();
|
||||
m_burn(password, strlen(password));
|
||||
|
||||
TRACE(("leave cli_auth_password"));
|
||||
return 1; /* Password auth can always be tried */
|
||||
|
||||
TRACE(("leave cli_auth_password"))
|
||||
}
|
||||
#endif
|
||||
#endif /* DROPBEAR_CLI_PASSWORD_AUTH */
|
||||
|
||||
223
cli-authpubkey.c
223
cli-authpubkey.c
@@ -30,48 +30,44 @@
|
||||
#include "ssh.h"
|
||||
#include "runopts.h"
|
||||
#include "auth.h"
|
||||
#include "agentfwd.h"
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype, int realsign);
|
||||
|
||||
/* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request.
|
||||
* We use it to remove the key we tried from the list */
|
||||
void cli_pubkeyfail() {
|
||||
|
||||
struct PubkeyList *keyitem;
|
||||
struct PubkeyList **previtem;
|
||||
|
||||
TRACE(("enter cli_pubkeyfail"));
|
||||
previtem = &cli_opts.pubkeys;
|
||||
|
||||
/* Find the key we failed with, and remove it */
|
||||
for (keyitem = cli_opts.pubkeys; keyitem != NULL; keyitem = keyitem->next) {
|
||||
if (keyitem == cli_ses.lastpubkey) {
|
||||
*previtem = keyitem->next;
|
||||
m_list_elem *iter;
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next) {
|
||||
sign_key *iter_key = (sign_key*)iter->item;
|
||||
|
||||
if (iter_key == cli_ses.lastprivkey)
|
||||
{
|
||||
/* found the failing key */
|
||||
list_remove(iter);
|
||||
sign_key_free(iter_key);
|
||||
cli_ses.lastprivkey = NULL;
|
||||
return;
|
||||
}
|
||||
previtem = &keyitem;
|
||||
}
|
||||
|
||||
sign_key_free(cli_ses.lastpubkey->key); /* It won't be used again */
|
||||
m_free(cli_ses.lastpubkey);
|
||||
|
||||
TRACE(("leave cli_pubkeyfail"));
|
||||
}
|
||||
|
||||
void recv_msg_userauth_pk_ok() {
|
||||
|
||||
struct PubkeyList *keyitem;
|
||||
buffer* keybuf;
|
||||
m_list_elem *iter;
|
||||
buffer* keybuf = NULL;
|
||||
char* algotype = NULL;
|
||||
unsigned int algolen;
|
||||
int keytype;
|
||||
enum signkey_type keytype;
|
||||
enum signature_type sigtype;
|
||||
unsigned int remotelen;
|
||||
|
||||
TRACE(("enter recv_msg_userauth_pk_ok"));
|
||||
TRACE(("enter recv_msg_userauth_pk_ok"))
|
||||
|
||||
algotype = buf_getstring(ses.payload, &algolen);
|
||||
keytype = signkey_type_from_name(algotype, algolen);
|
||||
TRACE(("recv_msg_userauth_pk_ok: type %d", keytype));
|
||||
sigtype = signature_type_from_name(algotype, algolen);
|
||||
keytype = signkey_type_from_signature(sigtype);
|
||||
TRACE(("recv_msg_userauth_pk_ok: type %d", sigtype))
|
||||
m_free(algotype);
|
||||
|
||||
keybuf = buf_new(MAX_PUBKEY_SIZE);
|
||||
@@ -80,17 +76,17 @@ void recv_msg_userauth_pk_ok() {
|
||||
|
||||
/* Iterate through our keys, find which one it was that matched, and
|
||||
* send a real request with that key */
|
||||
for (keyitem = cli_opts.pubkeys; keyitem != NULL; keyitem = keyitem->next) {
|
||||
|
||||
if (keyitem->type != keytype) {
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next) {
|
||||
sign_key *key = (sign_key*)iter->item;
|
||||
if (key->type != keytype) {
|
||||
/* Types differed */
|
||||
TRACE(("types differed"));
|
||||
TRACE(("types differed"))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now we compare the contents of the key */
|
||||
keybuf->pos = keybuf->len = 0;
|
||||
buf_put_pub_key(keybuf, keyitem->key, keytype);
|
||||
buf_put_pub_key(keybuf, key, keytype);
|
||||
buf_setpos(keybuf, 0);
|
||||
buf_incrpos(keybuf, 4); /* first int is the length of the remainder (ie
|
||||
remotelen) which has already been taken from
|
||||
@@ -98,41 +94,60 @@ void recv_msg_userauth_pk_ok() {
|
||||
|
||||
|
||||
if (keybuf->len-4 != remotelen) {
|
||||
TRACE(("lengths differed: localh %d remote %d", keybuf->len, remotelen));
|
||||
TRACE(("lengths differed: localh %d remote %d", keybuf->len, remotelen))
|
||||
/* Lengths differed */
|
||||
continue;
|
||||
}
|
||||
if (memcmp(buf_getptr(keybuf, remotelen),
|
||||
buf_getptr(ses.payload, remotelen), remotelen) != 0) {
|
||||
/* Data didn't match this key */
|
||||
TRACE(("data differed"));
|
||||
TRACE(("data differed"))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
break;
|
||||
}
|
||||
buf_free(keybuf);
|
||||
|
||||
if (keyitem != NULL) {
|
||||
TRACE(("matching key"));
|
||||
if (iter != NULL) {
|
||||
TRACE(("matching key"))
|
||||
/* XXX TODO: if it's an encrypted key, here we ask for their
|
||||
* password */
|
||||
send_msg_userauth_pubkey(keyitem->key, keytype, 1);
|
||||
send_msg_userauth_pubkey((sign_key*)iter->item, sigtype, 1);
|
||||
} else {
|
||||
TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part"));
|
||||
TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part"))
|
||||
}
|
||||
|
||||
TRACE(("leave recv_msg_userauth_pk_ok"));
|
||||
|
||||
TRACE(("leave recv_msg_userauth_pk_ok"))
|
||||
}
|
||||
|
||||
/* TODO: make it take an agent reference to use as well */
|
||||
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
static void cli_buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype,
|
||||
const buffer *data_buf) {
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
// TODO: rsa-sha256 agent
|
||||
if (key->source == SIGNKEY_SOURCE_AGENT) {
|
||||
/* Format the agent signature ourselves, as buf_put_sign would. */
|
||||
buffer *sigblob;
|
||||
sigblob = buf_new(MAX_PUBKEY_SIZE);
|
||||
agent_buf_sign(sigblob, key, data_buf, sigtype);
|
||||
buf_putbufstring(buf, sigblob);
|
||||
buf_free(sigblob);
|
||||
} else
|
||||
#endif /* DROPBEAR_CLI_AGENTFWD */
|
||||
{
|
||||
buf_put_sign(buf, key, sigtype, data_buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype, int realsign) {
|
||||
|
||||
const char *algoname = NULL;
|
||||
int algolen;
|
||||
unsigned int algolen;
|
||||
buffer* sigbuf = NULL;
|
||||
enum signkey_type keytype = signkey_type_from_signature(sigtype);
|
||||
|
||||
TRACE(("enter send_msg_userauth_pubkey"));
|
||||
TRACE(("enter send_msg_userauth_pubkey sigtype %d", sigtype))
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
|
||||
@@ -140,48 +155,136 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
strlen(cli_opts.username));
|
||||
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
SSH_SERVICE_CONNECTION_LEN);
|
||||
|
||||
buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
|
||||
buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
|
||||
AUTH_METHOD_PUBKEY_LEN);
|
||||
|
||||
buf_putbyte(ses.writepayload, realsign);
|
||||
|
||||
algoname = signkey_name_from_type(type, &algolen);
|
||||
|
||||
algoname = signature_name_from_type(sigtype, &algolen);
|
||||
buf_putstring(ses.writepayload, algoname, algolen);
|
||||
buf_put_pub_key(ses.writepayload, key, type);
|
||||
buf_put_pub_key(ses.writepayload, key, keytype);
|
||||
|
||||
if (realsign) {
|
||||
TRACE(("realsign"));
|
||||
TRACE(("realsign"))
|
||||
/* We put the signature as well - this contains string(session id), then
|
||||
* the contents of the write payload to this point */
|
||||
sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len);
|
||||
buf_putstring(sigbuf, ses.session_id, SHA1_HASH_SIZE);
|
||||
sigbuf = buf_new(4 + ses.session_id->len + ses.writepayload->len);
|
||||
buf_putbufstring(sigbuf, ses.session_id);
|
||||
buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
|
||||
buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len);
|
||||
cli_buf_put_sign(ses.writepayload, key, sigtype, sigbuf);
|
||||
buf_free(sigbuf); /* Nothing confidential in the buffer */
|
||||
}
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave send_msg_userauth_pubkey"));
|
||||
TRACE(("leave send_msg_userauth_pubkey"))
|
||||
}
|
||||
|
||||
/* Returns 1 if a key was tried */
|
||||
int cli_auth_pubkey() {
|
||||
enum signature_type sigtype = DROPBEAR_SIGNATURE_NONE;
|
||||
TRACE(("enter cli_auth_pubkey"))
|
||||
|
||||
TRACE(("enter cli_auth_pubkey"));
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
if (!cli_opts.agent_keys_loaded) {
|
||||
/* get the list of available keys from the agent */
|
||||
cli_load_agent_keys(cli_opts.privkeys);
|
||||
cli_opts.agent_keys_loaded = 1;
|
||||
TRACE(("cli_auth_pubkey: agent keys loaded"))
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cli_opts.pubkeys != NULL) {
|
||||
/* iterate through privkeys to remove ones not allowed in server-sig-algs */
|
||||
while (cli_opts.privkeys->first) {
|
||||
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
|
||||
if (cli_ses.server_sig_algs) {
|
||||
#if DROPBEAR_RSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA) {
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNATURE_RSA_SHA256)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
|
||||
TRACE(("server-sig-algs allows rsa sha256"))
|
||||
break;
|
||||
}
|
||||
#endif /* DROPBEAR_RSA_SHA256 */
|
||||
#if DROPBEAR_RSA_SHA1
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNKEY_RSA)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
TRACE(("server-sig-algs allows rsa sha1"))
|
||||
break;
|
||||
}
|
||||
#endif /* DROPBEAR_RSA_SHA256 */
|
||||
} else
|
||||
#endif /* DROPBEAR_RSA */
|
||||
{
|
||||
/* Not RSA */
|
||||
const char *name = NULL;
|
||||
sigtype = signature_type_from_signkey(key->type);
|
||||
name = signature_name_from_type(sigtype, NULL);
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, name)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
TRACE(("server-sig-algs allows %s", name))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* No match, skip this key */
|
||||
TRACE(("server-sig-algs no match keytype %d, skipping", key->type))
|
||||
key = list_remove(cli_opts.privkeys->first);
|
||||
sign_key_free(key);
|
||||
continue;
|
||||
} else {
|
||||
/* Server didn't provide a server-sig-algs list, we'll
|
||||
assume all except rsa-sha256 are OK. */
|
||||
#if DROPBEAR_RSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA) {
|
||||
#if DROPBEAR_RSA_SHA1
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
TRACE(("no server-sig-algs, using rsa sha1"))
|
||||
break;
|
||||
#else
|
||||
/* only support rsa-sha256, skip this key */
|
||||
TRACE(("no server-sig-algs, skipping rsa sha256"))
|
||||
key = list_remove(cli_opts.privkeys->first);
|
||||
sign_key_free(key);
|
||||
continue;
|
||||
#endif
|
||||
} /* key->type == DROPBEAR_SIGNKEY_RSA */
|
||||
#endif /* DROPBEAR_RSA */
|
||||
sigtype = signature_type_from_signkey(key->type);
|
||||
TRACE(("no server-sig-algs, using key"))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cli_opts.privkeys->first) {
|
||||
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
|
||||
/* Send a trial request */
|
||||
send_msg_userauth_pubkey(cli_opts.pubkeys->key,
|
||||
cli_opts.pubkeys->type, 0);
|
||||
cli_ses.lastpubkey = cli_opts.pubkeys;
|
||||
TRACE(("leave cli_auth_pubkey-success"));
|
||||
send_msg_userauth_pubkey(key, sigtype, 0);
|
||||
cli_ses.lastprivkey = key;
|
||||
TRACE(("leave cli_auth_pubkey-success"))
|
||||
return 1;
|
||||
} else {
|
||||
TRACE(("leave cli_auth_pubkey-failure"));
|
||||
/* no more keys left */
|
||||
TRACE(("leave cli_auth_pubkey-failure"))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void cli_auth_pubkey_cleanup() {
|
||||
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
m_close(cli_opts.agent_fd);
|
||||
cli_opts.agent_fd = -1;
|
||||
#endif
|
||||
|
||||
while (cli_opts.privkeys->first) {
|
||||
sign_key * key = list_remove(cli_opts.privkeys->first);
|
||||
sign_key_free(key);
|
||||
}
|
||||
}
|
||||
#endif /* Pubkey auth */
|
||||
|
||||
59
cli-channel.c
Normal file
59
cli-channel.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002-2004 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "channel.h"
|
||||
#include "buffer.h"
|
||||
#include "circbuffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "session.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/* We receive channel data - only used by the client chansession code*/
|
||||
void recv_msg_channel_extended_data() {
|
||||
|
||||
struct Channel *channel;
|
||||
unsigned int datatype;
|
||||
|
||||
TRACE(("enter recv_msg_channel_extended_data"))
|
||||
|
||||
channel = getchannel();
|
||||
|
||||
if (channel->type != &clichansess) {
|
||||
TRACE(("leave recv_msg_channel_extended_data: chantype is wrong"))
|
||||
return; /* we just ignore it */
|
||||
}
|
||||
|
||||
datatype = buf_getint(ses.payload);
|
||||
|
||||
if (datatype != SSH_EXTENDED_DATA_STDERR) {
|
||||
TRACE(("leave recv_msg_channel_extended_data: wrong datatype: %d",
|
||||
datatype))
|
||||
return;
|
||||
}
|
||||
|
||||
common_recv_msg_channel_data(channel, channel->errfd, channel->extrabuf);
|
||||
|
||||
TRACE(("leave recv_msg_channel_extended_data"))
|
||||
}
|
||||
@@ -32,48 +32,65 @@
|
||||
#include "ssh.h"
|
||||
#include "runopts.h"
|
||||
#include "termcodes.h"
|
||||
#include "chansession.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 void cli_chansessreq(struct Channel *channel);
|
||||
static void send_chansess_pty_req(const struct Channel *channel);
|
||||
static void send_chansess_shell_req(const struct Channel *channel);
|
||||
static void cli_escape_handler(const struct Channel *channel, const unsigned char* buf, int *len);
|
||||
static int cli_init_netcat(struct Channel *channel);
|
||||
|
||||
static void start_channel_request(struct Channel *channel, unsigned char *type);
|
||||
static void cli_tty_setup(void);
|
||||
|
||||
static void send_chansess_pty_req(struct Channel *channel);
|
||||
static void send_chansess_shell_req(struct Channel *channel);
|
||||
|
||||
static void cli_tty_setup();
|
||||
void cli_tty_cleanup();
|
||||
|
||||
static const struct ChanType clichansess = {
|
||||
const struct ChanType clichansess = {
|
||||
0, /* sepfds */
|
||||
"session", /* name */
|
||||
cli_initchansess, /* inithandler */
|
||||
NULL, /* checkclosehandler */
|
||||
NULL, /* reqhandler */
|
||||
cli_chansessreq, /* reqhandler */
|
||||
cli_closechansess, /* closehandler */
|
||||
NULL, /* cleanup */
|
||||
};
|
||||
|
||||
static void cli_chansessreq(struct Channel *channel) {
|
||||
|
||||
char* type = NULL;
|
||||
int wantreply;
|
||||
|
||||
TRACE(("enter cli_chansessreq"))
|
||||
|
||||
type = buf_getstring(ses.payload, NULL);
|
||||
wantreply = buf_getbool(ses.payload);
|
||||
|
||||
if (strcmp(type, "exit-status") == 0) {
|
||||
cli_ses.retval = buf_getint(ses.payload);
|
||||
TRACE(("got exit-status of '%d'", cli_ses.retval))
|
||||
} else if (strcmp(type, "exit-signal") == 0) {
|
||||
TRACE(("got exit-signal, ignoring it"))
|
||||
} else {
|
||||
TRACE(("unknown request '%s'", type))
|
||||
if (wantreply) {
|
||||
send_msg_channel_failure(channel);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(type);
|
||||
}
|
||||
|
||||
|
||||
/* If the main session goes, we close it up */
|
||||
static void cli_closechansess(struct Channel *channel) {
|
||||
static void cli_closechansess(const struct Channel *UNUSED(channel)) {
|
||||
cli_tty_cleanup(); /* Restore tty modes etc */
|
||||
|
||||
/* This channel hasn't gone yet, so we have > 1 */
|
||||
if (ses.chancount > 1) {
|
||||
dropbear_log(LOG_INFO, "Waiting for other channels to close...");
|
||||
}
|
||||
|
||||
cli_tty_cleanup(); /* Restore tty modes etc */
|
||||
|
||||
}
|
||||
|
||||
static void start_channel_request(struct Channel *channel,
|
||||
unsigned char *type) {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
|
||||
buf_putint(ses.writepayload, channel->remotechan);
|
||||
|
||||
buf_putstring(ses.writepayload, type, strlen(type));
|
||||
|
||||
}
|
||||
|
||||
/* Taken from OpenSSH's sshtty.c:
|
||||
@@ -82,10 +99,10 @@ static void cli_tty_setup() {
|
||||
|
||||
struct termios tio;
|
||||
|
||||
TRACE(("enter cli_pty_setup"));
|
||||
TRACE(("enter cli_pty_setup"))
|
||||
|
||||
if (cli_ses.tty_raw_mode == 1) {
|
||||
TRACE(("leave cli_tty_setup: already in raw mode!"));
|
||||
TRACE(("leave cli_tty_setup: already in raw mode!"))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -113,15 +130,15 @@ static void cli_tty_setup() {
|
||||
}
|
||||
|
||||
cli_ses.tty_raw_mode = 1;
|
||||
TRACE(("leave cli_tty_setup"));
|
||||
TRACE(("leave cli_tty_setup"))
|
||||
}
|
||||
|
||||
void cli_tty_cleanup() {
|
||||
|
||||
TRACE(("enter cli_tty_cleanup"));
|
||||
TRACE(("enter cli_tty_cleanup"))
|
||||
|
||||
if (cli_ses.tty_raw_mode == 0) {
|
||||
TRACE(("leave cli_tty_cleanup: not in raw mode"));
|
||||
TRACE(("leave cli_tty_cleanup: not in raw mode"))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -131,13 +148,11 @@ void cli_tty_cleanup() {
|
||||
cli_ses.tty_raw_mode = 0;
|
||||
}
|
||||
|
||||
TRACE(("leave cli_tty_cleanup"));
|
||||
TRACE(("leave cli_tty_cleanup"))
|
||||
}
|
||||
|
||||
static void put_termcodes() {
|
||||
|
||||
TRACE(("enter put_termcodes"));
|
||||
|
||||
struct termios tio;
|
||||
unsigned int sshcode;
|
||||
const struct TermCode *termcode;
|
||||
@@ -146,6 +161,8 @@ static void put_termcodes() {
|
||||
|
||||
unsigned int bufpos1, bufpos2;
|
||||
|
||||
TRACE(("enter put_termcodes"))
|
||||
|
||||
if (tcgetattr(STDIN_FILENO, &tio) == -1) {
|
||||
dropbear_log(LOG_WARNING, "Failed reading termmodes");
|
||||
buf_putint(ses.writepayload, 1); /* Just the terminator */
|
||||
@@ -206,7 +223,7 @@ static void put_termcodes() {
|
||||
buf_putint(ses.writepayload, bufpos2 - bufpos1 - 4); /* len(termcodes) */
|
||||
buf_setpos(ses.writepayload, bufpos2); /* Back where we were */
|
||||
|
||||
TRACE(("leave put_termcodes"));
|
||||
TRACE(("leave put_termcodes"))
|
||||
}
|
||||
|
||||
static void put_winsize() {
|
||||
@@ -228,7 +245,7 @@ static void put_winsize() {
|
||||
|
||||
}
|
||||
|
||||
static void sigwinch_handler(int dummy) {
|
||||
static void sigwinch_handler(int UNUSED(unused)) {
|
||||
|
||||
cli_ses.winchange = 1;
|
||||
|
||||
@@ -254,13 +271,13 @@ void cli_chansess_winchange() {
|
||||
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"))
|
||||
|
||||
start_channel_request(channel, "pty-req");
|
||||
start_send_channel_request(channel, "pty-req");
|
||||
|
||||
/* Don't want replies */
|
||||
buf_putbyte(ses.writepayload, 0);
|
||||
@@ -282,24 +299,28 @@ static void send_chansess_pty_req(struct Channel *channel) {
|
||||
|
||||
/* Set up a window-change handler */
|
||||
if (signal(SIGWINCH, sigwinch_handler) == SIG_ERR) {
|
||||
dropbear_exit("signal error");
|
||||
dropbear_exit("Signal error");
|
||||
}
|
||||
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"))
|
||||
|
||||
if (cli_opts.cmd) {
|
||||
reqtype = "exec";
|
||||
if (cli_opts.is_subsystem) {
|
||||
reqtype = "subsystem";
|
||||
} else {
|
||||
reqtype = "exec";
|
||||
}
|
||||
} else {
|
||||
reqtype = "shell";
|
||||
}
|
||||
|
||||
start_channel_request(channel, reqtype);
|
||||
start_send_channel_request(channel, reqtype);
|
||||
|
||||
/* XXX TODO */
|
||||
buf_putbyte(ses.writepayload, 0); /* Don't want replies */
|
||||
@@ -308,32 +329,99 @@ static void send_chansess_shell_req(struct Channel *channel) {
|
||||
}
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave send_chansess_shell_req"));
|
||||
TRACE(("leave send_chansess_shell_req"))
|
||||
}
|
||||
|
||||
/* Shared for normal client channel and netcat-alike */
|
||||
static int cli_init_stdpipe_sess(struct Channel *channel) {
|
||||
channel->writefd = STDOUT_FILENO;
|
||||
setnonblocking(STDOUT_FILENO);
|
||||
|
||||
channel->readfd = STDIN_FILENO;
|
||||
setnonblocking(STDIN_FILENO);
|
||||
|
||||
channel->errfd = STDERR_FILENO;
|
||||
setnonblocking(STDERR_FILENO);
|
||||
|
||||
channel->extrabuf = cbuf_new(opts.recv_window);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cli_init_netcat(struct Channel *channel) {
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
|
||||
return cli_init_stdpipe_sess(channel);
|
||||
}
|
||||
|
||||
static int cli_initchansess(struct Channel *channel) {
|
||||
|
||||
channel->infd = STDOUT_FILENO;
|
||||
//channel->outfd = STDIN_FILENO;
|
||||
//channel->errfd = STDERR_FILENO;
|
||||
cli_init_stdpipe_sess(channel);
|
||||
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
if (cli_opts.agent_fwd) {
|
||||
cli_setup_agent(channel);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cli_opts.wantpty) {
|
||||
send_chansess_pty_req(channel);
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE;
|
||||
} else {
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
|
||||
}
|
||||
|
||||
send_chansess_shell_req(channel);
|
||||
|
||||
if (cli_opts.wantpty) {
|
||||
cli_tty_setup();
|
||||
}
|
||||
channel->read_mangler = cli_escape_handler;
|
||||
cli_ses.last_char = '\r';
|
||||
}
|
||||
|
||||
return 0; /* Success */
|
||||
|
||||
}
|
||||
|
||||
#if DROPBEAR_CLI_NETCAT
|
||||
|
||||
static const struct ChanType cli_chan_netcat = {
|
||||
0, /* sepfds */
|
||||
"direct-tcpip",
|
||||
cli_init_netcat, /* inithandler */
|
||||
NULL,
|
||||
NULL,
|
||||
cli_closechansess,
|
||||
NULL,
|
||||
};
|
||||
|
||||
void cli_send_netcat_request() {
|
||||
|
||||
const char* source_host = "127.0.0.1";
|
||||
const int source_port = 22;
|
||||
|
||||
TRACE(("enter cli_send_netcat_request"))
|
||||
cli_opts.wantpty = 0;
|
||||
|
||||
if (send_msg_channel_open_init(STDIN_FILENO, &cli_chan_netcat)
|
||||
== DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Couldn't open initial channel");
|
||||
}
|
||||
|
||||
buf_putstring(ses.writepayload, cli_opts.netcat_host,
|
||||
strlen(cli_opts.netcat_host));
|
||||
buf_putint(ses.writepayload, cli_opts.netcat_port);
|
||||
|
||||
/* originator ip - localhost is accurate enough */
|
||||
buf_putstring(ses.writepayload, source_host, strlen(source_host));
|
||||
buf_putint(ses.writepayload, source_port);
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave cli_send_netcat_request"))
|
||||
}
|
||||
#endif
|
||||
|
||||
void cli_send_chansess_request() {
|
||||
|
||||
TRACE(("enter cli_send_chansess_request"));
|
||||
TRACE(("enter cli_send_chansess_request"))
|
||||
|
||||
if (send_msg_channel_open_init(STDIN_FILENO, &clichansess)
|
||||
== DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Couldn't open initial channel");
|
||||
@@ -341,6 +429,61 @@ void cli_send_chansess_request() {
|
||||
|
||||
/* No special channel request data */
|
||||
encrypt_packet();
|
||||
TRACE(("leave cli_send_chansess_request"));
|
||||
TRACE(("leave cli_send_chansess_request"))
|
||||
|
||||
}
|
||||
|
||||
/* returns 1 if the character should be consumed, 0 to pass through */
|
||||
static int
|
||||
do_escape(unsigned char c) {
|
||||
switch (c) {
|
||||
case '.':
|
||||
dropbear_exit("Terminated");
|
||||
return 1;
|
||||
case 0x1a:
|
||||
/* ctrl-z */
|
||||
cli_tty_cleanup();
|
||||
kill(getpid(), SIGTSTP);
|
||||
/* after continuation */
|
||||
cli_tty_setup();
|
||||
cli_ses.winchange = 1;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void cli_escape_handler(const struct Channel* UNUSED(channel), const unsigned char* buf, int *len) {
|
||||
char c;
|
||||
int skip_char = 0;
|
||||
|
||||
/* only handle escape characters if they are read one at a time. simplifies
|
||||
the code and avoids nasty people putting ~. at the start of a line to paste */
|
||||
if (*len != 1) {
|
||||
cli_ses.last_char = 0x0;
|
||||
return;
|
||||
}
|
||||
|
||||
c = buf[0];
|
||||
|
||||
if (cli_ses.last_char == DROPBEAR_ESCAPE_CHAR) {
|
||||
skip_char = do_escape(c);
|
||||
cli_ses.last_char = 0x0;
|
||||
} else {
|
||||
if (c == DROPBEAR_ESCAPE_CHAR) {
|
||||
if (cli_ses.last_char == '\r') {
|
||||
cli_ses.last_char = DROPBEAR_ESCAPE_CHAR;
|
||||
skip_char = 1;
|
||||
} else {
|
||||
cli_ses.last_char = 0x0;
|
||||
}
|
||||
} else {
|
||||
cli_ses.last_char = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip_char) {
|
||||
*len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
391
cli-kex.c
391
cli-kex.c
@@ -33,46 +33,77 @@
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
#include "runopts.h"
|
||||
#include "signkey.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
|
||||
|
||||
void send_msg_kexdh_init() {
|
||||
|
||||
cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
|
||||
|
||||
gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x);
|
||||
TRACE(("send_msg_kexdh_init()"))
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
|
||||
buf_putmpint(ses.writepayload, cli_ses.dh_e);
|
||||
switch (ses.newkeys->algo_kex->mode) {
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
case DROPBEAR_KEX_NORMAL_DH:
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.dh_param) {
|
||||
if (cli_ses.dh_param) {
|
||||
free_kexdh_param(cli_ses.dh_param);
|
||||
}
|
||||
cli_ses.dh_param = gen_kexdh_param();
|
||||
}
|
||||
buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub);
|
||||
break;
|
||||
#endif
|
||||
#if DROPBEAR_ECDH
|
||||
case DROPBEAR_KEX_ECDH:
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.ecdh_param) {
|
||||
if (cli_ses.ecdh_param) {
|
||||
free_kexecdh_param(cli_ses.ecdh_param);
|
||||
}
|
||||
cli_ses.ecdh_param = gen_kexecdh_param();
|
||||
}
|
||||
buf_put_ecc_raw_pubkey_string(ses.writepayload, &cli_ses.ecdh_param->key);
|
||||
break;
|
||||
#endif
|
||||
#if DROPBEAR_CURVE25519
|
||||
case DROPBEAR_KEX_CURVE25519:
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.curve25519_param) {
|
||||
if (cli_ses.curve25519_param) {
|
||||
free_kexcurve25519_param(cli_ses.curve25519_param);
|
||||
}
|
||||
cli_ses.curve25519_param = gen_kexcurve25519_param();
|
||||
}
|
||||
buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
cli_ses.param_kex_algo = ses.newkeys->algo_kex;
|
||||
encrypt_packet();
|
||||
ses.requirenext = SSH_MSG_KEXDH_REPLY;
|
||||
}
|
||||
|
||||
/* Handle a diffie-hellman key exchange reply. */
|
||||
void recv_msg_kexdh_reply() {
|
||||
|
||||
DEF_MP_INT(dh_f);
|
||||
sign_key *hostkey = NULL;
|
||||
unsigned int type, keybloblen;
|
||||
unsigned int keytype, keybloblen;
|
||||
unsigned char* keyblob = NULL;
|
||||
|
||||
|
||||
TRACE(("enter recv_msg_kexdh_reply"));
|
||||
TRACE(("enter recv_msg_kexdh_reply"))
|
||||
|
||||
if (cli_ses.kex_state != KEXDH_INIT_SENT) {
|
||||
dropbear_exit("Received out-of-order kexdhreply");
|
||||
}
|
||||
m_mp_init(&dh_f);
|
||||
type = ses.newkeys->algo_hostkey;
|
||||
TRACE(("type is %d", type));
|
||||
keytype = ses.newkeys->algo_hostkey;
|
||||
TRACE(("keytype is %d", keytype))
|
||||
|
||||
hostkey = new_sign_key();
|
||||
keybloblen = buf_getint(ses.payload);
|
||||
@@ -83,24 +114,69 @@ void recv_msg_kexdh_reply() {
|
||||
checkhostkey(keyblob, keybloblen);
|
||||
}
|
||||
|
||||
if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) {
|
||||
TRACE(("failed getting pubkey"));
|
||||
if (buf_get_pub_key(ses.payload, hostkey, &keytype) != DROPBEAR_SUCCESS) {
|
||||
TRACE(("failed getting pubkey"))
|
||||
dropbear_exit("Bad KEX packet");
|
||||
}
|
||||
|
||||
if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
|
||||
TRACE(("failed getting mpint"));
|
||||
dropbear_exit("Bad KEX packet");
|
||||
switch (ses.newkeys->algo_kex->mode) {
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
case DROPBEAR_KEX_NORMAL_DH:
|
||||
{
|
||||
DEF_MP_INT(dh_f);
|
||||
m_mp_init(&dh_f);
|
||||
if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
|
||||
TRACE(("failed getting mpint"))
|
||||
dropbear_exit("Bad KEX packet");
|
||||
}
|
||||
|
||||
kexdh_comb_key(cli_ses.dh_param, &dh_f, hostkey);
|
||||
mp_clear(&dh_f);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if DROPBEAR_ECDH
|
||||
case DROPBEAR_KEX_ECDH:
|
||||
{
|
||||
buffer *ecdh_qs = buf_getstringbuf(ses.payload);
|
||||
kexecdh_comb_key(cli_ses.ecdh_param, ecdh_qs, hostkey);
|
||||
buf_free(ecdh_qs);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if DROPBEAR_CURVE25519
|
||||
case DROPBEAR_KEX_CURVE25519:
|
||||
{
|
||||
buffer *ecdh_qs = buf_getstringbuf(ses.payload);
|
||||
kexcurve25519_comb_key(cli_ses.curve25519_param, ecdh_qs, hostkey);
|
||||
buf_free(ecdh_qs);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
kexdh_comb_key(cli_ses.dh_e, cli_ses.dh_x, &dh_f, hostkey);
|
||||
mp_clear(&dh_f);
|
||||
mp_clear_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
|
||||
m_free(cli_ses.dh_e);
|
||||
m_free(cli_ses.dh_x);
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
if (cli_ses.dh_param) {
|
||||
free_kexdh_param(cli_ses.dh_param);
|
||||
cli_ses.dh_param = NULL;
|
||||
}
|
||||
#endif
|
||||
#if DROPBEAR_ECDH
|
||||
if (cli_ses.ecdh_param) {
|
||||
free_kexecdh_param(cli_ses.ecdh_param);
|
||||
cli_ses.ecdh_param = NULL;
|
||||
}
|
||||
#endif
|
||||
#if DROPBEAR_CURVE25519
|
||||
if (cli_ses.curve25519_param) {
|
||||
free_kexcurve25519_param(cli_ses.curve25519_param);
|
||||
cli_ses.curve25519_param = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
cli_ses.param_kex_algo = NULL;
|
||||
if (buf_verify(ses.payload, hostkey, ses.newkeys->algo_signature,
|
||||
ses.hash) != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Bad hostkey signature");
|
||||
}
|
||||
|
||||
@@ -109,83 +185,137 @@ void recv_msg_kexdh_reply() {
|
||||
|
||||
send_msg_newkeys();
|
||||
ses.requirenext = SSH_MSG_NEWKEYS;
|
||||
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) {
|
||||
|
||||
char* fp = NULL;
|
||||
FILE *tty = NULL;
|
||||
int response = 'z';
|
||||
|
||||
fp = sign_key_fingerprint(keyblob, keybloblen);
|
||||
fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(fingerprint %s)\nDo you want to continue connecting? (y/n)\n",
|
||||
cli_opts.remotehost,
|
||||
fp);
|
||||
|
||||
if (getc(stdin) == 'y') {
|
||||
if (cli_opts.always_accept_key) {
|
||||
dropbear_log(LOG_INFO, "\nHost '%s' key accepted unconditionally.\n(%s fingerprint %s)\n",
|
||||
cli_opts.remotehost,
|
||||
algoname,
|
||||
fp);
|
||||
m_free(fp);
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(%s fingerprint %s)\nDo you want to continue connecting? (y/n) ",
|
||||
cli_opts.remotehost,
|
||||
algoname,
|
||||
fp);
|
||||
m_free(fp);
|
||||
|
||||
tty = fopen(_PATH_TTY, "r");
|
||||
if (tty) {
|
||||
response = getc(tty);
|
||||
fclose(tty);
|
||||
} else {
|
||||
response = getc(stdin);
|
||||
}
|
||||
|
||||
if (response == 'y') {
|
||||
return;
|
||||
}
|
||||
|
||||
dropbear_exit("Didn't validate host key");
|
||||
}
|
||||
|
||||
static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
|
||||
static FILE* open_known_hosts_file(int * readonly)
|
||||
{
|
||||
FILE * hostsfile = NULL;
|
||||
char * filename = NULL;
|
||||
FILE *hostsfile = NULL;
|
||||
int readonly = 0;
|
||||
struct passwd *pw = NULL;
|
||||
unsigned int hostlen, algolen;
|
||||
unsigned long len;
|
||||
const char *algoname = NULL;
|
||||
buffer * line = NULL;
|
||||
int ret;
|
||||
char * homedir = NULL;
|
||||
|
||||
pw = getpwuid(getuid());
|
||||
homedir = getenv("HOME");
|
||||
|
||||
if (pw == NULL) {
|
||||
dropbear_exit("Failed to get homedir");
|
||||
}
|
||||
|
||||
len = strlen(pw->pw_dir);
|
||||
filename = m_malloc(len + 18); /* "/.ssh/known_hosts" and null-terminator*/
|
||||
|
||||
snprintf(filename, len+18, "%s/.ssh", pw->pw_dir);
|
||||
/* Check that ~/.ssh exists - easiest way is just to mkdir */
|
||||
if (mkdir(filename, S_IRWXU) != 0) {
|
||||
if (errno != EEXIST) {
|
||||
dropbear_log(LOG_INFO, "Warning: failed creating ~/.ssh: %s",
|
||||
strerror(errno));
|
||||
TRACE(("mkdir didn't work: %s", strerror(errno)));
|
||||
ask_to_confirm(keyblob, keybloblen);
|
||||
goto out; /* only get here on success */
|
||||
if (!homedir) {
|
||||
struct passwd * pw = NULL;
|
||||
pw = getpwuid(getuid());
|
||||
if (pw) {
|
||||
homedir = pw->pw_dir;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(filename, len+18, "%s/.ssh/known_hosts", pw->pw_dir);
|
||||
hostsfile = fopen(filename, "a+");
|
||||
fseek(hostsfile, 0, SEEK_SET);
|
||||
|
||||
/* We mightn't have been able to open it if it was read-only */
|
||||
if (hostsfile == NULL && (errno == EACCES || errno == EROFS)) {
|
||||
TRACE(("trying readonly: %s", strerror(errno)));
|
||||
readonly = 1;
|
||||
hostsfile = fopen(filename, "r");
|
||||
if (homedir) {
|
||||
unsigned int len;
|
||||
len = strlen(homedir);
|
||||
filename = m_malloc(len + 18); /* "/.ssh/known_hosts" and null-terminator*/
|
||||
|
||||
snprintf(filename, len+18, "%s/.ssh", homedir);
|
||||
/* Check that ~/.ssh exists - easiest way is just to mkdir */
|
||||
if (mkdir(filename, S_IRWXU) != 0) {
|
||||
if (errno != EEXIST) {
|
||||
dropbear_log(LOG_INFO, "Warning: failed creating %s/.ssh: %s",
|
||||
homedir, strerror(errno));
|
||||
TRACE(("mkdir didn't work: %s", strerror(errno)))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(filename, len+18, "%s/.ssh/known_hosts", homedir);
|
||||
hostsfile = fopen(filename, "a+");
|
||||
|
||||
if (hostsfile != NULL) {
|
||||
*readonly = 0;
|
||||
fseek(hostsfile, 0, SEEK_SET);
|
||||
} else {
|
||||
/* We mightn't have been able to open it if it was read-only */
|
||||
if (errno == EACCES || errno == EROFS) {
|
||||
TRACE(("trying readonly: %s", strerror(errno)))
|
||||
*readonly = 1;
|
||||
hostsfile = fopen(filename, "r");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hostsfile == NULL) {
|
||||
TRACE(("hostsfile didn't open: %s", strerror(errno)));
|
||||
ask_to_confirm(keyblob, keybloblen);
|
||||
goto out; /* We only get here on success */
|
||||
TRACE(("hostsfile didn't open: %s", strerror(errno)))
|
||||
dropbear_log(LOG_WARNING, "Failed to open %s/.ssh/known_hosts",
|
||||
homedir);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(filename);
|
||||
return hostsfile;
|
||||
}
|
||||
|
||||
static void checkhostkey(const unsigned char* keyblob, unsigned int keybloblen) {
|
||||
|
||||
FILE *hostsfile = NULL;
|
||||
int readonly = 0;
|
||||
unsigned int hostlen, algolen;
|
||||
unsigned long len;
|
||||
const char *algoname = NULL;
|
||||
char * fingerprint = NULL;
|
||||
buffer * line = NULL;
|
||||
int ret;
|
||||
|
||||
if (cli_opts.no_hostkey_check) {
|
||||
dropbear_log(LOG_INFO, "Caution, skipping hostkey check for %s\n", cli_opts.remotehost);
|
||||
return;
|
||||
}
|
||||
|
||||
algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen);
|
||||
|
||||
hostsfile = open_known_hosts_file(&readonly);
|
||||
if (!hostsfile) {
|
||||
ask_to_confirm(keyblob, keybloblen, algoname);
|
||||
/* ask_to_confirm will exit upon failure */
|
||||
return;
|
||||
}
|
||||
|
||||
line = buf_new(MAX_KNOWNHOSTS_LINE);
|
||||
hostlen = strlen(cli_opts.remotehost);
|
||||
algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen);
|
||||
|
||||
do {
|
||||
if (buf_getline(line, hostsfile) == DROPBEAR_FAILURE) {
|
||||
TRACE(("failed reading line: prob EOF"));
|
||||
TRACE(("failed reading line: prob EOF"))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -194,82 +324,127 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
* buf_getfoo() past the end and die horribly - the base64 parsing
|
||||
* code is what tiptoes up to the end nicely */
|
||||
if (line->len < (hostlen+30) ) {
|
||||
TRACE(("line is too short to be sensible"));
|
||||
TRACE(("line is too short to be sensible"))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Compare hostnames */
|
||||
if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
|
||||
if (strncmp(cli_opts.remotehost, (const char *) buf_getptr(line, hostlen),
|
||||
hostlen) != 0) {
|
||||
TRACE(("hosts don't match"));
|
||||
continue;
|
||||
}
|
||||
|
||||
buf_incrpos(line, hostlen);
|
||||
if (buf_getbyte(line) != ' ') {
|
||||
/* there wasn't a space after the hostname, something dodgy */
|
||||
TRACE(("missing space afte matching hostname"));
|
||||
TRACE(("missing space afte matching hostname"))
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) {
|
||||
TRACE(("algo doesn't match"));
|
||||
if (strncmp((const char *) buf_getptr(line, algolen), algoname, algolen) != 0) {
|
||||
TRACE(("algo doesn't match"))
|
||||
continue;
|
||||
}
|
||||
|
||||
buf_incrpos(line, algolen);
|
||||
if (buf_getbyte(line) != ' ') {
|
||||
TRACE(("missing space after algo"));
|
||||
TRACE(("missing space after algo"))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now we're at the interesting hostkey */
|
||||
ret = cmp_base64_key(keyblob, keybloblen, algoname, algolen, line);
|
||||
ret = cmp_base64_key(keyblob, keybloblen, (const unsigned char *) algoname, algolen,
|
||||
line, &fingerprint);
|
||||
|
||||
if (ret == DROPBEAR_SUCCESS) {
|
||||
/* Good matching key */
|
||||
TRACE(("good matching key"));
|
||||
TRACE(("good matching key"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The keys didn't match. eep. */
|
||||
/* The keys didn't match. eep. Note that we're "leaking"
|
||||
the fingerprint strings here, but we're exiting anyway */
|
||||
dropbear_exit("\n\n%s host key mismatch for %s !\n"
|
||||
"Fingerprint is %s\n"
|
||||
"Expected %s\n"
|
||||
"If you know that the host key is correct you can\nremove the bad entry from ~/.ssh/known_hosts",
|
||||
algoname,
|
||||
cli_opts.remotehost,
|
||||
sign_key_fingerprint(keyblob, keybloblen),
|
||||
fingerprint ? fingerprint : "UNKNOWN");
|
||||
} while (1); /* keep going 'til something happens */
|
||||
|
||||
/* Key doesn't exist yet */
|
||||
ask_to_confirm(keyblob, keybloblen);
|
||||
ask_to_confirm(keyblob, keybloblen, algoname);
|
||||
|
||||
/* If we get here, they said yes */
|
||||
|
||||
if (readonly) {
|
||||
TRACE(("readonly"));
|
||||
TRACE(("readonly"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* put the new entry in the file */
|
||||
fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */
|
||||
buf_setpos(line, 0);
|
||||
buf_setlen(line, 0);
|
||||
buf_putbytes(line, ses.remotehost, hostlen);
|
||||
buf_putbyte(line, ' ');
|
||||
buf_putbytes(line, algoname, algolen);
|
||||
buf_putbyte(line, ' ');
|
||||
len = line->size - line->pos;
|
||||
TRACE(("keybloblen %d, len %d", keybloblen, len));
|
||||
/* The only failure with base64 is buffer_overflow, but buf_getwriteptr
|
||||
* will die horribly in the case anyway */
|
||||
base64_encode(keyblob, keybloblen, buf_getwriteptr(line, len), &len);
|
||||
buf_incrwritepos(line, len);
|
||||
buf_putbyte(line, '\n');
|
||||
buf_setpos(line, 0);
|
||||
fwrite(buf_getptr(line, line->len), line->len, 1, hostsfile);
|
||||
/* We ignore errors, since there's not much we can do about them */
|
||||
if (!cli_opts.always_accept_key) {
|
||||
/* put the new entry in the file */
|
||||
fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */
|
||||
buf_setpos(line, 0);
|
||||
buf_setlen(line, 0);
|
||||
buf_putbytes(line, (const unsigned char *) cli_opts.remotehost, hostlen);
|
||||
buf_putbyte(line, ' ');
|
||||
buf_putbytes(line, (const unsigned char *) algoname, algolen);
|
||||
buf_putbyte(line, ' ');
|
||||
len = line->size - line->pos;
|
||||
/* The only failure with base64 is buffer_overflow, but buf_getwriteptr
|
||||
* will die horribly in the case anyway */
|
||||
base64_encode(keyblob, keybloblen, buf_getwriteptr(line, len), &len);
|
||||
buf_incrwritepos(line, len);
|
||||
buf_putbyte(line, '\n');
|
||||
buf_setpos(line, 0);
|
||||
fwrite(buf_getptr(line, line->len), line->len, 1, hostsfile);
|
||||
/* We ignore errors, since there's not much we can do about them */
|
||||
}
|
||||
|
||||
out:
|
||||
if (hostsfile != NULL) {
|
||||
fclose(hostsfile);
|
||||
}
|
||||
m_free(filename);
|
||||
if (line != NULL) {
|
||||
buf_free(line);
|
||||
}
|
||||
m_free(fingerprint);
|
||||
}
|
||||
|
||||
void recv_msg_ext_info(void) {
|
||||
/* This message is not client-specific in the protocol but Dropbear only handles
|
||||
a server-sent message at present. */
|
||||
unsigned int num_ext;
|
||||
unsigned int i;
|
||||
|
||||
TRACE(("enter recv_msg_ext_info"))
|
||||
|
||||
/* Must be after the first SSH_MSG_NEWKEYS */
|
||||
TRACE(("last %d, donefirst %d, donescond %d", ses.lastpacket, ses.kexstate.donefirstkex, ses.kexstate.donesecondkex))
|
||||
if (!(ses.lastpacket == SSH_MSG_NEWKEYS && !ses.kexstate.donesecondkex)) {
|
||||
TRACE(("leave recv_msg_ext_info: ignoring packet received at the wrong time"))
|
||||
return;
|
||||
}
|
||||
|
||||
num_ext = buf_getint(ses.payload);
|
||||
TRACE(("received SSH_MSG_EXT_INFO with %d items", num_ext))
|
||||
|
||||
for (i = 0; i < num_ext; i++) {
|
||||
unsigned int name_len;
|
||||
char *ext_name = buf_getstring(ses.payload, &name_len);
|
||||
TRACE(("extension %d name '%s'", i, ext_name))
|
||||
if (cli_ses.server_sig_algs == NULL
|
||||
&& name_len == strlen(SSH_SERVER_SIG_ALGS)
|
||||
&& strcmp(ext_name, SSH_SERVER_SIG_ALGS) == 0) {
|
||||
cli_ses.server_sig_algs = buf_getbuf(ses.payload);
|
||||
} else {
|
||||
/* valid extension values could be >MAX_STRING_LEN */
|
||||
buf_eatstring(ses.payload);
|
||||
}
|
||||
m_free(ext_name);
|
||||
}
|
||||
TRACE(("leave recv_msg_ext_info"))
|
||||
}
|
||||
|
||||
161
cli-main.c
161
cli-main.c
@@ -28,45 +28,70 @@
|
||||
#include "dbutil.h"
|
||||
#include "runopts.h"
|
||||
#include "session.h"
|
||||
#include "dbrandom.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "netio.h"
|
||||
|
||||
static void cli_dropbear_exit(int exitcode, const char* format, va_list param);
|
||||
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);
|
||||
|
||||
#if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_dbclient) && defined(DROPBEAR_MULTI)
|
||||
#if DROPBEAR_CLI_PROXYCMD
|
||||
static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out);
|
||||
static void kill_proxy_sighandler(int signo);
|
||||
#endif
|
||||
|
||||
#if defined(DBMULTI_dbclient) || !DROPBEAR_MULTI
|
||||
#if defined(DBMULTI_dbclient) && DROPBEAR_MULTI
|
||||
int cli_main(int argc, char ** argv) {
|
||||
#else
|
||||
int main(int argc, char ** argv) {
|
||||
#endif
|
||||
|
||||
int sock;
|
||||
char* error = NULL;
|
||||
char* hostandport;
|
||||
int len;
|
||||
int sock_in, sock_out;
|
||||
struct dropbear_progress_connection *progress = NULL;
|
||||
|
||||
_dropbear_exit = cli_dropbear_exit;
|
||||
_dropbear_log = cli_dropbear_log;
|
||||
|
||||
disallow_core();
|
||||
|
||||
seedrandom();
|
||||
crypto_init();
|
||||
|
||||
cli_getopts(argc, argv);
|
||||
|
||||
TRACE(("user='%s' host='%s' port='%s'", cli_opts.username,
|
||||
cli_opts.remotehost, cli_opts.remoteport));
|
||||
#ifndef DISABLE_SYSLOG
|
||||
if (opts.usingsyslog) {
|
||||
startsyslog("dbclient");
|
||||
}
|
||||
#endif
|
||||
|
||||
sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
|
||||
0, &error);
|
||||
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 (sock < 0) {
|
||||
dropbear_exit("%s", error);
|
||||
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
||||
dropbear_exit("signal() error");
|
||||
}
|
||||
|
||||
/* Set up the host:port log */
|
||||
len = strlen(cli_opts.remotehost);
|
||||
len += 10; /* 16 bit port and leeway*/
|
||||
hostandport = (char*)m_malloc(len);
|
||||
snprintf(hostandport, len, "%s:%s",
|
||||
cli_opts.remotehost, cli_opts.remoteport);
|
||||
pid_t proxy_cmd_pid = 0;
|
||||
#if DROPBEAR_CLI_PROXYCMD
|
||||
if (cli_opts.proxycmd) {
|
||||
cli_proxy_cmd(&sock_in, &sock_out, &proxy_cmd_pid);
|
||||
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
|
||||
#endif
|
||||
{
|
||||
progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
|
||||
cli_connected, &ses, cli_opts.bind_address, cli_opts.bind_port);
|
||||
sock_in = sock_out = -1;
|
||||
}
|
||||
|
||||
cli_session(sock, hostandport);
|
||||
cli_session(sock_in, sock_out, progress, proxy_cmd_pid);
|
||||
|
||||
/* not reached */
|
||||
return -1;
|
||||
@@ -74,34 +99,104 @@ int main(int argc, char ** argv) {
|
||||
#endif /* DBMULTI stuff */
|
||||
|
||||
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) {
|
||||
snprintf(fmtbuf, sizeof(fmtbuf), "exited: %s",
|
||||
format);
|
||||
/* Render the formatted exit message */
|
||||
vsnprintf(exitmsg, sizeof(exitmsg), format, param);
|
||||
TRACE(("Exited, cleaning up: %s", exitmsg))
|
||||
|
||||
/* Add the prefix depending on session/auth state */
|
||||
if (!ses.init_done) {
|
||||
snprintf(fullmsg, sizeof(fullmsg), "Exited: %s", exitmsg);
|
||||
} else {
|
||||
snprintf(fmtbuf, sizeof(fmtbuf),
|
||||
"connection to %s@%s:%s exited: %s",
|
||||
snprintf(fullmsg, sizeof(fullmsg),
|
||||
"Connection to %s@%s:%s exited: %s",
|
||||
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 */
|
||||
cli_session_cleanup();
|
||||
common_session_cleanup();
|
||||
|
||||
_dropbear_log(LOG_INFO, fmtbuf, param);
|
||||
session_cleanup();
|
||||
/* Avoid printing onwards from terminal cruft */
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
dropbear_log(LOG_INFO, "%s", fullmsg);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
char printbuf[1024];
|
||||
const char *name;
|
||||
|
||||
name = cli_opts.progname;
|
||||
if (!name) {
|
||||
name = "dbclient";
|
||||
}
|
||||
|
||||
vsnprintf(printbuf, sizeof(printbuf), format, param);
|
||||
|
||||
fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf);
|
||||
#ifndef DISABLE_SYSLOG
|
||||
if (opts.usingsyslog) {
|
||||
syslog(priority, "%s", printbuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "%s: %s\n", name, printbuf);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
static void exec_proxy_cmd(const void *user_data_cmd) {
|
||||
const char *cmd = user_data_cmd;
|
||||
char *usershell;
|
||||
|
||||
usershell = m_strdup(get_user_shell());
|
||||
run_shell_command(cmd, ses.maxfd, usershell);
|
||||
dropbear_exit("Failed to run '%s'\n", cmd);
|
||||
}
|
||||
|
||||
#if DROPBEAR_CLI_PROXYCMD
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
|
||||
ex_cmdlen = strlen(cli_opts.proxycmd) + 6; /* "exec " + command + '\0' */
|
||||
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) {
|
||||
dropbear_exit("Failed running proxy command");
|
||||
*sock_in = *sock_out = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void kill_proxy_sighandler(int UNUSED(signo)) {
|
||||
kill_proxy_command();
|
||||
_exit(1);
|
||||
}
|
||||
#endif /* DROPBEAR_CLI_PROXYCMD */
|
||||
|
||||
892
cli-runopts.c
892
cli-runopts.c
File diff suppressed because it is too large
Load Diff
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2004 by Mihnea Stoenescu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "service.h"
|
||||
#include "dbutil.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "session.h"
|
||||
#include "ssh.h"
|
||||
|
||||
void send_msg_service_request(char* servicename) {
|
||||
|
||||
TRACE(("enter send_msg_service_request: servicename='%s'", servicename));
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST);
|
||||
buf_putstring(ses.writepayload, servicename, strlen(servicename));
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave send_msg_service_request"));
|
||||
}
|
||||
|
||||
/* This just sets up the state variables right for the main client session loop
|
||||
* to deal with */
|
||||
void recv_msg_service_accept() {
|
||||
|
||||
unsigned char* servicename;
|
||||
unsigned int len;
|
||||
|
||||
TRACE(("enter recv_msg_service_accept"));
|
||||
|
||||
servicename = buf_getstring(ses.payload, &len);
|
||||
|
||||
/* ssh-userauth */
|
||||
if (cli_ses.state == SERVICE_AUTH_REQ_SENT
|
||||
&& len == SSH_SERVICE_USERAUTH_LEN
|
||||
&& strncmp(SSH_SERVICE_USERAUTH, servicename, len) == 0) {
|
||||
|
||||
cli_ses.state = SERVICE_AUTH_ACCEPT_RCVD;
|
||||
m_free(servicename);
|
||||
TRACE(("leave recv_msg_service_accept: done ssh-userauth"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* ssh-connection */
|
||||
if (cli_ses.state == SERVICE_CONN_REQ_SENT
|
||||
&& len == SSH_SERVICE_CONNECTION_LEN
|
||||
&& strncmp(SSH_SERVICE_CONNECTION, servicename, len) == 0) {
|
||||
|
||||
if (ses.authstate.authdone != 1) {
|
||||
dropbear_exit("request for connection before auth");
|
||||
}
|
||||
|
||||
cli_ses.state = SERVICE_CONN_ACCEPT_RCVD;
|
||||
m_free(servicename);
|
||||
TRACE(("leave recv_msg_service_accept: done ssh-connection"));
|
||||
return;
|
||||
}
|
||||
|
||||
dropbear_exit("unrecognised service accept");
|
||||
/* m_free(servicename); not reached */
|
||||
|
||||
}
|
||||
279
cli-session.c
279
cli-session.c
@@ -31,15 +31,21 @@
|
||||
#include "packet.h"
|
||||
#include "tcpfwd.h"
|
||||
#include "channel.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
#include "service.h"
|
||||
#include "runopts.h"
|
||||
#include "chansession.h"
|
||||
#include "agentfwd.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "netio.h"
|
||||
|
||||
static void cli_remoteclosed();
|
||||
static void cli_sessionloop();
|
||||
static void cli_session_init();
|
||||
static void cli_finished();
|
||||
static void cli_remoteclosed(void) ATTRIB_NORETURN;
|
||||
static void cli_sessionloop(void);
|
||||
static void cli_session_init(pid_t proxy_cmd_pid);
|
||||
static void cli_finished(void) ATTRIB_NORETURN;
|
||||
static void recv_msg_service_accept(void);
|
||||
static void cli_session_cleanup(void);
|
||||
static void recv_msg_global_request_cli(void);
|
||||
|
||||
struct clientsession cli_ses; /* GLOBAL */
|
||||
|
||||
@@ -48,6 +54,7 @@ struct clientsession cli_ses; /* GLOBAL */
|
||||
static const packettype cli_packettypes[] = {
|
||||
/* TYPE, FUNCTION */
|
||||
{SSH_MSG_CHANNEL_DATA, recv_msg_channel_data},
|
||||
{SSH_MSG_CHANNEL_EXTENDED_DATA, recv_msg_channel_extended_data},
|
||||
{SSH_MSG_CHANNEL_WINDOW_ADJUST, recv_msg_channel_window_adjust},
|
||||
{SSH_MSG_USERAUTH_FAILURE, recv_msg_userauth_failure}, /* client */
|
||||
{SSH_MSG_USERAUTH_SUCCESS, recv_msg_userauth_success}, /* client */
|
||||
@@ -62,49 +69,78 @@ static const packettype cli_packettypes[] = {
|
||||
{SSH_MSG_CHANNEL_OPEN_CONFIRMATION, recv_msg_channel_open_confirmation},
|
||||
{SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure},
|
||||
{SSH_MSG_USERAUTH_BANNER, recv_msg_userauth_banner}, /* client */
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
{SSH_MSG_USERAUTH_PK_OK, recv_msg_userauth_pk_ok}, /* client */
|
||||
{SSH_MSG_USERAUTH_SPECIFIC_60, recv_msg_userauth_specific_60}, /* client */
|
||||
{SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_cli},
|
||||
{SSH_MSG_CHANNEL_SUCCESS, ignore_recv_response},
|
||||
{SSH_MSG_CHANNEL_FAILURE, ignore_recv_response},
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
{SSH_MSG_REQUEST_SUCCESS, cli_recv_msg_request_success}, /* client */
|
||||
{SSH_MSG_REQUEST_FAILURE, cli_recv_msg_request_failure}, /* client */
|
||||
#else
|
||||
/* For keepalive */
|
||||
{SSH_MSG_REQUEST_SUCCESS, ignore_recv_response},
|
||||
{SSH_MSG_REQUEST_FAILURE, ignore_recv_response},
|
||||
#endif
|
||||
{0, 0} /* End */
|
||||
{SSH_MSG_EXT_INFO, recv_msg_ext_info},
|
||||
{0, NULL} /* End */
|
||||
};
|
||||
|
||||
static const struct ChanType *cli_chantypes[] = {
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
&cli_chan_tcpremote,
|
||||
#endif
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
&cli_chan_agent,
|
||||
#endif
|
||||
NULL /* Null termination */
|
||||
};
|
||||
|
||||
void cli_session(int sock, char* remotehost) {
|
||||
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();
|
||||
}
|
||||
|
||||
crypto_init();
|
||||
common_session_init(sock, remotehost);
|
||||
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);
|
||||
|
||||
if (progress) {
|
||||
connect_set_writequeue(progress, &ses.writequeue);
|
||||
}
|
||||
|
||||
chaninitialise(cli_chantypes);
|
||||
|
||||
|
||||
/* Set up cli_ses vars */
|
||||
cli_session_init();
|
||||
cli_session_init(proxy_cmd_pid);
|
||||
|
||||
/* Ready to go */
|
||||
sessinitdone = 1;
|
||||
ses.init_done = 1;
|
||||
|
||||
/* Exchange identification */
|
||||
session_identification();
|
||||
send_session_identification();
|
||||
|
||||
seedrandom();
|
||||
kexfirstinitialise(); /* initialise the kex state */
|
||||
|
||||
send_msg_kexinit();
|
||||
|
||||
/* XXX here we do stuff differently */
|
||||
|
||||
session_loop(cli_sessionloop);
|
||||
|
||||
/* Not reached */
|
||||
|
||||
}
|
||||
|
||||
static void cli_session_init() {
|
||||
#if DROPBEAR_KEX_FIRST_FOLLOWS
|
||||
static void cli_send_kex_first_guess() {
|
||||
send_msg_kexdh_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void cli_session_init(pid_t proxy_cmd_pid) {
|
||||
|
||||
cli_ses.state = STATE_NOTHING;
|
||||
cli_ses.kex_state = KEX_NOTHING;
|
||||
@@ -112,56 +148,94 @@ static void cli_session_init() {
|
||||
cli_ses.tty_raw_mode = 0;
|
||||
cli_ses.winchange = 0;
|
||||
|
||||
/* We store std{in,out,err}'s flags, so we can set them back on exit
|
||||
* (otherwise busybox's ash isn't happy */
|
||||
cli_ses.stdincopy = dup(STDIN_FILENO);
|
||||
cli_ses.stdinflags = fcntl(STDIN_FILENO, F_GETFL, 0);
|
||||
cli_ses.stdoutcopy = dup(STDOUT_FILENO);
|
||||
cli_ses.stdoutflags = fcntl(STDOUT_FILENO, F_GETFL, 0);
|
||||
cli_ses.stderrcopy = dup(STDERR_FILENO);
|
||||
cli_ses.stderrflags = fcntl(STDERR_FILENO, F_GETFL, 0);
|
||||
|
||||
cli_ses.retval = EXIT_SUCCESS; /* Assume it's clean if we don't get a
|
||||
specific exit status */
|
||||
cli_ses.proxy_cmd_pid = proxy_cmd_pid;
|
||||
TRACE(("proxy command PID='%d'", proxy_cmd_pid));
|
||||
|
||||
/* Auth */
|
||||
cli_ses.lastpubkey = NULL;
|
||||
cli_ses.lastauthtype = NULL;
|
||||
cli_ses.lastprivkey = NULL;
|
||||
cli_ses.lastauthtype = 0;
|
||||
|
||||
/* For printing "remote host closed" for the user */
|
||||
ses.remoteclosed = cli_remoteclosed;
|
||||
ses.buf_match_algo = cli_buf_match_algo;
|
||||
|
||||
ses.extra_session_cleanup = cli_session_cleanup;
|
||||
|
||||
/* packet handlers */
|
||||
ses.packettypes = cli_packettypes;
|
||||
|
||||
ses.isserver = 0;
|
||||
|
||||
#if DROPBEAR_KEX_FIRST_FOLLOWS
|
||||
ses.send_kex_first_guess = cli_send_kex_first_guess;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void send_msg_service_request(const char* servicename) {
|
||||
|
||||
TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST);
|
||||
buf_putstring(ses.writepayload, servicename, strlen(servicename));
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave send_msg_service_request"))
|
||||
}
|
||||
|
||||
static void recv_msg_service_accept(void) {
|
||||
/* do nothing, if it failed then the server MUST have disconnected */
|
||||
}
|
||||
|
||||
/* This function drives the progress of the session - it initiates KEX,
|
||||
* service, userauth and channel requests */
|
||||
static void cli_sessionloop() {
|
||||
|
||||
TRACE(("enter cli_sessionloop"));
|
||||
TRACE2(("enter cli_sessionloop"))
|
||||
|
||||
if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
|
||||
cli_ses.kex_state = KEXINIT_RCVD;
|
||||
if (ses.lastpacket == 0) {
|
||||
TRACE2(("exit cli_sessionloop: no real packets yet"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (cli_ses.kex_state == KEXINIT_RCVD) {
|
||||
|
||||
if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
|
||||
/* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT
|
||||
* negotiation would have failed. */
|
||||
send_msg_kexdh_init();
|
||||
cli_ses.kex_state = KEXDH_INIT_SENT;
|
||||
TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD"));
|
||||
if (!ses.kexstate.our_first_follows_matches) {
|
||||
send_msg_kexdh_init();
|
||||
}
|
||||
cli_ses.kex_state = KEXDH_INIT_SENT;
|
||||
TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD"))
|
||||
return;
|
||||
}
|
||||
|
||||
/* A KEX has finished, so we should go back to our KEX_NOTHING state */
|
||||
if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.recvkexinit == 0
|
||||
&& ses.kexstate.sentkexinit == 0) {
|
||||
if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.sentnewkeys) {
|
||||
cli_ses.kex_state = KEX_NOTHING;
|
||||
}
|
||||
|
||||
/* We shouldn't do anything else if a KEX is in progress */
|
||||
if (cli_ses.kex_state != KEX_NOTHING) {
|
||||
TRACE(("leave cli_sessionloop: kex_state != KEX_NOTHING"));
|
||||
TRACE(("leave cli_sessionloop: kex_state != KEX_NOTHING"))
|
||||
return;
|
||||
}
|
||||
|
||||
/* We should exit if we haven't donefirstkex: we shouldn't reach here
|
||||
* in normal operation */
|
||||
if (ses.kexstate.donefirstkex == 0) {
|
||||
TRACE(("XXX XXX might be bad! leave cli_sessionloop: haven't donefirstkex"));
|
||||
/* We might reach here if we have partial packet reads or have
|
||||
* received SSG_MSG_IGNORE etc. Just skip it */
|
||||
TRACE2(("donefirstkex false\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -171,51 +245,68 @@ static void cli_sessionloop() {
|
||||
/* We've got the transport layer sorted, we now need to request
|
||||
* userauth */
|
||||
send_msg_service_request(SSH_SERVICE_USERAUTH);
|
||||
cli_ses.state = SERVICE_AUTH_REQ_SENT;
|
||||
TRACE(("leave cli_sessionloop: sent userauth service req"));
|
||||
return;
|
||||
|
||||
/* userauth code */
|
||||
case SERVICE_AUTH_ACCEPT_RCVD:
|
||||
cli_auth_getmethods();
|
||||
cli_ses.state = USERAUTH_REQ_SENT;
|
||||
TRACE(("leave cli_sessionloop: sent userauth methods req"));
|
||||
TRACE(("leave cli_sessionloop: sent userauth methods req"))
|
||||
return;
|
||||
|
||||
case USERAUTH_REQ_SENT:
|
||||
TRACE(("leave cli_sessionloop: waiting, req_sent"))
|
||||
return;
|
||||
|
||||
case USERAUTH_FAIL_RCVD:
|
||||
cli_auth_try();
|
||||
if (cli_auth_try() == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("No auth methods could be used.");
|
||||
}
|
||||
cli_ses.state = USERAUTH_REQ_SENT;
|
||||
TRACE(("leave cli_sessionloop: cli_auth_try"));
|
||||
TRACE(("leave cli_sessionloop: cli_auth_try"))
|
||||
return;
|
||||
|
||||
/*
|
||||
case USERAUTH_SUCCESS_RCVD:
|
||||
send_msg_service_request(SSH_SERVICE_CONNECTION);
|
||||
cli_ses.state = SERVICE_CONN_REQ_SENT;
|
||||
TRACE(("leave cli_sessionloop: sent ssh-connection service req"));
|
||||
return;
|
||||
|
||||
case SERVICE_CONN_ACCEPT_RCVD:
|
||||
cli_send_chansess_request();
|
||||
TRACE(("leave cli_sessionloop: cli_send_chansess_request"));
|
||||
cli_ses.state = SESSION_RUNNING;
|
||||
return;
|
||||
*/
|
||||
|
||||
case USERAUTH_SUCCESS_RCVD:
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
#ifndef DISABLE_SYSLOG
|
||||
if (opts.usingsyslog) {
|
||||
dropbear_log(LOG_INFO, "Authentication succeeded.");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cli_opts.backgrounded) {
|
||||
int devnull;
|
||||
/* keeping stdin open steals input from the terminal and
|
||||
is confusing, though stdout/stderr could be useful. */
|
||||
devnull = open(DROPBEAR_PATH_DEVNULL, O_RDONLY);
|
||||
if (devnull < 0) {
|
||||
dropbear_exit("Opening /dev/null: %d %s",
|
||||
errno, strerror(errno));
|
||||
}
|
||||
dup2(devnull, STDIN_FILENO);
|
||||
if (daemon(0, 1) < 0) {
|
||||
dropbear_exit("Backgrounding failed: %d %s",
|
||||
errno, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
#if DROPBEAR_CLI_NETCAT
|
||||
if (cli_opts.netcat_host) {
|
||||
cli_send_netcat_request();
|
||||
} else
|
||||
#endif
|
||||
if (!cli_opts.no_cmd) {
|
||||
cli_send_chansess_request();
|
||||
}
|
||||
|
||||
#if DROPBEAR_CLI_LOCALTCPFWD
|
||||
setup_localtcp();
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
setup_remotetcp();
|
||||
#endif
|
||||
cli_send_chansess_request();
|
||||
TRACE(("leave cli_sessionloop: cli_send_chansess_request"));
|
||||
|
||||
TRACE(("leave cli_sessionloop: running"))
|
||||
cli_ses.state = SESSION_RUNNING;
|
||||
return;
|
||||
|
||||
case SESSION_RUNNING:
|
||||
if (ses.chancount < 1) {
|
||||
if (ses.chancount < 1 && !cli_opts.no_cmd) {
|
||||
cli_finished();
|
||||
}
|
||||
|
||||
@@ -231,26 +322,49 @@ static void cli_sessionloop() {
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE(("leave cli_sessionloop: fell out"));
|
||||
TRACE2(("leave cli_sessionloop: fell out"))
|
||||
|
||||
}
|
||||
|
||||
void cli_session_cleanup() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sessinitdone) {
|
||||
static void cli_session_cleanup(void) {
|
||||
|
||||
if (!ses.init_done) {
|
||||
return;
|
||||
}
|
||||
cli_tty_cleanup();
|
||||
|
||||
kill_proxy_command();
|
||||
|
||||
/* Set std{in,out,err} back to non-blocking - busybox ash dies nastily if
|
||||
* we don't revert the flags */
|
||||
/* Ignore return value since there's nothing we can do */
|
||||
(void)fcntl(cli_ses.stdincopy, F_SETFL, cli_ses.stdinflags);
|
||||
(void)fcntl(cli_ses.stdoutcopy, F_SETFL, cli_ses.stdoutflags);
|
||||
(void)fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags);
|
||||
|
||||
cli_tty_cleanup();
|
||||
if (cli_ses.server_sig_algs) {
|
||||
buf_free(cli_ses.server_sig_algs);
|
||||
}
|
||||
}
|
||||
|
||||
static void cli_finished() {
|
||||
TRACE(("cli_finished()"))
|
||||
|
||||
cli_session_cleanup();
|
||||
common_session_cleanup();
|
||||
session_cleanup();
|
||||
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
|
||||
cli_opts.remotehost, cli_opts.remoteport);
|
||||
exit(EXIT_SUCCESS);
|
||||
exit(cli_ses.retval);
|
||||
}
|
||||
|
||||
|
||||
@@ -259,17 +373,20 @@ static void cli_remoteclosed() {
|
||||
|
||||
/* XXX TODO perhaps print a friendlier message if we get this but have
|
||||
* already sent/received disconnect message(s) ??? */
|
||||
close(ses.sock);
|
||||
ses.sock = -1;
|
||||
dropbear_exit("remote closed the connection");
|
||||
m_close(ses.sock_in);
|
||||
m_close(ses.sock_out);
|
||||
ses.sock_in = -1;
|
||||
ses.sock_out = -1;
|
||||
dropbear_exit("Remote closed the connection");
|
||||
}
|
||||
|
||||
/* Operates in-place turning dirty (untrusted potentially containing control
|
||||
* characters) text into clean text. */
|
||||
void cleantext(unsigned char* dirtytext) {
|
||||
* characters) text into clean text.
|
||||
* Note: this is safe only with ascii - other charsets could have problems. */
|
||||
void cleantext(char* dirtytext) {
|
||||
|
||||
unsigned int i, j;
|
||||
unsigned char c;
|
||||
char c;
|
||||
|
||||
j = 0;
|
||||
for (i = 0; dirtytext[i] != '\0'; i++) {
|
||||
@@ -284,3 +401,9 @@ void cleantext(unsigned char* dirtytext) {
|
||||
/* Null terminate */
|
||||
dirtytext[j] = '\0';
|
||||
}
|
||||
|
||||
static void recv_msg_global_request_cli(void) {
|
||||
TRACE(("recv_msg_global_request_cli"))
|
||||
/* Send a proper rejection */
|
||||
send_msg_request_failure();
|
||||
}
|
||||
|
||||
250
cli-tcpfwd.c
250
cli-tcpfwd.c
@@ -23,16 +23,15 @@
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "options.h"
|
||||
#include "dbutil.h"
|
||||
#include "tcpfwd.h"
|
||||
#include "channel.h"
|
||||
#include "runopts.h"
|
||||
#include "session.h"
|
||||
#include "ssh.h"
|
||||
#include "netio.h"
|
||||
|
||||
static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
|
||||
unsigned int remoteport);
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
static int newtcpforwarded(struct Channel * channel);
|
||||
|
||||
const struct ChanType cli_chan_tcpremote = {
|
||||
@@ -41,45 +40,73 @@ const struct ChanType cli_chan_tcpremote = {
|
||||
newtcpforwarded,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_CLI_LOCALTCPFWD
|
||||
static int cli_localtcp(const char* listenaddr,
|
||||
unsigned int listenport,
|
||||
const char* remoteaddr,
|
||||
unsigned int remoteport);
|
||||
static const struct ChanType cli_chan_tcplocal = {
|
||||
1, /* sepfds */
|
||||
"direct-tcpip",
|
||||
tcp_prio_inithandler,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
#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() {
|
||||
|
||||
m_list_elem *iter;
|
||||
int ret;
|
||||
|
||||
TRACE(("enter setup_localtcp"));
|
||||
TRACE(("enter setup_localtcp"))
|
||||
|
||||
if (cli_opts.localfwds == NULL) {
|
||||
TRACE(("cli_opts.localfwds == NULL"));
|
||||
}
|
||||
|
||||
while (cli_opts.localfwds != NULL) {
|
||||
ret = cli_localtcp(cli_opts.localfwds->listenport,
|
||||
cli_opts.localfwds->connectaddr,
|
||||
cli_opts.localfwds->connectport);
|
||||
for (iter = cli_opts.localfwds->first; iter; iter = iter->next) {
|
||||
struct TCPFwdEntry * fwd = (struct TCPFwdEntry*)iter->item;
|
||||
ret = cli_localtcp(
|
||||
fwd->listenaddr,
|
||||
fwd->listenport,
|
||||
fwd->connectaddr,
|
||||
fwd->connectport);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d",
|
||||
cli_opts.localfwds->listenport,
|
||||
cli_opts.localfwds->connectaddr,
|
||||
cli_opts.localfwds->connectport);
|
||||
}
|
||||
|
||||
cli_opts.localfwds = cli_opts.localfwds->next;
|
||||
fwd_failed("Failed local port forward %s:%d:%s:%d",
|
||||
fwd->listenaddr,
|
||||
fwd->listenport,
|
||||
fwd->connectaddr,
|
||||
fwd->connectport);
|
||||
}
|
||||
}
|
||||
TRACE(("leave setup_localtcp"));
|
||||
TRACE(("leave setup_localtcp"))
|
||||
|
||||
}
|
||||
|
||||
static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
|
||||
static int cli_localtcp(const char* listenaddr,
|
||||
unsigned int listenport,
|
||||
const char* remoteaddr,
|
||||
unsigned int remoteport) {
|
||||
|
||||
struct TCPListener* tcpinfo = NULL;
|
||||
@@ -88,106 +115,175 @@ static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
|
||||
TRACE(("enter cli_localtcp: %d %s %d", listenport, remoteaddr,
|
||||
remoteport));
|
||||
|
||||
tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*));
|
||||
tcpinfo->sendaddr = remoteaddr;
|
||||
tcpinfo->sendport = remoteport;
|
||||
tcpinfo->listenport = listenport;
|
||||
tcpinfo->chantype = &cli_chan_tcplocal;
|
||||
tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
|
||||
|
||||
ret = listen_tcpfwd(tcpinfo);
|
||||
tcpinfo->sendaddr = m_strdup(remoteaddr);
|
||||
tcpinfo->sendport = remoteport;
|
||||
|
||||
if (listenaddr)
|
||||
{
|
||||
tcpinfo->listenaddr = m_strdup(listenaddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opts.listen_fwd_all) {
|
||||
tcpinfo->listenaddr = m_strdup("");
|
||||
} else {
|
||||
tcpinfo->listenaddr = m_strdup("localhost");
|
||||
}
|
||||
}
|
||||
tcpinfo->listenport = listenport;
|
||||
|
||||
tcpinfo->chantype = &cli_chan_tcplocal;
|
||||
tcpinfo->tcp_type = direct;
|
||||
|
||||
ret = listen_tcpfwd(tcpinfo, NULL);
|
||||
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(tcpinfo);
|
||||
}
|
||||
TRACE(("leave cli_localtcp: %d", ret));
|
||||
TRACE(("leave cli_localtcp: %d", ret))
|
||||
return ret;
|
||||
}
|
||||
#endif /* DROPBEAR_CLI_LOCALTCPFWD */
|
||||
|
||||
static void send_msg_global_request_remotetcp(int port) {
|
||||
#if DROPBEAR_CLI_REMOTETCPFWD
|
||||
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"))
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
|
||||
buf_putstring(ses.writepayload, "tcpip-forward", 13);
|
||||
buf_putbyte(ses.writepayload, 0);
|
||||
buf_putstring(ses.writepayload, "0.0.0.0", 7); /* TODO: IPv6? */
|
||||
buf_putbyte(ses.writepayload, 1); /* want_reply */
|
||||
buf_putstring(ses.writepayload, addr, strlen(addr));
|
||||
buf_putint(ses.writepayload, port);
|
||||
|
||||
encrypt_packet();
|
||||
|
||||
TRACE(("leave send_msg_global_request_remotetcp"));
|
||||
TRACE(("leave send_msg_global_request_remotetcp"))
|
||||
}
|
||||
|
||||
/* The only global success/failure messages are for remotetcp.
|
||||
* Since there isn't any identifier in these messages, we have to rely on them
|
||||
* being in the same order as we sent the requests. This is the ordering
|
||||
* of the cli_opts.remotefwds list.
|
||||
* If the requested remote port is 0 the listen port will be
|
||||
* dynamically allocated by the server and the port number will be returned
|
||||
* to client and the port number reported to the user. */
|
||||
void cli_recv_msg_request_success() {
|
||||
/* We just mark off that we have received the reply,
|
||||
* so that we can report failure for later ones. */
|
||||
m_list_elem * iter = NULL;
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (!fwd->have_reply) {
|
||||
fwd->have_reply = 1;
|
||||
if (fwd->listenport == 0) {
|
||||
/* The server should let us know which port was allocated if we requested port 0 */
|
||||
int allocport = buf_getint(ses.payload);
|
||||
if (allocport > 0) {
|
||||
fwd->listenport = allocport;
|
||||
dropbear_log(LOG_INFO, "Allocated port %d for remote forward to %s:%d",
|
||||
allocport, fwd->connectaddr, fwd->connectport);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cli_recv_msg_request_failure() {
|
||||
m_list_elem *iter;
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (!fwd->have_reply) {
|
||||
fwd->have_reply = 1;
|
||||
fwd_failed("Remote TCP forward request failed (port %d -> %s:%d)",
|
||||
fwd->listenport,
|
||||
fwd->connectaddr,
|
||||
fwd->connectport);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup_remotetcp() {
|
||||
m_list_elem *iter;
|
||||
TRACE(("enter setup_remotetcp"))
|
||||
|
||||
struct TCPFwdList * iter = NULL;
|
||||
|
||||
TRACE(("enter setup_remotetcp"));
|
||||
|
||||
if (cli_opts.remotefwds == NULL) {
|
||||
TRACE(("cli_opts.remotefwds == NULL"));
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (!fwd->listenaddr)
|
||||
{
|
||||
/* we store the addresses so that we can compare them
|
||||
when the server sends them back */
|
||||
if (opts.listen_fwd_all) {
|
||||
fwd->listenaddr = m_strdup("");
|
||||
} else {
|
||||
fwd->listenaddr = m_strdup("localhost");
|
||||
}
|
||||
}
|
||||
send_msg_global_request_remotetcp(fwd->listenaddr, fwd->listenport);
|
||||
}
|
||||
|
||||
iter = cli_opts.remotefwds;
|
||||
|
||||
while (iter != NULL) {
|
||||
send_msg_global_request_remotetcp(iter->listenport);
|
||||
iter = iter->next;
|
||||
}
|
||||
TRACE(("leave setup_remotetcp"));
|
||||
TRACE(("leave setup_remotetcp"))
|
||||
}
|
||||
|
||||
static int newtcpforwarded(struct Channel * channel) {
|
||||
|
||||
char *origaddr = NULL;
|
||||
unsigned int origport;
|
||||
struct TCPFwdList * iter = NULL;
|
||||
m_list_elem * iter = NULL;
|
||||
struct TCPFwdEntry *fwd = NULL;
|
||||
char portstring[NI_MAXSERV];
|
||||
int sock;
|
||||
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
|
||||
|
||||
/* We don't care what address they connected to */
|
||||
buf_eatstring(ses.payload);
|
||||
|
||||
origaddr = buf_getstring(ses.payload, NULL);
|
||||
origport = buf_getint(ses.payload);
|
||||
|
||||
/* Find which port corresponds */
|
||||
iter = cli_opts.remotefwds;
|
||||
|
||||
while (iter != NULL) {
|
||||
if (origport == iter->listenport) {
|
||||
/* Find which port corresponds. First try and match address as well as port,
|
||||
in case they want to forward different ports separately ... */
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (origport == fwd->listenport
|
||||
&& strcmp(origaddr, fwd->listenaddr) == 0) {
|
||||
break;
|
||||
}
|
||||
iter = iter->next;
|
||||
}
|
||||
|
||||
if (iter == NULL) {
|
||||
if (!iter)
|
||||
{
|
||||
/* ... otherwise try to generically match the only forwarded port
|
||||
without address (also handles ::1 vs 127.0.0.1 vs localhost case).
|
||||
rfc4254 is vague about the definition of "address that was connected" */
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (origport == fwd->listenport) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (iter == NULL || fwd == NULL) {
|
||||
/* We didn't request forwarding on that port */
|
||||
dropbear_log(LOG_INFO, "Server send unrequested port, from port %d",
|
||||
origport);
|
||||
cleantext(origaddr);
|
||||
dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"",
|
||||
origaddr, origport);
|
||||
goto out;
|
||||
}
|
||||
|
||||
snprintf(portstring, sizeof(portstring), "%d", iter->connectport);
|
||||
sock = connect_remote(iter->connectaddr, portstring, 1, NULL);
|
||||
if (sock < 0) {
|
||||
TRACE(("leave newtcpdirect: sock failed"));
|
||||
err = SSH_OPEN_CONNECT_FAILED;
|
||||
goto out;
|
||||
}
|
||||
snprintf(portstring, sizeof(portstring), "%u", fwd->connectport);
|
||||
channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel, NULL, NULL);
|
||||
|
||||
ses.maxfd = MAX(ses.maxfd, sock);
|
||||
|
||||
/* Note that infd is actually the "outgoing" direction on the
|
||||
* tcp connection, vice versa for outfd.
|
||||
* We don't set outfd, that will get set after the connection's
|
||||
* progress succeeds */
|
||||
channel->infd = sock;
|
||||
channel->initconn = 1;
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
|
||||
|
||||
err = SSH_OPEN_IN_PROGRESS;
|
||||
|
||||
out:
|
||||
TRACE(("leave newtcpdirect: err %d", err));
|
||||
m_free(origaddr);
|
||||
TRACE(("leave newtcpdirect: err %d", err))
|
||||
return err;
|
||||
}
|
||||
#endif /* DROPBEAR_CLI_REMOTETCPFWD */
|
||||
|
||||
637
common-algo.c
637
common-algo.c
@@ -23,29 +23,57 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
#include "session.h"
|
||||
#include "dbutil.h"
|
||||
#include "dh_groups.h"
|
||||
#include "ltc_prng.h"
|
||||
#include "ecc.h"
|
||||
#include "gcm.h"
|
||||
#include "chachapoly.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/* This file (algo.c) organises the ciphers which can be used, and is used to
|
||||
* decide which ciphers/hashes/compression/signing to use during key exchange*/
|
||||
|
||||
static int void_cipher(const unsigned char* in, unsigned char* out,
|
||||
unsigned long len, void* UNUSED(cipher_state)) {
|
||||
if (in != out) {
|
||||
memmove(out, in, len);
|
||||
}
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int void_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
|
||||
const unsigned char* UNUSED(key),
|
||||
int UNUSED(keylen), int UNUSED(num_rounds), void* UNUSED(cipher_state)) {
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* Mappings for ciphers, parameters are
|
||||
{&cipher_desc, keysize, blocksize} */
|
||||
|
||||
#ifdef DROPBEAR_AES128_CBC
|
||||
const struct dropbear_cipher dropbear_aes128 =
|
||||
{&rijndael_desc, 16, 16};
|
||||
/* Remember to add new ciphers/hashes to regciphers/reghashes too */
|
||||
|
||||
#if DROPBEAR_AES256
|
||||
static const struct dropbear_cipher dropbear_aes256 =
|
||||
{&aes_desc, 32, 16};
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH_CBC
|
||||
const struct dropbear_cipher dropbear_blowfish =
|
||||
{&blowfish_desc, 16, 8};
|
||||
#if DROPBEAR_AES128
|
||||
static const struct dropbear_cipher dropbear_aes128 =
|
||||
{&aes_desc, 16, 16};
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH128_CBC
|
||||
const struct dropbear_cipher dropbear_twofish128 =
|
||||
#if DROPBEAR_TWOFISH256
|
||||
static const struct dropbear_cipher dropbear_twofish256 =
|
||||
{&twofish_desc, 32, 16};
|
||||
#endif
|
||||
#if DROPBEAR_TWOFISH128
|
||||
static const struct dropbear_cipher dropbear_twofish128 =
|
||||
{&twofish_desc, 16, 16};
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES_CBC
|
||||
const struct dropbear_cipher dropbear_3des =
|
||||
#if DROPBEAR_3DES
|
||||
static const struct dropbear_cipher dropbear_3des =
|
||||
{&des3_desc, 24, 8};
|
||||
#endif
|
||||
|
||||
@@ -53,15 +81,49 @@ const struct dropbear_cipher dropbear_3des =
|
||||
const struct dropbear_cipher dropbear_nocipher =
|
||||
{NULL, 16, 8};
|
||||
|
||||
/* A few void* s are required to silence warnings
|
||||
* about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
const struct dropbear_cipher_mode dropbear_mode_cbc =
|
||||
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt, NULL, NULL, NULL};
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
|
||||
const struct dropbear_cipher_mode dropbear_mode_none =
|
||||
{void_start, void_cipher, void_cipher, NULL, NULL, NULL};
|
||||
|
||||
#if DROPBEAR_ENABLE_CTR_MODE
|
||||
/* a wrapper to make ctr_start and cbc_start look the same */
|
||||
static int dropbear_big_endian_ctr_start(int cipher,
|
||||
const unsigned char *IV,
|
||||
const unsigned char *key, int keylen,
|
||||
int num_rounds, symmetric_CTR *ctr) {
|
||||
return ctr_start(cipher, IV, key, keylen, num_rounds, CTR_COUNTER_BIG_ENDIAN, ctr);
|
||||
}
|
||||
const struct dropbear_cipher_mode dropbear_mode_ctr =
|
||||
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt, NULL, NULL, NULL};
|
||||
#endif /* DROPBEAR_ENABLE_CTR_MODE */
|
||||
|
||||
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
|
||||
{&hash_desc, keysize, hashsize} */
|
||||
|
||||
#ifdef DROPBEAR_SHA1_HMAC
|
||||
const struct dropbear_hash dropbear_sha1 =
|
||||
#if DROPBEAR_SHA1_HMAC
|
||||
static const struct dropbear_hash dropbear_sha1 =
|
||||
{&sha1_desc, 20, 20};
|
||||
#endif
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
const struct dropbear_hash dropbear_md5 =
|
||||
#if DROPBEAR_SHA1_96_HMAC
|
||||
static const struct dropbear_hash dropbear_sha1_96 =
|
||||
{&sha1_desc, 20, 12};
|
||||
#endif
|
||||
#if DROPBEAR_SHA2_256_HMAC
|
||||
static const struct dropbear_hash dropbear_sha2_256 =
|
||||
{&sha256_desc, 32, 32};
|
||||
#endif
|
||||
#if DROPBEAR_SHA2_512_HMAC
|
||||
static const struct dropbear_hash dropbear_sha2_512 =
|
||||
{&sha512_desc, 64, 64};
|
||||
#endif
|
||||
#if DROPBEAR_MD5_HMAC
|
||||
static const struct dropbear_hash dropbear_md5 =
|
||||
{&md5_desc, 16, 16};
|
||||
#endif
|
||||
|
||||
@@ -69,139 +131,474 @@ const struct dropbear_hash dropbear_nohash =
|
||||
{NULL, 16, 0}; /* used initially */
|
||||
|
||||
|
||||
/* The following map ssh names to internal values */
|
||||
/* The following map ssh names to internal values.
|
||||
* The ordering here is important for the client - the first mode
|
||||
* that is also supported by the server will get used. */
|
||||
|
||||
algo_type sshciphers[] = {
|
||||
#ifdef DROPBEAR_AES128_CBC
|
||||
{"aes128-cbc", 0, (void*)&dropbear_aes128, 1},
|
||||
#if DROPBEAR_CHACHA20POLY1305
|
||||
{"chacha20-poly1305@openssh.com", 0, &dropbear_chachapoly, 1, &dropbear_mode_chachapoly},
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH_CBC
|
||||
{"blowfish-cbc", 0, (void*)&dropbear_blowfish, 1},
|
||||
|
||||
#if DROPBEAR_ENABLE_GCM_MODE
|
||||
#if DROPBEAR_AES128
|
||||
{"aes128-gcm@openssh.com", 0, &dropbear_aes128, 1, &dropbear_mode_gcm},
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH128_CBC
|
||||
{"twofish-cbc", 0, (void*)&dropbear_twofish128, 1},
|
||||
#if DROPBEAR_AES256
|
||||
{"aes256-gcm@openssh.com", 0, &dropbear_aes256, 1, &dropbear_mode_gcm},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES_CBC
|
||||
{"3des-cbc", 0, (void*)&dropbear_3des, 1},
|
||||
#endif /* DROPBEAR_ENABLE_GCM_MODE */
|
||||
|
||||
#if DROPBEAR_ENABLE_CTR_MODE
|
||||
#if DROPBEAR_AES128
|
||||
{"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0}
|
||||
#if DROPBEAR_AES256
|
||||
{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
|
||||
#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 */
|
||||
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
#if DROPBEAR_AES128
|
||||
{"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#if DROPBEAR_AES256
|
||||
{"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#if DROPBEAR_TWOFISH256
|
||||
{"twofish256-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
|
||||
{"twofish-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#if DROPBEAR_TWOFISH128
|
||||
{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
|
||||
#if DROPBEAR_3DES
|
||||
#if DROPBEAR_ENABLE_CTR_MODE
|
||||
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#endif /* DROPBEAR_3DES */
|
||||
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
algo_type sshhashes[] = {
|
||||
#ifdef DROPBEAR_SHA1_HMAC
|
||||
{"hmac-sha1", 0, (void*)&dropbear_sha1, 1},
|
||||
#if DROPBEAR_SHA1_96_HMAC
|
||||
{"hmac-sha1-96", 0, &dropbear_sha1_96, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
{"hmac-md5", 0, (void*)&dropbear_md5, 1},
|
||||
#if DROPBEAR_SHA1_HMAC
|
||||
{"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0}
|
||||
#if DROPBEAR_SHA2_256_HMAC
|
||||
{"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_SHA2_512_HMAC
|
||||
{"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_MD5_HMAC
|
||||
{"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
algo_type sshcompress[] = {
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1},
|
||||
#ifndef DISABLE_ZLIB
|
||||
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0}
|
||||
algo_type ssh_compress[] = {
|
||||
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
|
||||
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
algo_type sshhostkey[] = {
|
||||
#ifdef DROPBEAR_RSA
|
||||
{"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1},
|
||||
algo_type ssh_delaycompress[] = {
|
||||
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
{"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0}
|
||||
|
||||
algo_type ssh_nocompress[] = {
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
algo_type sigalgs[] = {
|
||||
#if DROPBEAR_ED25519
|
||||
{"ssh-ed25519", DROPBEAR_SIGNATURE_ED25519, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_ECDSA
|
||||
#if DROPBEAR_ECC_256
|
||||
{"ecdsa-sha2-nistp256", DROPBEAR_SIGNATURE_ECDSA_NISTP256, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_ECC_384
|
||||
{"ecdsa-sha2-nistp384", DROPBEAR_SIGNATURE_ECDSA_NISTP384, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_ECC_521
|
||||
{"ecdsa-sha2-nistp521", DROPBEAR_SIGNATURE_ECDSA_NISTP521, NULL, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
#if DROPBEAR_RSA
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
{"rsa-sha2-256", DROPBEAR_SIGNATURE_RSA_SHA256, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_RSA_SHA1
|
||||
{"ssh-rsa", DROPBEAR_SIGNATURE_RSA_SHA1, NULL, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
#if DROPBEAR_DSS
|
||||
{"ssh-dss", DROPBEAR_SIGNATURE_DSS, NULL, 1, NULL},
|
||||
#endif
|
||||
{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 };
|
||||
#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
|
||||
|
||||
#if DROPBEAR_ECDH
|
||||
#if DROPBEAR_ECC_256
|
||||
static const struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
|
||||
#endif
|
||||
#if DROPBEAR_ECC_384
|
||||
static const struct dropbear_kex kex_ecdh_nistp384 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp384, &sha384_desc };
|
||||
#endif
|
||||
#if DROPBEAR_ECC_521
|
||||
static const struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp521, &sha512_desc };
|
||||
#endif
|
||||
#endif /* DROPBEAR_ECDH */
|
||||
|
||||
#if DROPBEAR_CURVE25519
|
||||
/* Referred to directly */
|
||||
static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc };
|
||||
#endif
|
||||
|
||||
/* data == NULL for non-kex algorithm identifiers */
|
||||
algo_type sshkex[] = {
|
||||
{"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1},
|
||||
{NULL, 0, NULL, 0}
|
||||
#if DROPBEAR_CURVE25519
|
||||
{"curve25519-sha256", 0, &kex_curve25519, 1, NULL},
|
||||
{"curve25519-sha256@libssh.org", 0, &kex_curve25519, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_ECDH
|
||||
#if DROPBEAR_ECC_521
|
||||
{"ecdh-sha2-nistp521", 0, &kex_ecdh_nistp521, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_ECC_384
|
||||
{"ecdh-sha2-nistp384", 0, &kex_ecdh_nistp384, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_ECC_256
|
||||
{"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL},
|
||||
#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},
|
||||
#endif
|
||||
#if DROPBEAR_DH_GROUP16
|
||||
{"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_KEXGUESS2
|
||||
{KEXGUESS2_ALGO_NAME, 0, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_EXT_INFO
|
||||
#if DROPBEAR_CLIENT
|
||||
/* Set unusable by svr_algos_initialise() */
|
||||
{SSH_EXT_INFO_C, 0, NULL, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
/* Register the compiled in ciphers.
|
||||
* This should be run before using any of the ciphers/hashes */
|
||||
void crypto_init() {
|
||||
|
||||
const struct _cipher_descriptor *regciphers[] = {
|
||||
#ifdef DROPBEAR_AES128_CBC
|
||||
&rijndael_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH_CBC
|
||||
&blowfish_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH128_CBC
|
||||
&twofish_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES_CBC
|
||||
&des3_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct _hash_descriptor *reghashes[] = {
|
||||
/* we need sha1 for hostkey stuff regardless */
|
||||
&sha1_desc,
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
&md5_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; regciphers[i] != NULL; i++) {
|
||||
if (register_cipher(regciphers[i]) == -1) {
|
||||
dropbear_exit("error registering crypto");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; reghashes[i] != NULL; i++) {
|
||||
if (register_hash(reghashes[i]) == -1) {
|
||||
dropbear_exit("error registering crypto");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* algolen specifies the length of algo, algos is our local list to match
|
||||
* against.
|
||||
* Returns DROPBEAR_SUCCESS if we have a match for algo, DROPBEAR_FAILURE
|
||||
* otherwise */
|
||||
int have_algo(char* algo, size_t algolen, algo_type algos[]) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; algos[i].name != NULL; i++) {
|
||||
if (strlen(algos[i].name) == algolen
|
||||
&& (strncmp(algos[i].name, algo, algolen) == 0)) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Output a comma separated list of algorithms to a buffer */
|
||||
void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
|
||||
void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall) {
|
||||
unsigned int i, len;
|
||||
unsigned int donefirst = 0;
|
||||
unsigned int startpos;
|
||||
|
||||
unsigned int pos = 0, i, len;
|
||||
char str[50]; /* enough for local algo storage */
|
||||
startpos = buf->pos;
|
||||
/* Placeholder for length */
|
||||
buf_putint(buf, 0);
|
||||
for (i = 0; localalgos[i].name != NULL; i++) {
|
||||
if (localalgos[i].usable || useall) {
|
||||
if (donefirst) {
|
||||
buf_putbyte(buf, ',');
|
||||
}
|
||||
donefirst = 1;
|
||||
len = strlen(localalgos[i].name);
|
||||
buf_putbytes(buf, (const unsigned char *) localalgos[i].name, len);
|
||||
}
|
||||
}
|
||||
/* Fill out the length */
|
||||
len = buf->pos - startpos - 4;
|
||||
buf_setpos(buf, startpos);
|
||||
buf_putint(buf, len);
|
||||
TRACE(("algolist add %d '%*s'", len, len, buf_getptr(buf, len)))
|
||||
buf_incrwritepos(buf, len);
|
||||
}
|
||||
|
||||
void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
|
||||
buf_put_algolist_all(buf, localalgos, 0);
|
||||
}
|
||||
|
||||
/* returns a list of pointers into algolist, of null-terminated names.
|
||||
ret_list should be passed in with space for *ret_count elements,
|
||||
on return *ret_count has the number of names filled.
|
||||
algolist is modified. */
|
||||
static void get_algolist(char* algolist, unsigned int algolist_len,
|
||||
const char* *ret_list, unsigned int *ret_count) {
|
||||
unsigned int max_count = *ret_count;
|
||||
unsigned int i;
|
||||
|
||||
if (*ret_count == 0) {
|
||||
return;
|
||||
}
|
||||
if (algolist_len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
*ret_count = 0;
|
||||
}
|
||||
|
||||
/* ret_list will contain a list of the strings parsed out.
|
||||
We will have at least one string (even if it's just "") */
|
||||
ret_list[0] = algolist;
|
||||
*ret_count = 1;
|
||||
for (i = 0; i < algolist_len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
*ret_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (algolist[i] == ',') {
|
||||
if (*ret_count >= max_count) {
|
||||
/* Too many */
|
||||
*ret_count = 0;
|
||||
return;
|
||||
}
|
||||
algolist[i] = '\0';
|
||||
ret_list[*ret_count] = &algolist[i+1];
|
||||
(*ret_count)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return DROPBEAR_SUCCESS if the namelist contains algo,
|
||||
DROPBEAR_FAILURE otherwise. buf position is not incremented. */
|
||||
int buf_has_algo(buffer *buf, const char *algo) {
|
||||
unsigned char* algolist = NULL;
|
||||
unsigned int orig_pos = buf->pos;
|
||||
unsigned int len, remotecount, i;
|
||||
const char *remotenames[MAX_PROPOSED_ALGO];
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
algolist = buf_getstring(buf, &len);
|
||||
remotecount = MAX_PROPOSED_ALGO;
|
||||
get_algolist(algolist, len, remotenames, &remotecount);
|
||||
for (i = 0; i < remotecount; i++)
|
||||
{
|
||||
if (strcmp(remotenames[i], algo) == 0) {
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (algolist) {
|
||||
m_free(algolist);
|
||||
}
|
||||
buf_setpos(buf, orig_pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
algo_type * first_usable_algo(algo_type algos[]) {
|
||||
int i;
|
||||
for (i = 0; algos[i].name != NULL; i++) {
|
||||
if (algos[i].usable) {
|
||||
return &algos[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* match the first algorithm in the comma-separated list in buf which is
|
||||
* also in localalgos[], or return NULL on failure.
|
||||
* (*goodguess) is set to 1 if the preferred client/server algos match,
|
||||
* 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
|
||||
* guessed correctly */
|
||||
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int kexguess2, int *goodguess) {
|
||||
char * algolist = NULL;
|
||||
const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
unsigned int remotecount, localcount, clicount, servcount, i, j;
|
||||
algo_type * ret = NULL;
|
||||
const char **clinames, **servnames;
|
||||
|
||||
if (goodguess) {
|
||||
*goodguess = 0;
|
||||
}
|
||||
|
||||
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
|
||||
algolist = buf_getstring(buf, &len);
|
||||
TRACE(("buf_match_algo: %s", algolist))
|
||||
remotecount = MAX_PROPOSED_ALGO;
|
||||
get_algolist(algolist, len, remotenames, &remotecount);
|
||||
|
||||
for (i = 0; localalgos[i].name != NULL; i++) {
|
||||
if (localalgos[i].usable) {
|
||||
/* Avoid generating a trailing comma */
|
||||
if (pos)
|
||||
str[pos++] = ',';
|
||||
len = strlen(localalgos[i].name);
|
||||
memcpy(&str[pos], localalgos[i].name, len);
|
||||
pos += len;
|
||||
localnames[i] = localalgos[i].name;
|
||||
} else {
|
||||
localnames[i] = NULL;
|
||||
}
|
||||
}
|
||||
str[pos]=0;
|
||||
/* Debug this */
|
||||
TRACE(("buf_put_algolist: %s", str));
|
||||
buf_putstring(buf, str, pos);
|
||||
localcount = i;
|
||||
|
||||
if (IS_DROPBEAR_SERVER) {
|
||||
clinames = remotenames;
|
||||
clicount = remotecount;
|
||||
servnames = localnames;
|
||||
servcount = localcount;
|
||||
} else {
|
||||
clinames = localnames;
|
||||
clicount = localcount;
|
||||
servnames = remotenames;
|
||||
servcount = remotecount;
|
||||
}
|
||||
|
||||
/* iterate and find the first match */
|
||||
for (i = 0; i < clicount; i++) {
|
||||
for (j = 0; j < servcount; j++) {
|
||||
if (!(servnames[j] && clinames[i])) {
|
||||
/* unusable algos are NULL */
|
||||
continue;
|
||||
}
|
||||
if (strcmp(servnames[j], clinames[i]) == 0) {
|
||||
/* set if it was a good guess */
|
||||
if (goodguess != NULL) {
|
||||
if (kexguess2) {
|
||||
if (i == 0) {
|
||||
*goodguess = 1;
|
||||
}
|
||||
} else {
|
||||
if (i == 0 && j == 0) {
|
||||
*goodguess = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* set the algo to return */
|
||||
if (IS_DROPBEAR_SERVER) {
|
||||
ret = &localalgos[j];
|
||||
} else {
|
||||
ret = &localalgos[i];
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(algolist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
|
||||
char *
|
||||
algolist_string(const algo_type algos[])
|
||||
{
|
||||
char *ret_list;
|
||||
buffer *b = buf_new(200);
|
||||
buf_put_algolist(b, algos);
|
||||
buf_setpos(b, b->len);
|
||||
buf_putbyte(b, '\0');
|
||||
buf_setpos(b, 4);
|
||||
ret_list = m_strdup((const char *) buf_getptr(b, b->len - b->pos));
|
||||
buf_free(b);
|
||||
return ret_list;
|
||||
}
|
||||
|
||||
static algo_type*
|
||||
check_algo(const char* algo_name, algo_type *algos)
|
||||
{
|
||||
algo_type *a;
|
||||
for (a = algos; a->name != NULL; a++)
|
||||
{
|
||||
if (strcmp(a->name, algo_name) == 0)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Checks a user provided comma-separated algorithm list for available
|
||||
* options. Any that are not acceptable are removed in-place. Returns the
|
||||
* number of valid algorithms. */
|
||||
int
|
||||
check_user_algos(const char* user_algo_list, algo_type * algos,
|
||||
const char *algo_desc)
|
||||
{
|
||||
algo_type new_algos[MAX_PROPOSED_ALGO+1];
|
||||
char *work_list = m_strdup(user_algo_list);
|
||||
char *start = work_list;
|
||||
char *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++)
|
||||
{
|
||||
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';
|
||||
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++;
|
||||
start = c;
|
||||
}
|
||||
if (oc == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_free(work_list);
|
||||
/* n+1 to include a null terminator */
|
||||
memcpy(algos, new_algos, sizeof(*new_algos) * (n+1));
|
||||
return n;
|
||||
}
|
||||
#endif /* DROPBEAR_USER_ALGO_LIST */
|
||||
|
||||
1220
common-channel.c
1220
common-channel.c
File diff suppressed because it is too large
Load Diff
872
common-kex.c
872
common-kex.c
File diff suppressed because it is too large
Load Diff
@@ -28,12 +28,15 @@
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "auth.h"
|
||||
#include "algo.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
runopts opts; /* GLOBAL */
|
||||
|
||||
/* returns success or failure, and the keytype in *type. If we want
|
||||
* to restrict the type, type can contain a type to return */
|
||||
int readhostkey(const char * filename, sign_key * hostkey, int *type) {
|
||||
int readhostkey(const char * filename, sign_key * hostkey,
|
||||
enum signkey_type *type) {
|
||||
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
buffer *buf;
|
||||
@@ -44,6 +47,9 @@ int readhostkey(const char * filename, sign_key * hostkey, int *type) {
|
||||
goto out;
|
||||
}
|
||||
buf_setpos(buf, 0);
|
||||
|
||||
addrandom(buf_getptr(buf, buf->len), buf->len);
|
||||
|
||||
if (buf_get_priv_key(buf, hostkey, type) == DROPBEAR_FAILURE) {
|
||||
goto out;
|
||||
}
|
||||
@@ -55,3 +61,44 @@ out:
|
||||
buf_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
void
|
||||
parse_ciphers_macs() {
|
||||
int printed_help = 0;
|
||||
if (opts.cipher_list) {
|
||||
if (strcmp(opts.cipher_list, "help") == 0) {
|
||||
char *ciphers = algolist_string(sshciphers);
|
||||
dropbear_log(LOG_INFO, "Available ciphers: %s", ciphers);
|
||||
m_free(ciphers);
|
||||
printed_help = 1;
|
||||
} else {
|
||||
if (check_user_algos(opts.cipher_list, sshciphers, "cipher") == 0) {
|
||||
dropbear_exit("No valid ciphers specified for '-c'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.mac_list) {
|
||||
if (strcmp(opts.mac_list, "help") == 0) {
|
||||
char *macs = algolist_string(sshhashes);
|
||||
dropbear_log(LOG_INFO, "Available MACs: %s", macs);
|
||||
m_free(macs);
|
||||
printed_help = 1;
|
||||
} else {
|
||||
if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0) {
|
||||
dropbear_exit("No valid MACs specified for '-m'");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (printed_help) {
|
||||
dropbear_exit(".");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void print_version() {
|
||||
fprintf(stderr, "Dropbear v%s\n", DROPBEAR_VERSION);
|
||||
}
|
||||
|
||||
|
||||
|
||||
592
common-session.c
592
common-session.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@@ -30,70 +30,110 @@
|
||||
#include "buffer.h"
|
||||
#include "dss.h"
|
||||
#include "ssh.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
#include "kex.h"
|
||||
#include "channel.h"
|
||||
#include "atomicio.h"
|
||||
#include "runopts.h"
|
||||
#include "netio.h"
|
||||
|
||||
static void checktimeouts(void);
|
||||
static long select_timeout(void);
|
||||
static int ident_readln(int fd, char* buf, int count);
|
||||
static void read_session_identification(void);
|
||||
|
||||
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 */
|
||||
|
||||
|
||||
static void checktimeouts();
|
||||
static int ident_readln(int fd, char* buf, int count);
|
||||
|
||||
/* called only at the start of a session, set up initial state */
|
||||
void common_session_init(int sock, char* remotehost) {
|
||||
void common_session_init(int sock_in, int sock_out) {
|
||||
time_t now;
|
||||
|
||||
TRACE(("enter session_init"));
|
||||
#if DEBUG_TRACE
|
||||
debug_start_net();
|
||||
#endif
|
||||
|
||||
ses.remotehost = remotehost;
|
||||
TRACE(("enter session_init"))
|
||||
|
||||
ses.sock = sock;
|
||||
ses.maxfd = sock;
|
||||
ses.sock_in = sock_in;
|
||||
ses.sock_out = sock_out;
|
||||
ses.maxfd = MAX(sock_in, sock_out);
|
||||
|
||||
ses.connecttimeout = 0;
|
||||
if (sock_in >= 0) {
|
||||
setnonblocking(sock_in);
|
||||
}
|
||||
if (sock_out >= 0) {
|
||||
setnonblocking(sock_out);
|
||||
}
|
||||
|
||||
ses.socket_prio = DROPBEAR_PRIO_DEFAULT;
|
||||
/* Sets it to lowdelay */
|
||||
update_channel_prio();
|
||||
|
||||
#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();
|
||||
ses.connect_time = now;
|
||||
ses.last_packet_time_keepalive_recv = now;
|
||||
ses.last_packet_time_idle = now;
|
||||
ses.last_packet_time_any_sent = 0;
|
||||
ses.last_packet_time_keepalive_sent = 0;
|
||||
|
||||
kexfirstinitialise(); /* initialise the kex state */
|
||||
chaninitialise(); /* initialise the channel state */
|
||||
|
||||
ses.writepayload = buf_new(MAX_TRANS_PAYLOAD_LEN);
|
||||
#if DROPBEAR_FUZZ
|
||||
if (!fuzz.fuzzing)
|
||||
#endif
|
||||
{
|
||||
if (pipe(ses.signal_pipe) < 0) {
|
||||
dropbear_exit("Signal pipe failed");
|
||||
}
|
||||
setnonblocking(ses.signal_pipe[0]);
|
||||
setnonblocking(ses.signal_pipe[1]);
|
||||
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
|
||||
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
|
||||
}
|
||||
|
||||
ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN);
|
||||
ses.transseq = 0;
|
||||
|
||||
ses.readbuf = NULL;
|
||||
ses.decryptreadbuf = NULL;
|
||||
ses.payload = NULL;
|
||||
ses.recvseq = 0;
|
||||
|
||||
initqueue(&ses.writequeue);
|
||||
|
||||
ses.requirenext = SSH_MSG_KEXINIT;
|
||||
ses.dataallowed = 0; /* don't send data yet, we'll wait until after kex */
|
||||
ses.dataallowed = 1; /* we can send data until we actually
|
||||
send the SSH_MSG_KEXINIT */
|
||||
ses.ignorenext = 0;
|
||||
ses.lastpacket = 0;
|
||||
ses.reply_queue_head = NULL;
|
||||
ses.reply_queue_tail = NULL;
|
||||
|
||||
/* set all the algos to none */
|
||||
ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
ses.newkeys = NULL;
|
||||
ses.keys->recv_algo_crypt = &dropbear_nocipher;
|
||||
ses.keys->trans_algo_crypt = &dropbear_nocipher;
|
||||
ses.keys->recv.algo_crypt = &dropbear_nocipher;
|
||||
ses.keys->trans.algo_crypt = &dropbear_nocipher;
|
||||
ses.keys->recv.crypt_mode = &dropbear_mode_none;
|
||||
ses.keys->trans.crypt_mode = &dropbear_mode_none;
|
||||
|
||||
ses.keys->recv_algo_mac = &dropbear_nohash;
|
||||
ses.keys->trans_algo_mac = &dropbear_nohash;
|
||||
ses.keys->recv.algo_mac = &dropbear_nohash;
|
||||
ses.keys->trans.algo_mac = &dropbear_nohash;
|
||||
|
||||
ses.keys->algo_kex = -1;
|
||||
ses.keys->algo_kex = NULL;
|
||||
ses.keys->algo_hostkey = -1;
|
||||
ses.keys->recv_algo_comp = DROPBEAR_COMP_NONE;
|
||||
ses.keys->trans_algo_comp = DROPBEAR_COMP_NONE;
|
||||
ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
|
||||
ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE;
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
ses.keys->recv_zstream = NULL;
|
||||
ses.keys->trans_zstream = NULL;
|
||||
ses.keys->recv.zstream = NULL;
|
||||
ses.keys->trans.zstream = NULL;
|
||||
#endif
|
||||
|
||||
/* key exchange buffers */
|
||||
@@ -107,11 +147,14 @@ void common_session_init(int sock, char* remotehost) {
|
||||
|
||||
ses.allowprivport = 0;
|
||||
|
||||
#if DROPBEAR_PLUGIN
|
||||
ses.plugin_session = NULL;
|
||||
#endif
|
||||
|
||||
TRACE(("leave session_init"));
|
||||
TRACE(("leave session_init"))
|
||||
}
|
||||
|
||||
void session_loop(void(*loophandler)()) {
|
||||
void session_loop(void(*loophandler)(void)) {
|
||||
|
||||
fd_set readfd, writefd;
|
||||
struct timeval timeout;
|
||||
@@ -119,59 +162,90 @@ void session_loop(void(*loophandler)()) {
|
||||
|
||||
/* main loop, select()s for all sockets in use */
|
||||
for(;;) {
|
||||
const int writequeue_has_space = (ses.writequeue_len <= 2*TRANS_MAX_PAYLOAD_LEN);
|
||||
|
||||
timeout.tv_sec = SELECT_TIMEOUT;
|
||||
timeout.tv_sec = select_timeout();
|
||||
timeout.tv_usec = 0;
|
||||
FD_ZERO(&writefd);
|
||||
FD_ZERO(&readfd);
|
||||
assert(ses.payload == NULL);
|
||||
if (ses.sock != -1) {
|
||||
FD_SET(ses.sock, &readfd);
|
||||
if (!isempty(&ses.writequeue)) {
|
||||
FD_SET(ses.sock, &writefd);
|
||||
}
|
||||
DROPBEAR_FD_ZERO(&writefd);
|
||||
DROPBEAR_FD_ZERO(&readfd);
|
||||
|
||||
dropbear_assert(ses.payload == NULL);
|
||||
|
||||
/* We get woken up when signal handlers write to this pipe.
|
||||
SIGCHLD in svr-chansession is the only one currently. */
|
||||
#if DROPBEAR_FUZZ
|
||||
if (!fuzz.fuzzing)
|
||||
#endif
|
||||
{
|
||||
FD_SET(ses.signal_pipe[0], &readfd);
|
||||
}
|
||||
|
||||
/* set up for channels which require reading/writing */
|
||||
if (ses.dataallowed) {
|
||||
setchannelfds(&readfd, &writefd);
|
||||
/* set up for channels which can be read/written */
|
||||
setchannelfds(&readfd, &writefd, writequeue_has_space);
|
||||
|
||||
/* Pending connections to test */
|
||||
set_connect_fds(&writefd);
|
||||
|
||||
/* We delay reading from the input socket during initial setup until
|
||||
after we have written out our initial KEXINIT packet (empty writequeue).
|
||||
This means our initial packet can be in-flight while we're doing a blocking
|
||||
read for the remote ident.
|
||||
We also avoid reading from the socket if the writequeue is full, that avoids
|
||||
replies backing up */
|
||||
if (ses.sock_in != -1
|
||||
&& (ses.remoteident || isempty(&ses.writequeue))
|
||||
&& writequeue_has_space) {
|
||||
FD_SET(ses.sock_in, &readfd);
|
||||
}
|
||||
|
||||
/* Ordering is important, this test must occur after any other function
|
||||
might have queued packets (such as connection handlers) */
|
||||
if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
|
||||
FD_SET(ses.sock_out, &writefd);
|
||||
}
|
||||
|
||||
val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
|
||||
|
||||
if (exitflag) {
|
||||
if (ses.exitflag) {
|
||||
dropbear_exit("Terminated by signal");
|
||||
}
|
||||
|
||||
if (val < 0) {
|
||||
if (errno == EINTR) {
|
||||
/* This must happen even if we've been interrupted, so that
|
||||
* changed signal-handler vars can take effect etc */
|
||||
if (loophandler) {
|
||||
loophandler();
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
dropbear_exit("Error in select");
|
||||
}
|
||||
if (val < 0 && errno != EINTR) {
|
||||
dropbear_exit("Error in select");
|
||||
}
|
||||
|
||||
if (val <= 0) {
|
||||
/* If we were interrupted or the select timed out, we still
|
||||
* want to iterate over channels etc for reading, to handle
|
||||
* server processes exiting etc.
|
||||
* We don't want to read/write FDs. */
|
||||
DROPBEAR_FD_ZERO(&writefd);
|
||||
DROPBEAR_FD_ZERO(&readfd);
|
||||
}
|
||||
|
||||
/* 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
|
||||
wake up the select() above. */
|
||||
ses.channel_signal_pending = 0;
|
||||
if (FD_ISSET(ses.signal_pipe[0], &readfd)) {
|
||||
char x;
|
||||
TRACE(("signal pipe set"))
|
||||
while (read(ses.signal_pipe[0], &x, 1) > 0) {}
|
||||
ses.channel_signal_pending = 1;
|
||||
}
|
||||
|
||||
/* check for auth timeout, rekeying required etc */
|
||||
checktimeouts();
|
||||
|
||||
if (val == 0) {
|
||||
/* timeout */
|
||||
TRACE(("select timeout"));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* process session socket's incoming/outgoing data */
|
||||
if (ses.sock != -1) {
|
||||
if (FD_ISSET(ses.sock, &writefd) && !isempty(&ses.writequeue)) {
|
||||
write_packet();
|
||||
}
|
||||
|
||||
if (FD_ISSET(ses.sock, &readfd)) {
|
||||
read_packet();
|
||||
/* process session socket's incoming data */
|
||||
if (ses.sock_in != -1) {
|
||||
if (FD_ISSET(ses.sock_in, &readfd)) {
|
||||
if (!ses.remoteident) {
|
||||
/* blocking read of the version string */
|
||||
read_session_identification();
|
||||
} else {
|
||||
read_packet();
|
||||
}
|
||||
}
|
||||
|
||||
/* Process the decrypted packet. After this, the read buffer
|
||||
@@ -181,14 +255,25 @@ void session_loop(void(*loophandler)()) {
|
||||
}
|
||||
}
|
||||
|
||||
/* if required, flush out any queued reply packets that
|
||||
were being held up during a KEX */
|
||||
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
|
||||
* during rekeying ) */
|
||||
if (ses.dataallowed) {
|
||||
channelio(&readfd, &writefd);
|
||||
}
|
||||
channelio(&readfd, &writefd);
|
||||
|
||||
if (loophandler) {
|
||||
loophandler();
|
||||
/* process session socket's outgoing data */
|
||||
if (ses.sock_out != -1) {
|
||||
if (!isempty(&ses.writequeue)) {
|
||||
write_packet();
|
||||
}
|
||||
}
|
||||
|
||||
} /* for(;;) */
|
||||
@@ -196,55 +281,130 @@ void session_loop(void(*loophandler)()) {
|
||||
/* Not reached */
|
||||
}
|
||||
|
||||
/* clean up a session on exit */
|
||||
void common_session_cleanup() {
|
||||
|
||||
TRACE(("enter session_cleanup"));
|
||||
|
||||
/* we can't cleanup if we don't know the session state */
|
||||
if (!sessinitdone) {
|
||||
TRACE(("leave session_cleanup: !sessinitdone"));
|
||||
static void cleanup_buf(buffer **buf) {
|
||||
if (!*buf) {
|
||||
return;
|
||||
}
|
||||
buf_burn(*buf);
|
||||
buf_free(*buf);
|
||||
*buf = NULL;
|
||||
}
|
||||
|
||||
/* clean up a session on exit */
|
||||
void session_cleanup() {
|
||||
|
||||
m_free(ses.session_id);
|
||||
TRACE(("enter session_cleanup"))
|
||||
|
||||
/* we can't cleanup if we don't know the session state */
|
||||
if (!ses.init_done) {
|
||||
TRACE(("leave session_cleanup: !ses.init_done"))
|
||||
return;
|
||||
}
|
||||
|
||||
/* BEWARE of changing order of functions here. */
|
||||
|
||||
/* Must be before extra_session_cleanup() */
|
||||
chancleanup();
|
||||
|
||||
if (ses.extra_session_cleanup) {
|
||||
ses.extra_session_cleanup();
|
||||
}
|
||||
|
||||
/* After these are freed most functions will fail */
|
||||
#if DROPBEAR_CLEANUP
|
||||
/* listeners call cleanup functions, this should occur before
|
||||
other session state is freed. */
|
||||
remove_all_listeners();
|
||||
|
||||
remove_connect_pending();
|
||||
|
||||
while (!isempty(&ses.writequeue)) {
|
||||
buf_free(dequeue(&ses.writequeue));
|
||||
}
|
||||
|
||||
m_free(ses.newkeys);
|
||||
#ifndef DISABLE_ZLIB
|
||||
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_free(ses.keys);
|
||||
|
||||
chancleanup();
|
||||
|
||||
TRACE(("leave session_cleanup"));
|
||||
TRACE(("leave session_cleanup"))
|
||||
}
|
||||
|
||||
void send_session_identification() {
|
||||
buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
|
||||
buf_putbytes(writebuf, (const unsigned char *) LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
|
||||
writebuf_enqueue(writebuf);
|
||||
}
|
||||
|
||||
void session_identification() {
|
||||
|
||||
static void read_session_identification() {
|
||||
/* max length of 255 chars */
|
||||
char linebuf[256];
|
||||
int len = 0;
|
||||
char done = 0;
|
||||
int i;
|
||||
|
||||
/* write our version string, this blocks */
|
||||
if (atomicio(write, ses.sock, LOCAL_IDENT "\r\n",
|
||||
strlen(LOCAL_IDENT "\r\n")) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Error writing ident string");
|
||||
}
|
||||
/* Servers may send other lines of data before sending the
|
||||
* version string, client must be able to process such lines.
|
||||
* If they send more than 50 lines, something is wrong */
|
||||
for (i = IS_DROPBEAR_CLIENT ? 50 : 1; i > 0; i--) {
|
||||
len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
|
||||
|
||||
len = ident_readln(ses.sock, linebuf, 256);
|
||||
if (len >= 4 && memcmp(linebuf, "SSH-", 4) == 0) {
|
||||
/* start of line matches */
|
||||
done = 1;
|
||||
if (len < 0 && errno != EINTR) {
|
||||
/* It failed */
|
||||
break;
|
||||
}
|
||||
|
||||
if (len >= 4 && memcmp(linebuf, "SSH-", 4) == 0) {
|
||||
/* start of line matches */
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
dropbear_exit("Failed to get client version");
|
||||
TRACE(("error reading remote ident: %s\n", strerror(errno)))
|
||||
ses.remoteclosed();
|
||||
} else {
|
||||
/* linebuf is already null terminated */
|
||||
ses.remoteident = m_malloc(len);
|
||||
memcpy(ses.remoteident, linebuf, len);
|
||||
}
|
||||
|
||||
TRACE(("remoteident: %s", ses.remoteident));
|
||||
/* Shall assume that 2.x will be backwards compatible. */
|
||||
if (strncmp(ses.remoteident, "SSH-2.", 6) != 0
|
||||
&& strncmp(ses.remoteident, "SSH-1.99-", 9) != 0) {
|
||||
dropbear_exit("Incompatible remote version '%s'", ses.remoteident);
|
||||
}
|
||||
|
||||
TRACE(("remoteident: %s", ses.remoteident))
|
||||
|
||||
}
|
||||
|
||||
@@ -258,13 +418,13 @@ static int ident_readln(int fd, char* buf, int count) {
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
|
||||
TRACE(("enter ident_readln"));
|
||||
TRACE(("enter ident_readln"))
|
||||
|
||||
if (count < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
FD_ZERO(&fds);
|
||||
DROPBEAR_FD_ZERO(&fds);
|
||||
|
||||
/* select since it's a non-blocking fd */
|
||||
|
||||
@@ -279,7 +439,7 @@ static int ident_readln(int fd, char* buf, int count) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
TRACE(("leave ident_readln: select error"));
|
||||
TRACE(("leave ident_readln: select error"))
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -297,12 +457,12 @@ static int ident_readln(int fd, char* buf, int count) {
|
||||
if (errno == EINTR) {
|
||||
continue; /* not a real error */
|
||||
}
|
||||
TRACE(("leave ident_readln: read error"));
|
||||
TRACE(("leave ident_readln: read error"))
|
||||
return -1;
|
||||
}
|
||||
if (num == 0) {
|
||||
/* EOF */
|
||||
TRACE(("leave ident_readln: EOF"));
|
||||
TRACE(("leave ident_readln: EOF"))
|
||||
return -1;
|
||||
}
|
||||
if (in == '\n') {
|
||||
@@ -318,24 +478,52 @@ static int ident_readln(int fd, char* buf, int count) {
|
||||
}
|
||||
|
||||
buf[pos] = '\0';
|
||||
TRACE(("leave ident_readln: return %d", pos+1));
|
||||
TRACE(("leave ident_readln: return %d", pos+1))
|
||||
return pos+1;
|
||||
}
|
||||
|
||||
void ignore_recv_response() {
|
||||
/* Do nothing */
|
||||
TRACE(("Ignored msg_request_response"))
|
||||
}
|
||||
|
||||
static void send_msg_keepalive() {
|
||||
time_t old_time_idle = ses.last_packet_time_idle;
|
||||
struct Channel *chan = get_any_ready_channel();
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
if (chan) {
|
||||
/* Channel requests are preferable, more implementations
|
||||
handle them than SSH_MSG_GLOBAL_REQUEST */
|
||||
TRACE(("keepalive channel request %d", chan->index))
|
||||
start_send_channel_request(chan, DROPBEAR_KEEPALIVE_STRING);
|
||||
} else {
|
||||
TRACE(("keepalive global request"))
|
||||
/* Some peers will reply with SSH_MSG_REQUEST_FAILURE,
|
||||
some will reply with SSH_MSG_UNIMPLEMENTED, some will exit. */
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
|
||||
buf_putstring(ses.writepayload, DROPBEAR_KEEPALIVE_STRING,
|
||||
strlen(DROPBEAR_KEEPALIVE_STRING));
|
||||
}
|
||||
buf_putbyte(ses.writepayload, 1); /* want_reply */
|
||||
encrypt_packet();
|
||||
|
||||
ses.last_packet_time_keepalive_sent = monotonic_now();
|
||||
|
||||
/* keepalives shouldn't update idle timeout, reset it back */
|
||||
ses.last_packet_time_idle = old_time_idle;
|
||||
}
|
||||
|
||||
/* Check all timeouts which are required. Currently these are the time for
|
||||
* user authentication, and the automatic rekeying. */
|
||||
static void checktimeouts() {
|
||||
|
||||
struct timeval tv;
|
||||
long secs;
|
||||
|
||||
if (gettimeofday(&tv, 0) < 0) {
|
||||
dropbear_exit("Error getting time");
|
||||
}
|
||||
|
||||
secs = tv.tv_sec;
|
||||
time_t now;
|
||||
now = monotonic_now();
|
||||
|
||||
if (ses.connecttimeout != 0 && secs > ses.connecttimeout) {
|
||||
if (IS_DROPBEAR_SERVER && ses.connect_time != 0
|
||||
&& now - ses.connect_time >= AUTH_TIMEOUT) {
|
||||
dropbear_close("Timeout before auth");
|
||||
}
|
||||
|
||||
@@ -345,10 +533,168 @@ static void checktimeouts() {
|
||||
}
|
||||
|
||||
if (!ses.kexstate.sentkexinit
|
||||
&& (secs - ses.kexstate.lastkextime >= KEX_REKEY_TIMEOUT
|
||||
|| ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)){
|
||||
TRACE(("rekeying after timeout or max data reached"));
|
||||
&& (now - ses.kexstate.lastkextime >= KEX_REKEY_TIMEOUT
|
||||
|| ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)) {
|
||||
TRACE(("rekeying after timeout or max data reached"))
|
||||
send_msg_kexinit();
|
||||
}
|
||||
|
||||
if (opts.keepalive_secs > 0 && ses.authstate.authdone) {
|
||||
/* Avoid sending keepalives prior to auth - those are
|
||||
not valid pre-auth packet types */
|
||||
|
||||
/* Send keepalives if we've been idle */
|
||||
if (now - ses.last_packet_time_any_sent >= opts.keepalive_secs) {
|
||||
send_msg_keepalive();
|
||||
}
|
||||
|
||||
/* Also send an explicit keepalive message to trigger a response
|
||||
if the remote end hasn't sent us anything */
|
||||
if (now - ses.last_packet_time_keepalive_recv >= opts.keepalive_secs
|
||||
&& now - ses.last_packet_time_keepalive_sent >= opts.keepalive_secs) {
|
||||
send_msg_keepalive();
|
||||
}
|
||||
|
||||
if (now - ses.last_packet_time_keepalive_recv
|
||||
>= opts.keepalive_secs * DEFAULT_KEEPALIVE_LIMIT) {
|
||||
dropbear_exit("Keepalive timeout");
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.idle_timeout_secs > 0
|
||||
&& now - ses.last_packet_time_idle >= opts.idle_timeout_secs) {
|
||||
dropbear_close("Idle timeout");
|
||||
}
|
||||
}
|
||||
|
||||
static void update_timeout(long limit, long now, long last_event, long * timeout) {
|
||||
TRACE2(("update_timeout limit %ld, now %ld, last %ld, timeout %ld",
|
||||
limit, now, last_event, *timeout))
|
||||
if (last_event > 0 && limit > 0) {
|
||||
*timeout = MIN(*timeout, last_event+limit-now);
|
||||
TRACE2(("new timeout %ld", *timeout))
|
||||
}
|
||||
}
|
||||
|
||||
static long select_timeout() {
|
||||
/* determine the minimum timeout that might be required, so
|
||||
as to avoid waking when unneccessary */
|
||||
long timeout = KEX_REKEY_TIMEOUT;
|
||||
long now = monotonic_now();
|
||||
|
||||
if (!ses.kexstate.sentkexinit) {
|
||||
update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
|
||||
}
|
||||
|
||||
if (ses.authstate.authdone != 1 && IS_DROPBEAR_SERVER) {
|
||||
/* AUTH_TIMEOUT is only relevant before authdone */
|
||||
update_timeout(AUTH_TIMEOUT, now, ses.connect_time, &timeout);
|
||||
}
|
||||
|
||||
if (ses.authstate.authdone) {
|
||||
update_timeout(opts.keepalive_secs, now,
|
||||
MAX(ses.last_packet_time_keepalive_recv, ses.last_packet_time_keepalive_sent),
|
||||
&timeout);
|
||||
}
|
||||
|
||||
update_timeout(opts.idle_timeout_secs, now, ses.last_packet_time_idle,
|
||||
&timeout);
|
||||
|
||||
/* clamp negative timeouts to zero - event has already triggered */
|
||||
return MAX(timeout, 0);
|
||||
}
|
||||
|
||||
const char* get_user_shell() {
|
||||
/* an empty shell should be interpreted as "/bin/sh" */
|
||||
if (ses.authstate.pw_shell[0] == '\0') {
|
||||
return "/bin/sh";
|
||||
} else {
|
||||
return ses.authstate.pw_shell;
|
||||
}
|
||||
}
|
||||
void fill_passwd(const char* username) {
|
||||
struct passwd *pw = NULL;
|
||||
if (ses.authstate.pw_name)
|
||||
m_free(ses.authstate.pw_name);
|
||||
if (ses.authstate.pw_dir)
|
||||
m_free(ses.authstate.pw_dir);
|
||||
if (ses.authstate.pw_shell)
|
||||
m_free(ses.authstate.pw_shell);
|
||||
if (ses.authstate.pw_passwd)
|
||||
m_free(ses.authstate.pw_passwd);
|
||||
|
||||
pw = getpwnam(username);
|
||||
if (!pw) {
|
||||
return;
|
||||
}
|
||||
ses.authstate.pw_uid = pw->pw_uid;
|
||||
ses.authstate.pw_gid = pw->pw_gid;
|
||||
ses.authstate.pw_name = m_strdup(pw->pw_name);
|
||||
ses.authstate.pw_dir = m_strdup(pw->pw_dir);
|
||||
ses.authstate.pw_shell = m_strdup(pw->pw_shell);
|
||||
{
|
||||
char *passwd_crypt = pw->pw_passwd;
|
||||
#ifdef HAVE_SHADOW_H
|
||||
/* get the shadow password if possible */
|
||||
struct spwd *spasswd = getspnam(ses.authstate.pw_name);
|
||||
if (spasswd && spasswd->sp_pwdp) {
|
||||
passwd_crypt = spasswd->sp_pwdp;
|
||||
}
|
||||
#endif
|
||||
if (!passwd_crypt) {
|
||||
/* android supposedly returns NULL */
|
||||
passwd_crypt = "!!";
|
||||
}
|
||||
ses.authstate.pw_passwd = m_strdup(passwd_crypt);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called when channels are modified */
|
||||
void update_channel_prio() {
|
||||
enum dropbear_prio new_prio;
|
||||
int any = 0;
|
||||
unsigned int i;
|
||||
|
||||
TRACE(("update_channel_prio"))
|
||||
|
||||
if (ses.sock_out < 0) {
|
||||
TRACE(("leave update_channel_prio: no socket"))
|
||||
return;
|
||||
}
|
||||
|
||||
new_prio = DROPBEAR_PRIO_BULK;
|
||||
for (i = 0; i < ses.chansize; i++) {
|
||||
struct Channel *channel = ses.channels[i];
|
||||
if (!channel || channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
|
||||
if (channel && channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
|
||||
TRACE(("update_channel_prio: early %d", channel->index))
|
||||
}
|
||||
continue;
|
||||
}
|
||||
any = 1;
|
||||
if (channel->prio == DROPBEAR_CHANNEL_PRIO_INTERACTIVE)
|
||||
{
|
||||
TRACE(("update_channel_prio: lowdelay %d", channel->index))
|
||||
new_prio = DROPBEAR_PRIO_LOWDELAY;
|
||||
break;
|
||||
} else if (channel->prio == DROPBEAR_CHANNEL_PRIO_UNKNOWABLE
|
||||
&& new_prio == DROPBEAR_PRIO_BULK)
|
||||
{
|
||||
TRACE(("update_channel_prio: unknowable %d", channel->index))
|
||||
new_prio = DROPBEAR_PRIO_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
if (any == 0) {
|
||||
/* lowdelay during setup */
|
||||
TRACE(("update_channel_prio: not any"))
|
||||
new_prio = DROPBEAR_PRIO_LOWDELAY;
|
||||
}
|
||||
|
||||
if (new_prio != ses.socket_prio) {
|
||||
TRACE(("Dropbear priority transitioning %d -> %d", ses.socket_prio, new_prio))
|
||||
set_sock_priority(ses.sock_out, new_prio);
|
||||
ses.socket_prio = new_prio;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
25
compat.c
25
compat.c
@@ -114,8 +114,8 @@ size_t strlcpy(char *dst, const char *src, size_t size) {
|
||||
#endif /* HAVE_STRLCPY */
|
||||
|
||||
#ifndef HAVE_STRLCAT
|
||||
/* taken from openbsd-compat for OpenSSH 3.6.1p1 */
|
||||
/* "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $"
|
||||
/* taken from openbsd-compat for OpenSSH 7.2p2 */
|
||||
/* "$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
|
||||
* 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)).
|
||||
* If retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcat(dst, src, siz)
|
||||
char *dst;
|
||||
const char *src;
|
||||
size_t siz;
|
||||
size_t
|
||||
strlcat(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register size_t n = siz;
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
size_t dlen;
|
||||
|
||||
/* 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)
|
||||
(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, STDOUT_FILENO);
|
||||
(void)dup2(fd, STDERR_FILENO);
|
||||
@@ -193,6 +190,10 @@ int daemon(int nochdir, int noclose) {
|
||||
char *basename(const char *path) {
|
||||
|
||||
char *foo = strrchr(path, '/');
|
||||
if (!foo)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
return ++foo;
|
||||
}
|
||||
|
||||
@@ -231,7 +232,7 @@ void setusershell() {
|
||||
|
||||
static char **initshells() {
|
||||
/* don't touch this list. */
|
||||
const char *okshells[] = { "/bin/sh", "/bin/csh", NULL };
|
||||
static const char *okshells[] = { "/bin/sh", "/bin/csh", NULL };
|
||||
register char **sp, *cp;
|
||||
register FILE *fp;
|
||||
struct stat statb;
|
||||
|
||||
16
compat.h
16
compat.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _COMPAT_H_
|
||||
#define _COMPAT_H_
|
||||
#ifndef DROPBEAR_COMPAT_H_
|
||||
#define DROPBEAR_COMPAT_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
@@ -44,13 +44,13 @@ char *basename(const char* path);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETUSERSHELL
|
||||
char *getusershell();
|
||||
void setusershell();
|
||||
void endusershell();
|
||||
char *getusershell(void);
|
||||
void setusershell(void);
|
||||
void endusershell(void);
|
||||
#endif
|
||||
|
||||
#ifndef _PATH_DEVNULL
|
||||
#define _PATH_DEVNULL "/dev/null"
|
||||
#ifndef DROPBEAR_PATH_DEVNULL
|
||||
#define DROPBEAR_PATH_DEVNULL "/dev/null"
|
||||
#endif
|
||||
|
||||
#endif /* _COMPAT_H_ */
|
||||
#endif /* DROPBEAR_COMPAT_H_ */
|
||||
|
||||
1696
config.guess
vendored
1696
config.guess
vendored
File diff suppressed because it is too large
Load Diff
2569
config.sub
vendored
2569
config.sub
vendored
File diff suppressed because it is too large
Load Diff
885
configure.ac
Normal file
885
configure.ac
Normal file
@@ -0,0 +1,885 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf and autoheader to produce a configure script.
|
||||
|
||||
# This Autoconf file was cobbled from various locations. In particular, a bunch
|
||||
# of the platform checks have been taken straight from OpenSSH's configure.ac
|
||||
# Huge thanks to them for dealing with the horrible platform-specifics :)
|
||||
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT
|
||||
AC_CONFIG_SRCDIR(buffer.c)
|
||||
|
||||
# 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.
|
||||
AC_PROG_CC
|
||||
|
||||
if test -z "$LD" ; then
|
||||
LD=$CC
|
||||
fi
|
||||
AC_SUBST(LD)
|
||||
|
||||
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)
|
||||
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
|
||||
|
||||
# large file support is useful for scp
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
# Host specific options
|
||||
# this isn't a definitive list of hosts, they are just added as required
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
case "$host" in
|
||||
|
||||
*-*-linux*)
|
||||
no_ptmx_check=1
|
||||
;;
|
||||
|
||||
*-*-solaris*)
|
||||
CFLAGS="$CFLAGS -I/usr/local/include"
|
||||
LDFLAGS="$LDFLAGS -L/usr/local/lib -R/usr/local/lib"
|
||||
conf_lastlog_location="/var/adm/lastlog"
|
||||
AC_MSG_CHECKING(for obsolete utmp and wtmp in solaris2.x)
|
||||
sol2ver=`echo "$host"| sed -e 's/.*[[0-9]]\.//'`
|
||||
if test "$sol2ver" -ge 8; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(DISABLE_UTMP,1,Disable utmp)
|
||||
AC_DEFINE(DISABLE_WTMP,1,Disable wtmp)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket")
|
||||
AC_CHECK_LIB(nsl, yp_match, LIBS="$LIBS -lnsl")
|
||||
;;
|
||||
|
||||
*-*-aix*)
|
||||
AC_DEFINE(AIX,1,Using AIX)
|
||||
# OpenSSH thinks it's broken. If it isn't, let me know.
|
||||
AC_DEFINE(BROKEN_GETADDRINFO,1,Broken getaddrinfo)
|
||||
;;
|
||||
|
||||
*-*-hpux*)
|
||||
LIBS="$LIBS -lsec"
|
||||
# It's probably broken.
|
||||
AC_DEFINE(BROKEN_GETADDRINFO,1,Broken getaddrinfo)
|
||||
;;
|
||||
*-dec-osf*)
|
||||
AC_DEFINE(BROKEN_GETADDRINFO,1,Broken getaddrinfo)
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_CHECK_TOOL(AR, ar, :)
|
||||
AC_CHECK_TOOL(RANLIB, ranlib, :)
|
||||
AC_CHECK_TOOL(STRIP, strip, :)
|
||||
AC_CHECK_TOOL(INSTALL, install, :)
|
||||
|
||||
dnl Can't use login() or logout() with uclibc
|
||||
AC_CHECK_DECL(__UCLIBC__,
|
||||
[
|
||||
no_loginfunc_check=1
|
||||
AC_MSG_NOTICE([Using uClibc - login() and logout() probably don't work, so we won't use them.])
|
||||
],,)
|
||||
|
||||
dnl We test for crypt() specially. On Linux (and others?) it resides in libcrypt
|
||||
dnl but we don't want link all binaries to -lcrypt, just dropbear server.
|
||||
dnl OS X doesn't need -lcrypt
|
||||
AC_CHECK_FUNC(crypt, found_crypt_func=here)
|
||||
AC_CHECK_LIB(crypt, crypt,
|
||||
[
|
||||
CRYPTLIB="-lcrypt"
|
||||
found_crypt_func=here
|
||||
])
|
||||
AC_SUBST(CRYPTLIB)
|
||||
if test "t$found_crypt_func" = there; then
|
||||
AC_DEFINE(HAVE_CRYPT, 1, [crypt() function])
|
||||
fi
|
||||
|
||||
# Check if zlib is needed
|
||||
AC_ARG_WITH(zlib,
|
||||
[ --with-zlib=PATH Use zlib in PATH],
|
||||
[
|
||||
# option is given
|
||||
if test -d "$withval/lib"; then
|
||||
LDFLAGS="-L${withval}/lib ${LDFLAGS}"
|
||||
else
|
||||
LDFLAGS="-L${withval} ${LDFLAGS}"
|
||||
fi
|
||||
if test -d "$withval/include"; then
|
||||
CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
|
||||
else
|
||||
CPPFLAGS="-I${withval} ${CPPFLAGS}"
|
||||
fi
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(zlib,
|
||||
[ --disable-zlib Don't include zlib support],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
AC_DEFINE(DISABLE_ZLIB,1,Use zlib)
|
||||
AC_MSG_NOTICE(Disabling zlib)
|
||||
else
|
||||
AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***]))
|
||||
AC_MSG_NOTICE(Enabling zlib)
|
||||
fi
|
||||
],
|
||||
[
|
||||
# if not disabled, check for zlib
|
||||
AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***]))
|
||||
AC_MSG_NOTICE(Enabling zlib)
|
||||
]
|
||||
)
|
||||
|
||||
# Check if pam is needed
|
||||
AC_ARG_WITH(pam,
|
||||
[ --with-pam=PATH Use pam in PATH],
|
||||
[
|
||||
# option is given
|
||||
if test -d "$withval/lib"; then
|
||||
LDFLAGS="-L${withval}/lib ${LDFLAGS}"
|
||||
else
|
||||
LDFLAGS="-L${withval} ${LDFLAGS}"
|
||||
fi
|
||||
if test -d "$withval/include"; then
|
||||
CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
|
||||
else
|
||||
CPPFLAGS="-I${withval} ${CPPFLAGS}"
|
||||
fi
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
AC_ARG_ENABLE(pam,
|
||||
[ --enable-pam Try to include PAM support],
|
||||
[
|
||||
if test "x$enableval" = "xyes"; then
|
||||
AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***]))
|
||||
AC_MSG_NOTICE(Enabling PAM)
|
||||
AC_CHECK_FUNCS(pam_fail_delay)
|
||||
else
|
||||
AC_DEFINE(DISABLE_PAM,1,Use PAM)
|
||||
AC_MSG_NOTICE(Disabling PAM)
|
||||
fi
|
||||
],
|
||||
[
|
||||
# disable it by default
|
||||
AC_DEFINE(DISABLE_PAM,1,Use PAM)
|
||||
AC_MSG_NOTICE(Disabling PAM)
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(openpty,
|
||||
[ --disable-openpty Don't use openpty, use alternative method],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
AC_MSG_NOTICE(Not using openpty)
|
||||
else
|
||||
AC_MSG_NOTICE(Using openpty if available)
|
||||
AC_SEARCH_LIBS(openpty, util, [dropbear_cv_func_have_openpty=yes])
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_MSG_NOTICE(Using openpty if available)
|
||||
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,
|
||||
[ --disable-syslog Don't include syslog support],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
AC_DEFINE(DISABLE_SYSLOG,1,Using syslog)
|
||||
AC_MSG_NOTICE(Disabling syslog)
|
||||
else
|
||||
AC_MSG_NOTICE(Enabling syslog)
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_MSG_NOTICE(Enabling syslog)
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(shadow,
|
||||
[ --disable-shadow Don't use shadow passwords (if available)],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
AC_MSG_NOTICE(Not using shadow passwords)
|
||||
else
|
||||
AC_CHECK_HEADERS([shadow.h])
|
||||
AC_MSG_NOTICE(Using shadow passwords if available)
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_CHECK_HEADERS([shadow.h])
|
||||
AC_MSG_NOTICE(Using shadow passwords if available)
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(plugin,
|
||||
[ --enable-plugin Enable support for External Public Key Authentication plug-in],
|
||||
[
|
||||
AC_DEFINE(DROPBEAR_PLUGIN, 1, External Public Key Authentication)
|
||||
AC_MSG_NOTICE(Enabling support for External Public Key Authentication)
|
||||
DROPBEAR_PLUGIN=1
|
||||
],
|
||||
[
|
||||
AC_DEFINE(DROPBEAR_PLUGIN, 0, External Public Key Authentication)
|
||||
DROPBEAR_PLUGIN=0
|
||||
]
|
||||
|
||||
)
|
||||
AC_SUBST(DROPBEAR_PLUGIN)
|
||||
|
||||
AC_ARG_ENABLE(fuzz,
|
||||
[ --enable-fuzz Build fuzzing. Not recommended for deployment.],
|
||||
[
|
||||
if test "x$enableval" = "xyes"; then
|
||||
AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing)
|
||||
AC_MSG_NOTICE(Enabling fuzzing)
|
||||
DROPBEAR_FUZZ=1
|
||||
# libfuzzer needs linking with c++ libraries
|
||||
AC_PROG_CXX
|
||||
else
|
||||
AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
|
||||
AC_MSG_NOTICE(Disabling fuzzing)
|
||||
DROPBEAR_FUZZ=0
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
|
||||
AC_MSG_NOTICE(Disabling fuzzing)
|
||||
DROPBEAR_FUZZ=0
|
||||
]
|
||||
|
||||
)
|
||||
AC_SUBST(DROPBEAR_FUZZ)
|
||||
AC_SUBST(CXX)
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
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 \
|
||||
sys/random.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_TYPE_UID_T
|
||||
AC_TYPE_MODE_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_HEADER_TIME
|
||||
|
||||
AC_CHECK_TYPES([uint8_t, u_int8_t, uint16_t, u_int16_t, uint32_t, u_int32_t])
|
||||
AC_CHECK_TYPES([struct sockaddr_storage])
|
||||
AC_CHECK_TYPE([socklen_t], ,[
|
||||
AC_MSG_CHECKING([for socklen_t equivalent])
|
||||
AC_CACHE_VAL([curl_cv_socklen_t_equiv],
|
||||
[
|
||||
# Systems have either "struct sockaddr *" or
|
||||
# "void *" as the second argument to getpeername
|
||||
curl_cv_socklen_t_equiv=
|
||||
for arg2 in "struct sockaddr" void; do
|
||||
for t in int size_t unsigned long "unsigned long"; do
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
int getpeername (int, $arg2 *, $t *);
|
||||
]],[[
|
||||
$t len;
|
||||
getpeername(0,0,&len);
|
||||
]])],[
|
||||
curl_cv_socklen_t_equiv="$t"
|
||||
break
|
||||
])
|
||||
done
|
||||
done
|
||||
|
||||
if test "x$curl_cv_socklen_t_equiv" = x; then
|
||||
AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
|
||||
fi
|
||||
])
|
||||
AC_MSG_RESULT($curl_cv_socklen_t_equiv)
|
||||
AC_DEFINE_UNQUOTED(socklen_t, $curl_cv_socklen_t_equiv,
|
||||
[type to use in place of socklen_t if not defined])],
|
||||
[#include <sys/types.h>
|
||||
#include <sys/socket.h>])
|
||||
|
||||
# for the fake-rfc2553 stuff - straight from OpenSSH
|
||||
|
||||
AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage, [
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
]],
|
||||
[[ if (sizeof(struct sockaddr_storage)) return 0 ]])],
|
||||
[ ac_cv_have_struct_sockaddr_storage="yes" ],
|
||||
[ ac_cv_have_struct_sockaddr_storage="no" ]
|
||||
)
|
||||
])
|
||||
if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then
|
||||
AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
]],
|
||||
[[ if (sizeof(struct sockaddr_in6)) return 0 ]])],
|
||||
[ ac_cv_have_struct_sockaddr_in6="yes" ],
|
||||
[ ac_cv_have_struct_sockaddr_in6="no" ]
|
||||
)
|
||||
])
|
||||
if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then
|
||||
AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6,1,Have struct sockaddr_in6)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
]],
|
||||
[[ if (sizeof(struct in6_addr)) return 0 ]])],
|
||||
[ ac_cv_have_struct_in6_addr="yes" ],
|
||||
[ ac_cv_have_struct_in6_addr="no" ]
|
||||
)
|
||||
])
|
||||
if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
|
||||
AC_DEFINE(HAVE_STRUCT_IN6_ADDR,1,Have struct in6_addr)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
]],
|
||||
[[ if (sizeof(struct addrinfo)) return 0 ]])],
|
||||
[ ac_cv_have_struct_addrinfo="yes" ],
|
||||
[ ac_cv_have_struct_addrinfo="no" ]
|
||||
)
|
||||
])
|
||||
if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then
|
||||
AC_DEFINE(HAVE_STRUCT_ADDRINFO,1,Have struct addrinfo)
|
||||
fi
|
||||
|
||||
|
||||
# IRIX has a const char return value for gai_strerror()
|
||||
AC_CHECK_FUNCS(gai_strerror,[
|
||||
AC_DEFINE(HAVE_GAI_STRERROR)
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
const char *gai_strerror(int);]],[[
|
||||
char *str;
|
||||
|
||||
str = gai_strerror(0);]])],[
|
||||
AC_DEFINE(HAVE_CONST_GAI_STRERROR_PROTO, 1,
|
||||
[Define if gai_strerror() returns const char *])])])
|
||||
|
||||
# for loginrec.c
|
||||
|
||||
AC_CHECK_MEMBERS([struct utmp.ut_host, struct utmp.ut_pid, struct utmp.ut_type, struct utmp.ut_tv, struct utmp.ut_id, struct utmp.ut_addr, struct utmp.ut_addr_v6, struct utmp.ut_exit, struct utmp.ut_time],,,[
|
||||
#include <sys/types.h>
|
||||
#if HAVE_UTMP_H
|
||||
#include <utmp.h>
|
||||
#endif
|
||||
])
|
||||
|
||||
AC_CHECK_MEMBERS([struct utmpx.ut_host, struct utmpx.ut_syslen, struct utmpx.ut_type, struct utmpx.ut_id, struct utmpx.ut_addr, struct utmpx.ut_addr_v6, struct utmpx.ut_time, struct utmpx.ut_tv],,,[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#if HAVE_UTMPX_H
|
||||
#include <utmpx.h>
|
||||
#endif
|
||||
])
|
||||
|
||||
AC_CHECK_MEMBERS([struct sockaddr_storage.ss_family],,,[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
])
|
||||
|
||||
AC_CHECK_FUNCS(endutent getutent getutid getutline pututline setutent)
|
||||
AC_CHECK_FUNCS(utmpname)
|
||||
AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
|
||||
AC_CHECK_FUNCS(setutxent utmpxname)
|
||||
AC_CHECK_FUNCS(logout updwtmp logwtmp)
|
||||
|
||||
# POSIX monotonic time
|
||||
AC_CHECK_FUNCS(clock_gettime)
|
||||
|
||||
# OS X monotonic time
|
||||
AC_CHECK_HEADERS([mach/mach_time.h])
|
||||
AC_CHECK_FUNCS(mach_absolute_time)
|
||||
|
||||
AC_CHECK_FUNCS(explicit_bzero memset_s getrandom)
|
||||
|
||||
AC_ARG_ENABLE(bundled-libtom,
|
||||
[ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists.
|
||||
--disable-bundled-libtom Force using system libtomcrypt/libtommath, fail if it does not exist.
|
||||
Default is to use system if available, otherwise bundled.
|
||||
Dropbear requires system libtommath >= 1.2.0 and libtomcrypt >= 1.18.0],
|
||||
[
|
||||
if test "x$enableval" = "xyes"; then
|
||||
BUNDLED_LIBTOM=1
|
||||
AC_MSG_NOTICE(Forcing bundled libtom*)
|
||||
else
|
||||
BUNDLED_LIBTOM=0
|
||||
AC_CHECK_LIB(tommath, mp_to_ubin, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS",
|
||||
[AC_MSG_ERROR([Missing/old system libtommath and --disable-bundled-libtom was specified])] )
|
||||
AC_CHECK_LIB(tomcrypt, poly1305_init, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS",
|
||||
[AC_MSG_ERROR([Missing/old system libtomcrypt and --disable-bundled-libtom was specified])] )
|
||||
fi
|
||||
],
|
||||
[
|
||||
BUNDLED_LIBTOM=0
|
||||
AC_CHECK_LIB(tommath, mp_to_ubin, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
|
||||
AC_CHECK_LIB(tomcrypt, poly1305_init, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
|
||||
]
|
||||
)
|
||||
|
||||
if test $BUNDLED_LIBTOM = 1 ; then
|
||||
AC_DEFINE(BUNDLED_LIBTOM,1,Use bundled libtom)
|
||||
fi
|
||||
|
||||
AC_SUBST(LIBTOM_LIBS)
|
||||
AC_SUBST(BUNDLED_LIBTOM)
|
||||
|
||||
dnl Added from OpenSSH 3.6.1p2's configure.ac
|
||||
|
||||
dnl allow user to disable some login recording features
|
||||
AC_ARG_ENABLE(lastlog,
|
||||
[ --disable-lastlog Disable use of lastlog even if detected [no]],
|
||||
[
|
||||
if test "x$enableval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_LASTLOG,1,Disable use of lastlog())
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_ENABLE(utmp,
|
||||
[ --disable-utmp Disable use of utmp even if detected [no]],
|
||||
[
|
||||
if test "x$enableval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_UTMP,1,Disable use of utmp)
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_ENABLE(utmpx,
|
||||
[ --disable-utmpx Disable use of utmpx even if detected [no]],
|
||||
[
|
||||
if test "x$enableval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_UTMPX,1,Disable use of utmpx)
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_ENABLE(wtmp,
|
||||
[ --disable-wtmp Disable use of wtmp even if detected [no]],
|
||||
[
|
||||
if test "x$enableval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_WTMP,1,Disable use of wtmp)
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_ENABLE(wtmpx,
|
||||
[ --disable-wtmpx Disable use of wtmpx even if detected [no]],
|
||||
[
|
||||
if test "x$enableval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_WTMPX,1,Disable use of wtmpx)
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_ENABLE(loginfunc,
|
||||
[ --disable-loginfunc Disable use of login() etc. [no]],
|
||||
[ no_loginfunc_check=1
|
||||
AC_MSG_NOTICE([Not using login() etc]) ]
|
||||
)
|
||||
AC_ARG_ENABLE(pututline,
|
||||
[ --disable-pututline Disable use of pututline() etc. ([uw]tmp) [no]],
|
||||
[
|
||||
if test "x$enableval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_PUTUTLINE,1,Disable use of pututline())
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_ENABLE(pututxline,
|
||||
[ --disable-pututxline Disable use of pututxline() etc. ([uw]tmpx) [no]],
|
||||
[
|
||||
if test "x$enableval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_PUTUTXLINE,1,Disable use of pututxline())
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_WITH(lastlog,
|
||||
[ --with-lastlog=FILE|DIR specify lastlog location [common locations]],
|
||||
[
|
||||
if test "x$withval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_LASTLOG)
|
||||
else
|
||||
conf_lastlog_location=$withval
|
||||
fi
|
||||
]
|
||||
)
|
||||
|
||||
if test -z "$no_loginfunc_check"; then
|
||||
dnl Checks for libutil functions (login(), logout() etc, not openpty() )
|
||||
AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN,1,[Have login() function])])
|
||||
AC_CHECK_FUNCS(logout updwtmp logwtmp)
|
||||
fi
|
||||
|
||||
dnl lastlog, [uw]tmpx? detection
|
||||
dnl NOTE: set the paths in the platform section to avoid the
|
||||
dnl need for command-line parameters
|
||||
dnl lastlog and [uw]tmp are subject to a file search if all else fails
|
||||
|
||||
dnl lastlog detection
|
||||
dnl NOTE: the code itself will detect if lastlog is a directory
|
||||
AC_MSG_CHECKING([if your system defines LASTLOG_FILE])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_LASTLOG_H
|
||||
# include <lastlog.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
#ifdef HAVE_LOGIN_H
|
||||
# include <login.h>
|
||||
#endif
|
||||
]],
|
||||
[[ char *lastlog = LASTLOG_FILE; ]])],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_CHECKING([if your system defines _PATH_LASTLOG])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_LASTLOG_H
|
||||
# include <lastlog.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
]],
|
||||
[[ char *lastlog = _PATH_LASTLOG; ]])],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
system_lastlog_path=no
|
||||
])
|
||||
]
|
||||
)
|
||||
|
||||
if test -z "$conf_lastlog_location"; then
|
||||
if test x"$system_lastlog_path" = x"no" ; then
|
||||
for f in /var/log/lastlog /usr/adm/lastlog /var/adm/lastlog /etc/security/lastlog ; do
|
||||
if (test -d "$f" || test -f "$f") ; then
|
||||
conf_lastlog_location=$f
|
||||
fi
|
||||
done
|
||||
if test -z "$conf_lastlog_location"; then
|
||||
AC_MSG_WARN([** Cannot find lastlog **])
|
||||
dnl Don't define DISABLE_LASTLOG - that means we don't try wtmp/wtmpx
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$conf_lastlog_location"; then
|
||||
AC_DEFINE_UNQUOTED(CONF_LASTLOG_FILE, "$conf_lastlog_location", lastlog file location)
|
||||
fi
|
||||
|
||||
dnl utmp detection
|
||||
AC_MSG_CHECKING([if your system defines UTMP_FILE])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
]],
|
||||
[[ char *utmp = UTMP_FILE; ]])],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_utmp_path=no ]
|
||||
)
|
||||
if test -z "$conf_utmp_location"; then
|
||||
if test x"$system_utmp_path" = x"no" ; then
|
||||
for f in /etc/utmp /usr/adm/utmp /var/run/utmp; do
|
||||
if test -f $f ; then
|
||||
conf_utmp_location=$f
|
||||
fi
|
||||
done
|
||||
if test -z "$conf_utmp_location"; then
|
||||
AC_DEFINE(DISABLE_UTMP)
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test -n "$conf_utmp_location"; then
|
||||
AC_DEFINE_UNQUOTED(CONF_UTMP_FILE, "$conf_utmp_location", utmp file location)
|
||||
fi
|
||||
|
||||
dnl wtmp detection
|
||||
AC_MSG_CHECKING([if your system defines WTMP_FILE])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_UTMP_H
|
||||
# include <utmp.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
]],
|
||||
[[ char *wtmp = WTMP_FILE; ]])],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_wtmp_path=no ]
|
||||
)
|
||||
if test -z "$conf_wtmp_location"; then
|
||||
if test x"$system_wtmp_path" = x"no" ; then
|
||||
for f in /usr/adm/wtmp /var/log/wtmp; do
|
||||
if test -f $f ; then
|
||||
conf_wtmp_location=$f
|
||||
fi
|
||||
done
|
||||
if test -z "$conf_wtmp_location"; then
|
||||
AC_DEFINE(DISABLE_WTMP)
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test -n "$conf_wtmp_location"; then
|
||||
AC_DEFINE_UNQUOTED(CONF_WTMP_FILE, "$conf_wtmp_location", wtmp file location)
|
||||
fi
|
||||
|
||||
|
||||
dnl utmpx detection - I don't know any system so perverse as to require
|
||||
dnl utmpx, but not define UTMPX_FILE (ditto wtmpx.) No doubt it's out
|
||||
dnl there, though.
|
||||
AC_MSG_CHECKING([if your system defines UTMPX_FILE])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_UTMPX_H
|
||||
#include <utmpx.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
]],
|
||||
[[ char *utmpx = UTMPX_FILE; ]])],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_utmpx_path=no ]
|
||||
)
|
||||
if test -z "$conf_utmpx_location"; then
|
||||
if test x"$system_utmpx_path" = x"no" ; then
|
||||
AC_DEFINE(DISABLE_UTMPX)
|
||||
fi
|
||||
else
|
||||
AC_DEFINE_UNQUOTED(CONF_UTMPX_FILE, "$conf_utmpx_location", utmpx file location)
|
||||
fi
|
||||
|
||||
dnl wtmpx detection
|
||||
AC_MSG_CHECKING([if your system defines WTMPX_FILE])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_UTMP_H
|
||||
# include <utmp.h>
|
||||
#endif
|
||||
#ifdef HAVE_UTMPX_H
|
||||
# include <utmpx.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
]],
|
||||
[[ char *wtmpx = WTMPX_FILE; ]])],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_wtmpx_path=no ]
|
||||
)
|
||||
if test -z "$conf_wtmpx_location"; then
|
||||
if test x"$system_wtmpx_path" = x"no" ; then
|
||||
AC_DEFINE(DISABLE_WTMPX)
|
||||
fi
|
||||
else
|
||||
AC_DEFINE_UNQUOTED(CONF_WTMPX_FILE, "$conf_wtmpx_location", wtmpx file location)
|
||||
fi
|
||||
|
||||
# Checks for library functions.
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_FUNC_MEMCMP
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
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))
|
||||
|
||||
# Solaris needs ptmx
|
||||
if test -z "$no_ptmx_check" ; then
|
||||
if test x"$cross_compiling" = x"no" ; then
|
||||
if test -e /dev/ptmx ; then
|
||||
AC_DEFINE(USE_DEV_PTMX,1,Use /dev/ptmx)
|
||||
fi
|
||||
else
|
||||
AC_MSG_NOTICE([Not checking for /dev/ptmx, we're cross-compiling])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$no_ptc_check" ; then
|
||||
if test x"$cross_compiling" = x"no" ; then
|
||||
if test -e /dev/ptc ; then
|
||||
AC_DEFINE(HAVE_DEV_PTS_AND_PTC,1,Use /dev/ptc & /dev/pts)
|
||||
fi
|
||||
else
|
||||
AC_MSG_NOTICE([Not checking for /dev/ptc & /dev/pts since we're cross-compiling])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_EXEEXT
|
||||
|
||||
if test $BUNDLED_LIBTOM = 1 ; then
|
||||
(cd $srcdir; find libtomcrypt -type d) | xargs mkdir -pv
|
||||
LIBTOM_FILES="libtomcrypt/Makefile libtommath/Makefile"
|
||||
fi
|
||||
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_CONFIG_FILES(Makefile $LIBTOM_FILES)
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_NOTICE()
|
||||
if test $BUNDLED_LIBTOM = 1 ; then
|
||||
AC_MSG_NOTICE([Using bundled libtomcrypt and libtommath])
|
||||
else
|
||||
AC_MSG_NOTICE([Using system libtomcrypt and libtommath])
|
||||
fi
|
||||
|
||||
|
||||
if test "x$ac_cv_func_getpass" != xyes; then
|
||||
AC_MSG_NOTICE()
|
||||
AC_MSG_NOTICE([getpass() not available, dbclient will only have public-key authentication])
|
||||
fi
|
||||
|
||||
if test "t$found_crypt_func" != there; then
|
||||
AC_MSG_NOTICE()
|
||||
AC_MSG_NOTICE([crypt() not available, dropbear server will not have password authentication])
|
||||
fi
|
||||
|
||||
AC_MSG_NOTICE()
|
||||
AC_MSG_NOTICE([Now edit localoptions.h to choose features.])
|
||||
577
configure.in
577
configure.in
@@ -1,577 +0,0 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf and autoheader to produce a configure script.
|
||||
|
||||
# This Autoconf file was cobbled from various locations. In particular, a bunch
|
||||
# of the platform checks have been taken straight from OpenSSH's configure.ac
|
||||
# Huge thanks to them for dealing with the horrible platform-specifics :)
|
||||
|
||||
AC_PREREQ(2.50)
|
||||
AC_INIT(buffer.c)
|
||||
|
||||
OLDCFLAGS=$CFLAGS
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_MAKE_SET
|
||||
|
||||
if test -z "$LD" ; then
|
||||
LD=$CC
|
||||
fi
|
||||
AC_SUBST(LD)
|
||||
|
||||
if test -z "$OLDCFLAGS" && test "$GCC" = "yes"; then
|
||||
AC_MSG_RESULT(No \$CFLAGS set... using "-Os -W -Wall for GCC")
|
||||
CFLAGS="-Os -W -Wall"
|
||||
fi
|
||||
|
||||
# Host specific options
|
||||
# this isn't a definitive list of hosts, they are just added as required
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
case "$host" in
|
||||
|
||||
*-*-linux*)
|
||||
no_ptmx_check=1
|
||||
;;
|
||||
|
||||
*-*-solaris*)
|
||||
CFLAGS="$CFLAGS -I/usr/local/include"
|
||||
LDFLAGS="$LDFLAGS -L/usr/local/lib -R/usr/local/lib"
|
||||
conf_lastlog_location="/var/adm/lastlog"
|
||||
AC_MSG_CHECKING(for obsolete utmp and wtmp in solaris2.x)
|
||||
sol2ver=`echo "$host"| sed -e 's/.*[[0-9]]\.//'`
|
||||
if test "$sol2ver" -ge 8; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(DISABLE_UTMP,,Disable utmp)
|
||||
AC_DEFINE(DISABLE_WTMP,,Disable wtmp)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket")
|
||||
AC_CHECK_LIB(nsl, yp_match, LIBS="$LIBS -lnsl")
|
||||
;;
|
||||
|
||||
*-*-aix*)
|
||||
AC_DEFINE(AIX,,Using AIX)
|
||||
# OpenSSH thinks it's broken. If it isn't, let me know.
|
||||
AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
|
||||
;;
|
||||
|
||||
*-*-hpux*)
|
||||
LIBS="$LIBS -lsec"
|
||||
# It's probably broken.
|
||||
AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
|
||||
;;
|
||||
*-dec-osf*)
|
||||
AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_CHECK_TOOL(AR, ar, :)
|
||||
AC_CHECK_TOOL(RANLIB, ranlib, :)
|
||||
AC_CHECK_TOOL(STRIP, strip, :)
|
||||
AC_CHECK_TOOL(INSTALL, install, :)
|
||||
|
||||
dnl Can't use login() or logout() with uclibc
|
||||
AC_CHECK_DECL(__UCLIBC__,
|
||||
[
|
||||
no_loginfunc_check=1
|
||||
AC_MSG_RESULT(Using uClibc - login() and logout() probably don't work, so we won't use them.)
|
||||
],,,)
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB(crypt, crypt, LIBS="$LIBS -lcrypt")
|
||||
|
||||
# Check if zlib is needed
|
||||
AC_ARG_WITH(zlib,
|
||||
[ --with-zlib=PATH Use zlib in PATH],
|
||||
[
|
||||
# option is given
|
||||
if test -d "$withval/lib"; then
|
||||
LDFLAGS="-L${withval}/lib ${LDFLAGS}"
|
||||
else
|
||||
LDFLAGS="-L${withval} ${LDFLAGS}"
|
||||
fi
|
||||
if test -d "$withval/include"; then
|
||||
CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
|
||||
else
|
||||
CPPFLAGS="-I${withval} ${CPPFLAGS}"
|
||||
fi
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(zlib,
|
||||
[ --disable-zlib Don't include zlib support],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
AC_DEFINE(DISABLE_ZLIB,, Use zlib)
|
||||
AC_MSG_RESULT(Disabling zlib)
|
||||
else
|
||||
AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***]))
|
||||
AC_MSG_RESULT(Enabling zlib)
|
||||
fi
|
||||
],
|
||||
[
|
||||
# if not disabled, check for zlib
|
||||
AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***]))
|
||||
AC_MSG_RESULT(Enabling zlib)
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(openpty,
|
||||
[ --disable-openpty Don't use openpty, use alternative method],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
AC_MSG_RESULT(Not using openpty)
|
||||
else
|
||||
AC_MSG_RESULT(Using openpty if available)
|
||||
AC_SEARCH_LIBS(openpty, util, [AC_DEFINE(HAVE_OPENPTY,,Have openpty() function)])
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(Using openpty if available)
|
||||
AC_SEARCH_LIBS(openpty, util, [AC_DEFINE(HAVE_OPENPTY)])
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
AC_ARG_ENABLE(syslog,
|
||||
[ --disable-syslog Don't include syslog support],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
AC_DEFINE(DISABLE_SYSLOG,, Using syslog)
|
||||
AC_MSG_RESULT(Disabling syslog)
|
||||
else
|
||||
AC_MSG_RESULT(Enabling syslog)
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(Enabling syslog)
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(shadow,
|
||||
[ --disable-shadow Don't use shadow passwords (if available)],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
AC_MSG_RESULT(Not using shadow passwords)
|
||||
else
|
||||
AC_CHECK_HEADERS([shadow.h])
|
||||
AC_MSG_RESULT(Using shadow passwords if available)
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_CHECK_HEADERS([shadow.h])
|
||||
AC_MSG_RESULT(Using shadow passwords if available)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
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])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_TYPE_UID_T
|
||||
AC_TYPE_MODE_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_HEADER_TIME
|
||||
|
||||
AC_CHECK_TYPES([uint16_t, u_int16_t, struct sockaddr_storage])
|
||||
AC_CHECK_TYPE([socklen_t], ,[
|
||||
AC_MSG_CHECKING([for socklen_t equivalent])
|
||||
AC_CACHE_VAL([curl_cv_socklen_t_equiv],
|
||||
[
|
||||
# Systems have either "struct sockaddr *" or
|
||||
# "void *" as the second argument to getpeername
|
||||
curl_cv_socklen_t_equiv=
|
||||
for arg2 in "struct sockaddr" void; do
|
||||
for t in int size_t unsigned long "unsigned long"; do
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
int getpeername (int, $arg2 *, $t *);
|
||||
],[
|
||||
$t len;
|
||||
getpeername(0,0,&len);
|
||||
],[
|
||||
curl_cv_socklen_t_equiv="$t"
|
||||
break
|
||||
])
|
||||
done
|
||||
done
|
||||
|
||||
if test "x$curl_cv_socklen_t_equiv" = x; then
|
||||
AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
|
||||
fi
|
||||
])
|
||||
AC_MSG_RESULT($curl_cv_socklen_t_equiv)
|
||||
AC_DEFINE_UNQUOTED(socklen_t, $curl_cv_socklen_t_equiv,
|
||||
[type to use in place of socklen_t if not defined])],
|
||||
[#include <sys/types.h>
|
||||
#include <sys/socket.h>])
|
||||
|
||||
# for the fake-rfc2553 stuff - straight from OpenSSH
|
||||
|
||||
AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage, [
|
||||
AC_TRY_COMPILE(
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
],
|
||||
[ struct sockaddr_storage s; ],
|
||||
[ ac_cv_have_struct_sockaddr_storage="yes" ],
|
||||
[ ac_cv_have_struct_sockaddr_storage="no" ]
|
||||
)
|
||||
])
|
||||
if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then
|
||||
AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
|
||||
AC_TRY_COMPILE(
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
],
|
||||
[ struct sockaddr_in6 s; s.sin6_family = 0; ],
|
||||
[ ac_cv_have_struct_sockaddr_in6="yes" ],
|
||||
[ ac_cv_have_struct_sockaddr_in6="no" ]
|
||||
)
|
||||
])
|
||||
if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then
|
||||
AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6,,Have struct sockaddr_in6)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
|
||||
AC_TRY_COMPILE(
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
],
|
||||
[ struct in6_addr s; s.s6_addr[0] = 0; ],
|
||||
[ ac_cv_have_struct_in6_addr="yes" ],
|
||||
[ ac_cv_have_struct_in6_addr="no" ]
|
||||
)
|
||||
])
|
||||
if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
|
||||
AC_DEFINE(HAVE_STRUCT_IN6_ADDR,,Have struct in6_addr)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
|
||||
AC_TRY_COMPILE(
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
],
|
||||
[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ],
|
||||
[ ac_cv_have_struct_addrinfo="yes" ],
|
||||
[ ac_cv_have_struct_addrinfo="no" ]
|
||||
)
|
||||
])
|
||||
if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then
|
||||
AC_DEFINE(HAVE_STRUCT_ADDRINFO,,Have struct addrinfo)
|
||||
fi
|
||||
|
||||
|
||||
# IRIX has a const char return value for gai_strerror()
|
||||
AC_CHECK_FUNCS(gai_strerror,[
|
||||
AC_DEFINE(HAVE_GAI_STRERROR)
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
const char *gai_strerror(int);],[
|
||||
char *str;
|
||||
|
||||
str = gai_strerror(0);],[
|
||||
AC_DEFINE(HAVE_CONST_GAI_STRERROR_PROTO, 1,
|
||||
[Define if gai_strerror() returns const char *])])])
|
||||
|
||||
# for loginrec.c
|
||||
|
||||
AC_CHECK_MEMBERS([struct utmp.ut_host, struct utmp.ut_pid, struct utmp.ut_type, struct utmp.ut_tv, struct utmp.ut_id, struct utmp.ut_addr, struct utmp.ut_addr_v6, struct utmp.ut_exit, struct utmp.ut_time],,,[
|
||||
#include <sys/types.h>
|
||||
#if HAVE_UTMP_H
|
||||
#include <utmp.h>
|
||||
#endif
|
||||
])
|
||||
|
||||
AC_CHECK_MEMBERS([struct utmpx.ut_host, struct utmpx.ut_syslen, struct utmpx.ut_type, struct utmpx.ut_id, struct utmpx.ut_addr, struct utmpx.ut_addr_v6, struct utmpx.ut_time, struct utmpx.ut_tv],,,[
|
||||
#include <sys/types.h>
|
||||
#if HAVE_UTMPX_H
|
||||
#include <utmpx.h>
|
||||
#endif
|
||||
])
|
||||
|
||||
AC_CHECK_FUNCS(endutent getutent getutid getutline pututline setutent)
|
||||
AC_CHECK_FUNCS(utmpname)
|
||||
AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
|
||||
AC_CHECK_FUNCS(setutxent utmpxname)
|
||||
AC_CHECK_FUNCS(logout updwtmp logwtmp)
|
||||
|
||||
dnl Added from OpenSSH 3.6.1p2's configure.ac
|
||||
|
||||
dnl allow user to disable some login recording features
|
||||
AC_ARG_ENABLE(lastlog,
|
||||
[ --disable-lastlog Disable use of lastlog even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_LASTLOG,,Disable use of lastlog()) ]
|
||||
)
|
||||
AC_ARG_ENABLE(utmp,
|
||||
[ --disable-utmp Disable use of utmp even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_UTMP,,Disable use of utmp) ]
|
||||
)
|
||||
AC_ARG_ENABLE(utmpx,
|
||||
[ --disable-utmpx Disable use of utmpx even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_UTMPX,,Disable use of utmpx) ]
|
||||
)
|
||||
AC_ARG_ENABLE(wtmp,
|
||||
[ --disable-wtmp Disable use of wtmp even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_WTMP,,Disable use of wtmp) ]
|
||||
)
|
||||
AC_ARG_ENABLE(wtmpx,
|
||||
[ --disable-wtmpx Disable use of wtmpx even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_WTMPX,,Disable use of wtmpx) ]
|
||||
)
|
||||
AC_ARG_ENABLE(loginfunc,
|
||||
[ --disable-loginfunc Disable use of login() etc. [no]],
|
||||
[ no_loginfunc_check=1
|
||||
AC_MSG_RESULT(Not using login() etc) ]
|
||||
)
|
||||
AC_ARG_ENABLE(pututline,
|
||||
[ --disable-pututline Disable use of pututline() etc. ([uw]tmp) [no]],
|
||||
[ AC_DEFINE(DISABLE_PUTUTLINE,,Disable use of pututline()) ]
|
||||
)
|
||||
AC_ARG_ENABLE(pututxline,
|
||||
[ --disable-pututxline Disable use of pututxline() etc. ([uw]tmpx) [no]],
|
||||
[ AC_DEFINE(DISABLE_PUTUTXLINE,,Disable use of pututxline()) ]
|
||||
)
|
||||
AC_ARG_WITH(lastlog,
|
||||
[ --with-lastlog=FILE|DIR specify lastlog location [common locations]],
|
||||
[
|
||||
if test "x$withval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_LASTLOG)
|
||||
else
|
||||
conf_lastlog_location=$withval
|
||||
fi
|
||||
]
|
||||
)
|
||||
|
||||
if test -z "$no_loginfunc_check"; then
|
||||
dnl Checks for libutil functions (login(), logout() etc, not openpty() )
|
||||
AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN,,Have login() function)])
|
||||
AC_CHECK_FUNCS(logout updwtmp logwtmp)
|
||||
fi
|
||||
|
||||
dnl lastlog, [uw]tmpx? detection
|
||||
dnl NOTE: set the paths in the platform section to avoid the
|
||||
dnl need for command-line parameters
|
||||
dnl lastlog and [uw]tmp are subject to a file search if all else fails
|
||||
|
||||
dnl lastlog detection
|
||||
dnl NOTE: the code itself will detect if lastlog is a directory
|
||||
AC_MSG_CHECKING([if your system defines LASTLOG_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_LASTLOG_H
|
||||
# include <lastlog.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
#ifdef HAVE_LOGIN_H
|
||||
# include <login.h>
|
||||
#endif
|
||||
],
|
||||
[ char *lastlog = LASTLOG_FILE; ],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_CHECKING([if your system defines _PATH_LASTLOG])
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_LASTLOG_H
|
||||
# include <lastlog.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *lastlog = _PATH_LASTLOG; ],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
system_lastlog_path=no
|
||||
])
|
||||
]
|
||||
)
|
||||
|
||||
if test -z "$conf_lastlog_location"; then
|
||||
if test x"$system_lastlog_path" = x"no" ; then
|
||||
for f in /var/log/lastlog /usr/adm/lastlog /var/adm/lastlog /etc/security/lastlog ; do
|
||||
if (test -d "$f" || test -f "$f") ; then
|
||||
conf_lastlog_location=$f
|
||||
fi
|
||||
done
|
||||
if test -z "$conf_lastlog_location"; then
|
||||
AC_MSG_WARN([** Cannot find lastlog **])
|
||||
dnl Don't define DISABLE_LASTLOG - that means we don't try wtmp/wtmpx
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$conf_lastlog_location"; then
|
||||
AC_DEFINE_UNQUOTED(CONF_LASTLOG_FILE, "$conf_lastlog_location", lastlog file location)
|
||||
fi
|
||||
|
||||
dnl utmp detection
|
||||
AC_MSG_CHECKING([if your system defines UTMP_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *utmp = UTMP_FILE; ],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_utmp_path=no ]
|
||||
)
|
||||
if test -z "$conf_utmp_location"; then
|
||||
if test x"$system_utmp_path" = x"no" ; then
|
||||
for f in /etc/utmp /usr/adm/utmp /var/run/utmp; do
|
||||
if test -f $f ; then
|
||||
conf_utmp_location=$f
|
||||
fi
|
||||
done
|
||||
if test -z "$conf_utmp_location"; then
|
||||
AC_DEFINE(DISABLE_UTMP)
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test -n "$conf_utmp_location"; then
|
||||
AC_DEFINE_UNQUOTED(CONF_UTMP_FILE, "$conf_utmp_location", utmp file location)
|
||||
fi
|
||||
|
||||
dnl wtmp detection
|
||||
AC_MSG_CHECKING([if your system defines WTMP_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *wtmp = WTMP_FILE; ],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_wtmp_path=no ]
|
||||
)
|
||||
if test -z "$conf_wtmp_location"; then
|
||||
if test x"$system_wtmp_path" = x"no" ; then
|
||||
for f in /usr/adm/wtmp /var/log/wtmp; do
|
||||
if test -f $f ; then
|
||||
conf_wtmp_location=$f
|
||||
fi
|
||||
done
|
||||
if test -z "$conf_wtmp_location"; then
|
||||
AC_DEFINE(DISABLE_WTMP)
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test -n "$conf_wtmp_location"; then
|
||||
AC_DEFINE_UNQUOTED(CONF_WTMP_FILE, "$conf_wtmp_location", wtmp file location)
|
||||
fi
|
||||
|
||||
|
||||
dnl utmpx detection - I don't know any system so perverse as to require
|
||||
dnl utmpx, but not define UTMPX_FILE (ditto wtmpx.) No doubt it's out
|
||||
dnl there, though.
|
||||
AC_MSG_CHECKING([if your system defines UTMPX_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_UTMPX_H
|
||||
#include <utmpx.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *utmpx = UTMPX_FILE; ],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_utmpx_path=no ]
|
||||
)
|
||||
if test -z "$conf_utmpx_location"; then
|
||||
if test x"$system_utmpx_path" = x"no" ; then
|
||||
AC_DEFINE(DISABLE_UTMPX)
|
||||
fi
|
||||
else
|
||||
AC_DEFINE_UNQUOTED(CONF_UTMPX_FILE, "$conf_utmpx_location", utmpx file location)
|
||||
fi
|
||||
|
||||
dnl wtmpx detection
|
||||
AC_MSG_CHECKING([if your system defines WTMPX_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_UTMPX_H
|
||||
#include <utmpx.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *wtmpx = WTMPX_FILE; ],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_wtmpx_path=no ]
|
||||
)
|
||||
if test -z "$conf_wtmpx_location"; then
|
||||
if test x"$system_wtmpx_path" = x"no" ; then
|
||||
AC_DEFINE(DISABLE_WTMPX)
|
||||
fi
|
||||
else
|
||||
AC_DEFINE_UNQUOTED(CONF_WTMPX_FILE, "$conf_wtmpx_location", wtmpx file location)
|
||||
fi
|
||||
|
||||
# Checks for library functions.
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_FUNC_MEMCMP
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
AC_TYPE_SIGNAL
|
||||
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo])
|
||||
|
||||
AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
|
||||
|
||||
# Solaris needs ptmx
|
||||
if test -z "$no_ptmx_check" ; then
|
||||
if test x"$cross_compiling" = x"no" ; then
|
||||
AC_CHECK_FILE("/dev/ptmx", AC_DEFINE(USE_DEV_PTMX,,Use /dev/ptmx))
|
||||
else
|
||||
AC_MSG_RESULT(Not checking for /dev/ptmx, we're cross-compiling)
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$no_ptc_check" ; then
|
||||
if test x"$cross_compiling" = x"no" ; then
|
||||
AC_CHECK_FILE("/dev/ptc", AC_DEFINE(HAVE_DEV_PTS_AND_PTC,,Use /dev/ptc & /dev/pts))
|
||||
else
|
||||
AC_MSG_RESULT(Not checking for /dev/ptc & /dev/pts\, we're cross-compiling)
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_EXEEXT
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_OUTPUT(Makefile)
|
||||
AC_MSG_RESULT()
|
||||
AC_MSG_RESULT(Now edit options.h to choose features.)
|
||||
75
crypto_desc.c
Normal file
75
crypto_desc.c
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "ltc_prng.h"
|
||||
#include "ecc.h"
|
||||
|
||||
#if DROPBEAR_LTC_PRNG
|
||||
int dropbear_ltc_prng = -1;
|
||||
#endif
|
||||
|
||||
|
||||
/* Register the compiled in ciphers.
|
||||
* This should be run before using any of the ciphers/hashes */
|
||||
void crypto_init() {
|
||||
|
||||
const struct ltc_cipher_descriptor *regciphers[] = {
|
||||
#if DROPBEAR_AES
|
||||
&aes_desc,
|
||||
#endif
|
||||
#if DROPBEAR_BLOWFISH
|
||||
&blowfish_desc,
|
||||
#endif
|
||||
#if DROPBEAR_TWOFISH
|
||||
&twofish_desc,
|
||||
#endif
|
||||
#if DROPBEAR_3DES
|
||||
&des3_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct ltc_hash_descriptor *reghashes[] = {
|
||||
/* we need sha1 for hostkey stuff regardless */
|
||||
&sha1_desc,
|
||||
#if DROPBEAR_MD5_HMAC
|
||||
&md5_desc,
|
||||
#endif
|
||||
#if DROPBEAR_SHA256
|
||||
&sha256_desc,
|
||||
#endif
|
||||
#if DROPBEAR_SHA384
|
||||
&sha384_desc,
|
||||
#endif
|
||||
#if DROPBEAR_SHA512
|
||||
&sha512_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; regciphers[i] != NULL; i++) {
|
||||
if (register_cipher(regciphers[i]) == -1) {
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; reghashes[i] != NULL; i++) {
|
||||
if (register_hash(reghashes[i]) == -1) {
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
}
|
||||
|
||||
#if DROPBEAR_LTC_PRNG
|
||||
dropbear_ltc_prng = register_prng(&dropbear_prng_desc);
|
||||
if (dropbear_ltc_prng == -1) {
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_ECC
|
||||
ltc_mp = ltm_desc;
|
||||
dropbear_ecc_fill_dp();
|
||||
#endif
|
||||
}
|
||||
|
||||
9
crypto_desc.h
Normal file
9
crypto_desc.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef DROPBEAR_CRYPTO_DESC_H
|
||||
#define DROPBEAR_CRYPTO_DESC_H
|
||||
|
||||
void crypto_init(void);
|
||||
|
||||
extern int dropbear_ltc_prng;
|
||||
|
||||
#endif /* DROPBEAR_CRYPTO_DESC_H */
|
||||
|
||||
497
curve25519.c
Normal file
497
curve25519.c
Normal file
@@ -0,0 +1,497 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbrandom.h"
|
||||
#include "curve25519.h"
|
||||
|
||||
#if DROPBEAR_CURVE25519 || DROPBEAR_ED25519
|
||||
|
||||
/* Modified TweetNaCl version 20140427, a self-contained public-domain C library.
|
||||
* https://tweetnacl.cr.yp.to/ */
|
||||
|
||||
#define FOR(i,n) for (i = 0;i < n;++i)
|
||||
#define sv static void
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned long u32;
|
||||
typedef unsigned long long u64;
|
||||
typedef long long i64;
|
||||
typedef i64 gf[16];
|
||||
|
||||
#if DROPBEAR_CURVE25519
|
||||
static const gf
|
||||
_121665 = {0xDB41,1};
|
||||
#endif /* DROPBEAR_CURVE25519 */
|
||||
#if DROPBEAR_ED25519
|
||||
static const gf
|
||||
gf0,
|
||||
gf1 = {1},
|
||||
D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406},
|
||||
X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169},
|
||||
Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666};
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static const gf
|
||||
D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203},
|
||||
I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83};
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static int vn(const u8 *x,const u8 *y,u32 n)
|
||||
{
|
||||
u32 i,d = 0;
|
||||
FOR(i,n) d |= x[i]^y[i];
|
||||
return (1 & ((d - 1) >> 8)) - 1;
|
||||
}
|
||||
|
||||
static int crypto_verify_32(const u8 *x,const u8 *y)
|
||||
{
|
||||
return vn(x,y,32);
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
sv set25519(gf r, const gf a)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) r[i]=a[i];
|
||||
}
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
sv car25519(gf o)
|
||||
{
|
||||
int i;
|
||||
i64 c;
|
||||
FOR(i,16) {
|
||||
o[i]+=(1LL<<16);
|
||||
c=o[i]>>16;
|
||||
o[(i+1)*(i<15)]+=c-1+37*(c-1)*(i==15);
|
||||
o[i]-=c<<16;
|
||||
}
|
||||
}
|
||||
|
||||
sv sel25519(gf p,gf q,int b)
|
||||
{
|
||||
i64 t,i,c=~(b-1);
|
||||
FOR(i,16) {
|
||||
t= c&(p[i]^q[i]);
|
||||
p[i]^=t;
|
||||
q[i]^=t;
|
||||
}
|
||||
}
|
||||
|
||||
sv pack25519(u8 *o,const gf n)
|
||||
{
|
||||
int i,j,b;
|
||||
gf m,t;
|
||||
FOR(i,16) t[i]=n[i];
|
||||
car25519(t);
|
||||
car25519(t);
|
||||
car25519(t);
|
||||
FOR(j,2) {
|
||||
m[0]=t[0]-0xffed;
|
||||
for(i=1;i<15;i++) {
|
||||
m[i]=t[i]-0xffff-((m[i-1]>>16)&1);
|
||||
m[i-1]&=0xffff;
|
||||
}
|
||||
m[15]=t[15]-0x7fff-((m[14]>>16)&1);
|
||||
b=(m[15]>>16)&1;
|
||||
m[14]&=0xffff;
|
||||
sel25519(t,m,1-b);
|
||||
}
|
||||
FOR(i,16) {
|
||||
o[2*i]=t[i]&0xff;
|
||||
o[2*i+1]=t[i]>>8;
|
||||
}
|
||||
}
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static int neq25519(const gf a, const gf b)
|
||||
{
|
||||
u8 c[32],d[32];
|
||||
pack25519(c,a);
|
||||
pack25519(d,b);
|
||||
return crypto_verify_32(c,d);
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
static u8 par25519(const gf a)
|
||||
{
|
||||
u8 d[32];
|
||||
pack25519(d,a);
|
||||
return d[0]&1;
|
||||
}
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
sv unpack25519(gf o, const u8 *n)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) o[i]=n[2*i]+((i64)n[2*i+1]<<8);
|
||||
o[15]&=0x7fff;
|
||||
}
|
||||
|
||||
sv A(gf o,const gf a,const gf b)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) o[i]=a[i]+b[i];
|
||||
}
|
||||
|
||||
sv Z(gf o,const gf a,const gf b)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) o[i]=a[i]-b[i];
|
||||
}
|
||||
|
||||
sv M(gf o,const gf a,const gf b)
|
||||
{
|
||||
i64 i,j,t[31];
|
||||
FOR(i,31) t[i]=0;
|
||||
FOR(i,16) FOR(j,16) t[i+j]+=a[i]*b[j];
|
||||
FOR(i,15) t[i]+=38*t[i+16];
|
||||
FOR(i,16) o[i]=t[i];
|
||||
car25519(o);
|
||||
car25519(o);
|
||||
}
|
||||
|
||||
sv S(gf o,const gf a)
|
||||
{
|
||||
M(o,a,a);
|
||||
}
|
||||
|
||||
sv inv25519(gf o,const gf i)
|
||||
{
|
||||
gf c;
|
||||
int a;
|
||||
FOR(a,16) c[a]=i[a];
|
||||
for(a=253;a>=0;a--) {
|
||||
S(c,c);
|
||||
if(a!=2&&a!=4) M(c,c,i);
|
||||
}
|
||||
FOR(a,16) o[a]=c[a];
|
||||
}
|
||||
|
||||
#if DROPBEAR_ED25519 && DROPBEAR_SIGNKEY_VERIFY
|
||||
sv pow2523(gf o,const gf i)
|
||||
{
|
||||
gf c;
|
||||
int a;
|
||||
FOR(a,16) c[a]=i[a];
|
||||
for(a=250;a>=0;a--) {
|
||||
S(c,c);
|
||||
if(a!=1) M(c,c,i);
|
||||
}
|
||||
FOR(a,16) o[a]=c[a];
|
||||
}
|
||||
#endif /* DROPBEAR_ED25519 && DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
#if DROPBEAR_CURVE25519
|
||||
void dropbear_curve25519_scalarmult(u8 *q,const u8 *n,const u8 *p)
|
||||
{
|
||||
u8 z[32];
|
||||
i64 x[80],r,i;
|
||||
gf a,b,c,d,e,f;
|
||||
FOR(i,31) z[i]=n[i];
|
||||
z[31]=(n[31]&127)|64;
|
||||
z[0]&=248;
|
||||
unpack25519(x,p);
|
||||
FOR(i,16) {
|
||||
b[i]=x[i];
|
||||
d[i]=a[i]=c[i]=0;
|
||||
}
|
||||
a[0]=d[0]=1;
|
||||
for(i=254;i>=0;--i) {
|
||||
r=(z[i>>3]>>(i&7))&1;
|
||||
sel25519(a,b,r);
|
||||
sel25519(c,d,r);
|
||||
A(e,a,c);
|
||||
Z(a,a,c);
|
||||
A(c,b,d);
|
||||
Z(b,b,d);
|
||||
S(d,e);
|
||||
S(f,a);
|
||||
M(a,c,a);
|
||||
M(c,b,e);
|
||||
A(e,a,c);
|
||||
Z(a,a,c);
|
||||
S(b,a);
|
||||
Z(c,d,f);
|
||||
M(a,c,_121665);
|
||||
A(a,a,d);
|
||||
M(c,c,a);
|
||||
M(a,d,f);
|
||||
M(d,b,x);
|
||||
S(b,e);
|
||||
sel25519(a,b,r);
|
||||
sel25519(c,d,r);
|
||||
}
|
||||
FOR(i,16) {
|
||||
x[i+16]=a[i];
|
||||
x[i+32]=c[i];
|
||||
x[i+48]=b[i];
|
||||
x[i+64]=d[i];
|
||||
}
|
||||
inv25519(x+32,x+32);
|
||||
M(x+16,x+16,x+32);
|
||||
pack25519(q,x+16);
|
||||
}
|
||||
#endif /* DROPBEAR_CURVE25519 */
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
static int crypto_hash(u8 *out,const u8 *m,u64 n)
|
||||
{
|
||||
hash_state hs;
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs, m, n);
|
||||
return sha512_done(&hs, out);
|
||||
}
|
||||
|
||||
sv add(gf p[4],gf q[4])
|
||||
{
|
||||
gf a,b,c,d,t,e,f,g,h;
|
||||
|
||||
Z(a, p[1], p[0]);
|
||||
Z(t, q[1], q[0]);
|
||||
M(a, a, t);
|
||||
A(b, p[0], p[1]);
|
||||
A(t, q[0], q[1]);
|
||||
M(b, b, t);
|
||||
M(c, p[3], q[3]);
|
||||
M(c, c, D2);
|
||||
M(d, p[2], q[2]);
|
||||
A(d, d, d);
|
||||
Z(e, b, a);
|
||||
Z(f, d, c);
|
||||
A(g, d, c);
|
||||
A(h, b, a);
|
||||
|
||||
M(p[0], e, f);
|
||||
M(p[1], h, g);
|
||||
M(p[2], g, f);
|
||||
M(p[3], e, h);
|
||||
}
|
||||
|
||||
sv cswap(gf p[4],gf q[4],u8 b)
|
||||
{
|
||||
int i;
|
||||
FOR(i,4)
|
||||
sel25519(p[i],q[i],b);
|
||||
}
|
||||
|
||||
sv pack(u8 *r,gf p[4])
|
||||
{
|
||||
gf tx, ty, zi;
|
||||
inv25519(zi, p[2]);
|
||||
M(tx, p[0], zi);
|
||||
M(ty, p[1], zi);
|
||||
pack25519(r, ty);
|
||||
r[31] ^= par25519(tx) << 7;
|
||||
}
|
||||
|
||||
sv scalarmult(gf p[4],gf q[4],const u8 *s)
|
||||
{
|
||||
int i;
|
||||
set25519(p[0],gf0);
|
||||
set25519(p[1],gf1);
|
||||
set25519(p[2],gf1);
|
||||
set25519(p[3],gf0);
|
||||
for (i = 255;i >= 0;--i) {
|
||||
u8 b = (s[i/8]>>(i&7))&1;
|
||||
cswap(p,q,b);
|
||||
add(q,p);
|
||||
add(p,p);
|
||||
cswap(p,q,b);
|
||||
}
|
||||
}
|
||||
|
||||
sv scalarbase(gf p[4],const u8 *s)
|
||||
{
|
||||
gf q[4];
|
||||
set25519(q[0],X);
|
||||
set25519(q[1],Y);
|
||||
set25519(q[2],gf1);
|
||||
M(q[3],X,Y);
|
||||
scalarmult(p,q,s);
|
||||
}
|
||||
|
||||
void dropbear_ed25519_make_key(u8 *pk,u8 *sk)
|
||||
{
|
||||
u8 d[64];
|
||||
gf p[4];
|
||||
|
||||
genrandom(sk, 32);
|
||||
|
||||
crypto_hash(d, sk, 32);
|
||||
d[0] &= 248;
|
||||
d[31] &= 127;
|
||||
d[31] |= 64;
|
||||
|
||||
scalarbase(p,d);
|
||||
pack(pk,p);
|
||||
}
|
||||
|
||||
static const u64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10};
|
||||
|
||||
sv modL(u8 *r,i64 x[64])
|
||||
{
|
||||
i64 carry,i,j;
|
||||
for (i = 63;i >= 32;--i) {
|
||||
carry = 0;
|
||||
for (j = i - 32;j < i - 12;++j) {
|
||||
x[j] += carry - 16 * x[i] * L[j - (i - 32)];
|
||||
carry = (x[j] + 128) >> 8;
|
||||
x[j] -= carry << 8;
|
||||
}
|
||||
x[j] += carry;
|
||||
x[i] = 0;
|
||||
}
|
||||
carry = 0;
|
||||
FOR(j,32) {
|
||||
x[j] += carry - (x[31] >> 4) * L[j];
|
||||
carry = x[j] >> 8;
|
||||
x[j] &= 255;
|
||||
}
|
||||
FOR(j,32) x[j] -= carry * L[j];
|
||||
FOR(i,32) {
|
||||
x[i+1] += x[i] >> 8;
|
||||
r[i] = x[i] & 255;
|
||||
}
|
||||
}
|
||||
|
||||
sv reduce(u8 *r)
|
||||
{
|
||||
i64 x[64],i;
|
||||
FOR(i,64) x[i] = (u64) r[i];
|
||||
FOR(i,64) r[i] = 0;
|
||||
modL(r,x);
|
||||
}
|
||||
|
||||
void dropbear_ed25519_sign(const u8 *m,u32 mlen,u8 *s,u32 *slen,const u8 *sk, const u8 *pk)
|
||||
{
|
||||
hash_state hs;
|
||||
u8 d[64],h[64],r[64];
|
||||
i64 x[64];
|
||||
gf p[4];
|
||||
u32 i,j;
|
||||
|
||||
crypto_hash(d, sk, 32);
|
||||
d[0] &= 248;
|
||||
d[31] &= 127;
|
||||
d[31] |= 64;
|
||||
|
||||
*slen = 64;
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs,d + 32,32);
|
||||
sha512_process(&hs,m,mlen);
|
||||
sha512_done(&hs,r);
|
||||
reduce(r);
|
||||
scalarbase(p,r);
|
||||
pack(s,p);
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs,s,32);
|
||||
sha512_process(&hs,pk,32);
|
||||
sha512_process(&hs,m,mlen);
|
||||
sha512_done(&hs,h);
|
||||
reduce(h);
|
||||
|
||||
FOR(i,64) x[i] = 0;
|
||||
FOR(i,32) x[i] = (u64) r[i];
|
||||
FOR(i,32) FOR(j,32) x[i+j] += h[i] * (u64) d[j];
|
||||
modL(s + 32,x);
|
||||
}
|
||||
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static int unpackneg(gf r[4],const u8 p[32])
|
||||
{
|
||||
gf t, chk, num, den, den2, den4, den6;
|
||||
set25519(r[2],gf1);
|
||||
unpack25519(r[1],p);
|
||||
S(num,r[1]);
|
||||
M(den,num,D);
|
||||
Z(num,num,r[2]);
|
||||
A(den,r[2],den);
|
||||
|
||||
S(den2,den);
|
||||
S(den4,den2);
|
||||
M(den6,den4,den2);
|
||||
M(t,den6,num);
|
||||
M(t,t,den);
|
||||
|
||||
pow2523(t,t);
|
||||
M(t,t,num);
|
||||
M(t,t,den);
|
||||
M(t,t,den);
|
||||
M(r[0],t,den);
|
||||
|
||||
S(chk,r[0]);
|
||||
M(chk,chk,den);
|
||||
if (neq25519(chk, num)) M(r[0],r[0],I);
|
||||
|
||||
S(chk,r[0]);
|
||||
M(chk,chk,den);
|
||||
if (neq25519(chk, num)) return -1;
|
||||
|
||||
if (par25519(r[0]) == (p[31]>>7)) Z(r[0],gf0,r[0]);
|
||||
|
||||
M(r[3],r[0],r[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dropbear_ed25519_verify(const u8 *m,u32 mlen,const u8 *s,u32 slen,const u8 *pk)
|
||||
{
|
||||
hash_state hs;
|
||||
u8 t[32],h[64];
|
||||
gf p[4],q[4];
|
||||
|
||||
if (slen < 64) return -1;
|
||||
|
||||
if (unpackneg(q,pk)) return -1;
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs,s,32);
|
||||
sha512_process(&hs,pk,32);
|
||||
sha512_process(&hs,m,mlen);
|
||||
sha512_done(&hs,h);
|
||||
|
||||
reduce(h);
|
||||
scalarmult(p,q,h);
|
||||
|
||||
scalarbase(q,s + 32);
|
||||
add(p,q);
|
||||
pack(t,p);
|
||||
|
||||
if (crypto_verify_32(s, t))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
#endif /* DROPBEAR_CURVE25519 || DROPBEAR_ED25519 */
|
||||
37
curve25519.h
Normal file
37
curve25519.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef DROPBEAR_CURVE25519_H
|
||||
#define DROPBEAR_CURVE25519_H
|
||||
|
||||
void dropbear_curve25519_scalarmult(unsigned char *q, const unsigned char *n, const unsigned char *p);
|
||||
void dropbear_ed25519_make_key(unsigned char *pk, unsigned char *sk);
|
||||
void dropbear_ed25519_sign(const unsigned char *m, unsigned long mlen,
|
||||
unsigned char *s, unsigned long *slen,
|
||||
const unsigned char *sk, const unsigned char *pk);
|
||||
int dropbear_ed25519_verify(const unsigned char *m, unsigned long mlen,
|
||||
const unsigned char *s, unsigned long slen,
|
||||
const unsigned char *pk);
|
||||
|
||||
#endif /* DROPBEAR_CURVE25519_H */
|
||||
214
dbclient.1
Normal file
214
dbclient.1
Normal file
@@ -0,0 +1,214 @@
|
||||
.TH dbclient 1
|
||||
.SH NAME
|
||||
dbclient \- lightweight SSH client
|
||||
.SH SYNOPSIS
|
||||
.B dbclient
|
||||
[\fIflag arguments\fR] [\-p
|
||||
.I port\fR] [\-i
|
||||
.I id\fR] [\-L
|
||||
.I l\fR:\fIh\fR:\fIp\fR] [\-R
|
||||
.I l\fR:\fIh\fR:\fIp\fR] [\-l
|
||||
.IR user ]
|
||||
.I host
|
||||
.RI [ \fImore\ flags\fR ]
|
||||
.RI [ command ]
|
||||
|
||||
.B dbclient
|
||||
[\fIargs\fR]
|
||||
[\fIuser1\fR]@\fIhost1\fR[^\fIport1\fR],[\fIuser2\fR]@\fIhost2\fR[^\fIport2\fR],...
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B dbclient
|
||||
is a small SSH client
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.TP
|
||||
.B command
|
||||
A command to run on the remote host. This will normally be run by the remote host
|
||||
using the user's shell. The command begins at the first hyphen argument after the
|
||||
host argument. If no command is specified an interactive terminal will be opened
|
||||
(see -t and -T).
|
||||
.TP
|
||||
.B \-p \fIport
|
||||
Connect to
|
||||
.I port
|
||||
on the remote host. Alternatively a port can be specified as hostname^port.
|
||||
Default is 22.
|
||||
.TP
|
||||
.B \-i \fIidfile
|
||||
Identity file.
|
||||
Read the identity key from file
|
||||
.I idfile
|
||||
(multiple allowed). This file is created with dropbearkey(1) or converted
|
||||
from OpenSSH with dropbearconvert(1). The default path ~/.ssh/id_dropbear is used
|
||||
.TP
|
||||
.B \-L\fR [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
|
||||
Local port forwarding.
|
||||
Forward the port
|
||||
.I listenport
|
||||
on the local host through the SSH connection to port
|
||||
.I port
|
||||
on the host
|
||||
.IR host .
|
||||
.TP
|
||||
.B \-R\fR [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
|
||||
Remote port forwarding.
|
||||
Forward the port
|
||||
.I listenport
|
||||
on the remote host through the SSH connection to port
|
||||
.I port
|
||||
on the host
|
||||
.IR host .
|
||||
.TP
|
||||
.B \-l \fIuser
|
||||
Username.
|
||||
Login as
|
||||
.I user
|
||||
on the remote host.
|
||||
.TP
|
||||
.B \-t
|
||||
Allocate a PTY. This is the default when no command is given, it gives a full
|
||||
interactive remote session. The main effect is that keystrokes are sent remotely
|
||||
immediately as opposed to local line-based editing.
|
||||
.TP
|
||||
.B \-T
|
||||
Don't allocate a PTY. This is the default a command is given. See -t.
|
||||
.TP
|
||||
.B \-N
|
||||
Don't request a remote shell or run any commands. Any command arguments are ignored.
|
||||
.TP
|
||||
.B \-f
|
||||
Fork into the background after authentication. A command argument (or -N) is required.
|
||||
This is useful when using password authentication.
|
||||
.TP
|
||||
.B \-g
|
||||
Allow non-local hosts to connect to forwarded ports. Applies to -L and -R
|
||||
forwarded ports, though remote connections to -R forwarded ports may be limited
|
||||
by the ssh server.
|
||||
.TP
|
||||
.B \-y
|
||||
Always accept hostkeys if they are unknown. If a hostkey mismatch occurs the
|
||||
connection will abort as normal. If specified a second time no host key checking
|
||||
is performed at all, this is usually undesirable.
|
||||
.TP
|
||||
.B \-A
|
||||
Forward agent connections to the remote host. dbclient will use any
|
||||
OpenSSH-style agent program if available ($SSH_AUTH_SOCK will be set) for
|
||||
public key authentication. Forwarding is only enabled if -A is specified.
|
||||
.TP
|
||||
.B \-W \fIwindowsize
|
||||
Specify the per-channel receive window buffer size. Increasing this
|
||||
may improve network performance at the expense of memory use. Use -h to see the
|
||||
default buffer size.
|
||||
.TP
|
||||
.B \-K \fItimeout_seconds
|
||||
Ensure that traffic is transmitted at a certain interval in seconds. This is
|
||||
useful for working around firewalls or routers that drop connections after
|
||||
a certain period of inactivity. The trade-off is that a session may be
|
||||
closed if there is a temporary lapse of network connectivity. A setting
|
||||
if 0 disables keepalives. If no response is received for 3 consecutive keepalives the connection will be closed.
|
||||
.TP
|
||||
.B \-I \fIidle_timeout
|
||||
Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
|
||||
.TP
|
||||
|
||||
.\" TODO: how to avoid a line break between these two -J arguments?
|
||||
.B \-J \fIproxy_command
|
||||
.TP
|
||||
.B \-J \fI&fd
|
||||
.br
|
||||
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
|
||||
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
|
||||
.B \-B \fIendhost:endport
|
||||
"Netcat-alike" mode, where Dropbear will connect to the given host, then create a
|
||||
forwarded connection to \fIendhost\fR. This will then be presented as dbclient's
|
||||
standard input/output.
|
||||
.TP
|
||||
.B \-c \fIcipherlist
|
||||
Specify a comma separated list of ciphers to enable. Use \fI-c help\fR to list possibilities.
|
||||
.TP
|
||||
.B \-m \fIMAClist
|
||||
Specify a comma separated list of authentication MACs to enable. Use \fI-m help\fR to list possibilities.
|
||||
.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
|
||||
The specified command will be requested as a subsystem, used for sftp. Dropbear doesn't implement sftp itself but the OpenSSH sftp client can be used eg \fIsftp -S dbclient user@host\fR
|
||||
.TP
|
||||
.B \-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
|
||||
Print the version
|
||||
|
||||
.SH MULTI-HOP
|
||||
Dropbear will also allow multiple "hops" to be specified, separated by commas. In
|
||||
this case a connection will be made to the first host, then a TCP forwarded
|
||||
connection will be made through that to the second host, and so on. Hosts other than
|
||||
the final destination will not see anything other than the encrypted SSH stream.
|
||||
A port for a host can be specified with a caret (eg matt@martello^44 ).
|
||||
This syntax can also be used with scp or rsync (specifying dbclient as the
|
||||
ssh/rsh command). A file can be "bounced" through multiple SSH hops, eg
|
||||
|
||||
scp -S dbclient matt@martello,root@wrt,canyons:/tmp/dump .
|
||||
|
||||
Note that hostnames are resolved by the prior hop (so "canyons" would be resolved by the host "wrt")
|
||||
in the example above, the same way as other -L TCP forwarded hosts are. Host keys are
|
||||
checked locally based on the given hostname.
|
||||
|
||||
.SH ESCAPE CHARACTERS
|
||||
Typing a newline followed by the key sequence \fI~.\fR (tilde, dot) will terminate a connection.
|
||||
The sequence \fI~^Z\fR (tilde, ctrl-z) will background the connection. This behaviour only
|
||||
applies when a PTY is used.
|
||||
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
.B DROPBEAR_PASSWORD
|
||||
A password to use for remote authentication can be specified in the environment
|
||||
variable DROPBEAR_PASSWORD. Care should be taken that the password is not
|
||||
exposed to other users on a multi-user system, or stored in accessible files.
|
||||
.TP
|
||||
.B SSH_ASKPASS
|
||||
dbclient can use an external program to request a password from a user.
|
||||
SSH_ASKPASS should be set to the path of a program that will return a password
|
||||
on standard output. This program will only be used if either DISPLAY is set and
|
||||
standard input is not a TTY, or the environment variable SSH_ASKPASS_ALWAYS is
|
||||
set.
|
||||
.SH NOTES
|
||||
If compiled with zlib support and if the server supports it, dbclient will
|
||||
always use compression.
|
||||
|
||||
.SH AUTHOR
|
||||
Matt Johnston (matt@ucc.asn.au).
|
||||
.br
|
||||
Mihnea Stoenescu wrote initial Dropbear client support
|
||||
.br
|
||||
Gerrit Pape (pape@smarden.org) wrote this manual page.
|
||||
.SH SEE ALSO
|
||||
dropbear(8), dropbearkey(1)
|
||||
.P
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
18
dbhelpers.c
Normal file
18
dbhelpers.c
Normal 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
dbhelpers.h
Normal file
21
dbhelpers.h
Normal 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_ */
|
||||
192
dbmalloc.c
Normal file
192
dbmalloc.c
Normal file
@@ -0,0 +1,192 @@
|
||||
#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 */
|
||||
|
||||
void * m_realloc_ltm(void* ptr, size_t oldsize, size_t newsize) {
|
||||
(void)oldsize;
|
||||
return m_realloc(ptr, newsize);
|
||||
}
|
||||
|
||||
void m_free_ltm(void *mem, size_t size) {
|
||||
(void)size;
|
||||
m_free_direct(mem);
|
||||
}
|
||||
27
dbmalloc.h
Normal file
27
dbmalloc.h
Normal 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_ */
|
||||
34
dbmulti.c
34
dbmulti.c
@@ -26,17 +26,13 @@
|
||||
|
||||
/* definitions are cleanest if we just put them here */
|
||||
int dropbear_main(int argc, char ** argv);
|
||||
int cli_main(int argc, char ** argv);
|
||||
int dropbearkey_main(int argc, char ** argv);
|
||||
int dropbearconvert_main(int argc, char ** argv);
|
||||
int scp_main(int argc, char ** argv);
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
|
||||
char * progname;
|
||||
|
||||
if (argc > 0) {
|
||||
/* figure which form we're being called as */
|
||||
progname = basename(argv[0]);
|
||||
static int runprog(const char *progname, int argc, char ** argv, int *match) {
|
||||
*match = DROPBEAR_SUCCESS;
|
||||
|
||||
#ifdef DBMULTI_dropbear
|
||||
if (strcmp(progname, "dropbear") == 0) {
|
||||
@@ -64,15 +60,33 @@ int main(int argc, char ** argv) {
|
||||
return scp_main(argc, argv);
|
||||
}
|
||||
#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 multi-purpose version %s\n"
|
||||
"Make a symlink pointing at this binary with one of the following names:\n"
|
||||
fprintf(stderr, "Dropbear SSH multi-purpose v%s\n"
|
||||
"Make a symlink pointing at this binary with one of the\n"
|
||||
"following names or run 'dropbearmulti <command>'.\n"
|
||||
#ifdef DBMULTI_dropbear
|
||||
"'dropbear' - the Dropbear server\n"
|
||||
#endif
|
||||
#ifdef DBMULTI_dbclient
|
||||
"'dbclient' - the Dropbear client\n"
|
||||
"'dbclient' or 'ssh' - the Dropbear client\n"
|
||||
#endif
|
||||
#ifdef DBMULTI_dropbearkey
|
||||
"'dropbearkey' - the key generator\n"
|
||||
|
||||
378
dbrandom.c
Normal file
378
dbrandom.c
Normal file
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "bignum.h"
|
||||
#include "dbrandom.h"
|
||||
#include "runopts.h"
|
||||
|
||||
/* this is used to generate unique output from the same hashpool */
|
||||
static uint32_t counter = 0;
|
||||
/* the max value for the counter, so it won't integer overflow */
|
||||
#define MAX_COUNTER (1<<30)
|
||||
|
||||
static unsigned char hashpool[SHA1_HASH_SIZE] = {0};
|
||||
static int donerandinit = 0;
|
||||
|
||||
#define INIT_SEED_SIZE 32 /* 256 bits */
|
||||
|
||||
/* The basic setup is we read some data from /dev/(u)random or prngd and hash it
|
||||
* into hashpool. To read data, we hash together current hashpool contents,
|
||||
* and a counter. We feed more data in by hashing the current pool and new
|
||||
* data into the pool.
|
||||
*
|
||||
* It is important to ensure that counter doesn't wrap around before we
|
||||
* feed in new entropy.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Pass wantlen=0 to hash an entire file */
|
||||
static int
|
||||
process_file(hash_state *hs, const char *filename,
|
||||
unsigned int wantlen, int prngd) {
|
||||
int readfd = -1;
|
||||
unsigned int readcount;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
if (prngd) {
|
||||
#if DROPBEAR_USE_PRNGD
|
||||
readfd = connect_unix(filename);
|
||||
#endif
|
||||
} else {
|
||||
readfd = open(filename, O_RDONLY);
|
||||
}
|
||||
|
||||
if (readfd < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
readcount = 0;
|
||||
while (wantlen == 0 || readcount < wantlen) {
|
||||
int readlen, wantread;
|
||||
unsigned char readbuf[4096];
|
||||
if (wantlen == 0) {
|
||||
wantread = sizeof(readbuf);
|
||||
} else {
|
||||
wantread = MIN(sizeof(readbuf), wantlen-readcount);
|
||||
}
|
||||
|
||||
#if DROPBEAR_USE_PRNGD
|
||||
if (prngd) {
|
||||
char egdcmd[2];
|
||||
egdcmd[0] = 0x02; /* blocking read */
|
||||
egdcmd[1] = (unsigned char)wantread;
|
||||
if (write(readfd, egdcmd, 2) < 0) {
|
||||
dropbear_exit("Can't send command to egd");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
readlen = read(readfd, readbuf, wantread);
|
||||
if (readlen <= 0) {
|
||||
if (readlen < 0 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (readlen == 0 && wantlen == 0) {
|
||||
/* whole file was read as requested */
|
||||
break;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
sha1_process(hs, readbuf, readlen);
|
||||
readcount += readlen;
|
||||
}
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
out:
|
||||
close(readfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void addrandom(const unsigned char * buf, unsigned int len)
|
||||
{
|
||||
hash_state hs;
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* hash in the new seed data */
|
||||
sha1_init(&hs);
|
||||
/* existing state (zeroes on startup) */
|
||||
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
|
||||
|
||||
/* new */
|
||||
sha1_process(&hs, buf, len);
|
||||
sha1_done(&hs, hashpool);
|
||||
}
|
||||
|
||||
static void write_urandom()
|
||||
{
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if !DROPBEAR_USE_PRNGD
|
||||
/* This is opportunistic, don't worry about failure */
|
||||
unsigned char buf[INIT_SEED_SIZE];
|
||||
FILE *f = fopen(DROPBEAR_URANDOM_DEV, "w");
|
||||
if (!f) {
|
||||
return;
|
||||
}
|
||||
genrandom(buf, sizeof(buf));
|
||||
fwrite(buf, sizeof(buf), 1, f);
|
||||
fclose(f);
|
||||
#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
|
||||
|
||||
|
||||
#ifdef HAVE_GETRANDOM
|
||||
/* Reads entropy seed with getrandom().
|
||||
* May block if the kernel isn't ready.
|
||||
* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int process_getrandom(hash_state *hs) {
|
||||
char buf[INIT_SEED_SIZE];
|
||||
ssize_t ret;
|
||||
|
||||
/* First try non-blocking so that we can warn about waiting */
|
||||
ret = getrandom(buf, sizeof(buf), GRND_NONBLOCK);
|
||||
if (ret == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
/* Old kernel */
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
/* Other errors fall through to blocking getrandom() */
|
||||
TRACE(("first getrandom() failed: %d %s", errno, strerror(errno)))
|
||||
if (errno == EAGAIN) {
|
||||
dropbear_log(LOG_WARNING, "Waiting for kernel randomness to be initialised...");
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait blocking if needed. Loop in case we get EINTR */
|
||||
while (ret != sizeof(buf)) {
|
||||
ret = getrandom(buf, sizeof(buf), 0);
|
||||
|
||||
if (ret == sizeof(buf)) {
|
||||
/* Success */
|
||||
break;
|
||||
}
|
||||
if (ret == -1 && errno == EINTR) {
|
||||
/* Try again. */
|
||||
continue;
|
||||
}
|
||||
if (ret >= 0) {
|
||||
TRACE(("Short read %zd from getrandom() shouldn't happen", ret))
|
||||
/* Try again? */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Unexpected problem, fall back to /dev/urandom */
|
||||
TRACE(("2nd getrandom() failed: %d %s", errno, strerror(errno)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == sizeof(buf)) {
|
||||
/* Success, stir in the entropy */
|
||||
sha1_process(hs, (void*)buf, sizeof(buf));
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
return DROPBEAR_FAILURE;
|
||||
|
||||
}
|
||||
#endif /* HAVE_GETRANDOM */
|
||||
|
||||
/* Initialise the prng from /dev/urandom or prngd. This function can
|
||||
* be called multiple times */
|
||||
void seedrandom() {
|
||||
|
||||
hash_state hs;
|
||||
|
||||
pid_t pid;
|
||||
struct timeval tv;
|
||||
clock_t clockval;
|
||||
int urandom_seeded = 0;
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* hash in the new seed data */
|
||||
sha1_init(&hs);
|
||||
|
||||
/* existing state */
|
||||
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
|
||||
|
||||
#ifdef HAVE_GETRANDOM
|
||||
if (process_getrandom(&hs) == DROPBEAR_SUCCESS) {
|
||||
urandom_seeded = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!urandom_seeded) {
|
||||
#if DROPBEAR_USE_PRNGD
|
||||
if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_PRNGD_SOCKET);
|
||||
urandom_seeded = 1;
|
||||
}
|
||||
#else
|
||||
/* non-blocking random source (probably /dev/urandom) */
|
||||
if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_URANDOM_DEV);
|
||||
urandom_seeded = 1;
|
||||
}
|
||||
#endif
|
||||
} /* urandom_seeded */
|
||||
|
||||
/* A few other sources to fall back on.
|
||||
* Add more here for other platforms */
|
||||
#ifdef __linux__
|
||||
/* Seems to be a reasonable source of entropy from timers. Possibly hard
|
||||
* for even local attackers to reproduce */
|
||||
process_file(&hs, "/proc/timer_list", 0, 0);
|
||||
/* Might help on systems with wireless */
|
||||
process_file(&hs, "/proc/interrupts", 0, 0);
|
||||
|
||||
process_file(&hs, "/proc/loadavg", 0, 0);
|
||||
process_file(&hs, "/proc/sys/kernel/random/entropy_avail", 0, 0);
|
||||
|
||||
/* Mostly network visible but useful in some situations.
|
||||
* Limit size to avoid slowdowns on systems with lots of routes */
|
||||
process_file(&hs, "/proc/net/netstat", 4096, 0);
|
||||
process_file(&hs, "/proc/net/dev", 4096, 0);
|
||||
process_file(&hs, "/proc/net/tcp", 4096, 0);
|
||||
/* Also includes interface lo */
|
||||
process_file(&hs, "/proc/net/rt_cache", 4096, 0);
|
||||
process_file(&hs, "/proc/vmstat", 0, 0);
|
||||
#endif
|
||||
|
||||
pid = getpid();
|
||||
sha1_process(&hs, (void*)&pid, sizeof(pid));
|
||||
|
||||
/* gettimeofday() doesn't completely fill out struct timeval on
|
||||
OS X (10.8.3), avoid valgrind warnings by clearing it first */
|
||||
memset(&tv, 0x0, sizeof(tv));
|
||||
gettimeofday(&tv, NULL);
|
||||
sha1_process(&hs, (void*)&tv, sizeof(tv));
|
||||
|
||||
clockval = clock();
|
||||
sha1_process(&hs, (void*)&clockval, sizeof(clockval));
|
||||
|
||||
/* When a private key is read by the client or server it will
|
||||
* be added to the hashpool - see runopts.c */
|
||||
|
||||
sha1_done(&hs, hashpool);
|
||||
|
||||
counter = 0;
|
||||
donerandinit = 1;
|
||||
|
||||
/* Feed it all back into /dev/urandom - this might help if Dropbear
|
||||
* is running from inetd and gets new state each time */
|
||||
write_urandom();
|
||||
}
|
||||
|
||||
/* return len bytes of pseudo-random data */
|
||||
void genrandom(unsigned char* buf, unsigned int len) {
|
||||
|
||||
hash_state hs;
|
||||
unsigned char hash[SHA1_HASH_SIZE];
|
||||
unsigned int copylen;
|
||||
|
||||
if (!donerandinit) {
|
||||
dropbear_exit("seedrandom not done");
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
|
||||
sha1_process(&hs, (void*)&counter, sizeof(counter));
|
||||
sha1_done(&hs, hash);
|
||||
|
||||
counter++;
|
||||
if (counter > MAX_COUNTER) {
|
||||
seedrandom();
|
||||
}
|
||||
|
||||
copylen = MIN(len, SHA1_HASH_SIZE);
|
||||
memcpy(buf, hash, copylen);
|
||||
len -= copylen;
|
||||
buf += copylen;
|
||||
}
|
||||
m_burn(hash, sizeof(hash));
|
||||
}
|
||||
|
||||
/* Generates a random mp_int.
|
||||
* max is a *mp_int specifying an upper bound.
|
||||
* rand must be an initialised *mp_int for the result.
|
||||
* the result rand satisfies: 0 < rand < max
|
||||
* */
|
||||
void gen_random_mpint(mp_int *max, mp_int *rand) {
|
||||
|
||||
unsigned char *randbuf = NULL;
|
||||
unsigned int len = 0;
|
||||
const unsigned char masks[] = {0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f};
|
||||
|
||||
const int size_bits = mp_count_bits(max);
|
||||
|
||||
len = size_bits / 8;
|
||||
if ((size_bits % 8) != 0) {
|
||||
len += 1;
|
||||
}
|
||||
|
||||
randbuf = (unsigned char*)m_malloc(len);
|
||||
do {
|
||||
genrandom(randbuf, len);
|
||||
/* Mask out the unrequired bits - mp_read_unsigned_bin expects
|
||||
* MSB first.*/
|
||||
randbuf[0] &= masks[size_bits % 8];
|
||||
|
||||
bytes_to_mp(rand, randbuf, len);
|
||||
|
||||
/* keep regenerating until we get one satisfying
|
||||
* 0 < rand < max */
|
||||
} while (!(mp_cmp(rand, max) == MP_LT && mp_cmp_d(rand, 0) == MP_GT));
|
||||
m_burn(randbuf, len);
|
||||
m_free(randbuf);
|
||||
}
|
||||
35
dbrandom.h
Normal file
35
dbrandom.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef DROPBEAR_RANDOM_H_
|
||||
#define DROPBEAR_RANDOM_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
void seedrandom(void);
|
||||
void genrandom(unsigned char* buf, unsigned int len);
|
||||
void addrandom(const unsigned char * buf, unsigned int len);
|
||||
void gen_random_mpint(mp_int *max, mp_int *rand);
|
||||
|
||||
#endif /* DROPBEAR_RANDOM_H_ */
|
||||
731
dbutil.c
731
dbutil.c
@@ -48,6 +48,19 @@
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#define _GNU_SOURCE
|
||||
/* To call clock_gettime() directly */
|
||||
#include <sys/syscall.h>
|
||||
#endif /* __linux */
|
||||
|
||||
#ifdef HAVE_MACH_MACH_TIME_H
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "buffer.h"
|
||||
@@ -57,20 +70,23 @@
|
||||
#define MAX_FMT 100
|
||||
|
||||
static void generic_dropbear_exit(int exitcode, const char* format,
|
||||
va_list param);
|
||||
va_list param) ATTRIB_NORETURN;
|
||||
static void generic_dropbear_log(int priority, const char* format,
|
||||
va_list param);
|
||||
|
||||
void (*_dropbear_exit)(int exitcode, const char* format, va_list param)
|
||||
void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN
|
||||
= generic_dropbear_exit;
|
||||
void (*_dropbear_log)(int priority, const char* format, va_list param)
|
||||
= generic_dropbear_log;
|
||||
|
||||
int usingsyslog = 0; /* set by runopts, but required externally to sessions */
|
||||
#ifndef DISABLE_SYSLOG
|
||||
void startsyslog() {
|
||||
#if DEBUG_TRACE
|
||||
int debug_trace = 0;
|
||||
#endif
|
||||
|
||||
openlog(PROGNAME, LOG_PID, LOG_AUTHPRIV);
|
||||
#ifndef DISABLE_SYSLOG
|
||||
void startsyslog(const char *ident) {
|
||||
|
||||
openlog(ident, LOG_PID, LOG_AUTHPRIV);
|
||||
|
||||
}
|
||||
#endif /* DISABLE_SYSLOG */
|
||||
@@ -104,10 +120,21 @@ static void generic_dropbear_exit(int exitcode, const char* format,
|
||||
|
||||
_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);
|
||||
}
|
||||
|
||||
static void generic_dropbear_log(int priority, const char* format,
|
||||
void fail_assert(const char* expr, const char* file, int line) {
|
||||
dropbear_exit("Failed assertion (%s:%d): `%s'", file, line, expr);
|
||||
}
|
||||
|
||||
static void generic_dropbear_log(int UNUSED(priority), const char* format,
|
||||
va_list param) {
|
||||
|
||||
char printbuf[1024];
|
||||
@@ -129,278 +156,234 @@ void dropbear_log(int priority, const char* format, ...) {
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
void dropbear_trace(const char* format, ...) {
|
||||
#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, ...) {
|
||||
va_list param;
|
||||
|
||||
if (!debug_trace) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_start(param, format);
|
||||
fprintf(stderr, "TRACE: ");
|
||||
fprintf(stderr, "TRACE (%d) %f: ", getpid(), time_since_start());
|
||||
vfprintf(stderr, format, param);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(param);
|
||||
}
|
||||
|
||||
void dropbear_trace2(const char* format, ...) {
|
||||
static int trace_env = -1;
|
||||
va_list param;
|
||||
|
||||
if (trace_env == -1) {
|
||||
trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0;
|
||||
}
|
||||
|
||||
if (!(debug_trace && trace_env)) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_start(param, format);
|
||||
fprintf(stderr, "TRACE2 (%d) %f: ", getpid(), time_since_start());
|
||||
vfprintf(stderr, format, param);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(param);
|
||||
}
|
||||
#endif /* DEBUG_TRACE */
|
||||
|
||||
/* Listen on address:port. Unless address is NULL, in which case listen on
|
||||
* everything. If called with address == "", we'll listen on localhost/loopback.
|
||||
* 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) {
|
||||
/* Connect to a given unix socket. The socket is blocking */
|
||||
#if ENABLE_CONNECT_UNIX
|
||||
int connect_unix(const char* path) {
|
||||
struct sockaddr_un addr;
|
||||
int fd = -1;
|
||||
|
||||
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;
|
||||
|
||||
if (address && address[0] == '\0') {
|
||||
TRACE(("dropbear_listen: local loopback"));
|
||||
address = NULL;
|
||||
} else {
|
||||
TRACE(("dropbear_listen: not local loopback"));
|
||||
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));
|
||||
}
|
||||
TRACE(("leave dropbear_listen: failed resolving"));
|
||||
memset((void*)&addr, 0x0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
|
||||
fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
TRACE(("Failed to open unix socket"))
|
||||
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));
|
||||
|
||||
/* disable nagle */
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
|
||||
|
||||
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
err = errno;
|
||||
close(sock);
|
||||
TRACE(("bind(%s) failed", port));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (listen(sock, 20) < 0) {
|
||||
err = errno;
|
||||
close(sock);
|
||||
TRACE(("listen() failed"));
|
||||
continue;
|
||||
}
|
||||
|
||||
*maxfd = MAX(*maxfd, sock);
|
||||
|
||||
nsock++;
|
||||
}
|
||||
|
||||
if (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 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 = 20 + strlen(gai_strerror(err));
|
||||
*errstring = (char*)m_malloc(len);
|
||||
snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
|
||||
}
|
||||
TRACE(("Error resolving: %s", gai_strerror(err)));
|
||||
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
TRACE(("Failed to connect to '%s' socket", path))
|
||||
m_close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
sock = -1;
|
||||
err = EADDRNOTAVAIL;
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
/* Sets up a pipe for a, returning three non-blocking file descriptors
|
||||
* and the pid. exec_fn is the function that will actually execute the child process,
|
||||
* it will be run after the child has fork()ed, and is passed exec_data.
|
||||
* If ret_errfd == NULL then stderr will not be captured.
|
||||
* ret_pid can be passed as NULL to discard the pid. */
|
||||
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 infds[2];
|
||||
int outfds[2];
|
||||
int errfds[2];
|
||||
pid_t pid;
|
||||
|
||||
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if (sock < 0) {
|
||||
err = errno;
|
||||
continue;
|
||||
}
|
||||
const int FDIN = 0;
|
||||
const int FDOUT = 1;
|
||||
|
||||
if (nonblocking) {
|
||||
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
|
||||
close(sock);
|
||||
sock = -1;
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
*errstring = m_strdup("Failed non-blocking");
|
||||
}
|
||||
TRACE(("Failed non-blocking: %s", strerror(errno)));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
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 */
|
||||
/* redirect stdin/stdout/stderr */
|
||||
if (pipe(infds) != 0) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
if (pipe(outfds) != 0) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
if (ret_errfd && pipe(errfds) != 0) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
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));
|
||||
#if DROPBEAR_VFORK
|
||||
pid = vfork();
|
||||
#else
|
||||
pid = fork();
|
||||
#endif
|
||||
|
||||
if (pid < 0) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
if (!pid) {
|
||||
/* child */
|
||||
|
||||
TRACE(("back to normal sigchld"))
|
||||
/* Revert to normal sigchld handling */
|
||||
if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) {
|
||||
dropbear_exit("signal() error");
|
||||
}
|
||||
TRACE(("Error connecting: %s", strerror(err)));
|
||||
|
||||
/* redirect stdin/stdout */
|
||||
|
||||
if ((dup2(infds[FDIN], STDIN_FILENO) < 0) ||
|
||||
(dup2(outfds[FDOUT], STDOUT_FILENO) < 0) ||
|
||||
(ret_errfd && dup2(errfds[FDOUT], STDERR_FILENO) < 0)) {
|
||||
TRACE(("leave noptycommand: error redirecting FDs"))
|
||||
dropbear_exit("Child dup2() failure");
|
||||
}
|
||||
|
||||
close(infds[FDOUT]);
|
||||
close(infds[FDIN]);
|
||||
close(outfds[FDIN]);
|
||||
close(outfds[FDOUT]);
|
||||
if (ret_errfd)
|
||||
{
|
||||
close(errfds[FDIN]);
|
||||
close(errfds[FDOUT]);
|
||||
}
|
||||
|
||||
exec_fn(exec_data);
|
||||
/* not reached */
|
||||
return DROPBEAR_FAILURE;
|
||||
} else {
|
||||
/* Success */
|
||||
/* (err is used as a dummy var here) */
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&err, sizeof(err));
|
||||
}
|
||||
/* parent */
|
||||
close(infds[FDIN]);
|
||||
close(outfds[FDOUT]);
|
||||
|
||||
freeaddrinfo(res0);
|
||||
if (sock > 0 && errstring != NULL && *errstring != NULL) {
|
||||
m_free(*errstring);
|
||||
}
|
||||
setnonblocking(outfds[FDIN]);
|
||||
setnonblocking(infds[FDOUT]);
|
||||
|
||||
TRACE(("leave connect_remote: sock %d\n", sock));
|
||||
return sock;
|
||||
if (ret_errfd) {
|
||||
close(errfds[FDOUT]);
|
||||
setnonblocking(errfds[FDIN]);
|
||||
}
|
||||
|
||||
if (ret_pid) {
|
||||
*ret_pid = pid;
|
||||
}
|
||||
|
||||
*ret_writefd = infds[FDOUT];
|
||||
*ret_readfd = outfds[FDIN];
|
||||
if (ret_errfd) {
|
||||
*ret_errfd = errfds[FDIN];
|
||||
}
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return a string representation of the socket address passed. The return
|
||||
* value is allocated with malloc() */
|
||||
unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
|
||||
/* Runs a command with "sh -c". Will close FDs (except stdin/stdout/stderr) and
|
||||
* re-enabled SIGPIPE. If cmd is NULL, will run a login shell.
|
||||
*/
|
||||
void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) {
|
||||
char * argv[4];
|
||||
char * baseshell = NULL;
|
||||
unsigned int i;
|
||||
|
||||
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
|
||||
char *retstring = NULL;
|
||||
int ret;
|
||||
unsigned int len;
|
||||
baseshell = basename(usershell);
|
||||
|
||||
len = sizeof(struct sockaddr_storage);
|
||||
|
||||
ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
|
||||
sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST);
|
||||
|
||||
if (ret != 0) {
|
||||
/* This is a fairly bad failure - it'll fallback to IP if it
|
||||
* just can't resolve */
|
||||
dropbear_exit("failed lookup (%d, %d)", ret, errno);
|
||||
}
|
||||
|
||||
if (withport) {
|
||||
len = strlen(hbuf) + 2 + strlen(sbuf);
|
||||
retstring = (char*)m_malloc(len);
|
||||
snprintf(retstring, len, "%s:%s", hbuf, sbuf);
|
||||
if (cmd != NULL) {
|
||||
argv[0] = baseshell;
|
||||
} else {
|
||||
retstring = m_strdup(hbuf);
|
||||
/* a login shell should be "-bash" for "/bin/bash" etc */
|
||||
int len = strlen(baseshell) + 2; /* 2 for "-" */
|
||||
argv[0] = (char*)m_malloc(len);
|
||||
snprintf(argv[0], len, "-%s", baseshell);
|
||||
}
|
||||
|
||||
return retstring;
|
||||
|
||||
}
|
||||
|
||||
/* Get the hostname corresponding to the address addr. On failure, the IP
|
||||
* address is returned. The return value is allocated with strdup() */
|
||||
char* getaddrhostname(struct sockaddr_storage * addr) {
|
||||
|
||||
char hbuf[NI_MAXHOST];
|
||||
char sbuf[NI_MAXSERV];
|
||||
int ret;
|
||||
unsigned int len;
|
||||
|
||||
len = sizeof(struct sockaddr_storage);
|
||||
|
||||
ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
|
||||
sbuf, sizeof(sbuf), NI_NUMERICSERV);
|
||||
|
||||
if (ret != 0) {
|
||||
/* 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. */
|
||||
return getaddrstring(addr, 0);
|
||||
if (cmd != NULL) {
|
||||
argv[1] = "-c";
|
||||
argv[2] = (char*)cmd;
|
||||
argv[3] = NULL;
|
||||
} else {
|
||||
/* construct a shell of the form "-bash" etc */
|
||||
argv[1] = NULL;
|
||||
}
|
||||
|
||||
return m_strdup(hbuf);
|
||||
/* Re-enable SIGPIPE for the executed process */
|
||||
if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) {
|
||||
dropbear_exit("signal() error");
|
||||
}
|
||||
|
||||
/* close file descriptors except stdin/stdout/stderr
|
||||
* Need to be sure FDs are closed here to avoid reading files as root */
|
||||
for (i = 3; i <= maxfd; i++) {
|
||||
m_close(i);
|
||||
}
|
||||
|
||||
execv(usershell, argv);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
void printhex(unsigned char* buf, int len) {
|
||||
#if DEBUG_TRACE
|
||||
void printhex(const char * label, const unsigned char * buf, int len) {
|
||||
|
||||
int i;
|
||||
|
||||
fprintf(stderr, "%s\n", label);
|
||||
for (i = 0; i < len; i++) {
|
||||
fprintf(stderr, "%02x", buf[i]);
|
||||
if (i % 16 == 15) {
|
||||
@@ -412,6 +395,15 @@ void printhex(unsigned char* buf, int len) {
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void printmpint(const char *label, mp_int *mp) {
|
||||
buffer *buf = buf_new(1000);
|
||||
buf_putmpint(buf, mp);
|
||||
fprintf(stderr, "%d bits ", mp_count_bits(mp));
|
||||
printhex(label, buf->data, buf->len);
|
||||
buf_free(buf);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Strip all control characters from text (a null-terminated string), except
|
||||
@@ -445,39 +437,47 @@ char * stripcontrol(const char * text) {
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_readfile(buffer* buf, const char* filename) {
|
||||
|
||||
int fd;
|
||||
int fd = -1;
|
||||
int len;
|
||||
int maxlen;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
close(fd);
|
||||
return DROPBEAR_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
do {
|
||||
maxlen = buf->size - buf->pos;
|
||||
len = read(fd, buf_getwriteptr(buf, maxlen),
|
||||
maxlen);
|
||||
len = read(fd, buf_getwriteptr(buf, maxlen), maxlen);
|
||||
if (len < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
buf_incrwritepos(buf, len);
|
||||
} while (len < maxlen && len > 0);
|
||||
|
||||
close(fd);
|
||||
return DROPBEAR_SUCCESS;
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
|
||||
out:
|
||||
if (fd >= 0) {
|
||||
m_close(fd);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* get a line from the file into buffer in the style expected for an
|
||||
* authkeys file.
|
||||
* Will return DROPBEAR_SUCCESS if data is read, or DROPBEAR_FAILURE on EOF.*/
|
||||
/* 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 c = EOF;
|
||||
|
||||
TRACE(("enter buf_getline"));
|
||||
|
||||
buf_setpos(line, 0);
|
||||
buf_setlen(line, 0);
|
||||
|
||||
@@ -491,99 +491,198 @@ int buf_getline(buffer * line, FILE * authfile) {
|
||||
buf_putbyte(line, (unsigned char)c);
|
||||
}
|
||||
|
||||
TRACE(("leave getauthline: line too long"));
|
||||
TRACE(("leave getauthline: line too long"))
|
||||
/* We return success, but the line length will be zeroed - ie we just
|
||||
* ignore that line */
|
||||
buf_setlen(line, 0);
|
||||
|
||||
out:
|
||||
|
||||
buf_setpos(line, 0);
|
||||
|
||||
/* if we didn't read anything before EOF or error, exit */
|
||||
if (c == EOF && line->pos == 0) {
|
||||
TRACE(("leave getauthline: failure"));
|
||||
return DROPBEAR_FAILURE;
|
||||
} else {
|
||||
TRACE(("leave getauthline: success"));
|
||||
buf_setpos(line, 0);
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
TRACE(("leave buf_getline"));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* loop until the socket is closed (in case of EINTR) or
|
||||
* we get and error.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int m_close(int fd) {
|
||||
|
||||
/* make sure that the socket closes */
|
||||
void m_close(int fd) {
|
||||
int val;
|
||||
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
val = close(fd);
|
||||
} while (val < 0 && errno == EINTR);
|
||||
|
||||
if (val == 0 || errno == EBADF) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
} else {
|
||||
return DROPBEAR_FAILURE;
|
||||
if (val < 0 && errno != EBADF) {
|
||||
/* Linux says EIO can happen */
|
||||
dropbear_exit("Error closing fd %d, %s", fd, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void * m_malloc(size_t size) {
|
||||
void setnonblocking(int fd) {
|
||||
|
||||
void* ret;
|
||||
TRACE(("setnonblocking: %d", fd))
|
||||
|
||||
if (size == 0) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
ret = malloc(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_free(void* ptr) {
|
||||
if (ptr != NULL) {
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
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" */
|
||||
void m_burn(void *data, unsigned int len) {
|
||||
volatile char *p = data;
|
||||
|
||||
if (data == NULL)
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
return;
|
||||
while (len--) {
|
||||
*p++ = 0x66;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
|
||||
if (errno == ENODEV) {
|
||||
/* Some devices (like /dev/null redirected in)
|
||||
* can't be set to non-blocking */
|
||||
TRACE(("ignoring ENODEV for setnonblocking"))
|
||||
} else {
|
||||
{
|
||||
dropbear_exit("Couldn't set nonblocking");
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE(("leave setnonblocking"))
|
||||
}
|
||||
|
||||
void disallow_core() {
|
||||
struct rlimit lim;
|
||||
lim.rlim_cur = lim.rlim_max = 0;
|
||||
setrlimit(RLIMIT_CORE, &lim);
|
||||
}
|
||||
|
||||
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE, with the result in *val */
|
||||
int m_str_to_uint(const char* str, unsigned int *val) {
|
||||
unsigned long l;
|
||||
errno = 0;
|
||||
l = strtoul(str, NULL, 10);
|
||||
/* The c99 spec doesn't actually seem to define EINVAL, but most platforms
|
||||
* I've looked at mention it in their manpage */
|
||||
if ((l == 0 && errno == EINVAL)
|
||||
|| (l == ULONG_MAX && errno == ERANGE)
|
||||
|| (l > UINT_MAX)) {
|
||||
return DROPBEAR_FAILURE;
|
||||
} else {
|
||||
*val = l;
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns malloced path. inpath beginning with '/' is returned as-is,
|
||||
otherwise home directory is prepended */
|
||||
char * expand_homedir_path(const char *inpath) {
|
||||
struct passwd *pw = NULL;
|
||||
if (inpath[0] != '/') {
|
||||
pw = getpwuid(getuid());
|
||||
if (pw && pw->pw_dir) {
|
||||
int len = strlen(inpath) + strlen(pw->pw_dir) + 2;
|
||||
char *buf = m_malloc(len);
|
||||
snprintf(buf, len, "%s/%s", pw->pw_dir, inpath);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback */
|
||||
return m_strdup(inpath);
|
||||
}
|
||||
|
||||
int constant_time_memcmp(const void* a, const void *b, size_t n)
|
||||
{
|
||||
const char *xa = a, *xb = b;
|
||||
uint8_t c = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
c |= (xa[i] ^ xb[i]);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/* higher-resolution monotonic timestamp, falls back to gettimeofday */
|
||||
void gettime_wrapper(struct timespec *now) {
|
||||
struct timeval tv;
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
/* time stands still when fuzzing */
|
||||
now->tv_sec = 5;
|
||||
now->tv_nsec = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
|
||||
/* POSIX monotonic clock. Newer Linux, BSD, MacOSX >10.12 */
|
||||
if (clock_gettime(CLOCK_MONOTONIC, now) == 0) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && defined(SYS_clock_gettime)
|
||||
{
|
||||
/* Old linux toolchain - kernel might support it but not the build headers */
|
||||
/* Also glibc <2.17 requires -lrt which we neglect to add */
|
||||
static int linux_monotonic_failed = 0;
|
||||
if (!linux_monotonic_failed) {
|
||||
/* CLOCK_MONOTONIC isn't in some headers */
|
||||
int clock_source_monotonic = 1;
|
||||
if (syscall(SYS_clock_gettime, clock_source_monotonic, now) == 0) {
|
||||
return;
|
||||
} else {
|
||||
/* Don't try again */
|
||||
linux_monotonic_failed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* linux fallback clock_gettime */
|
||||
|
||||
#if defined(HAVE_MACH_ABSOLUTE_TIME)
|
||||
{
|
||||
/* OS X pre 10.12, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
|
||||
static mach_timebase_info_data_t timebase_info;
|
||||
uint64_t scaled_time;
|
||||
if (timebase_info.denom == 0) {
|
||||
mach_timebase_info(&timebase_info);
|
||||
}
|
||||
scaled_time = mach_absolute_time() * timebase_info.numer / timebase_info.denom;
|
||||
now->tv_sec = scaled_time / 1000000000;
|
||||
now->tv_nsec = scaled_time % 1000000000;
|
||||
}
|
||||
#endif /* osx mach_absolute_time */
|
||||
|
||||
/* Fallback for everything else - this will sometimes go backwards */
|
||||
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
|
||||
}
|
||||
|
||||
81
dbutil.h
81
dbutil.h
@@ -22,46 +22,79 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _DBUTIL_H_
|
||||
#ifndef DROPBEAR_DBUTIL_H_
|
||||
|
||||
#define _DBUTIL_H_
|
||||
#define DROPBEAR_DBUTIL_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "queue.h"
|
||||
#include "dbhelpers.h"
|
||||
#include "dbmalloc.h"
|
||||
|
||||
#ifndef DISABLE_SYSLOG
|
||||
void startsyslog();
|
||||
void startsyslog(const char *ident);
|
||||
#endif
|
||||
|
||||
extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param);
|
||||
extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
|
||||
extern void (*_dropbear_log)(int priority, const char* format, va_list param);
|
||||
|
||||
void dropbear_exit(const char* format, ...);
|
||||
void dropbear_close(const char* format, ...);
|
||||
void dropbear_log(int priority, const char* format, ...);
|
||||
#ifdef DEBUG_TRACE
|
||||
void dropbear_trace(const char* format, ...);
|
||||
void printhex(unsigned char* buf, int len);
|
||||
void dropbear_exit(const char* format, ...) ATTRIB_PRINTF(1,2) ATTRIB_NORETURN;
|
||||
|
||||
void dropbear_close(const char* format, ...) ATTRIB_PRINTF(1,2) ;
|
||||
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;
|
||||
|
||||
#if DEBUG_TRACE
|
||||
void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
|
||||
void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2);
|
||||
void printhex(const char * label, const unsigned char * buf, int len);
|
||||
void printmpint(const char *label, mp_int *mp);
|
||||
void debug_start_net(void);
|
||||
extern int debug_trace;
|
||||
#endif
|
||||
|
||||
char * stripcontrol(const char * text);
|
||||
unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport);
|
||||
int dropbear_listen(const char* address, const char* port,
|
||||
int *socks, unsigned int sockcount, char **errstring, int *maxfd);
|
||||
int connect_remote(const char* remotehost, const char* remoteport,
|
||||
int nonblocking, char ** errstring);
|
||||
char* getaddrhostname(struct sockaddr_storage * addr);
|
||||
|
||||
int spawn_command(void(*exec_fn)(const void *user_data), const void *exec_data,
|
||||
int *writefd, int *readfd, int *errfd, pid_t *pid);
|
||||
void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell);
|
||||
#if ENABLE_CONNECT_UNIX
|
||||
int connect_unix(const char* addr);
|
||||
#endif
|
||||
int buf_readfile(buffer* buf, const char* filename);
|
||||
int buf_getline(buffer * line, FILE * authfile);
|
||||
|
||||
int 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) __m_free(X); (X) = NULL;
|
||||
void __m_free(void* ptr);
|
||||
void m_burn(void* data, unsigned int len);
|
||||
void m_close(int fd);
|
||||
void setnonblocking(int fd);
|
||||
void disallow_core(void);
|
||||
int m_str_to_uint(const char* str, unsigned int *val);
|
||||
|
||||
/* Used to force mp_ints to be initialised */
|
||||
#define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL}
|
||||
|
||||
#endif /* _DBUTIL_H_ */
|
||||
/* Dropbear assertion */
|
||||
#define dropbear_assert(X) do { if (!(X)) { fail_assert(#X, __FILE__, __LINE__); } } while (0)
|
||||
|
||||
/* Returns 0 if a and b have the same contents */
|
||||
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
|
||||
a real-world clock */
|
||||
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);
|
||||
|
||||
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_ */
|
||||
|
||||
15
debian/README.Debian.diet
vendored
Normal file
15
debian/README.Debian.diet
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
Building with the diet libc
|
||||
---------------------------
|
||||
|
||||
This package optionally can be built with the diet libc instead of the
|
||||
glibc to provide small statically linked programs. The resulting package
|
||||
has no dependency on any other package.
|
||||
|
||||
To use the diet libc, make sure the latest versions of the dietlibc-dev
|
||||
package is installed, and set DEB_BUILD_OPTIONS=diet in the environment
|
||||
when building the package, e.g.:
|
||||
|
||||
# apt-get install dietlibc-dev
|
||||
$ DEB_BUILD_OPTIONS=diet fakeroot apt-get source -b dropbear
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org>, Sat, 17 Jul 2004 19:09:34 +0000
|
||||
16
debian/README.runit
vendored
16
debian/README.runit
vendored
@@ -31,16 +31,16 @@ run script
|
||||
|
||||
# vi /etc/dropbear/run
|
||||
|
||||
Finally enable the service by linking dropbear's service directory to
|
||||
/var/service/. The service will be started within five seconds, and
|
||||
automatically at boot time. The sysv init script is disabled; see the
|
||||
runsvctrl(8) program for information on how to control services handled by
|
||||
runit. See the svlogd(8) program on how to configure the log service.
|
||||
Finally enable the service through runit's update-service(8) program, the
|
||||
service will be started within five seconds, and automatically at boot
|
||||
time, and the sysv init script will automatically be disabled; see the
|
||||
sv(8) program for information on how to control services handled by runit.
|
||||
See the svlogd(8) program on how to configure the log service.
|
||||
|
||||
# ln -s /etc/dropbear /var/service/
|
||||
# update-service --add /etc/dropbear
|
||||
|
||||
Optionally check the status of the service a few seconds later
|
||||
|
||||
# runsvstat -l /var/service/dropbear
|
||||
# sv status dropbear
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org>, Sun, 16 May 2004 15:52:34 +0000
|
||||
-- Gerrit Pape <pape@smarden.org>, Fri, 02 Mar 2007 20:41:08 +0000
|
||||
|
||||
341
debian/changelog
vendored
341
debian/changelog
vendored
@@ -1,29 +1,340 @@
|
||||
dropbear (0.44test2-1) unstable; urgency=low
|
||||
dropbear (2020.79-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream beta, various minor fixes.
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Tues, 17 August 2004 19:00:00 +0800
|
||||
-- Matt Johnston <matt@ucc.asn.au> Mon, 15 Jun 2020 22:51:57 +0800
|
||||
|
||||
dropbear (0.44test1-1) unstable; urgency=low
|
||||
dropbear (2019.78-0.1) unstable; urgency=low
|
||||
|
||||
* Upstream beta 0.44test1
|
||||
* Huge changes to allow client functionality
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Sat, 14 August 2004 23:00:00 +0800
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 27 Mar 2019 22:51:57 +0800
|
||||
|
||||
dropbear (0.43-1) unstable; urgency=high
|
||||
dropbear (2019.77-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release 0.43
|
||||
* SECURITY: Don't attempt to free uninitialised buffers in DSS verification
|
||||
code
|
||||
* Handle portforwarding to servers which don't send any initial data
|
||||
(Closes: #258426)
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Fri, 16 July 2004 17:44:54 +0800
|
||||
-- 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
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 23 Oct 2014 22:54:00 +0800
|
||||
|
||||
dropbear (2014.65-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Fri, 8 Aug 2014 22:54:00 +0800
|
||||
|
||||
dropbear (2014.64-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Sun, 27 Jul 2014 22:54:00 +0800
|
||||
|
||||
dropbear (2014.63-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 19 Feb 2014 22:54:00 +0800
|
||||
|
||||
dropbear (2013.62) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Tue, 7 Dec 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2013.60-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 16 Oct 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2013.59-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* Build with DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Fri, 4 Oct 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2013.58-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 18 Apr 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2013.57-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Mon, 15 Apr 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2013.56-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 21 Mar 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2012.55-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 22 Feb 2012 22:54:00 +0800
|
||||
|
||||
dropbear (2011.54-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Tues, 8 Nov 2011 22:54:00 +0800
|
||||
|
||||
dropbear (0.53.1-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 2 Mar 2011 22:54:00 +0900
|
||||
|
||||
dropbear (0.53-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 24 Feb 2011 22:54:00 +0900
|
||||
|
||||
dropbear (0.52-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 12 Nov 2008 22:54:00 +0900
|
||||
|
||||
dropbear (0.51-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 27 Mar 2008 19:14:00 +0900
|
||||
|
||||
dropbear (0.50-4) unstable; urgency=low
|
||||
|
||||
* debian/dropbear.init: apply patch from Petter Reinholdtsen: add LSB
|
||||
formatted dependency info in init.d script (closes: #466257).
|
||||
* debian/rules: no longer include symlinks for ./supervise/ subdirectories.
|
||||
* debian/dropbear.postinst: upgrade from << 0.50-4: if dropbear is managed
|
||||
by runit, remove service, and re-add using update-service(8).
|
||||
* debian/control: Standards-Version: 3.7.3.0.
|
||||
* debian/rules: target clean: don't ignore errors but check for readable
|
||||
./Makefile.
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org> Thu, 06 Mar 2008 19:06:58 +0000
|
||||
|
||||
dropbear (0.50-3) unstable; urgency=low
|
||||
|
||||
* debian/dropbear.init: use the update-service(8) program from the runit
|
||||
package instead of directly checking for the symlink in /var/service/.
|
||||
* debian/README.runit: talk about update-service(8) instead of symlinks
|
||||
in /var/service/.
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org> Fri, 15 Feb 2008 00:32:37 +0000
|
||||
|
||||
dropbear (0.50-2) unstable; urgency=low
|
||||
|
||||
* debian/dropbear.README.Debian: no longer talk about entropy from
|
||||
/dev/random, /dev/urandom is now used by default (thx Joey Hess,
|
||||
closes: #441515).
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org> Mon, 24 Sep 2007 16:49:17 +0000
|
||||
|
||||
dropbear (0.50-1) unstable; urgency=low
|
||||
|
||||
* debian/README.runit: minor.
|
||||
* new upstream version.
|
||||
* debian/diff/0001-options.h-use-dev-urandom-instead-of-dev-random-a.diff:
|
||||
remove; fixed upstream.
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org> Thu, 09 Aug 2007 23:01:01 +0000
|
||||
|
||||
dropbear (0.49-2) unstable; urgency=low
|
||||
|
||||
* debian/rules: apply diffs from debian/diff/ with patch -p1 instead of
|
||||
-p0.
|
||||
* debian/diff/0001-options.h-use-dev-urandom-instead-of-dev-random-a.diff:
|
||||
new; options.h: use /dev/urandom instead of /dev/random as
|
||||
DROPBEAR_RANDOM_DEV (closes: #386976).
|
||||
* debian/rules: target clean: remove libtomcrypt/Makefile,
|
||||
libtommath/Makefile.
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org> Sat, 09 Jun 2007 08:59:59 +0000
|
||||
|
||||
dropbear (0.49-1) unstable; urgency=high
|
||||
|
||||
* new upstream release, fixes
|
||||
* CVE-2007-1099: dropbear dbclient insufficient warning on hostkey
|
||||
mismatch (closes: #412899).
|
||||
* dbclient uses static "Password:" prompt instead of using the server's
|
||||
prompt (closes: #394996).
|
||||
* debian/control: Suggests: openssh-client, not ssh (closes: #405686);
|
||||
Standards-Version: 3.7.2.2.
|
||||
* debian/README.Debian: ssh -> openssh-server, openssh-client; remove
|
||||
'Replacing OpenSSH "sshd" with Dropbear' part, this is simply done by not
|
||||
installing the openssh-server package.
|
||||
* debian/README.runit: runsvstat -> sv status.
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org> Fri, 2 Mar 2007 20:48:18 +0000
|
||||
|
||||
dropbear (0.48.1-1) unstable; urgency=medium
|
||||
|
||||
* new upstream point release.
|
||||
* Compile fix for scp
|
||||
* debian/diff/dbclient.1.diff: new: document -R option to dbclient
|
||||
accurately (thx Markus Schaber; closes: #351882).
|
||||
* debian/dropbear.README.Debian: document a workaround for systems with
|
||||
possibly blocking /dev/random device (closes: #355414)..
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org> Sun, 16 Apr 2006 16:16:40 +0000
|
||||
|
||||
dropbear (0.48-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release.
|
||||
* SECURITY: Improve handling of denial of service attempts from a single
|
||||
IP.
|
||||
|
||||
* debian/implicit: update to revision 1.11.
|
||||
* new upstream release updates to scp from OpenSSH 4.3p2 - fixes a
|
||||
security issue where use of system() could cause users to execute
|
||||
arbitrary code through malformed filenames; CVE-2006-0225 (see also
|
||||
#349645); the scp binary is not provided by this package though.
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org> Fri, 10 Mar 2006 22:00:32 +0000
|
||||
|
||||
dropbear (0.47-1) unstable; urgency=high
|
||||
|
||||
* New upstream release.
|
||||
* SECURITY: Fix incorrect buffer sizing; CVE-2005-4178.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 8 Dec 2005 19:20:21 +0800
|
||||
|
||||
dropbear (0.46-2) unstable; urgency=low
|
||||
|
||||
* debian/control: Standards-Version: 3.6.2.1; update descriptions to
|
||||
mention included server and client (thx Tino Keitel).
|
||||
* debian/dropbear.init: allow '/etc/init.d/dropbear stop' even though
|
||||
'NO_START is not set to zero.' (closes: #336723).
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org> Tue, 6 Dec 2005 13:30:49 +0000
|
||||
|
||||
dropbear (0.46-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release, various fixes.
|
||||
* debian/diff/dbclient-usage-typo.diff, debian/diff/manpages.diff: remove;
|
||||
obsolete.
|
||||
* debian/dbclient.1: move to ./dbclient.1.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Fri, 8 July 2005 21:32:55 +0800
|
||||
|
||||
dropbear (0.45-3) unstable; urgency=low
|
||||
|
||||
* debian/dropbear.init: init script prints human readable message in case
|
||||
it's disabled (closes: #309099).
|
||||
* debian/dropbear.postinst: configure: restart service through init script
|
||||
instead of start.
|
||||
* debian/dropbear.prerm: set -u -> set -e.
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org> Wed, 25 May 2005 22:38:17 +0000
|
||||
|
||||
dropbear (0.45-2) unstable; urgency=low
|
||||
|
||||
* Matt Johnston:
|
||||
* New upstream release, various fixes.
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org> Sat, 12 Mar 2005 15:17:55 +0000
|
||||
|
||||
dropbear (0.44-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* debian/rules: install /usr/bin/dbclient; handle possible patches more
|
||||
gracefully; install debian/dbclient.1 man page; enable target patch;
|
||||
minor.
|
||||
* debian/implicit: update to revision 1.10.
|
||||
* debian/dbclient.1: new; man page.
|
||||
* debian/diff/dbclient-usage-typo.diff: new; fix typo.
|
||||
* debian/diff/manpages.diff: new; add references to dbclient man page.
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org> Sat, 8 Jan 2005 22:50:43 +0000
|
||||
|
||||
dropbear (0.43-2) unstable; urgency=high
|
||||
|
||||
* Matt Johnston:
|
||||
* New upstream release 0.43
|
||||
* SECURITY: Don't attempt to free uninitialised buffers in DSS verification
|
||||
code
|
||||
* Handle portforwarding to servers which don't send any initial data
|
||||
(Closes: #258426)
|
||||
* debian/dropbear.postinst: remove code causing bothersome warning on
|
||||
package install (closes: #256752).
|
||||
* debian/README.Debian.diet: new; how to build with the diet libc.
|
||||
* debian/dropbear.docs: add debian/README.Debian.diet.
|
||||
* debian/rules: support "diet" in DEB_BUILD_OPTIONS; minor cleanup.
|
||||
|
||||
-- Gerrit Pape <pape@smarden.org> Sat, 17 Jul 2004 19:31:19 +0000
|
||||
|
||||
dropbear (0.42-1) unstable; urgency=low
|
||||
|
||||
* New upstream release 0.42
|
||||
* New upstream release 0.42.
|
||||
* debian/diff/cvs-20040520.diff: remove; obsolete.
|
||||
* debian/rules: disable target patch.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 16 June 2004 12:44:54 +0800
|
||||
|
||||
|
||||
1
debian/compat
vendored
1
debian/compat
vendored
@@ -1 +0,0 @@
|
||||
4
|
||||
0
debian/conffiles
vendored
0
debian/conffiles
vendored
12
debian/control
vendored
12
debian/control
vendored
@@ -3,16 +3,16 @@ Section: net
|
||||
Priority: optional
|
||||
Maintainer: Gerrit Pape <pape@smarden.org>
|
||||
Build-Depends: libz-dev
|
||||
Standards-Version: 3.6.1.0
|
||||
Standards-Version: 3.7.3.0
|
||||
|
||||
Package: dropbear
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}
|
||||
Suggests: ssh, runit
|
||||
Description: lightweight SSH2 server
|
||||
dropbear is a SSH 2 server designed to be small enough to be used in small
|
||||
memory environments, while still being functional and secure enough for
|
||||
general use.
|
||||
Suggests: openssh-client, runit
|
||||
Description: lightweight SSH2 server and client
|
||||
dropbear is a SSH 2 server and client designed to be small enough to
|
||||
be used in small memory environments, while still being functional and
|
||||
secure enough for general use.
|
||||
.
|
||||
It implements most required features of the SSH 2 protocol, and other
|
||||
features such as X11 and authentication agent forwarding.
|
||||
|
||||
2
debian/dirs
vendored
2
debian/dirs
vendored
@@ -1,2 +0,0 @@
|
||||
usr/bin
|
||||
usr/sbin
|
||||
2
debian/docs
vendored
2
debian/docs
vendored
@@ -1,2 +0,0 @@
|
||||
README
|
||||
TODO
|
||||
44
debian/dropbear.README.Debian
vendored
44
debian/dropbear.README.Debian
vendored
@@ -1,41 +1,19 @@
|
||||
Dropbear for Debian
|
||||
-------------------
|
||||
|
||||
This package will attempt to listen on port 22. If the OpenSSH
|
||||
package ("ssh") is installed, the file /etc/default/dropbear
|
||||
will be set up so that the server does not start by default.
|
||||
This package will attempt to setup the Dropbear ssh server to listen on
|
||||
port 22. If the OpenSSH server package ("openssh-server") is installed,
|
||||
the file /etc/default/dropbear will be set up so that the server does not
|
||||
start by default.
|
||||
|
||||
You can run Dropbear concurrently with OpenSSH 'sshd' by
|
||||
modifying /etc/default/dropbear so that "NO_START" is set to
|
||||
"0" and changing the port number that Dropbear runs on. Follow
|
||||
the instructions in the file.
|
||||
You can run Dropbear concurrently with OpenSSH 'sshd' by modifying
|
||||
/etc/default/dropbear so that "NO_START" is set to "0", and changing the
|
||||
port number that Dropbear runs on. Follow the instructions in the file.
|
||||
|
||||
This package suggests you install the "ssh" package. This package
|
||||
provides the "ssh" client program, as well as the "/usr/bin/scp"
|
||||
binary you will need to be able to retrieve files from a server
|
||||
running Dropbear via SCP.
|
||||
|
||||
Replacing OpenSSH "sshd" with Dropbear
|
||||
--------------------------------------
|
||||
|
||||
You will still want to have the "ssh" package installed, as it
|
||||
provides the "ssh" and "scp" binaries. When you install this
|
||||
package, it checks for existing OpenSSH host keys and if found,
|
||||
converts them to the Dropbear format.
|
||||
|
||||
If this appears to have worked, you should be able to change over
|
||||
by following these steps:
|
||||
|
||||
1. Stop the OpenSSH server
|
||||
% /etc/init.d/ssh stop
|
||||
2. Prevent the OpenSSH server from starting in the future
|
||||
% touch /etc/ssh/sshd_not_to_be_run
|
||||
3. Modify the Dropbear defaults file, set NO_START to 0 and
|
||||
ensure DROPBEAR_PORT is set to 22.
|
||||
% editor /etc/default/dropbear
|
||||
4. Restart the Dropbear server.
|
||||
% /etc/init.d/dropbear restart
|
||||
This package suggests you install the "openssh-client" package, which
|
||||
provides the "ssh" client program, as well as the "/usr/bin/scp" binary
|
||||
you will need to be able to retrieve files via SCP from a server running
|
||||
Dropbear.
|
||||
|
||||
See the Dropbear homepage for more information:
|
||||
http://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
|
||||
|
||||
2
debian/dropbear.docs
vendored
2
debian/dropbear.docs
vendored
@@ -1,3 +1,3 @@
|
||||
README
|
||||
TODO
|
||||
debian/README.runit
|
||||
debian/README.Debian.diet
|
||||
|
||||
23
debian/dropbear.init
vendored
23
debian/dropbear.init
vendored
@@ -1,4 +1,12 @@
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: dropbear
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Dropbear SSH server
|
||||
### END INIT INFO
|
||||
#
|
||||
# Do not configure this file. Edit /etc/default/dropbear instead!
|
||||
#
|
||||
@@ -14,10 +22,11 @@ NO_START=0
|
||||
|
||||
set -e
|
||||
|
||||
cancel() { echo "$1" >&2; exit 0; };
|
||||
test ! -r /etc/default/dropbear || . /etc/default/dropbear
|
||||
test "$NO_START" = "0" || exit 0
|
||||
test -x "$DAEMON" || exit 0
|
||||
test ! -h /var/service/dropbear || exit 0
|
||||
test -x "$DAEMON" || cancel "$DAEMON does not exist or is not executable."
|
||||
test ! -x /usr/sbin/update-service || ! update-service --check dropbear ||
|
||||
cancel 'The dropbear service is controlled through runit, use the sv(8) program'
|
||||
|
||||
test -z "$DROPBEAR_BANNER" || \
|
||||
DROPBEAR_EXTRA_ARGS="$DROPBEAR_EXTRA_ARGS -b $DROPBEAR_BANNER"
|
||||
@@ -25,13 +34,16 @@ test -n "$DROPBEAR_RSAKEY" || \
|
||||
DROPBEAR_RSAKEY="/etc/dropbear/dropbear_rsa_host_key"
|
||||
test -n "$DROPBEAR_DSSKEY" || \
|
||||
DROPBEAR_DSSKEY="/etc/dropbear/dropbear_dss_host_key"
|
||||
test -n "$DROPBEAR_RECEIVE_WINDOW" || \
|
||||
DROPBEAR_RECEIVE_WINDOW="65536"
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
test "$NO_START" = "0" || cancel 'NO_START is not set to zero.'
|
||||
echo -n "Starting $DESC: "
|
||||
start-stop-daemon --start --quiet --pidfile /var/run/"$NAME".pid \
|
||||
--exec "$DAEMON" -- -d "$DROPBEAR_DSSKEY" -r "$DROPBEAR_RSAKEY" \
|
||||
-p "$DROPBEAR_PORT" $DROPBEAR_EXTRA_ARGS
|
||||
-p "$DROPBEAR_PORT" -W "$DROPBEAR_RECEIVE_WINDOW" $DROPBEAR_EXTRA_ARGS
|
||||
echo "$NAME."
|
||||
;;
|
||||
stop)
|
||||
@@ -40,12 +52,13 @@ case "$1" in
|
||||
echo "$NAME."
|
||||
;;
|
||||
restart|force-reload)
|
||||
test "$NO_START" = "0" || cancel 'NO_START is not set to zero.'
|
||||
echo -n "Restarting $DESC: "
|
||||
start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/"$NAME".pid
|
||||
sleep 1
|
||||
start-stop-daemon --start --quiet --pidfile /var/run/"$NAME".pid \
|
||||
--exec "$DAEMON" -- -d "$DROPBEAR_DSSKEY" -r "$DROPBEAR_RSAKEY" \
|
||||
-p "$DROPBEAR_PORT" $DROPBEAR_EXTRA_ARGS
|
||||
-p "$DROPBEAR_PORT" -W "$DROPBEAR_RECEIVE_WINDOW" $DROPBEAR_EXTRA_ARGS
|
||||
echo "$NAME."
|
||||
;;
|
||||
*)
|
||||
|
||||
17
debian/dropbear.postinst
vendored
17
debian/dropbear.postinst
vendored
@@ -2,7 +2,6 @@
|
||||
set -e
|
||||
|
||||
test "$1" = 'configure' || exit 0
|
||||
test -n "$2" || chown log /etc/dropbear/log/main || true
|
||||
|
||||
if test ! -e /etc/dropbear/dropbear_rsa_host_key; then
|
||||
if test -f /etc/ssh/ssh_host_rsa_key; then
|
||||
@@ -55,14 +54,26 @@ DROPBEAR_BANNER=""
|
||||
|
||||
# DSS hostkey file (default: /etc/dropbear/dropbear_dss_host_key)
|
||||
#DROPBEAR_DSSKEY="/etc/dropbear/dropbear_dss_host_key"
|
||||
|
||||
# Receive window size - this is a tradeoff between memory and
|
||||
# network performance
|
||||
DROPBEAR_RECEIVE_WINDOW=65536
|
||||
EOT
|
||||
fi
|
||||
|
||||
if test -x /etc/init.d/dropbear; then
|
||||
update-rc.d dropbear defaults >/dev/null
|
||||
if test -x /usr/sbin/invoke-rc.d; then
|
||||
invoke-rc.d dropbear start
|
||||
invoke-rc.d dropbear restart
|
||||
else
|
||||
/etc/init.d/dropbear start
|
||||
/etc/init.d/dropbear restart
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$2" && dpkg --compare-versions "$2" lt '0.50-4' &&
|
||||
update-service --check dropbear 2>/dev/null; then
|
||||
update-service --remove /etc/dropbear 2>/dev/null || :
|
||||
sleep 6
|
||||
rm -rf /var/run/dropbear /var/run/dropbear.log
|
||||
update-service --add /etc/dropbear || :
|
||||
fi
|
||||
|
||||
2
debian/dropbear.prerm
vendored
2
debian/dropbear.prerm
vendored
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
set -u
|
||||
set -e
|
||||
|
||||
test "$1" = 'remove' || test "$1" = 'deconfigure' || exit 0
|
||||
if test -x /etc/init.d/dropbear; then
|
||||
|
||||
20
debian/implicit
vendored
20
debian/implicit
vendored
@@ -1,4 +1,4 @@
|
||||
# $Id: implicit,v 1.1 2004/06/16 05:08:32 matt Exp $
|
||||
# $Id: implicit,v 1.11 2005/11/29 21:57:55 pape Exp $
|
||||
|
||||
.PHONY: deb-checkdir deb-checkuid
|
||||
|
||||
@@ -12,6 +12,10 @@ deb-checkuid:
|
||||
$*.deb-docs-docs $*.deb-docs-examples $*.deb-DEBIAN \
|
||||
$*.deb-DEBIAN-dir $*.deb-DEBIAN-scripts $*.deb-DEBIAN-md5sums
|
||||
|
||||
%.udeb: %.deb-DEBIAN
|
||||
@rm -f $*.deb $*.deb-checkdir $*.deb-DEBIAN $*.deb-DEBIAN-dir \
|
||||
$*.deb-DEBIAN-scripts $*.deb-DEBIAN-md5sums
|
||||
|
||||
%.deb-checkdir:
|
||||
@test -d debian/$* || sh -cx '! : directory debian/$* missing'
|
||||
@test "`id -u`" -eq 0 || sh -cx '! : need root privileges'
|
||||
@@ -29,9 +33,19 @@ deb-checkuid:
|
||||
@test -r debian/$*/usr/share/doc/$*/changelog || \
|
||||
sh -cx 'mv debian/$*/usr/share/doc/$*/changelog.Debian \
|
||||
debian/$*/usr/share/doc/$*/changelog'
|
||||
@test -s debian/$*/usr/share/doc/$*/changelog || \
|
||||
sh -cx 'rm -f debian/$*/usr/share/doc/$*/changelog'
|
||||
@gzip -9 debian/$*/usr/share/doc/$*/changelog*
|
||||
%.deb-docs-docs:
|
||||
@for i in `cat debian/$*.docs 2>/dev/null || :`; do \
|
||||
if test -d $$i; then \
|
||||
sh -cx "install -d -m0755 debian/$*/usr/share/doc/$*/$${i##*/}" && \
|
||||
for j in $$i/*; do \
|
||||
sh -cx "install -m0644 $$j \
|
||||
debian/$*/usr/share/doc/$*/$${i##*/}/" || exit 1; \
|
||||
done || exit 1; \
|
||||
continue; \
|
||||
fi; \
|
||||
sh -cx "install -m0644 $$i debian/$*/usr/share/doc/$*/" || exit 1; \
|
||||
done
|
||||
@test ! -r debian/$*.README.Debian || \
|
||||
@@ -58,13 +72,13 @@ deb-checkuid:
|
||||
@rm -rf debian/$*/DEBIAN
|
||||
: debian/$*/DEBIAN/
|
||||
@install -d -m0755 debian/$*/DEBIAN
|
||||
@for i in conffiles shlibs; do \
|
||||
@for i in conffiles shlibs templates; do \
|
||||
test ! -r debian/$*.$$i || \
|
||||
sh -cx "install -m0644 debian/$*.$$i debian/$*/DEBIAN/$$i" \
|
||||
|| exit 1; \
|
||||
done
|
||||
%.deb-DEBIAN-scripts:
|
||||
@for i in preinst prerm postinst postrm; do \
|
||||
@for i in preinst prerm postinst postrm config; do \
|
||||
test ! -r debian/$*.$$i || \
|
||||
sh -cx "install -m0755 debian/$*.$$i debian/$*/DEBIAN/$$i" \
|
||||
|| exit 1; \
|
||||
|
||||
90
debian/postinst
vendored
90
debian/postinst
vendored
@@ -1,90 +0,0 @@
|
||||
#! /bin/sh
|
||||
# postinst script for #PACKAGE#
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <postinst> `configure' <most-recently-configured-version>
|
||||
# * <old-postinst> `abort-upgrade' <new version>
|
||||
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
|
||||
# <new-version>
|
||||
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
|
||||
# <failed-install-package> <version> `removing'
|
||||
# <conflicting-package> <version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
#
|
||||
# quoting from the policy:
|
||||
# Any necessary prompting should almost always be confined to the
|
||||
# post-installation script, and should be protected with a conditional
|
||||
# so that unnecessary prompting doesn't happen if a package's
|
||||
# installation fails and the `postinst' is called with `abort-upgrade',
|
||||
# `abort-remove' or `abort-deconfigure'.
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
if [ ! -e /etc/dropbear/dropbear_rsa_host_key ]; then
|
||||
if [ -f /etc/ssh/ssh_host_rsa_key ]; then
|
||||
echo "Converting existing OpenSSH RSA host key to Dropbear format."
|
||||
/usr/bin/dropbearconvert openssh dropbear /etc/ssh/ssh_host_rsa_key /etc/dropbear/dropbear_rsa_host_key
|
||||
else
|
||||
echo "Generating Dropbear RSA key. Please wait."
|
||||
/usr/bin/dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
|
||||
fi
|
||||
fi
|
||||
if [ ! -e /etc/dropbear/dropbear_dss_host_key ]; then
|
||||
if [ -f /etc/ssh/ssh_host_dsa_key ]; then
|
||||
echo "Converting existing OpenSSH RSA host key to Dropbear format."
|
||||
/usr/bin/dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key /etc/dropbear/dropbear_dss_host_key
|
||||
else
|
||||
echo "Generating Dropbear DSS key. Please wait."
|
||||
/usr/bin/dropbearkey -t dss -f /etc/dropbear/dropbear_dss_host_key
|
||||
fi
|
||||
fi
|
||||
if [ ! -s /etc/default/dropbear ]; then
|
||||
# check whether OpenSSH seems to be installed.
|
||||
if dpkg -l ssh >/dev/null 2>&1; then
|
||||
echo "OpenSSH appears to be installed. Setting /etc/default/dropbear"
|
||||
echo "so that Dropbear will not start by default. Edit this file to change"
|
||||
echo "this behaviour."
|
||||
echo "# disabled because OpenSSH is installed, change to NO_START=0 to enable Dropbear" > /etc/default/dropbear
|
||||
echo "NO_START=1" >> /etc/default/dropbear
|
||||
fi
|
||||
echo "# the TCP port that Dropbear listens on" >> /etc/default/dropbear
|
||||
echo "DROPBEAR_PORT=22" >> /etc/default/dropbear
|
||||
echo "# any additional arguments for Dropbear" >> /etc/default/dropbear
|
||||
echo "DROPBEAR_EXTRA_ARGS=" >> /etc/default/dropbear
|
||||
echo "# specify an optional banner file containing a message to be" >> /etc/default/dropbear
|
||||
echo "# sent to clients before they connect, such as \"/etc/issue.net\"" >> /etc/default/dropbear
|
||||
echo "DROPBEAR_BANNER=\"\"" >> /etc/default/dropbear
|
||||
echo "# RSA hostkey file (default: /etc/dropbear/dropbear_rsa_host_key" >> /etc/default/dropbear
|
||||
echo "#DROPBEAR_RSAKEY=\"/etc/dropbear/dropbear_rsa_host_key\"" >> /etc/default/dropbear
|
||||
echo "# DSS hostkey file (default: /etc/dropbear/dropbear_dss_host_key" >> /etc/default/dropbear
|
||||
echo "#DROPBEAR_DSSKEY=\"/etc/dropbear/dropbear_dss_host_key\"" >> /etc/default/dropbear
|
||||
fi
|
||||
if [ -e /etc/init.d/dropbear ]; then
|
||||
update-rc.d dropbear defaults >/dev/null
|
||||
/etc/init.d/dropbear restart
|
||||
fi
|
||||
;;
|
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postinst called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
|
||||
|
||||
exit 0
|
||||
|
||||
|
||||
45
debian/postrm
vendored
45
debian/postrm
vendored
@@ -1,45 +0,0 @@
|
||||
#! /bin/sh
|
||||
# postrm script for #PACKAGE#
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <postrm> `remove'
|
||||
# * <postrm> `purge'
|
||||
# * <old-postrm> `upgrade' <new-version>
|
||||
# * <new-postrm> `failed-upgrade' <old-version>
|
||||
# * <new-postrm> `abort-install'
|
||||
# * <new-postrm> `abort-install' <old-version>
|
||||
# * <new-postrm> `abort-upgrade' <old-version>
|
||||
# * <disappearer's-postrm> `disappear' <r>overwrit>r> <new-version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
|
||||
|
||||
case "$1" in
|
||||
purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
||||
if [ "$1" = "purge" ]
|
||||
then
|
||||
if [ -e /etc/dropbear ]; then
|
||||
rm -f /etc/dropbear/dropbear_rsa_host_key
|
||||
rm -f /etc/dropbear/dropbear_dss_host_key
|
||||
rmdir --ignore-fail-on-non-empty /etc/dropbear
|
||||
fi
|
||||
update-rc.d dropbear remove >/dev/null
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postrm called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
104
debian/rules
vendored
Normal file → Executable file
104
debian/rules
vendored
Normal file → Executable file
@@ -1,5 +1,9 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
DPKG_EXPORT_BUILDFLAGS = 1
|
||||
include /usr/share/dpkg/buildflags.mk
|
||||
|
||||
#export DH_OPTIONS
|
||||
DEB_HOST_GNU_TYPE ?=$(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
DEB_BUILD_GNU_TYPE ?=$(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
|
||||
@@ -9,86 +13,88 @@ ifneq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
STRIP =: nostrip
|
||||
endif
|
||||
|
||||
CFLAGS =-Wall -g
|
||||
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
|
||||
CFLAGS +=-O0
|
||||
else
|
||||
CFLAGS +=-O2
|
||||
endif
|
||||
|
||||
CONFFLAGS =
|
||||
CC =gcc
|
||||
ifneq (,$(findstring diet,$(DEB_BUILD_OPTIONS)))
|
||||
CC =diet -v -Os gcc
|
||||
CONFFLAGS =--disable-zlib
|
||||
CC =diet -v -Os gcc -nostdinc
|
||||
endif
|
||||
|
||||
DIR=`pwd`/debian/dropbear
|
||||
DIR =$(shell pwd)/debian/dropbear
|
||||
|
||||
patch: deb-checkdir patch-stamp
|
||||
patch-stamp:
|
||||
# no patches for now
|
||||
# for i in debian/diff/*.diff; do patch -p0 <$$i || exit 1; done
|
||||
for i in `ls -1 debian/diff/*.diff || :`; do \
|
||||
patch -p1 <$$i || exit 1; \
|
||||
done
|
||||
touch patch-stamp
|
||||
|
||||
config.status: patch-stamp configure
|
||||
CFLAGS="$(CFLAGS)"' -DSFTPSERVER_PATH="\"/usr/lib/sftp-server\""' \
|
||||
./configure --host="$(DEB_HOST_GNU_TYPE)" \
|
||||
--build="$(DEB_BUILD_GNU_TYPE)" --prefix=/usr \
|
||||
--mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info
|
||||
CC='$(CC)' \
|
||||
CFLAGS='$(CFLAGS)'' -DSFTPSERVER_PATH="\"/usr/lib/sftp-server\""' \
|
||||
./configure --host='$(DEB_HOST_GNU_TYPE)' \
|
||||
--build='$(DEB_BUILD_GNU_TYPE)' --prefix=/usr \
|
||||
--mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info \
|
||||
$(CONFFLAGS)
|
||||
|
||||
build: deb-checkdir build-stamp
|
||||
build-stamp: config.status
|
||||
$(MAKE) CC="$(CC)" LD="$(CC)"
|
||||
$(MAKE) CC='$(CC)' LD='$(CC)'
|
||||
touch build-stamp
|
||||
|
||||
clean: deb-checkdir deb-checkuid
|
||||
-$(MAKE) distclean
|
||||
# test ! -e patch-stamp || \
|
||||
# for i in debian/diff/*.diff; do patch -p0 -R <$$i; done
|
||||
test ! -r Makefile || $(MAKE) distclean
|
||||
rm -f libtomcrypt/Makefile libtommath/Makefile
|
||||
test ! -e patch-stamp || \
|
||||
for i in `ls -1r debian/diff/*.diff || :`; do \
|
||||
patch -p1 -R <$$i; \
|
||||
done
|
||||
rm -f patch-stamp build-stamp config.log config.status
|
||||
rm -rf "$(DIR)"
|
||||
rm -rf '$(DIR)'
|
||||
rm -f debian/files debian/substvars debian/copyright changelog
|
||||
|
||||
install: deb-checkdir deb-checkuid build-stamp
|
||||
rm -rf "$(DIR)"
|
||||
install -d -m0755 "$(DIR)"/etc/dropbear
|
||||
rm -rf '$(DIR)'
|
||||
install -d -m0755 '$(DIR)'/etc/dropbear
|
||||
# programs
|
||||
install -d -m0755 "$(DIR)"/usr/sbin
|
||||
install -m0755 dropbear "$(DIR)"/usr/sbin/dropbear
|
||||
install -d -m0755 "$(DIR)"/usr/bin
|
||||
install -m0755 dbclient "$(DIR)"/usr/bin/dbclient
|
||||
install -m0755 dropbearkey "$(DIR)"/usr/bin/dropbearkey
|
||||
install -d -m0755 "$(DIR)"/usr/lib/dropbear
|
||||
install -d -m0755 '$(DIR)'/usr/sbin
|
||||
install -m0755 dropbear '$(DIR)'/usr/sbin/dropbear
|
||||
install -d -m0755 '$(DIR)'/usr/bin
|
||||
install -m0755 dbclient '$(DIR)'/usr/bin/dbclient
|
||||
install -m0755 dropbearkey '$(DIR)'/usr/bin/dropbearkey
|
||||
install -d -m0755 '$(DIR)'/usr/lib/dropbear
|
||||
install -m0755 dropbearconvert \
|
||||
"$(DIR)"/usr/lib/dropbear/dropbearconvert
|
||||
$(STRIP) -R .comment -R .note "$(DIR)"/usr/sbin/* \
|
||||
"$(DIR)"/usr/bin/* "$(DIR)"/usr/lib/dropbear/*
|
||||
'$(DIR)'/usr/lib/dropbear/dropbearconvert
|
||||
$(STRIP) -R .comment -R .note '$(DIR)'/usr/sbin/* \
|
||||
'$(DIR)'/usr/bin/* '$(DIR)'/usr/lib/dropbear/*
|
||||
# init and run scripts
|
||||
install -d -m0755 "$(DIR)"/etc/init.d
|
||||
install -m0755 debian/dropbear.init "$(DIR)"/etc/init.d/dropbear
|
||||
install -m0755 debian/service/run "$(DIR)"/etc/dropbear/run
|
||||
install -d -m0755 "$(DIR)"/etc/dropbear/log
|
||||
install -m0755 debian/service/log "$(DIR)"/etc/dropbear/log/run
|
||||
ln -s /var/log/dropbear "$(DIR)"/etc/dropbear/log/main
|
||||
ln -s /var/run/dropbear "$(DIR)"/etc/dropbear/supervise
|
||||
ln -s /var/run/dropbear.log "$(DIR)"/etc/dropbear/log/supervise
|
||||
install -d -m0755 '$(DIR)'/etc/init.d
|
||||
install -m0755 debian/dropbear.init '$(DIR)'/etc/init.d/dropbear
|
||||
install -m0755 debian/service/run '$(DIR)'/etc/dropbear/run
|
||||
install -d -m0755 '$(DIR)'/etc/dropbear/log
|
||||
install -m0755 debian/service/log '$(DIR)'/etc/dropbear/log/run
|
||||
ln -s /var/log/dropbear '$(DIR)'/etc/dropbear/log/main
|
||||
# man pages
|
||||
install -d -m0755 "$(DIR)"/usr/share/man/man8
|
||||
for i in dropbear.8 dropbearkey.8; do \
|
||||
install -m644 $$i "$(DIR)"/usr/share/man/man8/ || exit 1; \
|
||||
install -d -m0755 '$(DIR)'/usr/share/man/man8
|
||||
install -d -m0755 '$(DIR)'/usr/share/man/man1
|
||||
install -m644 dropbear.8 '$(DIR)'/usr/share/man/man8/
|
||||
for i in dbclient.1 dropbearkey.1 dropbearconvert.1; do \
|
||||
install -m644 $$i '$(DIR)'/usr/share/man/man1/ || exit 1; \
|
||||
done
|
||||
gzip -9 "$(DIR)"/usr/share/man/man8/*.8
|
||||
gzip -9 '$(DIR)'/usr/share/man/man8/*.8
|
||||
gzip -9 '$(DIR)'/usr/share/man/man1/*.1
|
||||
# copyright, changelog
|
||||
cat debian/copyright.in LICENSE >debian/copyright
|
||||
ln -s CHANGES changelog
|
||||
test -r changelog || ln -s CHANGES changelog
|
||||
|
||||
binary-indep:
|
||||
|
||||
binary-arch: install dropbear.deb
|
||||
test "$(CC)" != 'gcc' || \
|
||||
dpkg-shlibdeps "$(DIR)"/usr/sbin/* "$(DIR)"/usr/bin/* \
|
||||
"$(DIR)"/usr/lib/dropbear/*
|
||||
dpkg-gencontrol -isp -pdropbear -P"$(DIR)"
|
||||
dpkg -b "$(DIR)" ..
|
||||
test '$(CC)' != 'gcc' || \
|
||||
dpkg-shlibdeps '$(DIR)'/usr/sbin/* '$(DIR)'/usr/bin/* \
|
||||
'$(DIR)'/usr/lib/dropbear/*
|
||||
dpkg-gencontrol -isp -pdropbear -P'$(DIR)'
|
||||
dpkg -b '$(DIR)' ..
|
||||
|
||||
binary: binary-arch binary-indep
|
||||
|
||||
|
||||
34
debug.h
34
debug.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
#ifndef DROPBEAR_DEBUG_H_
|
||||
#define DROPBEAR_DEBUG_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
@@ -33,21 +33,15 @@
|
||||
* etc. Don't use this normally, it might cause problems */
|
||||
/* #define DEBUG_VALGRIND */
|
||||
|
||||
/* Define this to print trace statements - very verbose */
|
||||
/* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
|
||||
* since the printing does not sanitise strings etc */
|
||||
/* #define DEBUG_TRACE */
|
||||
|
||||
/* All functions writing to the cleartext payload buffer call
|
||||
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
|
||||
* attempting to track down a problem */
|
||||
#define CHECKCLEARTOWRITE() assert(ses.writepayload->len == 0 && \
|
||||
ses.writepayload->pos == 0)
|
||||
/*#define CHECKCLEARTOWRITE() assert(ses.writepayload->len == 0 && \
|
||||
ses.writepayload->pos == 0)*/
|
||||
|
||||
/* 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.
|
||||
* It's useful to run dropbear -F, so you don't fork as much */
|
||||
/*#define DEBUG_FORKGPROF*/
|
||||
#ifndef CHECKCLEARTOWRITE
|
||||
#define CHECKCLEARTOWRITE()
|
||||
#endif
|
||||
|
||||
/* A couple of flags, not usually useful, and mightn't do anything */
|
||||
|
||||
@@ -55,12 +49,22 @@
|
||||
/*#define DEBUG_RSA*/
|
||||
|
||||
/* you don't need to touch this block */
|
||||
#ifdef DEBUG_TRACE
|
||||
#define TRACE(X) (dropbear_trace X)
|
||||
#if DEBUG_TRACE
|
||||
extern int debug_trace;
|
||||
#define TRACE(X) dropbear_trace X;
|
||||
#define TRACE2(X) dropbear_trace2 X;
|
||||
#else /*DEBUG_TRACE*/
|
||||
#define TRACE(X)
|
||||
#define TRACE2(X)
|
||||
#endif /*DEBUG_TRACE*/
|
||||
|
||||
/* To debug with GDB it is easier to run with no forking of child processes.
|
||||
You will need to pass "-F" as well. */
|
||||
#ifndef DEBUG_NOFORK
|
||||
#define DEBUG_NOFORK 0
|
||||
#endif
|
||||
|
||||
|
||||
/* For testing as non-root on shadowed systems, include the crypt of a password
|
||||
* here. You can then log in as any user with this password. Ensure that you
|
||||
* make your own password, and are careful about using this. This will also
|
||||
|
||||
314
default_options.h
Normal file
314
default_options.h
Normal file
@@ -0,0 +1,314 @@
|
||||
#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"
|
||||
#define ED25519_PRIV_FILENAME "/etc/dropbear/dropbear_ed25519_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 0
|
||||
|
||||
/* 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_AES256 1
|
||||
#define DROPBEAR_3DES 0
|
||||
#define DROPBEAR_TWOFISH256 0
|
||||
#define DROPBEAR_TWOFISH128 0
|
||||
|
||||
/* Enable Chacha20-Poly1305 authenticated encryption mode. This is
|
||||
* generally faster than AES256 on CPU w/o dedicated AES instructions,
|
||||
* having the same key size. Recommended.
|
||||
* Compiling in will add ~5,5kB to binary size on x86-64 */
|
||||
#define DROPBEAR_CHACHA20POLY1305 1
|
||||
|
||||
/* Enable "Counter Mode" for ciphers. Recommended. */
|
||||
#define DROPBEAR_ENABLE_CTR_MODE 1
|
||||
|
||||
/* Enable CBC mode for ciphers. This has security issues though
|
||||
may be required for compatibility with old implementations */
|
||||
#define DROPBEAR_ENABLE_CBC_MODE 0
|
||||
|
||||
/* Enable "Galois/Counter Mode" for ciphers. This authenticated
|
||||
* encryption mode is combination of CTR mode and GHASH. Recommended
|
||||
* for security and forwards compatibility, but slower than CTR on
|
||||
* CPU w/o dedicated AES/GHASH instructions.
|
||||
* Compiling in will add ~6kB to binary size on x86-64 */
|
||||
#define DROPBEAR_ENABLE_GCM_MODE 0
|
||||
|
||||
/* Message integrity. sha2-256 is recommended as a default,
|
||||
sha1 for compatibility */
|
||||
#define DROPBEAR_SHA1_HMAC 1
|
||||
#define DROPBEAR_SHA2_256_HMAC 1
|
||||
#define DROPBEAR_SHA1_96_HMAC 0
|
||||
|
||||
/* 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
|
||||
/* Ed25519 is faster than ECDSA. Compiling in Ed25519 code increases
|
||||
binary size - around 7,5kB on x86-64 */
|
||||
#define DROPBEAR_ED25519 1
|
||||
|
||||
/* RSA must be >=1024 */
|
||||
#define DROPBEAR_DEFAULT_RSA_SIZE 2048
|
||||
/* DSS is always 1024 */
|
||||
/* ECDSA defaults to largest size configured, usually 521 */
|
||||
/* Ed25519 is always 256 */
|
||||
|
||||
/* 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 ~2,5kB 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 1
|
||||
#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_ */
|
||||
97
dh_groups.c
Normal file
97
dh_groups.c
Normal file
@@ -0,0 +1,97 @@
|
||||
#include "options.h"
|
||||
#include "dh_groups.h"
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
|
||||
#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;
|
||||
|
||||
#endif /* DROPBEAR_NORMAL_DH */
|
||||
26
dh_groups.h
Normal file
26
dh_groups.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef DROPBEAR_DH_GROUPS_H
|
||||
#define DROPBEAR_DH_GROUPS_H
|
||||
#include "options.h"
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
|
||||
#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 /* DROPBEAR_NORMAL_DH */
|
||||
|
||||
#endif
|
||||
202
dropbear.8
Normal file
202
dropbear.8
Normal file
@@ -0,0 +1,202 @@
|
||||
.TH dropbear 8
|
||||
.SH NAME
|
||||
dropbear \- lightweight SSH server
|
||||
.SH SYNOPSIS
|
||||
.B dropbear
|
||||
[\fIflag arguments\fR] [\-b
|
||||
.I banner\fR]
|
||||
[\-r
|
||||
.I hostkeyfile\fR] [\-p [\fIaddress\fR:]\fIport\fR]
|
||||
.SH DESCRIPTION
|
||||
.B dropbear
|
||||
is a small SSH server
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-b \fIbanner
|
||||
bannerfile.
|
||||
Display the contents of the file
|
||||
.I banner
|
||||
before user login (default: none).
|
||||
.TP
|
||||
.B \-r \fIhostkey
|
||||
Use the contents of the file
|
||||
.I hostkey
|
||||
for the SSH hostkey.
|
||||
This file is generated with
|
||||
.BR dropbearkey (1)
|
||||
or automatically with the '-R' option. See "Host Key Files" below.
|
||||
.TP
|
||||
.B \-R
|
||||
Generate hostkeys automatically. See "Host Key Files" below.
|
||||
.TP
|
||||
.B \-F
|
||||
Don't fork into background.
|
||||
.TP
|
||||
.B \-E
|
||||
Log to standard error rather than syslog.
|
||||
.TP
|
||||
.B \-m
|
||||
Don't display the message of the day on login.
|
||||
.TP
|
||||
.B \-w
|
||||
Disallow root logins.
|
||||
.TP
|
||||
.B \-s
|
||||
Disable password logins.
|
||||
.TP
|
||||
.B \-g
|
||||
Disable password logins for root.
|
||||
.TP
|
||||
.B \-j
|
||||
Disable local port forwarding.
|
||||
.TP
|
||||
.B \-k
|
||||
Disable remote port forwarding.
|
||||
.TP
|
||||
.B \-p\fR [\fIaddress\fR:]\fIport
|
||||
Listen on specified
|
||||
.I address
|
||||
and TCP
|
||||
.I port.
|
||||
If just a port is given listen
|
||||
on all addresses.
|
||||
up to 10 can be specified (default 22 if none specified).
|
||||
.TP
|
||||
.B \-i
|
||||
Service program mode.
|
||||
Use this option to run
|
||||
.B dropbear
|
||||
under TCP/IP servers like inetd, tcpsvd, or tcpserver.
|
||||
In program mode the \-F option is implied, and \-p options are ignored.
|
||||
.TP
|
||||
.B \-P \fIpidfile
|
||||
Specify a pidfile to create when running as a daemon. If not specified, the
|
||||
default is /var/run/dropbear.pid
|
||||
.TP
|
||||
.B \-a
|
||||
Allow remote hosts to connect to forwarded ports.
|
||||
.TP
|
||||
.B \-W \fIwindowsize
|
||||
Specify the per-channel receive window buffer size. Increasing this
|
||||
may improve network performance at the expense of memory use. Use -h to see the
|
||||
default buffer size.
|
||||
.TP
|
||||
.B \-K \fItimeout_seconds
|
||||
Ensure that traffic is transmitted at a certain interval in seconds. This is
|
||||
useful for working around firewalls or routers that drop connections after
|
||||
a certain period of inactivity. The trade-off is that a session may be
|
||||
closed if there is a temporary lapse of network connectivity. A setting
|
||||
if 0 disables keepalives. If no response is received for 3 consecutive keepalives the connection will be closed.
|
||||
.TP
|
||||
.B \-I \fIidle_timeout
|
||||
Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
|
||||
.TP
|
||||
.B \-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
|
||||
Print the version
|
||||
|
||||
.SH FILES
|
||||
|
||||
.TP
|
||||
Authorized Keys
|
||||
|
||||
~/.ssh/authorized_keys can be set up to allow remote login with a RSA,
|
||||
ECDSA, Ed25519 or DSS
|
||||
key. Each line is of the form
|
||||
.TP
|
||||
[restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment]
|
||||
|
||||
and can be extracted from a Dropbear private host key with "dropbearkey -y". This is the same format as used by OpenSSH, though the restrictions are a subset (keys with unknown restrictions are ignored).
|
||||
Restrictions are comma separated, with double quotes around spaces in arguments.
|
||||
Available restrictions are:
|
||||
|
||||
.TP
|
||||
.B no-port-forwarding
|
||||
Don't allow port forwarding for this connection
|
||||
|
||||
.TP
|
||||
.B no-agent-forwarding
|
||||
Don't allow agent forwarding for this connection
|
||||
|
||||
.TP
|
||||
.B no-X11-forwarding
|
||||
Don't allow X11 forwarding for this connection
|
||||
|
||||
.TP
|
||||
.B no-pty
|
||||
Disable PTY allocation. Note that a user can still obtain most of the
|
||||
same functionality with other means even if no-pty is set.
|
||||
|
||||
.TP
|
||||
.B command=\fR"\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
|
||||
writable by the user, otherwise Dropbear will not allow a login using public
|
||||
key authentication.
|
||||
|
||||
.TP
|
||||
Host Key Files
|
||||
|
||||
Host key files are read at startup from a standard location, by default
|
||||
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key,
|
||||
/etc/dropbear/dropbear_ecdsa_host_key and /etc/dropbear/dropbear_ed25519_host_key
|
||||
|
||||
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
|
||||
connection is established. This had the benefit that the system /dev/urandom
|
||||
random number source has a better chance of being securely seeded.
|
||||
|
||||
.TP
|
||||
Message Of The Day
|
||||
|
||||
By default the file /etc/motd will be printed for any login shell (unless
|
||||
disabled at compile-time). This can also be disabled per-user
|
||||
by creating a file ~/.hushlogin .
|
||||
|
||||
.SH ENVIRONMENT VARIABLES
|
||||
Dropbear sets the standard variables USER, LOGNAME, HOME, SHELL, PATH, and TERM.
|
||||
|
||||
The variables below are set for sessions as appropriate.
|
||||
|
||||
.TP
|
||||
.B SSH_TTY
|
||||
This is set to the allocated TTY if a PTY was used.
|
||||
|
||||
.TP
|
||||
.B SSH_CONNECTION
|
||||
Contains "<remote_ip> <remote_port> <local_ip> <local_port>".
|
||||
|
||||
.TP
|
||||
.B DISPLAY
|
||||
Set X11 forwarding is used.
|
||||
|
||||
.TP
|
||||
.B SSH_ORIGINAL_COMMAND
|
||||
If a 'command=' authorized_keys option was used, the original command is specified
|
||||
in this variable. If a shell was requested this is set to an empty value.
|
||||
|
||||
.TP
|
||||
.B SSH_AUTH_SOCK
|
||||
Set to a forwarded ssh-agent connection.
|
||||
|
||||
.SH NOTES
|
||||
Dropbear only supports SSH protocol version 2.
|
||||
|
||||
.SH AUTHOR
|
||||
Matt Johnston (matt@ucc.asn.au).
|
||||
.br
|
||||
Gerrit Pape (pape@smarden.org) wrote this manual page.
|
||||
.SH SEE ALSO
|
||||
dropbearkey(1), dbclient(1), dropbearconvert(1)
|
||||
.P
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
8
dropbear_lint.sh
Executable file
8
dropbear_lint.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
EXITCODE=0
|
||||
|
||||
# #ifdef instead of #if
|
||||
grep '#ifdef DROPBEAR' -I *.c *.h && EXITCODE=1
|
||||
|
||||
exit $EXITCODE
|
||||
50
dropbearconvert.1
Normal file
50
dropbearconvert.1
Normal file
@@ -0,0 +1,50 @@
|
||||
.TH dropbearconvert 1
|
||||
.SH NAME
|
||||
dropbearconvert \- convert between Dropbear and OpenSSH private key formats
|
||||
.SH SYNOPSIS
|
||||
.B dropbearconvert
|
||||
.I input_type
|
||||
.I output_type
|
||||
.I input_file
|
||||
.I output_file
|
||||
.SH DESCRIPTION
|
||||
.B Dropbear
|
||||
and
|
||||
.B OpenSSH
|
||||
SSH implementations have different private key formats.
|
||||
.B dropbearconvert
|
||||
can convert between the two.
|
||||
.P
|
||||
Dropbear uses the same SSH public key format as OpenSSH, it can be extracted
|
||||
from a private key by using
|
||||
.B dropbearkey \-y
|
||||
.P
|
||||
Encrypted private keys are not supported, use ssh-keygen(1) to decrypt them
|
||||
first.
|
||||
.SH ARGUMENTS
|
||||
.TP
|
||||
.I input_type
|
||||
Either
|
||||
.I dropbear
|
||||
or
|
||||
.I openssh
|
||||
.TP
|
||||
.I output_type
|
||||
Either
|
||||
.I dropbear
|
||||
or
|
||||
.I openssh
|
||||
.TP
|
||||
.I input_file
|
||||
An existing Dropbear or OpenSSH private key file
|
||||
.TP
|
||||
.I output_file
|
||||
The path to write the converted private key file. For client authentication ~/.ssh/id_dropbear is loaded by default
|
||||
.SH EXAMPLE
|
||||
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_dropbear
|
||||
.SH AUTHOR
|
||||
Matt Johnston (matt@ucc.asn.au).
|
||||
.SH SEE ALSO
|
||||
dropbearkey(1), ssh-keygen(1)
|
||||
.P
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "keyimport.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
|
||||
static int do_convert(int intype, const char* infile, int outtype,
|
||||
@@ -51,8 +53,8 @@ static void printhelp(char * progname) {
|
||||
progname);
|
||||
}
|
||||
|
||||
#if defined(DBMULTI_dropbearconvert) || !defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_dropbearconvert) && defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_dropbearconvert) || !DROPBEAR_MULTI
|
||||
#if defined(DBMULTI_dropbearconvert) && DROPBEAR_MULTI
|
||||
int dropbearconvert_main(int argc, char ** argv) {
|
||||
#else
|
||||
int main(int argc, char ** argv) {
|
||||
@@ -62,6 +64,14 @@ int main(int argc, char ** argv) {
|
||||
const char* infile;
|
||||
const char* outfile;
|
||||
|
||||
crypto_init();
|
||||
seedrandom();
|
||||
|
||||
#if DEBUG_TRACE
|
||||
/* It's hard for it to get in the way _too_ much */
|
||||
debug_trace = 1;
|
||||
#endif
|
||||
|
||||
/* get the commandline options */
|
||||
if (argc != 5) {
|
||||
fprintf(stderr, "All arguments must be specified\n");
|
||||
@@ -106,7 +116,7 @@ static int do_convert(int intype, const char* infile, int outtype,
|
||||
const char* outfile) {
|
||||
|
||||
sign_key * key = NULL;
|
||||
char * keytype = NULL;
|
||||
const char * keytype = NULL;
|
||||
int ret = 1;
|
||||
|
||||
key = import_read(infile, NULL, intype);
|
||||
@@ -116,16 +126,7 @@ static int do_convert(int intype, const char* infile, int outtype,
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (key->rsakey != NULL) {
|
||||
keytype = "RSA";
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (key->dsskey != NULL) {
|
||||
keytype = "DSS";
|
||||
}
|
||||
#endif
|
||||
keytype = signkey_name_from_type(key->type, NULL);
|
||||
|
||||
fprintf(stderr, "Key is a %s key\n", keytype);
|
||||
|
||||
|
||||
61
dropbearkey.1
Normal file
61
dropbearkey.1
Normal file
@@ -0,0 +1,61 @@
|
||||
.TH dropbearkey 1
|
||||
.SH NAME
|
||||
dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
|
||||
.SH SYNOPSIS
|
||||
.B dropbearkey
|
||||
\-t
|
||||
.I type
|
||||
\-f
|
||||
.I file
|
||||
[\-s
|
||||
.IR bits ]
|
||||
[\-y]
|
||||
.SH DESCRIPTION
|
||||
.B dropbearkey
|
||||
generates a
|
||||
\fIRSA\fR, \fIDSS\fR, \fIECDSA\fR, or \fIEd25519\fR
|
||||
format SSH private key, and saves it to a file for the use with the
|
||||
Dropbear client or server.
|
||||
Note that
|
||||
some SSH implementations
|
||||
use the term "DSA" rather than "DSS", they mean the same thing.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-t \fItype
|
||||
Type of key to generate.
|
||||
Must be one of
|
||||
.I rsa
|
||||
.I ecdsa
|
||||
.I ed25519
|
||||
or
|
||||
.IR dss .
|
||||
.TP
|
||||
.B \-f \fIfile
|
||||
Write the secret key to the file
|
||||
\fIfile\fR. For client authentication ~/.ssh/id_dropbear is loaded by default
|
||||
.TP
|
||||
.B \-s \fIbits
|
||||
Set the key size to
|
||||
.I bits
|
||||
bits, should be multiple of 8 (optional).
|
||||
.TP
|
||||
.B \-y
|
||||
Just print the publickey and fingerprint for the private key in \fIfile\fR.
|
||||
.SH NOTES
|
||||
The program dropbearconvert(1) can be used to convert between Dropbear and OpenSSH key formats.
|
||||
.P
|
||||
Dropbear does not support encrypted keys.
|
||||
.SH EXAMPLE
|
||||
generate a host-key:
|
||||
# dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
|
||||
|
||||
extract a public key suitable for authorized_keys from private key:
|
||||
# dropbearkey -y -f id_rsa | grep "^ssh-rsa " >> authorized_keys
|
||||
.SH AUTHOR
|
||||
Matt Johnston (matt@ucc.asn.au).
|
||||
.br
|
||||
Gerrit Pape (pape@smarden.org) wrote this manual page.
|
||||
.SH SEE ALSO
|
||||
dropbear(8), dbclient(1), dropbearconvert(1)
|
||||
.P
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
276
dropbearkey.c
276
dropbearkey.c
@@ -23,7 +23,7 @@
|
||||
* SOFTWARE. */
|
||||
|
||||
/* The format of the keyfiles is basically a raw dump of the buffer. Data types
|
||||
* are specified in the transport draft - string is a 32-bit len then the
|
||||
* are specified in the transport rfc 4253 - string is a 32-bit len then the
|
||||
* non-null-terminated string, mp_int is a 32-bit len then the bignum data.
|
||||
* The actual functions are buf_put_rsa_priv_key() and buf_put_dss_priv_key()
|
||||
|
||||
@@ -43,6 +43,10 @@
|
||||
* mp_int y
|
||||
* mp_int x
|
||||
*
|
||||
* Ed25519:
|
||||
* string "ssh-ed25519"
|
||||
* string k (32 bytes) + A (32 bytes)
|
||||
*
|
||||
*/
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
@@ -51,53 +55,115 @@
|
||||
|
||||
#include "genrsa.h"
|
||||
#include "gendss.h"
|
||||
#include "gened25519.h"
|
||||
#include "ecdsa.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "dbrandom.h"
|
||||
#include "gensignkey.h"
|
||||
|
||||
static void printhelp(char * progname);
|
||||
|
||||
#define RSA_SIZE (1024/8) /* 1024 bit */
|
||||
#define DSS_SIZE (1024/8) /* 1024 bit */
|
||||
|
||||
static void buf_writefile(buffer * buf, const char * filename);
|
||||
static void printpubkey(sign_key * key, int keytype);
|
||||
static void justprintpub(const char* filename);
|
||||
static int printpubfile(const char* filename);
|
||||
|
||||
/* Print a help message */
|
||||
static void printhelp(char * progname) {
|
||||
|
||||
fprintf(stderr, "Usage: %s -t <type> -f <filename> [-s bits]\n"
|
||||
"Options are:\n"
|
||||
"-t type Type of key to generate. One of:\n"
|
||||
#ifdef DROPBEAR_RSA
|
||||
#if DROPBEAR_RSA
|
||||
" rsa\n"
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
#if DROPBEAR_DSS
|
||||
" dss\n"
|
||||
#endif
|
||||
"-f filename Use filename for the secret key\n"
|
||||
#if DROPBEAR_ECDSA
|
||||
" ecdsa\n"
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
" ed25519\n"
|
||||
#endif
|
||||
"-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"
|
||||
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n",
|
||||
progname);
|
||||
#if DROPBEAR_DSS
|
||||
" DSS has a fixed size of 1024 bits\n"
|
||||
#endif
|
||||
#if DROPBEAR_ECDSA
|
||||
" ECDSA has sizes "
|
||||
#if DROPBEAR_ECC_256
|
||||
"256 "
|
||||
#endif
|
||||
#if DROPBEAR_ECC_384
|
||||
"384 "
|
||||
#endif
|
||||
#if DROPBEAR_ECC_521
|
||||
"521 "
|
||||
#endif
|
||||
"\n"
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
" Ed25519 has a fixed size of 256 bits\n"
|
||||
#endif
|
||||
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
|
||||
#if DEBUG_TRACE
|
||||
"-v verbose\n"
|
||||
#endif
|
||||
,progname);
|
||||
}
|
||||
|
||||
#if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_dropbearkey) && defined(DROPBEAR_MULTI)
|
||||
/* fails fatally */
|
||||
static void check_signkey_bits(enum signkey_type type, int bits)
|
||||
{
|
||||
switch (type) {
|
||||
#if DROPBEAR_ED25519
|
||||
case DROPBEAR_SIGNKEY_ED25519:
|
||||
if (bits != 256) {
|
||||
dropbear_exit("Ed25519 keys have a fixed size of 256 bits\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
|
||||
dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a"
|
||||
" multiple of 8\n");
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if DROPEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
if (bits != 1024) {
|
||||
dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
(void)0; /* quiet, compiler. ecdsa handles checks itself */
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DBMULTI_dropbearkey) || !DROPBEAR_MULTI
|
||||
#if defined(DBMULTI_dropbearkey) && DROPBEAR_MULTI
|
||||
int dropbearkey_main(int argc, char ** argv) {
|
||||
#else
|
||||
int main(int argc, char ** argv) {
|
||||
#endif
|
||||
|
||||
int i;
|
||||
char ** next = 0;
|
||||
sign_key *key = NULL;
|
||||
buffer *buf = NULL;
|
||||
char ** next = NULL;
|
||||
char * filename = NULL;
|
||||
int keytype = -1;
|
||||
enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
|
||||
char * typetext = NULL;
|
||||
char * sizetext = NULL;
|
||||
unsigned int bits;
|
||||
unsigned int keysize;
|
||||
unsigned int bits = 0, genbits;
|
||||
int printpub = 0;
|
||||
|
||||
crypto_init();
|
||||
seedrandom();
|
||||
|
||||
/* get the commandline options */
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i] == NULL) {
|
||||
@@ -127,6 +193,11 @@ int main(int argc, char ** argv) {
|
||||
printhelp(argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
#if DEBUG_TRACE
|
||||
case 'v':
|
||||
debug_trace = 1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
fprintf(stderr, "Unknown argument %s\n", argv[i]);
|
||||
printhelp(argv[0]);
|
||||
@@ -143,8 +214,8 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
|
||||
if (printpub) {
|
||||
justprintpub(filename);
|
||||
/* Not reached */
|
||||
int ret = printpubfile(filename);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
/* check/parse args */
|
||||
@@ -154,21 +225,32 @@ int main(int argc, char ** argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (strlen(typetext) == 3) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (strncmp(typetext, "rsa", 3) == 0) {
|
||||
keytype = DROPBEAR_SIGNKEY_RSA;
|
||||
TRACE(("type is rsa"));
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (strncmp(typetext, "dss", 3) == 0) {
|
||||
keytype = DROPBEAR_SIGNKEY_DSS;
|
||||
TRACE(("type is dss"));
|
||||
}
|
||||
#endif
|
||||
#if DROPBEAR_RSA
|
||||
if (strcmp(typetext, "rsa") == 0)
|
||||
{
|
||||
keytype = DROPBEAR_SIGNKEY_RSA;
|
||||
}
|
||||
if (keytype == -1) {
|
||||
#endif
|
||||
#if DROPBEAR_DSS
|
||||
if (strcmp(typetext, "dss") == 0)
|
||||
{
|
||||
keytype = DROPBEAR_SIGNKEY_DSS;
|
||||
}
|
||||
#endif
|
||||
#if DROPBEAR_ECDSA
|
||||
if (strcmp(typetext, "ecdsa") == 0)
|
||||
{
|
||||
keytype = DROPBEAR_SIGNKEY_ECDSA_KEYGEN;
|
||||
}
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
if (strcmp(typetext, "ed25519") == 0)
|
||||
{
|
||||
keytype = DROPBEAR_SIGNKEY_ED25519;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (keytype == DROPBEAR_SIGNKEY_NONE) {
|
||||
fprintf(stderr, "Unknown key type '%s'\n", typetext);
|
||||
printhelp(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -179,73 +261,28 @@ int main(int argc, char ** argv) {
|
||||
fprintf(stderr, "Bits must be an integer\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
|
||||
fprintf(stderr, "Bits must satisfy 512 <= bits <= 4096, and be a"
|
||||
" multiple of 8\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
keysize = bits / 8;
|
||||
} else {
|
||||
if (keytype == DROPBEAR_SIGNKEY_DSS) {
|
||||
keysize = DSS_SIZE;
|
||||
} else if (keytype == DROPBEAR_SIGNKEY_RSA) {
|
||||
keysize = RSA_SIZE;
|
||||
} else {
|
||||
exit(EXIT_FAILURE); /* not reached */
|
||||
}
|
||||
|
||||
check_signkey_bits(keytype, bits);;
|
||||
}
|
||||
|
||||
|
||||
fprintf(stderr, "Will output %d bit %s secret key to '%s'\n", keysize*8,
|
||||
typetext, filename);
|
||||
|
||||
/* don't want the file readable by others */
|
||||
umask(077);
|
||||
|
||||
/* now we can generate the key */
|
||||
key = new_sign_key();
|
||||
|
||||
fprintf(stderr, "Generating key, this may take a while...\n");
|
||||
switch(keytype) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
key->rsakey = gen_rsa_priv_key(keysize); /* 128 bytes = 1024 bit */
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
key->dsskey = gen_dss_priv_key(keysize); /* 128 bytes = 1024 bit */
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
fprintf(stderr, "Internal error, bad key type\n");
|
||||
exit(EXIT_FAILURE);
|
||||
genbits = signkey_generate_get_bits(keytype, bits);
|
||||
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");
|
||||
}
|
||||
|
||||
buf = buf_new(MAX_PRIVKEY_SIZE);
|
||||
|
||||
buf_put_priv_key(buf, key, keytype);
|
||||
buf_setpos(buf, 0);
|
||||
buf_writefile(buf, filename);
|
||||
|
||||
buf_burn(buf);
|
||||
buf_free(buf);
|
||||
|
||||
printpubkey(key, keytype);
|
||||
|
||||
sign_key_free(key);
|
||||
printpubfile(filename);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void justprintpub(const char* filename) {
|
||||
static int printpubfile(const char* filename) {
|
||||
|
||||
buffer *buf = NULL;
|
||||
sign_key *key = NULL;
|
||||
int keytype;
|
||||
enum signkey_type keytype;
|
||||
int ret;
|
||||
int err = DROPBEAR_FAILURE;
|
||||
|
||||
@@ -275,9 +312,11 @@ out:
|
||||
buf_burn(buf);
|
||||
buf_free(buf);
|
||||
buf = NULL;
|
||||
sign_key_free(key);
|
||||
key = NULL;
|
||||
exit(err);
|
||||
if (key) {
|
||||
sign_key_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void printpubkey(sign_key * key, int keytype) {
|
||||
@@ -289,6 +328,9 @@ static void printpubkey(sign_key * key, int keytype) {
|
||||
const char * typestring = NULL;
|
||||
char *fp = NULL;
|
||||
int len;
|
||||
struct passwd * pw = NULL;
|
||||
char * username = NULL;
|
||||
char hostname[100];
|
||||
|
||||
buf = buf_new(MAX_PUBKEY_SIZE);
|
||||
buf_put_pub_key(buf, key, keytype);
|
||||
@@ -303,45 +345,23 @@ static void printpubkey(sign_key * key, int keytype) {
|
||||
fprintf(stderr, "base64 failed");
|
||||
}
|
||||
|
||||
typestring = signkey_name_from_type(keytype, &err);
|
||||
typestring = signkey_name_from_type(keytype, NULL);
|
||||
|
||||
fp = sign_key_fingerprint(buf_getptr(buf, len), len);
|
||||
|
||||
printf("Public key portion is:\n%s %s\nFingerprint: %s\n",
|
||||
typestring, base64key, fp);
|
||||
/* a user@host comment is informative */
|
||||
username = "";
|
||||
pw = getpwuid(getuid());
|
||||
if (pw) {
|
||||
username = pw->pw_name;
|
||||
}
|
||||
|
||||
gethostname(hostname, sizeof(hostname));
|
||||
hostname[sizeof(hostname)-1] = '\0';
|
||||
|
||||
printf("Public key portion is:\n%s %s %s@%s\nFingerprint: %s\n",
|
||||
typestring, base64key, username, hostname, fp);
|
||||
|
||||
m_free(fp);
|
||||
buf_free(buf);
|
||||
}
|
||||
|
||||
/* Write a buffer to a file specified, failing if the file exists */
|
||||
static void buf_writefile(buffer * buf, const char * filename) {
|
||||
|
||||
int fd;
|
||||
int len;
|
||||
|
||||
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Couldn't create new file %s\n", filename);
|
||||
perror("Reason");
|
||||
buf_burn(buf);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* write the file now */
|
||||
while (buf->pos != buf->len) {
|
||||
len = write(fd, buf_getptr(buf, buf->len - buf->pos),
|
||||
buf->len - buf->pos);
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (len <= 0) {
|
||||
fprintf(stderr, "Failed writing file '%s'\n",filename);
|
||||
perror("Reason");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
buf_incrpos(buf, len);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
259
dss.c
259
dss.c
@@ -28,7 +28,7 @@
|
||||
#include "dss.h"
|
||||
#include "buffer.h"
|
||||
#include "ssh.h"
|
||||
#include "random.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
/* Handle DSS (Digital Signature Standard), aka DSA (D.S. Algorithm),
|
||||
* operations, such as key reading, signing, verification. Key generation
|
||||
@@ -37,21 +37,18 @@
|
||||
* See FIPS186 or the Handbook of Applied Cryptography for details of the
|
||||
* algorithm */
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
#if DROPBEAR_DSS
|
||||
|
||||
/* Load a dss key from a buffer, initialising the values.
|
||||
* The key will have the same format as buf_put_dss_key.
|
||||
* These should be freed with dss_key_free.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_dss_pub_key(buffer* buf, 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"));
|
||||
assert(key != NULL);
|
||||
key->p = m_malloc(sizeof(mp_int));
|
||||
key->q = m_malloc(sizeof(mp_int));
|
||||
key->g = m_malloc(sizeof(mp_int));
|
||||
key->y = m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(key->p, key->q, key->g, key->y, NULL);
|
||||
TRACE(("enter buf_get_dss_pub_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, NULL);
|
||||
key->x = NULL;
|
||||
|
||||
buf_incrpos(buf, 4+SSH_SIGNKEY_DSS_LEN); /* int + "ssh-dss" */
|
||||
@@ -59,72 +56,79 @@ int buf_get_dss_pub_key(buffer* buf, dss_key *key) {
|
||||
|| buf_getmpint(buf, key->q) == DROPBEAR_FAILURE
|
||||
|| buf_getmpint(buf, key->g) == DROPBEAR_FAILURE
|
||||
|| buf_getmpint(buf, key->y) == DROPBEAR_FAILURE) {
|
||||
TRACE(("leave buf_get_dss_pub_key: failed reading mpints"));
|
||||
return DROPBEAR_FAILURE;
|
||||
TRACE(("leave buf_get_dss_pub_key: failed reading mpints"))
|
||||
ret = DROPBEAR_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mp_count_bits(key->p) < MIN_DSS_KEYLEN) {
|
||||
dropbear_log(LOG_WARNING, "DSS key too short");
|
||||
TRACE(("leave buf_get_dss_pub_key: short key"));
|
||||
return DROPBEAR_FAILURE;
|
||||
if (mp_count_bits(key->p) != DSS_P_BITS) {
|
||||
dropbear_log(LOG_WARNING, "Bad DSS p");
|
||||
ret = DROPBEAR_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
TRACE(("leave buf_get_dss_pub_key: success"));
|
||||
return DROPBEAR_SUCCESS;
|
||||
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"))
|
||||
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.
|
||||
* Loads a private dss key from a buffer
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_dss_priv_key(buffer* buf, dss_key *key) {
|
||||
int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
|
||||
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
assert(key != NULL);
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
ret = buf_get_dss_pub_key(buf, key);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
key->x = m_malloc(sizeof(mp_int));
|
||||
m_mp_init(key->x);
|
||||
m_mp_alloc_init_multi(&key->x, NULL);
|
||||
ret = buf_getmpint(buf, key->x);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_mp_free_multi(&key->x, NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Clear and free the memory used by a public or private key */
|
||||
void dss_key_free(dss_key *key) {
|
||||
void dss_key_free(dropbear_dss_key *key) {
|
||||
|
||||
TRACE(("enter dsa_key_free"));
|
||||
TRACE2(("enter dsa_key_free"))
|
||||
if (key == NULL) {
|
||||
TRACE(("enter dsa_key_free: key == NULL"));
|
||||
TRACE2(("enter dsa_key_free: key == NULL"))
|
||||
return;
|
||||
}
|
||||
if (key->p) {
|
||||
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_mp_free_multi(&key->p, &key->q, &key->g, &key->y, &key->x, NULL);
|
||||
m_free(key);
|
||||
TRACE(("leave dsa_key_free"));
|
||||
TRACE2(("leave dsa_key_free"))
|
||||
}
|
||||
|
||||
/* put the dss public key into the buffer in the required format:
|
||||
@@ -135,9 +139,9 @@ void dss_key_free(dss_key *key) {
|
||||
* mpint g
|
||||
* mpint y
|
||||
*/
|
||||
void buf_put_dss_pub_key(buffer* buf, dss_key *key) {
|
||||
void buf_put_dss_pub_key(buffer* buf, const dropbear_dss_key *key) {
|
||||
|
||||
assert(key != NULL);
|
||||
dropbear_assert(key != NULL);
|
||||
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
|
||||
buf_putmpint(buf, key->p);
|
||||
buf_putmpint(buf, key->q);
|
||||
@@ -147,20 +151,18 @@ void buf_put_dss_pub_key(buffer* buf, dss_key *key) {
|
||||
}
|
||||
|
||||
/* Same as buf_put_dss_pub_key, but with the private "x" key appended */
|
||||
void buf_put_dss_priv_key(buffer* buf, dss_key *key) {
|
||||
void buf_put_dss_priv_key(buffer* buf, const dropbear_dss_key *key) {
|
||||
|
||||
assert(key != NULL);
|
||||
dropbear_assert(key != NULL);
|
||||
buf_put_dss_pub_key(buf, key);
|
||||
buf_putmpint(buf, key->x);
|
||||
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
/* Verify a DSS signature (in buf) made on data by the key given.
|
||||
* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
int buf_dss_verify(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf) {
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
hash_state hs;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
@@ -169,10 +171,10 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
DEF_MP_INT(val3);
|
||||
DEF_MP_INT(val4);
|
||||
char * string = NULL;
|
||||
int stringlen;
|
||||
unsigned int stringlen;
|
||||
|
||||
TRACE(("enter buf_dss_verify"));
|
||||
assert(key != NULL);
|
||||
TRACE(("enter buf_dss_verify"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
m_mp_init_multi(&val1, &val2, &val3, &val4, NULL);
|
||||
|
||||
@@ -182,20 +184,32 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
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 */
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, data, len);
|
||||
sha1_process(&hs, data_buf->data, data_buf->len);
|
||||
sha1_done(&hs, msghash);
|
||||
|
||||
/* create the signature - s' and r' are the received signatures in buf */
|
||||
/* w = (s')-1 mod q */
|
||||
/* let val1 = s' */
|
||||
if (mp_read_unsigned_bin(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE)
|
||||
!= MP_OKAY) {
|
||||
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) {
|
||||
TRACE(("verify failed, s' >= q"))
|
||||
goto out;
|
||||
}
|
||||
if (mp_cmp(&val1, key->q) != MP_LT) {
|
||||
TRACE(("verify failed, s' >= q"));
|
||||
if (mp_cmp_d(&val1, 0) != MP_GT) {
|
||||
TRACE(("verify failed, s' <= 0"))
|
||||
goto out;
|
||||
}
|
||||
/* let val2 = w = (s')^-1 mod q*/
|
||||
@@ -205,9 +219,11 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
|
||||
/* u1 = ((SHA(M')w) mod q */
|
||||
/* let val1 = SHA(M') = msghash */
|
||||
if (mp_read_unsigned_bin(&val1, msghash, SHA1_HASH_SIZE) != MP_OKAY) {
|
||||
goto out;
|
||||
}
|
||||
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 */
|
||||
if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {
|
||||
goto out;
|
||||
@@ -215,12 +231,13 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
|
||||
/* u2 = ((r')w) mod q */
|
||||
/* let val1 = r' */
|
||||
if (mp_read_unsigned_bin(&val1, &string[0], SHA1_HASH_SIZE)
|
||||
!= MP_OKAY) {
|
||||
bytes_to_mp(&val1, (const unsigned char*) &string[0], SHA1_HASH_SIZE);
|
||||
if (mp_cmp(&val1, key->q) != MP_LT) {
|
||||
TRACE(("verify failed, r' >= q"))
|
||||
goto out;
|
||||
}
|
||||
if (mp_cmp(&val1, key->q) != MP_LT) {
|
||||
TRACE(("verify failed, r' >= q"));
|
||||
if (mp_cmp_d(&val1, 0) != MP_GT) {
|
||||
TRACE(("verify failed, r' <= 0"))
|
||||
goto out;
|
||||
}
|
||||
/* let val4 = u2 = ((r')w) mod q */
|
||||
@@ -262,32 +279,12 @@ out:
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
/* Sign the data presented with key, writing the signature contents
|
||||
* to the buffer
|
||||
*
|
||||
* When DSS_PROTOK is #defined:
|
||||
* The alternate k generation method is based on the method used in PuTTY.
|
||||
* In particular to avoid being vulnerable to attacks using flaws in random
|
||||
* generation of k, we use the following:
|
||||
*
|
||||
* proto_k = SHA512 ( SHA512(x) || SHA160(message) )
|
||||
* k = proto_k mod q
|
||||
*
|
||||
* Now we aren't relying on the random number generation to protect the private
|
||||
* key x, which is a long term secret */
|
||||
void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
* to the buffer */
|
||||
void buf_put_dss_sign(buffer* buf, const dropbear_dss_key *key, const buffer *data_buf) {
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
unsigned int writelen;
|
||||
unsigned int i;
|
||||
#ifdef DSS_PROTOK
|
||||
unsigned char privkeyhash[SHA512_HASH_SIZE];
|
||||
unsigned char *privkeytmp;
|
||||
unsigned char proto_k[SHA512_HASH_SIZE];
|
||||
DEF_MP_INT(dss_protok);
|
||||
#else
|
||||
unsigned char kbuf[SHA1_HASH_SIZE];
|
||||
#endif
|
||||
size_t written;
|
||||
DEF_MP_INT(dss_k);
|
||||
DEF_MP_INT(dss_m);
|
||||
DEF_MP_INT(dss_temp1);
|
||||
@@ -296,114 +293,86 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
DEF_MP_INT(dss_s);
|
||||
hash_state hs;
|
||||
|
||||
TRACE(("enter buf_put_dss_sign"));
|
||||
assert(key != NULL);
|
||||
TRACE(("enter buf_put_dss_sign"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
/* hash the data */
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, data, len);
|
||||
sha1_process(&hs, data_buf->data, data_buf->len);
|
||||
sha1_done(&hs, msghash);
|
||||
|
||||
m_mp_init_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
|
||||
&dss_m, NULL);
|
||||
#ifdef DSS_PROTOK
|
||||
/* hash the privkey */
|
||||
privkeytmp = mptobytes(key->x, &i);
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs, "the quick brown fox jumped over the lazy dog", 44);
|
||||
sha512_process(&hs, privkeytmp, i);
|
||||
sha512_done(&hs, privkeyhash);
|
||||
m_burn(privkeytmp, i);
|
||||
m_free(privkeytmp);
|
||||
|
||||
/* calculate proto_k */
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs, privkeyhash, SHA512_HASH_SIZE);
|
||||
sha512_process(&hs, msghash, SHA1_HASH_SIZE);
|
||||
sha512_done(&hs, proto_k);
|
||||
|
||||
/* generate k */
|
||||
m_mp_init(&dss_protok);
|
||||
bytestomp(&dss_protok, proto_k, SHA512_HASH_SIZE);
|
||||
mp_mod(&dss_protok, key->q, &dss_k);
|
||||
mp_clear(&dss_protok);
|
||||
m_burn(proto_k, SHA512_HASH_SIZE);
|
||||
#else /* DSS_PROTOK not defined*/
|
||||
do {
|
||||
genrandom(kbuf, SHA1_HASH_SIZE);
|
||||
if (mp_read_unsigned_bin(&dss_k, kbuf, SHA1_HASH_SIZE) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
}
|
||||
} while (mp_cmp(&dss_k, key->q) == MP_GT || mp_cmp_d(&dss_k, 0) != MP_GT);
|
||||
m_burn(kbuf, SHA1_HASH_SIZE);
|
||||
#endif
|
||||
/* the random number generator's input has included the private key which
|
||||
* avoids DSS's problem of private key exposure due to low entropy */
|
||||
gen_random_mpint(key->q, &dss_k);
|
||||
|
||||
/* now generate the actual signature */
|
||||
bytestomp(&dss_m, msghash, SHA1_HASH_SIZE);
|
||||
bytes_to_mp(&dss_m, msghash, SHA1_HASH_SIZE);
|
||||
|
||||
/* g^k mod p */
|
||||
if (mp_exptmod(key->g, &dss_k, key->p, &dss_temp1) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
/* r = (g^k mod p) mod q */
|
||||
if (mp_mod(&dss_temp1, key->q, &dss_r) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
|
||||
/* x*r mod q */
|
||||
if (mp_mulmod(&dss_r, key->x, key->q, &dss_temp1) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
/* (SHA1(M) + xr) mod q) */
|
||||
if (mp_addmod(&dss_m, &dss_temp1, key->q, &dss_temp2) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
|
||||
/* (k^-1) mod q */
|
||||
if (mp_invmod(&dss_k, key->q, &dss_temp1) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
|
||||
/* s = (k^-1(SHA1(M) + xr)) mod q */
|
||||
if (mp_mulmod(&dss_temp1, &dss_temp2, key->q, &dss_s) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
|
||||
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
|
||||
buf_putint(buf, 2*SHA1_HASH_SIZE);
|
||||
|
||||
writelen = mp_unsigned_bin_size(&dss_r);
|
||||
assert(writelen <= SHA1_HASH_SIZE);
|
||||
writelen = mp_ubin_size(&dss_r);
|
||||
dropbear_assert(writelen <= SHA1_HASH_SIZE);
|
||||
/* need to pad to 160 bits with leading zeros */
|
||||
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
|
||||
buf_putbyte(buf, 0);
|
||||
}
|
||||
if (mp_to_unsigned_bin(&dss_r, buf_getwriteptr(buf, writelen))
|
||||
if (mp_to_ubin(&dss_r, buf_getwriteptr(buf, writelen), writelen, &written)
|
||||
!= MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
mp_clear(&dss_r);
|
||||
buf_incrwritepos(buf, writelen);
|
||||
buf_incrwritepos(buf, written);
|
||||
|
||||
writelen = mp_unsigned_bin_size(&dss_s);
|
||||
assert(writelen <= SHA1_HASH_SIZE);
|
||||
writelen = mp_ubin_size(&dss_s);
|
||||
dropbear_assert(writelen <= SHA1_HASH_SIZE);
|
||||
/* need to pad to 160 bits with leading zeros */
|
||||
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
|
||||
buf_putbyte(buf, 0);
|
||||
}
|
||||
if (mp_to_unsigned_bin(&dss_s, buf_getwriteptr(buf, writelen))
|
||||
if (mp_to_ubin(&dss_s, buf_getwriteptr(buf, writelen), writelen, &written)
|
||||
!= MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
mp_clear(&dss_s);
|
||||
buf_incrwritepos(buf, writelen);
|
||||
buf_incrwritepos(buf, written);
|
||||
|
||||
mp_clear_multi(&dss_k, &dss_temp1, &dss_temp1, &dss_r, &dss_s,
|
||||
mp_clear_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
|
||||
&dss_m, NULL);
|
||||
|
||||
/* create the signature to return */
|
||||
|
||||
TRACE(("leave buf_put_dss_sign"));
|
||||
TRACE(("leave buf_put_dss_sign"))
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
36
dss.h
36
dss.h
@@ -22,40 +22,38 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _DSS_H_
|
||||
#define _DSS_H_
|
||||
#ifndef DROPBEAR_DSS_H_
|
||||
#define DROPBEAR_DSS_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
#if DROPBEAR_DSS
|
||||
|
||||
#define DSS_SIGNATURE_SIZE 4+SSH_SIGNKEY_DSS_LEN+4+2*SHA1_HASH_SIZE
|
||||
|
||||
struct DSS_key {
|
||||
typedef struct dropbear_DSS_Key {
|
||||
|
||||
mp_int* p;
|
||||
mp_int* q;
|
||||
mp_int* g;
|
||||
mp_int* y;
|
||||
/* x is the private part */
|
||||
mp_int* x;
|
||||
|
||||
};
|
||||
} dropbear_dss_key;
|
||||
|
||||
typedef struct DSS_key dss_key;
|
||||
#define DSS_P_BITS 1024
|
||||
#define DSS_Q_BITS 160
|
||||
|
||||
void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
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
|
||||
int buf_get_dss_pub_key(buffer* buf, dss_key *key);
|
||||
int buf_get_dss_priv_key(buffer* buf, dss_key *key);
|
||||
void buf_put_dss_pub_key(buffer* buf, dss_key *key);
|
||||
void buf_put_dss_priv_key(buffer* buf, dss_key *key);
|
||||
void dss_key_free(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);
|
||||
void buf_put_dss_pub_key(buffer* buf, const 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);
|
||||
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
#endif /* _DSS_H_ */
|
||||
#endif /* DROPBEAR_DSS_H_ */
|
||||
|
||||
264
ecc.c
Normal file
264
ecc.c
Normal file
@@ -0,0 +1,264 @@
|
||||
#include "includes.h"
|
||||
#include "ecc.h"
|
||||
#include "dbutil.h"
|
||||
#include "bignum.h"
|
||||
|
||||
#if DROPBEAR_ECC
|
||||
|
||||
/* .dp members are filled out by dropbear_ecc_fill_dp() at startup */
|
||||
#if DROPBEAR_ECC_256
|
||||
struct dropbear_ecc_curve ecc_curve_nistp256 = {
|
||||
32, /* .ltc_size */
|
||||
NULL, /* .dp */
|
||||
&sha256_desc, /* .hash_desc */
|
||||
"nistp256" /* .name */
|
||||
};
|
||||
#endif
|
||||
#if DROPBEAR_ECC_384
|
||||
struct dropbear_ecc_curve ecc_curve_nistp384 = {
|
||||
48, /* .ltc_size */
|
||||
NULL, /* .dp */
|
||||
&sha384_desc, /* .hash_desc */
|
||||
"nistp384" /* .name */
|
||||
};
|
||||
#endif
|
||||
#if DROPBEAR_ECC_521
|
||||
struct dropbear_ecc_curve ecc_curve_nistp521 = {
|
||||
66, /* .ltc_size */
|
||||
NULL, /* .dp */
|
||||
&sha512_desc, /* .hash_desc */
|
||||
"nistp521" /* .name */
|
||||
};
|
||||
#endif
|
||||
|
||||
struct dropbear_ecc_curve *dropbear_ecc_curves[] = {
|
||||
#if DROPBEAR_ECC_256
|
||||
&ecc_curve_nistp256,
|
||||
#endif
|
||||
#if DROPBEAR_ECC_384
|
||||
&ecc_curve_nistp384,
|
||||
#endif
|
||||
#if DROPBEAR_ECC_521
|
||||
&ecc_curve_nistp521,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
void dropbear_ecc_fill_dp() {
|
||||
struct dropbear_ecc_curve **curve;
|
||||
/* libtomcrypt guarantees they're ordered by size */
|
||||
const ltc_ecc_set_type *dp = ltc_ecc_sets;
|
||||
for (curve = dropbear_ecc_curves; *curve; curve++) {
|
||||
for (;dp->size > 0; dp++) {
|
||||
if (dp->size == (*curve)->ltc_size) {
|
||||
(*curve)->dp = dp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!(*curve)->dp) {
|
||||
dropbear_exit("Missing ECC params %s", (*curve)->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp) {
|
||||
struct dropbear_ecc_curve **curve = NULL;
|
||||
for (curve = dropbear_ecc_curves; *curve; curve++) {
|
||||
if ((*curve)->dp == dp) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(*curve);
|
||||
return *curve;
|
||||
}
|
||||
|
||||
ecc_key * new_ecc_key(void) {
|
||||
ecc_key *key = m_malloc(sizeof(*key));
|
||||
m_mp_alloc_init_multi((mp_int**)&key->pubkey.x, (mp_int**)&key->pubkey.y,
|
||||
(mp_int**)&key->pubkey.z, (mp_int**)&key->k, NULL);
|
||||
return key;
|
||||
}
|
||||
|
||||
/* Copied from libtomcrypt ecc_import.c (version there is static), modified
|
||||
for different mp_int pointer without LTC_SOURCE */
|
||||
static int ecc_is_point(const ecc_key *key)
|
||||
{
|
||||
mp_int *prime, *b, *t1, *t2;
|
||||
int err;
|
||||
|
||||
m_mp_alloc_init_multi(&prime, &b, &t1, &t2, NULL);
|
||||
|
||||
/* load prime and b */
|
||||
if ((err = mp_read_radix(prime, key->dp->prime, 16)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_read_radix(b, key->dp->B, 16)) != CRYPT_OK) { goto error; }
|
||||
|
||||
/* compute y^2 */
|
||||
if ((err = mp_sqr(key->pubkey.y, t1)) != CRYPT_OK) { goto error; }
|
||||
|
||||
/* compute x^3 */
|
||||
if ((err = mp_sqr(key->pubkey.x, t2)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_mod(t2, prime, t2)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_mul(key->pubkey.x, t2, t2)) != CRYPT_OK) { goto error; }
|
||||
|
||||
/* compute y^2 - x^3 */
|
||||
if ((err = mp_sub(t1, t2, t1)) != CRYPT_OK) { goto error; }
|
||||
|
||||
/* compute y^2 - x^3 + 3x */
|
||||
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_mod(t1, prime, t1)) != CRYPT_OK) { goto error; }
|
||||
while (mp_cmp_d(t1, 0) == LTC_MP_LT) {
|
||||
if ((err = mp_add(t1, prime, t1)) != CRYPT_OK) { goto error; }
|
||||
}
|
||||
while (mp_cmp(t1, prime) != LTC_MP_LT) {
|
||||
if ((err = mp_sub(t1, prime, t1)) != CRYPT_OK) { goto error; }
|
||||
}
|
||||
|
||||
/* compare to b */
|
||||
if (mp_cmp(t1, b) != LTC_MP_EQ) {
|
||||
err = CRYPT_INVALID_PACKET;
|
||||
} else {
|
||||
err = CRYPT_OK;
|
||||
}
|
||||
|
||||
error:
|
||||
mp_clear_multi(prime, b, t1, t2, NULL);
|
||||
m_free(prime);
|
||||
m_free(b);
|
||||
m_free(t1);
|
||||
m_free(t2);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* For the "ephemeral public key octet string" in ECDH (rfc5656 section 4) */
|
||||
void buf_put_ecc_raw_pubkey_string(buffer *buf, ecc_key *key) {
|
||||
unsigned long len = key->dp->size*2 + 1;
|
||||
int err;
|
||||
buf_putint(buf, len);
|
||||
err = ecc_ansi_x963_export(key, buf_getwriteptr(buf, len), &len);
|
||||
if (err != CRYPT_OK) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
buf_incrwritepos(buf, len);
|
||||
}
|
||||
|
||||
/* For the "ephemeral public key octet string" in ECDH (rfc5656 section 4) */
|
||||
ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve) {
|
||||
ecc_key *key = NULL;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
const unsigned int size = curve->dp->size;
|
||||
unsigned char first;
|
||||
|
||||
TRACE(("enter buf_get_ecc_raw_pubkey"))
|
||||
|
||||
buf_setpos(buf, 0);
|
||||
first = buf_getbyte(buf);
|
||||
if (first == 2 || first == 3) {
|
||||
dropbear_log(LOG_WARNING, "Dropbear doesn't support ECC point compression");
|
||||
return NULL;
|
||||
}
|
||||
if (first != 4 || buf->len != 1+2*size) {
|
||||
TRACE(("leave, wrong size"))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key = new_ecc_key();
|
||||
key->dp = curve->dp;
|
||||
|
||||
if (mp_from_ubin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
TRACE(("failed to read x"))
|
||||
goto out;
|
||||
}
|
||||
buf_incrpos(buf, size);
|
||||
|
||||
if (mp_from_ubin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
TRACE(("failed to read y"))
|
||||
goto out;
|
||||
}
|
||||
buf_incrpos(buf, size);
|
||||
|
||||
mp_set(key->pubkey.z, 1);
|
||||
|
||||
if (ecc_is_point(key) != CRYPT_OK) {
|
||||
TRACE(("failed, not a point"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* SEC1 3.2.3.1 Check that Q != 0 */
|
||||
if (mp_cmp_d(key->pubkey.x, 0) == LTC_MP_EQ) {
|
||||
TRACE(("failed, x == 0"))
|
||||
goto out;
|
||||
}
|
||||
if (mp_cmp_d(key->pubkey.y, 0) == LTC_MP_EQ) {
|
||||
TRACE(("failed, y == 0"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
|
||||
out:
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
if (key) {
|
||||
ecc_free(key);
|
||||
m_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
|
||||
}
|
||||
|
||||
/* a modified version of libtomcrypt's "ecc_shared_secret" to output
|
||||
a mp_int instead. */
|
||||
mp_int * dropbear_ecc_shared_secret(ecc_key *public_key, const ecc_key *private_key)
|
||||
{
|
||||
ecc_point *result = NULL;
|
||||
mp_int *prime = NULL, *shared_secret = NULL;
|
||||
int err = DROPBEAR_FAILURE;
|
||||
|
||||
/* type valid? */
|
||||
if (private_key->type != PK_PRIVATE) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (private_key->dp != public_key->dp) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* make new point */
|
||||
result = ltc_ecc_new_point();
|
||||
if (result == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
prime = m_malloc(sizeof(*prime));
|
||||
m_mp_init(prime);
|
||||
|
||||
if (mp_read_radix(prime, (char *)private_key->dp->prime, 16) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
if (ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1) != CRYPT_OK) {
|
||||
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;
|
||||
out:
|
||||
if (err == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
return shared_secret;
|
||||
}
|
||||
|
||||
#endif
|
||||
35
ecc.h
Normal file
35
ecc.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef DROPBEAR_DROPBEAR_ECC_H
|
||||
#define DROPBEAR_DROPBEAR_ECC_H
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
#if DROPBEAR_ECC
|
||||
|
||||
struct dropbear_ecc_curve {
|
||||
int ltc_size; /* to match the byte sizes in ltc_ecc_sets[] */
|
||||
const ltc_ecc_set_type *dp; /* curve domain parameters */
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
extern struct dropbear_ecc_curve ecc_curve_nistp256;
|
||||
extern struct dropbear_ecc_curve ecc_curve_nistp384;
|
||||
extern struct dropbear_ecc_curve ecc_curve_nistp521;
|
||||
extern struct dropbear_ecc_curve *dropbear_ecc_curves[];
|
||||
|
||||
void dropbear_ecc_fill_dp(void);
|
||||
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
|
||||
and private keys */
|
||||
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);
|
||||
int buf_get_ecc_privkey_string(buffer *buf, ecc_key *key);
|
||||
|
||||
mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, const ecc_key *priv_key);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* DROPBEAR_DROPBEAR_ECC_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user