mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 20:30:38 +09:00
Compare commits
650 Commits
libssh-0.7
...
libssh-0.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d66ea0b3b1 | ||
|
|
1d93b94086 | ||
|
|
efc427fdce | ||
|
|
0f64bc78a8 | ||
|
|
2dbb7ff091 | ||
|
|
b77fa93551 | ||
|
|
8ce4004260 | ||
|
|
8c11367410 | ||
|
|
460026459b | ||
|
|
6c87316a9c | ||
|
|
96476f74af | ||
|
|
52b57077de | ||
|
|
2839d48cb8 | ||
|
|
5ea81166bf | ||
|
|
a86d1d335b | ||
|
|
18dd902307 | ||
|
|
d85827f646 | ||
|
|
6e74c6c1dc | ||
|
|
ec6df9896a | ||
|
|
ab7c5c448c | ||
|
|
5871d604cd | ||
|
|
f6fe7488e3 | ||
|
|
24aef4fbf1 | ||
|
|
fbfe002460 | ||
|
|
c7525c056c | ||
|
|
1509693cce | ||
|
|
67ef808a95 | ||
|
|
aeefcd8199 | ||
|
|
9bc050d07d | ||
|
|
c2776f70c1 | ||
|
|
e6020f94bf | ||
|
|
9305762fcd | ||
|
|
e0e0d62a71 | ||
|
|
708f127788 | ||
|
|
dd3d867452 | ||
|
|
5443863723 | ||
|
|
edcdef94ee | ||
|
|
04cc7b769a | ||
|
|
83b43443e5 | ||
|
|
6a077fe750 | ||
|
|
b2a681bd29 | ||
|
|
18077673ac | ||
|
|
25407209b0 | ||
|
|
0e886ba803 | ||
|
|
c8429113fa | ||
|
|
e1d2454dd7 | ||
|
|
ed738bee34 | ||
|
|
12284b75fa | ||
|
|
afa4021ded | ||
|
|
c425082394 | ||
|
|
db9da99a36 | ||
|
|
c3dac948c9 | ||
|
|
c866768da4 | ||
|
|
2b40ad29c0 | ||
|
|
38c53db953 | ||
|
|
c503bb572e | ||
|
|
36a727e656 | ||
|
|
7b9a07c363 | ||
|
|
4b298ca770 | ||
|
|
8e211c0689 | ||
|
|
d25b8fb550 | ||
|
|
f1b36c18f6 | ||
|
|
b3a7e86a4a | ||
|
|
d316390825 | ||
|
|
3141dec632 | ||
|
|
539d7ba249 | ||
|
|
83a46c7756 | ||
|
|
2d90bc9d6b | ||
|
|
de44fdfd35 | ||
|
|
65a5154eff | ||
|
|
613dcc95e6 | ||
|
|
77e1761734 | ||
|
|
e49e4e13f3 | ||
|
|
e73ae60e1a | ||
|
|
584c345451 | ||
|
|
bfbd574098 | ||
|
|
b4462bdea0 | ||
|
|
6b8d1aa836 | ||
|
|
d90b88588f | ||
|
|
6a715b80d6 | ||
|
|
084769b88c | ||
|
|
f4408f38a3 | ||
|
|
6dd9303729 | ||
|
|
a19513b87a | ||
|
|
21962dd154 | ||
|
|
8917b84840 | ||
|
|
4b0fd10a99 | ||
|
|
3350fd7479 | ||
|
|
c98b00a5f4 | ||
|
|
88673b2d1f | ||
|
|
f425ebb098 | ||
|
|
f6284eafd6 | ||
|
|
cf250171de | ||
|
|
a82e24f024 | ||
|
|
60450ef936 | ||
|
|
d11d764c9d | ||
|
|
ac5c90d771 | ||
|
|
14045f516e | ||
|
|
3e70f06fc8 | ||
|
|
a2a6dddacf | ||
|
|
a366bb3b45 | ||
|
|
a4a6017e6e | ||
|
|
e60cb2ee10 | ||
|
|
da0f360478 | ||
|
|
206f3ff895 | ||
|
|
81b4320318 | ||
|
|
bed60f9b84 | ||
|
|
10728f8577 | ||
|
|
72141cae0b | ||
|
|
ec842c3ca3 | ||
|
|
054d2dffc1 | ||
|
|
d971983d5e | ||
|
|
946f8f64ef | ||
|
|
84ac7d1de0 | ||
|
|
f4ddf9df53 | ||
|
|
d7477dc745 | ||
|
|
1444ae5add | ||
|
|
aa95eb1965 | ||
|
|
649a7490a6 | ||
|
|
c089b700c6 | ||
|
|
c8d6445d44 | ||
|
|
d4a4ce4d44 | ||
|
|
7a2624dee4 | ||
|
|
f827833d82 | ||
|
|
6f38e0b771 | ||
|
|
622ff855f5 | ||
|
|
26734a547a | ||
|
|
1ece5a849c | ||
|
|
23accdde1a | ||
|
|
321ec2cb1c | ||
|
|
27711f6a4c | ||
|
|
238202d380 | ||
|
|
8a735d5eb7 | ||
|
|
d038c4dee7 | ||
|
|
ebd76bf347 | ||
|
|
acc1ade74a | ||
|
|
72e4500da9 | ||
|
|
c4f3bf4ffa | ||
|
|
c563ed636a | ||
|
|
f3de2974a9 | ||
|
|
1b8ce5a6ed | ||
|
|
deb7630c67 | ||
|
|
cbd9569b99 | ||
|
|
a45a04ff4d | ||
|
|
7aa496d844 | ||
|
|
bf10a66b5d | ||
|
|
adc817cf13 | ||
|
|
787a649390 | ||
|
|
54690e6cdd | ||
|
|
4e3fb81172 | ||
|
|
6273c409e3 | ||
|
|
7798d39187 | ||
|
|
58ef1e96b8 | ||
|
|
732818ebb2 | ||
|
|
448de134ac | ||
|
|
fd3d8d6496 | ||
|
|
0b90ab102e | ||
|
|
cd3170fcb1 | ||
|
|
9eaf55898e | ||
|
|
10e1e396fc | ||
|
|
c1db283c39 | ||
|
|
6c97122120 | ||
|
|
0dd33d8ed1 | ||
|
|
0db12d7f75 | ||
|
|
c1d8ba47dd | ||
|
|
dc4cc08c3a | ||
|
|
e880cafed0 | ||
|
|
1ae014f52a | ||
|
|
1369559385 | ||
|
|
7ef72ec91f | ||
|
|
b74a184172 | ||
|
|
b50fb638f7 | ||
|
|
e06ae8e096 | ||
|
|
0940b0f29b | ||
|
|
03b05c8a5e | ||
|
|
9e4f9a26d4 | ||
|
|
f5f8c0fc76 | ||
|
|
c4dbe3b863 | ||
|
|
669678119c | ||
|
|
34e7a3cf8c | ||
|
|
1001cbbb99 | ||
|
|
36d52ee205 | ||
|
|
0ad462102a | ||
|
|
c6ee41bff3 | ||
|
|
5012a9c146 | ||
|
|
93781f9d5a | ||
|
|
4550c99222 | ||
|
|
a209f928d2 | ||
|
|
f23dbe6f42 | ||
|
|
974e1831a0 | ||
|
|
963c46e4fb | ||
|
|
32c49ea134 | ||
|
|
a465ea2d49 | ||
|
|
702e9e8ad5 | ||
|
|
250bf37a28 | ||
|
|
952c64b4c0 | ||
|
|
bcaeaf17af | ||
|
|
f4e57a6e22 | ||
|
|
8457580f61 | ||
|
|
f1ff9ae00c | ||
|
|
ed4ea51bb8 | ||
|
|
22a92da30d | ||
|
|
362b20a0bc | ||
|
|
72f6b34dbc | ||
|
|
816234350d | ||
|
|
4aeb0cfd9c | ||
|
|
be414423d7 | ||
|
|
abd1a1f372 | ||
|
|
c705fb6e3b | ||
|
|
1a36aa21ba | ||
|
|
c2f8010b60 | ||
|
|
64985f7bea | ||
|
|
3f562ee586 | ||
|
|
eb796b4bbb | ||
|
|
87b8d232bd | ||
|
|
6f1f8d2bdb | ||
|
|
a95bc8a016 | ||
|
|
f3a19d8c96 | ||
|
|
e005fd310f | ||
|
|
fb2fefb3c6 | ||
|
|
6026fc8036 | ||
|
|
2cc5b5865c | ||
|
|
8d65edb41f | ||
|
|
1247ba3398 | ||
|
|
be22c0d442 | ||
|
|
467d78a442 | ||
|
|
a4aeee972c | ||
|
|
16217454d5 | ||
|
|
7e1e0e5098 | ||
|
|
3fa0e3959c | ||
|
|
dd20253fec | ||
|
|
85ab4ee53a | ||
|
|
25f31760aa | ||
|
|
d11869bdb6 | ||
|
|
81847bf513 | ||
|
|
bba40abc76 | ||
|
|
0c12643466 | ||
|
|
1319d2ceb2 | ||
|
|
cc1f496741 | ||
|
|
963111b836 | ||
|
|
ebcff9fd63 | ||
|
|
25ff1214a4 | ||
|
|
d84b0926f0 | ||
|
|
f19158cadf | ||
|
|
459677e20e | ||
|
|
43bd7b6eee | ||
|
|
d7c47f529f | ||
|
|
2cff66c155 | ||
|
|
78ce67f579 | ||
|
|
2fb8198c48 | ||
|
|
2ea3683347 | ||
|
|
aaeb938ca4 | ||
|
|
ef4a81ea0c | ||
|
|
e9073a6bdb | ||
|
|
9086d5ca33 | ||
|
|
3c65057fad | ||
|
|
f9b1dece41 | ||
|
|
f7a2330de7 | ||
|
|
67b8f3d6df | ||
|
|
b0af812710 | ||
|
|
d13a17a27c | ||
|
|
ddfc36aa56 | ||
|
|
a5997d180d | ||
|
|
51875db70c | ||
|
|
5ad7da7fd2 | ||
|
|
59308bc269 | ||
|
|
fd2ef07f37 | ||
|
|
e19163eabb | ||
|
|
37acd3eca8 | ||
|
|
cc13e85202 | ||
|
|
720739bc2a | ||
|
|
ea99215664 | ||
|
|
c3c492a190 | ||
|
|
778652460f | ||
|
|
5c3b1ee0a4 | ||
|
|
4dec2f989c | ||
|
|
5fdfa8fe44 | ||
|
|
176b92a4f4 | ||
|
|
afc6a4e973 | ||
|
|
53d84abb17 | ||
|
|
dab8985c05 | ||
|
|
0bd6ccc066 | ||
|
|
5c7b8802f2 | ||
|
|
b8e301ade3 | ||
|
|
99c5160cb5 | ||
|
|
110da49504 | ||
|
|
f3754dc072 | ||
|
|
78a3ab2eaa | ||
|
|
4da7985204 | ||
|
|
2a66c38efa | ||
|
|
2e31dffdb7 | ||
|
|
88e43d2502 | ||
|
|
4166bb2a26 | ||
|
|
f818e63f8f | ||
|
|
094aa5eb02 | ||
|
|
5d3ab421e1 | ||
|
|
f8f7989c3d | ||
|
|
b92c499626 | ||
|
|
9fce33a2e3 | ||
|
|
7a65f7f028 | ||
|
|
f525fdb2e1 | ||
|
|
01994ea302 | ||
|
|
c4ddf62f7e | ||
|
|
2ec633f33d | ||
|
|
748d749675 | ||
|
|
77f632a559 | ||
|
|
54165a394a | ||
|
|
16818bd0e4 | ||
|
|
d29d199592 | ||
|
|
17c03005d8 | ||
|
|
509fa8a7b2 | ||
|
|
954da14c15 | ||
|
|
7527876fad | ||
|
|
9d79b7629c | ||
|
|
538f1bc00e | ||
|
|
f0ddde4826 | ||
|
|
d3834f69bc | ||
|
|
f7b8394127 | ||
|
|
72cf2e3ae2 | ||
|
|
164cee66ee | ||
|
|
9003f92e8f | ||
|
|
8d7563a9c3 | ||
|
|
4c4a03f056 | ||
|
|
73d76a2638 | ||
|
|
1c9eb4dfb9 | ||
|
|
94fa1e382f | ||
|
|
2e70077bbc | ||
|
|
2493e962fe | ||
|
|
a9846ccc0d | ||
|
|
7204d2f485 | ||
|
|
6252aab88a | ||
|
|
4c602f2255 | ||
|
|
6803c2f86d | ||
|
|
316ee071cf | ||
|
|
895055ab38 | ||
|
|
de35212789 | ||
|
|
337306600b | ||
|
|
efb7635162 | ||
|
|
8ecd65bcdb | ||
|
|
74d17a6531 | ||
|
|
b9b89ef7c6 | ||
|
|
a4dc74064c | ||
|
|
fa86229673 | ||
|
|
c317d95911 | ||
|
|
380390c4b6 | ||
|
|
e66f370682 | ||
|
|
a5bc81d406 | ||
|
|
2f42296edd | ||
|
|
d9ff44b46e | ||
|
|
c480ac8522 | ||
|
|
a89a67e008 | ||
|
|
a97db12f4f | ||
|
|
14d8e940e6 | ||
|
|
effd7ba13c | ||
|
|
a64ddff3fe | ||
|
|
25384e9558 | ||
|
|
0cb2974bd8 | ||
|
|
87527adada | ||
|
|
0cffb88b80 | ||
|
|
b0c2ca1b66 | ||
|
|
c50f2d1356 | ||
|
|
48e7b098f8 | ||
|
|
5333be5988 | ||
|
|
e4f80bd142 | ||
|
|
abbd6e304a | ||
|
|
7c79b5c154 | ||
|
|
5eb41492c4 | ||
|
|
c78c6c6542 | ||
|
|
d5d8349224 | ||
|
|
67a2ba6f99 | ||
|
|
79437fa0c9 | ||
|
|
76ba2b0055 | ||
|
|
68b7ca6e92 | ||
|
|
c165c396de | ||
|
|
f21ddefedb | ||
|
|
0cf1c85542 | ||
|
|
57550e6211 | ||
|
|
34bdc1ca78 | ||
|
|
5f202d7ffa | ||
|
|
c3a8b5009f | ||
|
|
9ef7e90821 | ||
|
|
38cb19268a | ||
|
|
72fdb4867e | ||
|
|
9dc650b7fb | ||
|
|
3ec8babfaf | ||
|
|
462c7726c3 | ||
|
|
e0fa48d2ed | ||
|
|
73e8277072 | ||
|
|
c7e9dc2ee3 | ||
|
|
166b9f7709 | ||
|
|
de369b46b1 | ||
|
|
043560d7dd | ||
|
|
4b33c6bb97 | ||
|
|
2f6a866373 | ||
|
|
f8ef200e76 | ||
|
|
3daf1760a1 | ||
|
|
2dff359a33 | ||
|
|
3341f49a49 | ||
|
|
5d2e9ee66e | ||
|
|
607c671f67 | ||
|
|
cf1e808e2f | ||
|
|
b6cfde8987 | ||
|
|
d73f665edd | ||
|
|
52efbc3a23 | ||
|
|
639dc3b5fd | ||
|
|
cff7882391 | ||
|
|
5d1a8cd88b | ||
|
|
528b9c5323 | ||
|
|
fab85b495e | ||
|
|
293ab4bd40 | ||
|
|
a45db022e9 | ||
|
|
02be4802d5 | ||
|
|
5437deed1b | ||
|
|
422271bd40 | ||
|
|
801bc29494 | ||
|
|
857ce2376e | ||
|
|
1bf6c965e4 | ||
|
|
fa2332354b | ||
|
|
e9aebb1198 | ||
|
|
fbe8ccdf3b | ||
|
|
34241cbb2b | ||
|
|
e9ba2da9e9 | ||
|
|
5b84772343 | ||
|
|
d8474207b6 | ||
|
|
b78f2ed75d | ||
|
|
2af88a679d | ||
|
|
ad0ac12c40 | ||
|
|
e3a866b8c1 | ||
|
|
f62cded9f0 | ||
|
|
7e315629b9 | ||
|
|
3c2ea78a09 | ||
|
|
85bcfab719 | ||
|
|
67ffe26dea | ||
|
|
bc78383fac | ||
|
|
1ec528b048 | ||
|
|
2a9c396603 | ||
|
|
4f392ebc7e | ||
|
|
1cc1a352fc | ||
|
|
cfe7065ce1 | ||
|
|
f561e6bcb3 | ||
|
|
83421c0e8c | ||
|
|
095733ed9c | ||
|
|
155a155d1d | ||
|
|
dbf72ffba2 | ||
|
|
47d21b6420 | ||
|
|
72eb4adbf0 | ||
|
|
3f9ce10525 | ||
|
|
412c501442 | ||
|
|
5c70dd8b85 | ||
|
|
d5068ed07d | ||
|
|
bc2db86d1c | ||
|
|
2fe9c2e352 | ||
|
|
d4e3401c23 | ||
|
|
2bd6501552 | ||
|
|
4f7be0dbb2 | ||
|
|
1da5c94b44 | ||
|
|
3d1edffe77 | ||
|
|
cb52ed7b12 | ||
|
|
22799b107d | ||
|
|
c3ce3d5cc3 | ||
|
|
32eea120af | ||
|
|
8e42d3959c | ||
|
|
f8be4d1b3b | ||
|
|
9b3648ded0 | ||
|
|
0701745cbc | ||
|
|
bbe437dbb1 | ||
|
|
5c67530f1e | ||
|
|
e40e6e8686 | ||
|
|
6f3a7d36bb | ||
|
|
5dddebd338 | ||
|
|
80d88dd3d9 | ||
|
|
0faffac020 | ||
|
|
5aaae4cb6b | ||
|
|
c092101e01 | ||
|
|
d7df4429eb | ||
|
|
ffe8b98cc2 | ||
|
|
aa5c7c3b0c | ||
|
|
886fdc8bc2 | ||
|
|
33ecaaac01 | ||
|
|
3c69092cde | ||
|
|
e8b28f978e | ||
|
|
92fdf31d29 | ||
|
|
878a650c7a | ||
|
|
e518ec1cb7 | ||
|
|
ed34425306 | ||
|
|
1d7f87fc0e | ||
|
|
735e34f932 | ||
|
|
fea9e3050c | ||
|
|
bbd0522026 | ||
|
|
e37fd83254 | ||
|
|
926b9e937b | ||
|
|
fc9434465c | ||
|
|
ba3ee9f007 | ||
|
|
38d8befcd0 | ||
|
|
e1d36314a2 | ||
|
|
9a54f91bb7 | ||
|
|
16d58e93af | ||
|
|
2384236849 | ||
|
|
252cd6eae9 | ||
|
|
8fe8dbb378 | ||
|
|
8923a01264 | ||
|
|
6cbab4936d | ||
|
|
0310cba2b6 | ||
|
|
0b9804a95b | ||
|
|
7c2db045a8 | ||
|
|
5027627344 | ||
|
|
4d43fbfb50 | ||
|
|
4e6ff36a9a | ||
|
|
f8bde7156f | ||
|
|
66c6ae1a55 | ||
|
|
1bc4176d65 | ||
|
|
de309c51a7 | ||
|
|
f128ffd88b | ||
|
|
063430744d | ||
|
|
cbd75c3e35 | ||
|
|
1729d4a168 | ||
|
|
773771659e | ||
|
|
c365ff3d05 | ||
|
|
1bbfe058f9 | ||
|
|
02d9b05f54 | ||
|
|
5c5b1aaaa7 | ||
|
|
6953c8ec91 | ||
|
|
58aff4495e | ||
|
|
3e2a61cc47 | ||
|
|
120d2b5333 | ||
|
|
d1d003c232 | ||
|
|
3cf72e5258 | ||
|
|
05fd0acf45 | ||
|
|
25707e9752 | ||
|
|
9774b1062d | ||
|
|
954341dd1f | ||
|
|
56d0e91e10 | ||
|
|
d7349d04d0 | ||
|
|
1226add976 | ||
|
|
234b05708c | ||
|
|
e368d01385 | ||
|
|
310c41a89a | ||
|
|
1102ea4c55 | ||
|
|
c487f5db5b | ||
|
|
501faacf8e | ||
|
|
adc8c20ac1 | ||
|
|
63e52afd5b | ||
|
|
6f60449e18 | ||
|
|
77052d3a1e | ||
|
|
898be61fc6 | ||
|
|
9ccb6864be | ||
|
|
2379ddff17 | ||
|
|
41a10699e6 | ||
|
|
b1c0121507 | ||
|
|
f6bea8d061 | ||
|
|
9bb7e68b86 | ||
|
|
20718ec52b | ||
|
|
a3557b81de | ||
|
|
485d78d768 | ||
|
|
7aa84318ae | ||
|
|
0e98f1214d | ||
|
|
6e7eae968a | ||
|
|
5bb9b570f4 | ||
|
|
571f547556 | ||
|
|
af3de262b6 | ||
|
|
bd4a0aa705 | ||
|
|
4bc6af6c17 | ||
|
|
27834cce2c | ||
|
|
a30d16c48a | ||
|
|
e4653b82bd | ||
|
|
b65dcb3a35 | ||
|
|
c1fb948397 | ||
|
|
be25b58380 | ||
|
|
66f51df9df | ||
|
|
3014e3c458 | ||
|
|
dd0d04ae8d | ||
|
|
112d4cc7e6 | ||
|
|
ee8664418a | ||
|
|
ae89b6c078 | ||
|
|
d403c01a30 | ||
|
|
14f1ce2e5b | ||
|
|
62b0f58d24 | ||
|
|
c3f963e71e | ||
|
|
fd09c4cb29 | ||
|
|
13f68fc2d5 | ||
|
|
7a523597ad | ||
|
|
c2d636270c | ||
|
|
21b0d29e38 | ||
|
|
6596d27e19 | ||
|
|
ed6294b4bb | ||
|
|
12da51ac5a | ||
|
|
b3ad6a015b | ||
|
|
be36586d74 | ||
|
|
0d7da3207f | ||
|
|
71ce6592e4 | ||
|
|
a5d6ccdc2c | ||
|
|
378fcccc0a | ||
|
|
3ed3833a38 | ||
|
|
5450b478f5 | ||
|
|
94d00009cc | ||
|
|
21bf499bb4 | ||
|
|
8ec46cbd42 | ||
|
|
0409a302bb | ||
|
|
84a85803b4 | ||
|
|
d46fe6a51c | ||
|
|
e83b4e8129 | ||
|
|
392e09e3de | ||
|
|
06b9901e64 | ||
|
|
677fa8ced2 | ||
|
|
3c333aa9b4 | ||
|
|
73d8c919b7 | ||
|
|
747e7d05db | ||
|
|
1f3a9105ff | ||
|
|
b0f22fde62 | ||
|
|
11f43df873 | ||
|
|
1254ed1833 | ||
|
|
f55b10e4ed | ||
|
|
d8be35de7f | ||
|
|
bdfe6870f6 | ||
|
|
9775f78ab2 | ||
|
|
6da4e21065 | ||
|
|
7bfe8d2f03 | ||
|
|
3b0b1c3ee3 | ||
|
|
82a80b205b | ||
|
|
5b586fdfec | ||
|
|
2f193b5cbb | ||
|
|
e6f93c887b | ||
|
|
36d9b62f1f | ||
|
|
da4bebbe1e | ||
|
|
d54a1ab798 | ||
|
|
e1081796af | ||
|
|
672c3be9ed | ||
|
|
dc9c4d22ab | ||
|
|
71d86be42e | ||
|
|
267fe02088 | ||
|
|
52b5258ed4 | ||
|
|
2bf6e66ffe | ||
|
|
728c2fbd01 | ||
|
|
613b71b385 | ||
|
|
70cc11618a | ||
|
|
387fd2cf53 | ||
|
|
0423057424 | ||
|
|
cc25d747d4 | ||
|
|
7637351065 | ||
|
|
7aeba71a92 | ||
|
|
e020dd8d59 | ||
|
|
a65af1b3b8 | ||
|
|
5478de1a64 | ||
|
|
fa9fbb1d67 | ||
|
|
ef751a26d0 | ||
|
|
30a7229fc5 | ||
|
|
1d69e073af | ||
|
|
c480a29052 | ||
|
|
4aef82237d | ||
|
|
8a4a22d7b7 |
4
.arcconfig
Normal file
4
.arcconfig
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"phabricator.uri" : "https://bugs.libssh.org/",
|
||||
"history.immutable": true
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
-DWITH_SERVER=1
|
||||
-DWITH_GSSAPI=1
|
||||
-DWITH_ZLIB=1
|
||||
-DWITH_SFTP=1
|
||||
-DWITH_SSH1=1
|
||||
-DWITH_PCAP=1
|
||||
-DHAVE_ECDH=1
|
||||
-DHAVE_ECC=1
|
||||
-Iinclude/libssh
|
||||
-Iinclude
|
||||
-Ibuild
|
||||
-Itests
|
||||
-Isrc
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,7 +3,7 @@
|
||||
.*
|
||||
*.swp
|
||||
*~$
|
||||
obj
|
||||
cscope.*
|
||||
tags
|
||||
build
|
||||
/build
|
||||
/obj*
|
||||
|
||||
302
.gitlab-ci.yml
Normal file
302
.gitlab-ci.yml
Normal file
@@ -0,0 +1,302 @@
|
||||
variables:
|
||||
BUILD_IMAGES_PROJECT: libssh/build-images
|
||||
FEDORA_BUILD: buildenv-fedora
|
||||
CENTOS7_BUILD: buildenv-centos7
|
||||
TUMBLEWEED_BUILD: buildenv-tumbleweed
|
||||
MINGW_BUILD: buildenv-mingw
|
||||
DEBIAN_CROSS_BUILD: buildenv-debian-cross
|
||||
|
||||
# torture_auth fails on centos7 docker images, so we don't use -DCLIENT_TESTING=ON
|
||||
centos7/openssl_1.0.x/x86-64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS7_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake3 -DUNIT_TESTING=ON -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON
|
||||
-DWITH_PCAP=ON .. && make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/openssl_1.1.x/x86-64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
# Address sanitizer doesn't mix well with LD_PRELOAD used in the testsuite
|
||||
.fedora/address-sanitizer:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_C_FLAGS="-O2 -g -fsanitize=address"
|
||||
-DCMAKE_LINK_FLAGS="-fsanitize=address -static-libasan"
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/undefined-sanitizer:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_C_FLAGS="-fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover"
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON ..
|
||||
&& make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/static-analysis:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- export CCC_CC=clang
|
||||
- export CCC_CXX=clang++
|
||||
- mkdir -p obj && cd obj && scan-build cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
||||
-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang .. &&
|
||||
scan-build --status-bugs -o scan make -j$(nproc)
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/scan
|
||||
|
||||
# That is a specific runner that we cannot enable universally.
|
||||
# We restrict it to builds under the $BUILD_IMAGES_PROJECT project.
|
||||
freebsd/x86-64:
|
||||
image:
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make && ctest --output-on-failure
|
||||
tags:
|
||||
- freebsd
|
||||
except:
|
||||
- tags
|
||||
only:
|
||||
- branches@libssh/libssh-mirror
|
||||
- branches@cryptomilk/libssh-mirror
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/libgcrypt/x86-64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
||||
-DWITH_GCRYPT=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/mbedtls/x86-64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
||||
-DWITH_MBEDTLS=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
tumbleweed/openssl_1.1.x/x86-64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
tumbleweed/openssl_1.1.x/x86:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cross-m32.cmake
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
tumbleweed/undefined-sanitizer:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_C_FLAGS="-fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover"
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON ..
|
||||
&& make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
tumbleweed/static-analysis:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
||||
script:
|
||||
- export CCC_CC=clang
|
||||
- export CCC_CXX=clang++
|
||||
- mkdir -p obj && cd obj && scan-build cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
||||
-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang .. &&
|
||||
scan-build --status-bugs -o scan make -j$(nproc)
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/scan
|
||||
|
||||
# Unit testing only, no client and pkd testing, because cwrap is not available
|
||||
# for MinGW
|
||||
mingw64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
|
||||
script:
|
||||
- Xvfb :1 -screen 0 1024x768x16 -ac +extension GLX +render -noreset -nolisten tcp &
|
||||
- export DISPLAY=:1
|
||||
- mkdir -p obj && cd obj && mingw64-cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc)
|
||||
- export WINEPATH=/usr/x86_64-w64-mingw32/sys-root/mingw/bin
|
||||
- ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
# Unit testing only, no client and pkd testing, because cwrap is not available
|
||||
# for MinGW
|
||||
mingw32:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
|
||||
script:
|
||||
- Xvfb :1 -screen 0 1024x768x16 -ac +extension GLX +render -noreset -nolisten tcp &
|
||||
- export DISPLAY=:1
|
||||
- mkdir -p obj && cd obj && mingw32-cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc)
|
||||
- export WINEPATH=/usr/i686-w64-mingw32/sys-root/mingw/bin
|
||||
- ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
.Debian.cross.template: &Debian_cross_template
|
||||
stage: test
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$DEBIAN_CROSS_BUILD
|
||||
script:
|
||||
- build=$(dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
- host="${CI_JOB_NAME#*.cross.}"
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_C_COMPILER="$(which $host-gcc)"
|
||||
-DCMAKE_CXX_COMPILER="$(which $host-g++)"
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
-DUNIT_TESTING=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON
|
||||
-DWITH_PCAP=ON .. && make -j$(nproc)
|
||||
- ctest --output-on-failure -j$(nproc)
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
Debian.cross.mips-linux-gnu:
|
||||
<<: *Debian_cross_template
|
||||
117
CMakeLists.txt
117
CMakeLists.txt
@@ -1,17 +1,11 @@
|
||||
project(libssh C)
|
||||
cmake_minimum_required(VERSION 3.2.0)
|
||||
cmake_policy(SET CMP0048 NEW)
|
||||
|
||||
# Required cmake version
|
||||
cmake_minimum_required(VERSION 2.8.5)
|
||||
project(libssh VERSION 0.8.0 LANGUAGES C)
|
||||
|
||||
# global needed variables
|
||||
# global needed variable
|
||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
|
||||
set(APPLICATION_VERSION_MAJOR "0")
|
||||
set(APPLICATION_VERSION_MINOR "7")
|
||||
set(APPLICATION_VERSION_PATCH "0")
|
||||
|
||||
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")
|
||||
|
||||
# SOVERSION scheme: CURRENT.AGE.REVISION
|
||||
# If there was an incompatible interface change:
|
||||
# Increment CURRENT. Set AGE and REVISION to 0
|
||||
@@ -19,12 +13,12 @@ set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINO
|
||||
# Increment AGE. Set REVISION to 0
|
||||
# If the source code was changed, but there were no interface changes:
|
||||
# Increment REVISION.
|
||||
set(LIBRARY_VERSION "4.4.0")
|
||||
set(LIBRARY_VERSION "4.5.0")
|
||||
set(LIBRARY_SOVERSION "4")
|
||||
|
||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||
set(CMAKE_MODULE_PATH
|
||||
${CMAKE_SOURCE_DIR}/cmake/Modules
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules
|
||||
)
|
||||
|
||||
# add definitions
|
||||
@@ -49,18 +43,27 @@ if (WITH_GCRYPT)
|
||||
if (NOT GCRYPT_FOUND)
|
||||
message(FATAL_ERROR "Could not find GCrypt")
|
||||
endif (NOT GCRYPT_FOUND)
|
||||
elseif(WITH_MBEDTLS)
|
||||
find_package(MbedTLS REQUIRED)
|
||||
if (NOT MBEDTLS_FOUND)
|
||||
message(FATAL_ERROR "Could not find mbedTLS")
|
||||
endif (NOT MBEDTLS_FOUND)
|
||||
else (WITH_GCRYPT)
|
||||
find_package(OpenSSL)
|
||||
if (NOT OPENSSL_FOUND)
|
||||
find_package(GCrypt)
|
||||
if (NOT GCRYPT_FOUND)
|
||||
message(FATAL_ERROR "Could not find OpenSSL or GCrypt")
|
||||
find_package(MbedTLS)
|
||||
if (NOT MBEDTLS_FOUND)
|
||||
message(FATAL_ERROR "Could not find OpenSSL, GCrypt or mbedTLS")
|
||||
endif (NOT MBEDTLS_FOUND)
|
||||
endif (NOT GCRYPT_FOUND)
|
||||
endif (NOT OPENSSL_FOUND)
|
||||
endif(WITH_GCRYPT)
|
||||
|
||||
# Find out if we have threading available
|
||||
set(CMAKE_THREAD_PREFER_PTHREADS ON)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads)
|
||||
|
||||
if (WITH_GSSAPI)
|
||||
@@ -74,6 +77,17 @@ if (WITH_NACL)
|
||||
endif (NOT NACL_FOUND)
|
||||
endif (WITH_NACL)
|
||||
|
||||
if (BSD OR SOLARIS OR OSX)
|
||||
find_package(Argp)
|
||||
endif (BSD OR SOLARIS OR OSX)
|
||||
|
||||
# Disable symbol versioning in non UNIX platforms
|
||||
if (UNIX)
|
||||
find_package(ABIMap)
|
||||
else (UNIX)
|
||||
set(WITH_SYMBOL_VERSIONING OFF)
|
||||
endif (UNIX)
|
||||
|
||||
# config.h checks
|
||||
include(ConfigureChecks.cmake)
|
||||
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
@@ -84,21 +98,20 @@ add_subdirectory(include)
|
||||
add_subdirectory(src)
|
||||
|
||||
# pkg-config file
|
||||
if (UNIX)
|
||||
configure_file(libssh.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh.pc)
|
||||
configure_file(libssh_threads.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc)
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc
|
||||
DESTINATION
|
||||
${LIB_INSTALL_DIR}/pkgconfig
|
||||
COMPONENT
|
||||
pkgconfig
|
||||
)
|
||||
endif (UNIX)
|
||||
|
||||
# cmake config files
|
||||
set(LIBSSH_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}ssh${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
set(LIBSSH_THREADS_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}ssh${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
|
||||
configure_file(${PROJECT_NAME}-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake @ONLY)
|
||||
configure_file(${PROJECT_NAME}-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake @ONLY)
|
||||
@@ -120,32 +133,94 @@ if (WITH_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif (WITH_EXAMPLES)
|
||||
|
||||
if (WITH_TESTING)
|
||||
if (UNIT_TESTING)
|
||||
find_package(CMocka REQUIRED)
|
||||
include(AddCMockaTest)
|
||||
add_subdirectory(tests)
|
||||
endif (WITH_TESTING)
|
||||
endif (UNIT_TESTING)
|
||||
|
||||
### SOURCE PACKAGE
|
||||
if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
||||
# Get the current ABI version from source
|
||||
get_filename_component(current_abi_path
|
||||
"${CMAKE_SOURCE_DIR}/src/ABI/current"
|
||||
ABSOLUTE)
|
||||
|
||||
# Check if the ABI version should be updated
|
||||
file(READ ${current_abi_path} CURRENT_ABI_CONTENT)
|
||||
string(STRIP "${CURRENT_ABI_CONTENT}" CURRENT_ABI_VERSION)
|
||||
|
||||
if (LIBRARY_VERSION VERSION_GREATER CURRENT_ABI_VERSION)
|
||||
set(UPDATE_ABI TRUE)
|
||||
endif ()
|
||||
|
||||
if (UPDATE_ABI)
|
||||
message(STATUS "Library version bumped to ${LIBRARY_VERSION}: Updating ABI")
|
||||
|
||||
# Get the list of header files
|
||||
get_file_list("${PROJECT_NAME}_header_list"
|
||||
DIRECTORIES "${CMAKE_SOURCE_DIR}/include/libssh"
|
||||
FILES_PATTERNS "*.h")
|
||||
|
||||
# Extract the symbols marked as "LIBSSH_API" from the header files
|
||||
extract_symbols(${PROJECT_NAME}.symbols
|
||||
HEADERS_LIST_FILE "${PROJECT_NAME}_header_list"
|
||||
FILTER_PATTERN "LIBSSH_API"
|
||||
COPY_TO "${CMAKE_SOURCE_DIR}/src/ABI/${PROJECT_NAME}-${LIBRARY_VERSION}.symbols")
|
||||
|
||||
if (WITH_ABI_BREAK)
|
||||
set(ALLOW_ABI_BREAK "BREAK_ABI")
|
||||
endif()
|
||||
|
||||
# Target we can depend on in 'make dist'
|
||||
set(_SYMBOL_TARGET "${PROJECT_NAME}.map")
|
||||
|
||||
# Set the path to the current map file
|
||||
set(MAP_PATH "${CMAKE_SOURCE_DIR}/src/${_SYMBOL_TARGET}")
|
||||
|
||||
# Generate the symbol version map file
|
||||
generate_map_file(${_SYMBOL_TARGET}
|
||||
SYMBOLS "${PROJECT_NAME}.symbols"
|
||||
RELEASE_NAME_VERSION ${PROJECT_NAME}_${LIBRARY_VERSION}
|
||||
CURRENT_MAP ${MAP_PATH}
|
||||
COPY_TO ${MAP_PATH}
|
||||
FINAL
|
||||
${ALLOW_ABI_BREAK})
|
||||
|
||||
# Write the current version to the source
|
||||
file(WRITE ${current_abi_path} ${LIBRARY_VERSION})
|
||||
endif(UPDATE_ABI)
|
||||
endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
||||
|
||||
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source DEPENDS ${_SYMBOL_TARGET})
|
||||
|
||||
message(STATUS "********************************************")
|
||||
message(STATUS "********** ${PROJECT_NAME} build options : **********")
|
||||
|
||||
message(STATUS "zlib support: ${WITH_ZLIB}")
|
||||
message(STATUS "libgcrypt support: ${WITH_GCRYPT}")
|
||||
message(STATUS "libmbedTLS support: ${WITH_MBEDTLS}")
|
||||
message(STATUS "libnacl support: ${WITH_NACL}")
|
||||
message(STATUS "SSH-1 support: ${WITH_SSH1}")
|
||||
message(STATUS "SFTP support: ${WITH_SFTP}")
|
||||
message(STATUS "Server support : ${WITH_SERVER}")
|
||||
message(STATUS "GSSAPI support : ${WITH_GSSAPI}")
|
||||
message(STATUS "Pcap debugging support : ${WITH_PCAP}")
|
||||
message(STATUS "With static library: ${WITH_STATIC_LIB}")
|
||||
message(STATUS "Unit testing: ${WITH_TESTING}")
|
||||
message(STATUS "Client code Unit testing: ${WITH_CLIENT_TESTING}")
|
||||
message(STATUS "Unit testing: ${UNIT_TESTING}")
|
||||
message(STATUS "Client code testing: ${CLIENT_TESTING}")
|
||||
set(_SERVER_TESTING OFF)
|
||||
if (WITH_SERVER)
|
||||
set(_SERVER_TESTING ${SERVER_TESTING})
|
||||
endif()
|
||||
message(STATUS "Server code testing: ${_SERVER_TESTING}")
|
||||
if (WITH_INTERNAL_DOC)
|
||||
message(STATUS "Internal documentation generation")
|
||||
else (WITH_INTERNAL_DOC)
|
||||
message(STATUS "Public API documentation generation")
|
||||
endif (WITH_INTERNAL_DOC)
|
||||
message(STATUS "Benchmarks: ${WITH_BENCHMARKS}")
|
||||
message(STATUS "Symbol versioning: ${WITH_SYMBOL_VERSIONING}")
|
||||
message(STATUS "Allow ABI break: ${WITH_ABI_BREAK}")
|
||||
message(STATUS "Release is final: ${WITH_FINAL}")
|
||||
message(STATUS "********************************************")
|
||||
|
||||
|
||||
@@ -1,27 +1,19 @@
|
||||
# For help take a look at:
|
||||
# http://www.cmake.org/Wiki/CMake:CPackConfiguration
|
||||
|
||||
### general settings
|
||||
set(CPACK_PACKAGE_NAME ${APPLICATION_NAME})
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The SSH library")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README")
|
||||
### GENERAL SETTINGS
|
||||
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The SSH Library")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README")
|
||||
set(CPACK_PACKAGE_VENDOR "The SSH Library Development Team")
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")
|
||||
|
||||
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
|
||||
|
||||
### versions
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${APPLICATION_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${APPLICATION_VERSION_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${APPLICATION_VERSION_PATCH})
|
||||
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
|
||||
|
||||
|
||||
### source generator
|
||||
set(CPACK_SOURCE_GENERATOR "TGZ")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;/obj/;tags;cscope.*")
|
||||
# SOURCE GENERATOR
|
||||
set(CPACK_SOURCE_GENERATOR "TXZ")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]git/;.gitignore;build;obj*;tags;cscope.*")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
||||
|
||||
### NSIS INSTALLER
|
||||
if (WIN32)
|
||||
set(CPACK_GENERATOR "ZIP")
|
||||
|
||||
@@ -46,7 +38,6 @@ set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION
|
||||
set(CPACK_COMPONENT_HEADERS_DESCRIPTION
|
||||
"C/C++ header files for use with libssh")
|
||||
set(CPACK_COMPONENT_HEADERS_DEPENDS libraries)
|
||||
#set(CPACK_COMPONENT_APPLICATIONS_GROUP "Runtime")
|
||||
set(CPACK_COMPONENT_LIBRARIES_GROUP "Development")
|
||||
set(CPACK_COMPONENT_HEADERS_GROUP "Development")
|
||||
|
||||
|
||||
49
ChangeLog
49
ChangeLog
@@ -1,7 +1,54 @@
|
||||
ChangeLog
|
||||
==========
|
||||
|
||||
version 0.7.0 (released 2015-05-xx)
|
||||
version 0.8.0 (released 2018-08-10)
|
||||
* Removed support for deprecated SSHv1 protocol
|
||||
* Added new connector API for clients
|
||||
* Added new known_hosts parsing API
|
||||
* Added support for OpenSSL 1.1
|
||||
* Added support for chacha20-poly1305 cipher
|
||||
* Added crypto backend for mbedtls crypto library
|
||||
* Added ECDSA support with gcrypt backend
|
||||
* Added advanced client and server testing using cwrap.org
|
||||
* Added support for curve25519-sha256 alias
|
||||
* Added support for global known_hosts file
|
||||
* Added support for symbol versioning
|
||||
* Improved ssh_config parsing
|
||||
* Improved threading support
|
||||
|
||||
version 0.7.5 (released 2017-04-13)
|
||||
* Fixed a memory allocation issue with buffers
|
||||
* Fixed PKI on Windows
|
||||
* Fixed some SSHv1 functions
|
||||
* Fixed config hostname expansion
|
||||
|
||||
version 0.7.4 (released 2017-02-03)
|
||||
* Added id_ed25519 to the default identity list
|
||||
* Fixed sftp EOF packet handling
|
||||
* Fixed ssh_send_banner() to confirm with RFC 4253
|
||||
* Fixed some memory leaks
|
||||
|
||||
version 0.7.3 (released 2016-01-23)
|
||||
* Fixed CVE-2016-0739
|
||||
* Fixed ssh-agent on big endian
|
||||
* Fixed some documentation issues
|
||||
|
||||
version 0.7.2 (released 2015-09-15)
|
||||
* Fixed OpenSSL detection on Windows
|
||||
* Fixed return status for ssh_userauth_agent()
|
||||
* Fixed KEX to prefer hmac-sha2-256
|
||||
* Fixed sftp packet handling
|
||||
* Fixed return values of ssh_key_is_(public|private)
|
||||
* Fixed bug in global success reply
|
||||
|
||||
version 0.7.1 (released 2015-06-30)
|
||||
* Fixed SSH_AUTH_PARTIAL auth with auto public key
|
||||
* Fixed memory leak in session options
|
||||
* Fixed allocation of ed25519 public keys
|
||||
* Fixed channel exit-status and exit-signal
|
||||
* Reintroduce ssh_forward_listen()
|
||||
|
||||
version 0.7.0 (released 2015-05-11)
|
||||
* Added support for ed25519 keys
|
||||
* Added SHA2 algorithms for HMAC
|
||||
* Added improved and more secure buffer handling code
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
include(CheckIncludeFile)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckLibraryExists)
|
||||
@@ -41,23 +42,32 @@ if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2)
|
||||
"void __attribute__((visibility(\"default\"))) test() {}
|
||||
int main(void){ return 0; }
|
||||
" WITH_VISIBILITY_HIDDEN)
|
||||
set(CMAKE_REQUIRED_FLAGS "")
|
||||
unset(CMAKE_REQUIRED_FLAGS)
|
||||
endif (NOT GNUCC_VERSION EQUAL 34)
|
||||
endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2)
|
||||
|
||||
# HEADER FILES
|
||||
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${ARGP_INCLUDE_DIR})
|
||||
check_include_file(argp.h HAVE_ARGP_H)
|
||||
unset(CMAKE_REQUIRED_INCLUDES)
|
||||
|
||||
check_include_file(pty.h HAVE_PTY_H)
|
||||
check_include_file(utmp.h HAVE_UTMP_H)
|
||||
check_include_file(termios.h HAVE_TERMIOS_H)
|
||||
check_include_file(unistd.h HAVE_UNISTD_H)
|
||||
check_include_file(stdint.h HAVE_STDINT_H)
|
||||
check_include_file(util.h HAVE_UTIL_H)
|
||||
check_include_file(libutil.h HAVE_LIBUTIL_H)
|
||||
check_include_file(sys/time.h HAVE_SYS_TIME_H)
|
||||
check_include_file(sys/utime.h HAVE_SYS_UTIME_H)
|
||||
check_include_file(sys/param.h HAVE_SYS_PARAM_H)
|
||||
check_include_file(arpa/inet.h HAVE_ARPA_INET_H)
|
||||
check_include_file(byteswap.h HAVE_BYTESWAP_H)
|
||||
check_include_file(glob.h HAVE_GLOB_H)
|
||||
|
||||
if (WIN32)
|
||||
check_include_file(io.h HAVE_IO_H)
|
||||
|
||||
check_include_files("winsock2.h;ws2tcpip.h;wspiapi.h" HAVE_WSPIAPI_H)
|
||||
if (NOT HAVE_WSPIAPI_H)
|
||||
message(STATUS "WARNING: Without wspiapi.h, this build will only work on Windows XP and newer versions")
|
||||
@@ -65,29 +75,64 @@ if (WIN32)
|
||||
check_include_files("winsock2.h;ws2tcpip.h" HAVE_WS2TCPIP_H)
|
||||
endif (WIN32)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/aes.h HAVE_OPENSSL_AES_H)
|
||||
if (OPENSSL_FOUND)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/des.h HAVE_OPENSSL_DES_H)
|
||||
if (NOT HAVE_OPENSSL_DES_H)
|
||||
message(FATAL_ERROR "Could not detect openssl/des.h")
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/blowfish.h HAVE_OPENSSL_BLOWFISH_H)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/aes.h HAVE_OPENSSL_AES_H)
|
||||
if (NOT HAVE_OPENSSL_AES_H)
|
||||
message(FATAL_ERROR "Could not detect openssl/aes.h")
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/des.h HAVE_OPENSSL_DES_H)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/blowfish.h HAVE_OPENSSL_BLOWFISH_H)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/ecdh.h HAVE_OPENSSL_ECDH_H)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/ecdh.h HAVE_OPENSSL_ECDH_H)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/ec.h HAVE_OPENSSL_EC_H)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/ec.h HAVE_OPENSSL_EC_H)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/ecdsa.h HAVE_OPENSSL_ECDSA_H)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/ecdsa.h HAVE_OPENSSL_ECDSA_H)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(EVP_aes_128_ctr HAVE_OPENSSL_EVP_AES_CTR)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(EVP_aes_128_cbc HAVE_OPENSSL_EVP_AES_CBC)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(CRYPTO_THREADID_set_callback HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(CRYPTO_ctr128_encrypt HAVE_OPENSSL_CRYPTO_CTR128_ENCRYPT)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(EVP_CIPHER_CTX_new HAVE_OPENSSL_EVP_CIPHER_CTX_NEW)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(RAND_priv_bytes HAVE_OPENSSL_RAND_PRIV_BYTES)
|
||||
|
||||
unset(CMAKE_REQUIRED_INCLUDES)
|
||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||
endif()
|
||||
|
||||
if (CMAKE_HAVE_PTHREAD_H)
|
||||
set(HAVE_PTHREAD_H 1)
|
||||
endif (CMAKE_HAVE_PTHREAD_H)
|
||||
|
||||
if (NOT WITH_GCRYPT)
|
||||
if (NOT WITH_GCRYPT AND NOT WITH_MBEDTLS)
|
||||
if (HAVE_OPENSSL_EC_H AND HAVE_OPENSSL_ECDSA_H)
|
||||
set(HAVE_OPENSSL_ECC 1)
|
||||
endif (HAVE_OPENSSL_EC_H AND HAVE_OPENSSL_ECDSA_H)
|
||||
@@ -95,22 +140,37 @@ if (NOT WITH_GCRYPT)
|
||||
if (HAVE_OPENSSL_ECC)
|
||||
set(HAVE_ECC 1)
|
||||
endif (HAVE_OPENSSL_ECC)
|
||||
endif (NOT WITH_GCRYPT)
|
||||
endif ()
|
||||
|
||||
if (NOT WITH_MBEDTLS)
|
||||
set(HAVE_DSA 1)
|
||||
endif (NOT WITH_MBEDTLS)
|
||||
|
||||
# FUNCTIONS
|
||||
|
||||
check_function_exists(isblank HAVE_ISBLANK)
|
||||
check_function_exists(strncpy HAVE_STRNCPY)
|
||||
check_function_exists(vsnprintf HAVE_VSNPRINTF)
|
||||
check_function_exists(snprintf HAVE_SNPRINTF)
|
||||
check_function_exists(strtoull HAVE_STRTOULL)
|
||||
check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO)
|
||||
check_function_exists(memset_s HAVE_MEMSET_S)
|
||||
|
||||
if (HAVE_GLOB_H)
|
||||
check_function_exists(glob HAVE_GLOB)
|
||||
endif (HAVE_GLOB_H)
|
||||
|
||||
if (NOT WIN32)
|
||||
check_function_exists(vsnprintf HAVE_VSNPRINTF)
|
||||
check_function_exists(snprintf HAVE_SNPRINTF)
|
||||
endif (NOT WIN32)
|
||||
|
||||
if (WIN32)
|
||||
check_function_exists(_strtoui64 HAVE__STRTOUI64)
|
||||
check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF)
|
||||
check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF)
|
||||
|
||||
check_function_exists(_vsnprintf_s HAVE__VSNPRINTF_S)
|
||||
check_function_exists(_vsnprintf HAVE__VSNPRINTF)
|
||||
check_function_exists(_snprintf HAVE__SNPRINTF)
|
||||
check_function_exists(_snprintf_s HAVE__SNPRINTF_S)
|
||||
check_symbol_exists(_vsnprintf_s "stdio.h" HAVE__VSNPRINTF_S)
|
||||
check_symbol_exists(_vsnprintf "stdio.h" HAVE__VSNPRINTF)
|
||||
check_symbol_exists(_snprintf "stdio.h" HAVE__SNPRINTF)
|
||||
check_symbol_exists(_snprintf_s "stdio.h" HAVE__SNPRINTF_S)
|
||||
|
||||
if (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
|
||||
check_symbol_exists(ntohll winsock2.h HAVE_NTOHLL)
|
||||
@@ -121,10 +181,14 @@ if (WIN32)
|
||||
check_symbol_exists(poll "winsock2.h;ws2tcpip.h" HAVE_SELECT)
|
||||
# The getaddrinfo function is defined to the WspiapiGetAddrInfo inline function
|
||||
check_symbol_exists(getaddrinfo "winsock2.h;ws2tcpip.h" HAVE_GETADDRINFO)
|
||||
set(CMAKE_REQUIRED_LIBRARIES)
|
||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||
endif (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
|
||||
|
||||
check_function_exists(_strtoui64 HAVE__STRTOUI64)
|
||||
|
||||
set(HAVE_SELECT TRUE)
|
||||
|
||||
check_symbol_exists(SecureZeroMemory "windows.h" HAVE_SECURE_ZERO_MEMORY)
|
||||
else (WIN32)
|
||||
check_function_exists(poll HAVE_POLL)
|
||||
check_function_exists(select HAVE_SELECT)
|
||||
@@ -141,13 +205,13 @@ if (UNIX)
|
||||
check_library_exists(socket getaddrinfo "" HAVE_LIBSOCKET)
|
||||
if (HAVE_LIBSOCKET)
|
||||
set(HAVE_GETADDRINFO TRUE)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} socket)
|
||||
set(_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} socket)
|
||||
endif (HAVE_LIBSOCKET)
|
||||
|
||||
# libnsl/inet_pton (Solaris)
|
||||
check_library_exists(nsl inet_pton "" HAVE_LIBNSL)
|
||||
if (HAVE_LIBNSL)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} nsl)
|
||||
set(_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} nsl)
|
||||
endif (HAVE_LIBNSL)
|
||||
|
||||
# librt
|
||||
@@ -156,16 +220,15 @@ if (UNIX)
|
||||
|
||||
check_library_exists(rt clock_gettime "" HAVE_CLOCK_GETTIME)
|
||||
if (HAVE_LIBRT OR HAVE_CLOCK_GETTIME)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} rt)
|
||||
set(_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} rt)
|
||||
endif (HAVE_LIBRT OR HAVE_CLOCK_GETTIME)
|
||||
|
||||
check_library_exists(util forkpty "" HAVE_LIBUTIL)
|
||||
check_function_exists(cfmakeraw HAVE_CFMAKERAW)
|
||||
check_function_exists(strtoull HAVE_STRTOULL)
|
||||
check_function_exists(__strtoull HAVE___STRTOULL)
|
||||
endif (UNIX)
|
||||
|
||||
set(LIBSSH_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "libssh required system libraries")
|
||||
set(LIBSSH_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} CACHE INTERNAL "libssh required system libraries")
|
||||
|
||||
# LIBRARIES
|
||||
if (OPENSSL_FOUND)
|
||||
@@ -175,11 +238,16 @@ endif (OPENSSL_FOUND)
|
||||
if (GCRYPT_FOUND)
|
||||
set(HAVE_LIBGCRYPT 1)
|
||||
if (GCRYPT_VERSION VERSION_GREATER "1.4.6")
|
||||
#set(HAVE_GCRYPT_ECC 1)
|
||||
#set(HAVE_ECC 1)
|
||||
set(HAVE_GCRYPT_ECC 1)
|
||||
set(HAVE_ECC 1)
|
||||
endif (GCRYPT_VERSION VERSION_GREATER "1.4.6")
|
||||
endif (GCRYPT_FOUND)
|
||||
|
||||
if (MBEDTLS_FOUND)
|
||||
set(HAVE_LIBMBEDCRYPTO 1)
|
||||
set(HAVE_ECC 1)
|
||||
endif (MBEDTLS_FOUND)
|
||||
|
||||
if (CMAKE_USE_PTHREADS_INIT)
|
||||
set(HAVE_PTHREAD 1)
|
||||
endif (CMAKE_USE_PTHREADS_INIT)
|
||||
@@ -199,6 +267,33 @@ int main(void) {
|
||||
return 0;
|
||||
}" HAVE_MSC_THREAD_LOCAL_STORAGE)
|
||||
|
||||
check_c_source_compiles("
|
||||
#define FALL_THROUGH __attribute__((fallthrough))
|
||||
|
||||
enum direction_e {
|
||||
UP = 0,
|
||||
DOWN,
|
||||
};
|
||||
|
||||
int main(void) {
|
||||
enum direction_e key = UP;
|
||||
int i = 10;
|
||||
int j = 0;
|
||||
|
||||
switch (key) {
|
||||
case UP:
|
||||
i = 5;
|
||||
FALL_THROUGH;
|
||||
case DOWN:
|
||||
j = i * 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}" HAVE_FALLTHROUGH_ATTRIBUTE)
|
||||
|
||||
check_c_source_compiles("
|
||||
#include <string.h>
|
||||
|
||||
@@ -206,7 +301,7 @@ int main(void)
|
||||
{
|
||||
char buf[] = \"This is some content\";
|
||||
|
||||
memset(buf, '\\\\0', sizeof(buf)); __asm__ volatile(\"\" : : \"r\"(&buf) : \"memory\");
|
||||
memset(buf, '\\\\0', sizeof(buf)); __asm__ volatile(\"\" : : \"g\"(&buf) : \"memory\");
|
||||
|
||||
return 0;
|
||||
}" HAVE_GCC_VOLATILE_MEMORY_PROTECTION)
|
||||
@@ -238,10 +333,19 @@ int main(void) {
|
||||
}" HAVE_COMPILER__FUNCTION__)
|
||||
|
||||
|
||||
check_c_source_compiles("
|
||||
void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits)
|
||||
__attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN)));
|
||||
int main(void) { return 0; }" HAVE_GCC_BOUNDED_ATTRIBUTE)
|
||||
|
||||
if (WITH_DEBUG_CRYPTO)
|
||||
set(DEBUG_CRYPTO 1)
|
||||
endif (WITH_DEBUG_CRYPTO)
|
||||
|
||||
if (WITH_DEBUG_PACKET)
|
||||
set(DEBUG_PACKET 1)
|
||||
endif (WITH_DEBUG_PACKET)
|
||||
|
||||
if (WITH_DEBUG_CALLTRACE)
|
||||
set(DEBUG_CALLTRACE 1)
|
||||
endif (WITH_DEBUG_CALLTRACE)
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
option(WITH_GSSAPI "Build with GSSAPI support" ON)
|
||||
option(WITH_ZLIB "Build with ZLIB support" ON)
|
||||
option(WITH_SSH1 "Build with SSH1 support" OFF)
|
||||
option(WITH_SFTP "Build with SFTP support" ON)
|
||||
option(WITH_SERVER "Build with SSH server support" ON)
|
||||
option(WITH_STATIC_LIB "Build with a static library" OFF)
|
||||
option(WITH_DEBUG_CRYPTO "Build with cryto debug output" OFF)
|
||||
option(WITH_DEBUG_PACKET "Build with packet debug output" OFF)
|
||||
option(WITH_DEBUG_CALLTRACE "Build with calltrace debug output" ON)
|
||||
option(WITH_GCRYPT "Compile against libgcrypt" OFF)
|
||||
option(WITH_MBEDTLS "Compile against libmbedtls" OFF)
|
||||
option(WITH_PCAP "Compile with Pcap generation support" ON)
|
||||
option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
|
||||
option(WITH_TESTING "Build with unit tests" OFF)
|
||||
option(WITH_CLIENT_TESTING "Build with client tests; requires a running sshd" OFF)
|
||||
option(UNIT_TESTING "Build with unit tests" OFF)
|
||||
option(CLIENT_TESTING "Build with client tests; requires openssh" OFF)
|
||||
option(SERVER_TESTING "Build with server tests; requires openssh and dropbear" OFF)
|
||||
option(WITH_BENCHMARKS "Build benchmarks tools" OFF)
|
||||
option(WITH_EXAMPLES "Build examples" ON)
|
||||
option(WITH_NACL "Build with libnacl (curve25519" ON)
|
||||
option(WITH_NACL "Build with libnacl (curve25519)" ON)
|
||||
option(WITH_SYMBOL_VERSIONING "Build with symbol versioning" ON)
|
||||
option(WITH_ABI_BREAK "Allow ABI break" OFF)
|
||||
option(FUZZ_TESTING "Build with fuzzer for the server" OFF)
|
||||
if (WITH_ZLIB)
|
||||
set(WITH_LIBZ ON)
|
||||
else (WITH_ZLIB)
|
||||
@@ -21,13 +26,17 @@ else (WITH_ZLIB)
|
||||
endif (WITH_ZLIB)
|
||||
|
||||
if(WITH_BENCHMARKS)
|
||||
set(WITH_TESTING ON)
|
||||
set(UNIT_TESTING ON)
|
||||
endif(WITH_BENCHMARKS)
|
||||
|
||||
if (WITH_TESTING)
|
||||
if (UNIT_TESTING)
|
||||
set(WITH_STATIC_LIB ON)
|
||||
endif (WITH_TESTING)
|
||||
endif (UNIT_TESTING)
|
||||
|
||||
if (WITH_NACL)
|
||||
set(WITH_NACL ON)
|
||||
endif (WITH_NACL)
|
||||
endif (WITH_NACL)
|
||||
|
||||
if (WITH_ABI_BREAK)
|
||||
set(WITH_SYMBOL_VERSIONING ON)
|
||||
endif (WITH_ABI_BREAK)
|
||||
|
||||
20
INSTALL
20
INSTALL
@@ -14,6 +14,10 @@ or
|
||||
|
||||
optional:
|
||||
- [libz](http://www.zlib.net) >= 1.2
|
||||
- [socket_wrapper](https://cwrap.org/) >= 1.1.5
|
||||
- [nss_wrapper](https://cwrap.org/) >= 1.1.2
|
||||
- [uid_wrapper](https://cwrap.org/) >= 1.2.0
|
||||
- [pam_wrapper](https://cwrap.org/) >= 1.0.1
|
||||
|
||||
Note that these version numbers are version we know works correctly. If you
|
||||
build and run libssh successfully with an older version, please let us know.
|
||||
@@ -31,13 +35,27 @@ First, you need to configure the compilation, using CMake. Go inside the
|
||||
|
||||
GNU/Linux, MacOS X, MSYS/MinGW:
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
|
||||
cmake -DUNIT_TESTING=ON -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
|
||||
make
|
||||
|
||||
On Windows you should choose a makefile gernerator with -G or use
|
||||
|
||||
cmake-gui.exe ..
|
||||
|
||||
To enable additional client tests against a local OpenSSH server, add the
|
||||
compile option -DCLIENT_TESTING=ON. These tests require an OpenSSH
|
||||
server package and some wrapper libraries (see optional requirements) to
|
||||
be installed.
|
||||
|
||||
If you're interested in server testing, then a OpenSSH client should be
|
||||
installed on the system and if possible also dropbear. Once that is done
|
||||
enable server support with -DWITH_SERVER=ON and enable testing of it with
|
||||
-DSERVER_TESTING=ON.
|
||||
|
||||
## Testing build
|
||||
|
||||
make test
|
||||
|
||||
### CMake standard options
|
||||
Here is a list of the most interesting options provided out of the box by
|
||||
CMake.
|
||||
|
||||
125
README
125
README
@@ -33,130 +33,11 @@ If you ask yourself how to compile libssh, please read INSTALL before anything.
|
||||
|
||||
http://www.libssh.org
|
||||
|
||||
4* API Changes !
|
||||
4* Contributing
|
||||
-_-_-_-_-_-_-_-_-_
|
||||
|
||||
Changes between 0.4 and 0.5
|
||||
---------------------------
|
||||
|
||||
We use the ssh_ prefix as namespace for every function now. There is a legacy.h
|
||||
which could be used to get the old function names.
|
||||
|
||||
Changes between 0.3 and 0.4
|
||||
---------------------------
|
||||
|
||||
We changed libssh to be typesafe now:
|
||||
|
||||
SSH_SESSION *session -> ssh_session session
|
||||
SFTP_SESSION *sftp -> sftp_session sftp
|
||||
CHANNEL *channel -> ssh_channel channel
|
||||
STRING *string -> ssh_string string
|
||||
...
|
||||
|
||||
The options structure has been removed and there is a new function. This
|
||||
function can set all available options now. You can find the enum in the
|
||||
header file and it is documented. Example:
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
|
||||
5* Copyright policy
|
||||
-_-_-_-_-_-_-_-_-_-_
|
||||
|
||||
libssh is a project with distributed copyright ownership, which means we prefer
|
||||
the copyright on parts of libssh to be held by individuals rather than
|
||||
corporations if possible. There are historical legal reasons for this, but one
|
||||
of the best ways to explain it is that it’s much easier to work with
|
||||
individuals who have ownership than corporate legal departments if we ever need
|
||||
to make reasonable compromises with people using and working with libssh.
|
||||
|
||||
We track the ownership of every part of libssh via git, our source code control
|
||||
system, so we know the provenance of every piece of code that is committed to
|
||||
libssh.
|
||||
|
||||
So if possible, if you’re doing libssh changes on behalf of a company who
|
||||
normally owns all the work you do please get them to assign personal copyright
|
||||
ownership of your changes to you as an individual, that makes things very easy
|
||||
for us to work with and avoids bringing corporate legal departments into the
|
||||
picture.
|
||||
|
||||
If you can’t do this we can still accept patches from you owned by your
|
||||
employer under a standard employment contract with corporate copyright
|
||||
ownership. It just requires a simple set-up process first.
|
||||
|
||||
We use a process very similar to the way things are done in the Linux Kernel
|
||||
community, so it should be very easy to get a sign off from your corporate
|
||||
legal department. The only changes we’ve made are to accommodate the license we
|
||||
use, which is LGPLv2 (or later) whereas the Linux kernel uses GPLv2.
|
||||
|
||||
The process is called signing.
|
||||
|
||||
How to sign your work
|
||||
----------------------
|
||||
|
||||
Once you have permission to contribute to libssh from your employer, simply
|
||||
email a copy of the following text from your corporate email address to:
|
||||
|
||||
contributing@libssh.org
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
libssh Developer's Certificate of Origin. Version 1.0
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the appropriate
|
||||
version of the GNU General Public License; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best of
|
||||
my knowledge, is covered under an appropriate open source license
|
||||
and I have the right under that license to submit that work with
|
||||
modifications, whether created in whole or in part by me, under
|
||||
the GNU General Public License, in the appropriate version; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a) or (b) and I have not modified it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution are
|
||||
public and that a record of the contribution (including all
|
||||
metadata and personal information I submit with it, including my
|
||||
sign-off) is maintained indefinitely and may be redistributed
|
||||
consistent with the libssh Team's policies and the requirements of
|
||||
the GNU GPL where they are relevant.
|
||||
|
||||
(e) I am granting this work to this project under the terms of the
|
||||
GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2.1 of
|
||||
the License, or (at the option of the project) any later version.
|
||||
|
||||
http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
We will maintain a copy of that email as a record that you have the rights to
|
||||
contribute code to libssh under the required licenses whilst working for the
|
||||
company where the email came from.
|
||||
|
||||
Then when sending in a patch via the normal mechanisms described above, add a
|
||||
line that states:
|
||||
|
||||
|
||||
Signed-off-by: Random J Developer <random@developer.example.org>
|
||||
|
||||
|
||||
using your real name and the email address you sent the original email you used
|
||||
to send the libssh Developer’s Certificate of Origin to us (sorry, no
|
||||
pseudonyms or anonymous contributions.)
|
||||
|
||||
That’s it! Such code can then quite happily contain changes that have copyright
|
||||
messages such as:
|
||||
|
||||
|
||||
(c) Example Corporation.
|
||||
|
||||
|
||||
and can be merged into the libssh codebase in the same way as patches from any
|
||||
other individual. You don’t need to send in a copy of the libssh Developer’s
|
||||
Certificate of Origin for each patch, or inside each patch. Just the sign-off
|
||||
message is all that is required once we’ve received the initial email.
|
||||
Please read the file 'SubmittingPatches' next to this README file. It explains
|
||||
our copyright policy and how you should send patches for upstream inclusion.
|
||||
|
||||
Have fun and happy libssh hacking!
|
||||
|
||||
|
||||
@@ -287,6 +287,27 @@ Good Examples:
|
||||
return rc;
|
||||
}
|
||||
|
||||
Initialize pointers
|
||||
-------------------
|
||||
|
||||
All pointer variables MUST be initialized to NULL. History has
|
||||
demonstrated that uninitialized pointer variables have lead to various
|
||||
bugs and security issues.
|
||||
|
||||
Pointers MUST be initialized even if the assignment directly follows
|
||||
the declaration, like pointer2 in the example below, because the
|
||||
instructions sequence may change over time.
|
||||
|
||||
Good Example:
|
||||
|
||||
char *pointer1 = NULL;
|
||||
char *pointer2 = NULL;
|
||||
|
||||
pointer2 = some_func2();
|
||||
|
||||
...
|
||||
|
||||
pointer1 = some_func1();
|
||||
|
||||
Typedefs
|
||||
---------
|
||||
|
||||
11
README.mbedtls
Normal file
11
README.mbedtls
Normal file
@@ -0,0 +1,11 @@
|
||||
mbedTLS and libssh in multithreaded applications
|
||||
==================================================
|
||||
|
||||
To use libssh with mbedTLS in a multithreaded application, mbedTLS has to be
|
||||
built with threading support enabled.
|
||||
|
||||
If threading support is not available and multi threading is used, ssh_init
|
||||
will fail.
|
||||
|
||||
More information about building mbedTLS with threading support can be found
|
||||
in the mbedTLS documentation.
|
||||
44
README.md
Normal file
44
README.md
Normal file
@@ -0,0 +1,44 @@
|
||||
[](https://gitlab.com/libssh/libssh-mirror/commits/master)
|
||||
|
||||
```
|
||||
_ _ _ _
|
||||
(_) (_) (_) (_)
|
||||
(_) _ (_) _ _ _ _ _ (_) _
|
||||
(_) (_) (_)(_) _ (_)(_) (_)(_) (_)(_) _
|
||||
(_) (_) (_) (_) _ (_) _ (_) (_) (_)
|
||||
(_) (_) (_)(_)(_) (_)(_) (_)(_) (_) (_).org
|
||||
|
||||
The SSH library
|
||||
|
||||
```
|
||||
|
||||
# Why?
|
||||
|
||||
Why not ? :) I've began to work on my own implementation of the ssh protocol
|
||||
because i didn't like the currently public ones.
|
||||
Not any allowed you to import and use the functions as a powerful library,
|
||||
and so i worked on a library-based SSH implementation which was non-existing
|
||||
in the free and open source software world.
|
||||
|
||||
|
||||
# How/Who?
|
||||
|
||||
If you downloaded this file, you must know what it is : a library for
|
||||
accessing ssh client services through C libraries calls in a simple manner.
|
||||
Everybody can use this software under the terms of the LGPL - see the COPYING
|
||||
file
|
||||
|
||||
If you ask yourself how to compile libssh, please read INSTALL before anything.
|
||||
|
||||
# Where ?
|
||||
|
||||
https://www.libssh.org
|
||||
|
||||
# Contributing
|
||||
|
||||
Please read the file 'SubmittingPatches' next to this README file. It explains
|
||||
our copyright policy and how you should send patches for upstream inclusion.
|
||||
|
||||
Have fun and happy libssh hacking!
|
||||
|
||||
The libssh Team
|
||||
@@ -1,9 +1,9 @@
|
||||
How to contribute a patch to libssh
|
||||
====================================
|
||||
|
||||
Simple, just make the code change, and email it as either a "diff -u"
|
||||
change, or as a "git format-patch" change against the original source
|
||||
code to libssh@libssh.org, or attach it to a bug report at
|
||||
Please checkout the libssh source code using git. Change the code and then
|
||||
use "git format-patch" to create a patch. The patch should be signed (see
|
||||
below) and send it to libssh@libssh.org, or attach it to a bug report at
|
||||
https://red.libssh.org/
|
||||
|
||||
For larger code changes, breaking the changes up into a set of simple
|
||||
|
||||
@@ -23,8 +23,16 @@ if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW)
|
||||
set(CMAKE_EXEC_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" CACHE STRING "Address sanitizer executable linker flags")
|
||||
endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW)
|
||||
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
if (WIN32)
|
||||
find_program(WINE_EXECUTABLE
|
||||
NAMES wine)
|
||||
set(TARGET_SYSTEM_EMULATOR ${WINE_EXECUTABLE})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function (ADD_CMOCKA_TEST _testName _testSource)
|
||||
add_executable(${_testName} ${_testSource})
|
||||
target_link_libraries(${_testName} ${ARGN})
|
||||
add_test(${_testName} ${CMAKE_CURRENT_BINARY_DIR}/${_testName})
|
||||
add_test(${_testName} ${TARGET_SYSTEM_EMULATOR} ${CMAKE_CURRENT_BINARY_DIR}/${_testName}${CMAKE_EXECUTABLE_SUFFIX})
|
||||
endfunction (ADD_CMOCKA_TEST)
|
||||
|
||||
88
cmake/Modules/ExtractSymbols.cmake
Normal file
88
cmake/Modules/ExtractSymbols.cmake
Normal file
@@ -0,0 +1,88 @@
|
||||
#
|
||||
# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
#.rst:
|
||||
# ExtractSymbols
|
||||
# --------------
|
||||
#
|
||||
# This is a helper script for FindABImap.cmake.
|
||||
#
|
||||
# Extract symbols from header files and output a list to a file.
|
||||
# This script is run in build time to extract symbols from the provided header
|
||||
# files. This way, symbols added or removed can be checked and used to update
|
||||
# the symbol version script.
|
||||
#
|
||||
# All symbols followed by the character ``'('`` are extracted. If a
|
||||
# ``FILTER_PATTERN`` is provided, only the lines containing the given string are
|
||||
# considered.
|
||||
#
|
||||
# Expected defined variables
|
||||
# --------------------------
|
||||
#
|
||||
# ``HEADERS_LIST_FILE``:
|
||||
# Required, expects a file containing the list of header files to be parsed.
|
||||
#
|
||||
# ``OUTPUT_PATH``:
|
||||
# Required, expects the output file path.
|
||||
#
|
||||
# Optionally defined variables
|
||||
# ----------------------------
|
||||
#
|
||||
# ``FILTER_PATTERN``:
|
||||
# Expects a string. Only lines containing the given string will be considered
|
||||
# when extracting symbols.
|
||||
#
|
||||
|
||||
if (NOT DEFINED OUTPUT_PATH)
|
||||
message(SEND_ERROR "OUTPUT_PATH not defined")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED HEADERS_LIST_FILE)
|
||||
message(SEND_ERROR "HEADERS not defined")
|
||||
endif()
|
||||
|
||||
file(READ ${HEADERS_LIST_FILE} HEADERS_LIST)
|
||||
|
||||
set(symbols)
|
||||
foreach(header ${HEADERS_LIST})
|
||||
|
||||
# Filter only lines containing the FILTER_PATTERN
|
||||
file(STRINGS ${header} contain_filter
|
||||
REGEX "^.*${FILTER_PATTERN}.*[(]"
|
||||
)
|
||||
|
||||
# Remove function-like macros
|
||||
foreach(line ${contain_filter})
|
||||
if (NOT ${line} MATCHES ".*#[ ]*define")
|
||||
list(APPEND not_macro ${line})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(functions)
|
||||
|
||||
# Get only the function names followed by '('
|
||||
foreach(line ${not_macro})
|
||||
string(REGEX MATCHALL "[a-zA-Z0-9_]+[ ]*[(]" func ${line})
|
||||
list(APPEND functions ${func})
|
||||
endforeach()
|
||||
|
||||
set(extracted_symbols)
|
||||
|
||||
# Remove '('
|
||||
foreach(line ${functions})
|
||||
string(REGEX REPLACE "[(]" "" symbol ${line})
|
||||
string(STRIP "${symbol}" symbol)
|
||||
list(APPEND extracted_symbols ${symbol})
|
||||
endforeach()
|
||||
|
||||
list(APPEND symbols ${extracted_symbols})
|
||||
endforeach()
|
||||
|
||||
list(REMOVE_DUPLICATES symbols)
|
||||
|
||||
file(WRITE ${OUTPUT_PATH} "${symbols}")
|
||||
394
cmake/Modules/FindABIMap.cmake
Normal file
394
cmake/Modules/FindABIMap.cmake
Normal file
@@ -0,0 +1,394 @@
|
||||
#
|
||||
# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
#.rst:
|
||||
# FindABIMap
|
||||
# ----------
|
||||
#
|
||||
# This file provides functions to generate the symbol version script. It uses
|
||||
# the ``abimap`` tool to generate and update the linker script file. It can be
|
||||
# installed by calling::
|
||||
#
|
||||
# $ pip install abimap
|
||||
#
|
||||
# The ``function generate_map_file`` generates a symbol version script
|
||||
# containing the provided symbols. It defines a custom command which sets
|
||||
# ``target_name`` as its ``OUTPUT``.
|
||||
#
|
||||
# The experimental function ``extract_symbols()`` is provided as a simple
|
||||
# parser to extract the symbols from C header files. It simply extracts symbols
|
||||
# followed by an opening '``(``'. It is recommended to use a filter pattern to
|
||||
# select the lines to be considered. It defines a custom command which sets
|
||||
# ``target_name`` as its output.
|
||||
#
|
||||
# The helper function ``get_files_list()`` is provided to find files given a
|
||||
# name pattern. It defines a custom command which sets ``target_name`` as its
|
||||
# output.
|
||||
#
|
||||
# Functions provided
|
||||
# ------------------
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# generate_map_file(target_name
|
||||
# RELEASE_NAME_VERSION release_name
|
||||
# SYMBOLS symbols_file
|
||||
# [CURRENT_MAP cur_map]
|
||||
# [FINAL]
|
||||
# [BREAK_ABI]
|
||||
# [COPY_TO output]
|
||||
# )
|
||||
#
|
||||
# ``target_name``:
|
||||
# Required, expects the name of the file to receive the generated symbol
|
||||
# version script. It should be added as a dependency for the library. Use the
|
||||
# linker option ``--version-script filename`` to add the version information
|
||||
# to the symbols when building the library.
|
||||
#
|
||||
# ``RELEASE_NAME_VERSION``:
|
||||
# Required, expects a string containing the name and version information to be
|
||||
# added to the symbols in the format ``lib_name_1_2_3``.
|
||||
#
|
||||
# ``SYMBOLS``:
|
||||
# Required, expects a file containing the list of symbols to be added to the
|
||||
# symbol version script.
|
||||
#
|
||||
# ``CURRENT_MAP``:
|
||||
# Optional. If given, the new set of symbols will be checked against the
|
||||
# ones contained in the ``cur_map`` file and updated properly. If an
|
||||
# incompatible change is detected and ``BREAK_ABI`` is not defined, the build
|
||||
# will fail.
|
||||
#
|
||||
# ``FINAL``:
|
||||
# Optional. If given, will provide the ``--final`` option to ``abimap`` tool,
|
||||
# which will mark the modified release in the symbol version script with a
|
||||
# special comment, preventing later changes. This option should be set when
|
||||
# creating a library release and the resulting map file should be stored with
|
||||
# the source code.
|
||||
#
|
||||
# ``BREAK_ABI``:
|
||||
# Optional. If provided, will use ``abimap`` ``--allow-abi-break`` option, which
|
||||
# accepts incompatible changes to the set of symbols. This is necessary if any
|
||||
# previously existing symbol were removed.
|
||||
#
|
||||
# ``COPY_TO``:
|
||||
# Optional, expects a string containing the path to where the generated
|
||||
# map file will be copied.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# .. code-block:: cmake
|
||||
#
|
||||
# find_package(ABIMap)
|
||||
# generate_map_file("lib.map"
|
||||
# RELEASE_NAME_VERSION "lib_1_0_0"
|
||||
# SYMBOLS "symbol1;symbol2"
|
||||
# )
|
||||
#
|
||||
# This example would result in the symbol version script to be created in
|
||||
# ``${CMAKE_CURRENT_BINARY_DIR}/lib.map`` containing the provided symbols.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# get_files_list(target_name
|
||||
# DIRECTORIES dir1 [dir2 ...]
|
||||
# FILES_PATTERNS exp1 [exp2 ...]
|
||||
# [COPY_TO output]
|
||||
# )
|
||||
#
|
||||
# ``target_name``:
|
||||
# Required, expects the name of the target to be created. A file named after
|
||||
# the string given in ``target_name`` will be created in
|
||||
# ``${CMAKE_CURRENT_BINARY_DIR}`` to receive the list of files found.
|
||||
#
|
||||
# ``DIRECTORIES``:
|
||||
# Required, expects a list of directories paths. Only absolute paths are
|
||||
# supported.
|
||||
#
|
||||
# ``FILES_PATTERN``:
|
||||
# Required, expects a list of matching expressions to find the files to be
|
||||
# considered.
|
||||
#
|
||||
# ``COPY_TO``:
|
||||
# Optional, expects a string containing the path to where the file containing
|
||||
# the list of files will be copied.
|
||||
#
|
||||
# This command searches the directories provided in ``DIRECTORIES`` for files
|
||||
# matching any of the patterns provided in ``FILES_PATTERNS``. The obtained list
|
||||
# is written to the path specified by ``output``.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# .. code-block:: cmake
|
||||
#
|
||||
# find_package(ABIMap)
|
||||
# get_files_list(target
|
||||
# DIRECTORIES "/include/mylib"
|
||||
# FILES_PATTERNS "*.h"
|
||||
# COPY_TO "my_list.txt"
|
||||
# )
|
||||
#
|
||||
# Consider that ``/include/mylib`` contains 3 files, ``h1.h``, ``h2.h``, and
|
||||
# ``h3.hpp``
|
||||
#
|
||||
# Will result in a file ``my_list.txt`` containing::
|
||||
#
|
||||
# ``h1.h;h2.h``
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# extract_symbols(target_name
|
||||
# HEADERS_LIST_FILE headers_list
|
||||
# [FILTER_PATTERN pattern]
|
||||
# [COPY_TO output]
|
||||
# )
|
||||
#
|
||||
# ``target_name``:
|
||||
# Required, expects the name of the target to be created. A file named after
|
||||
# the string given in ``target_name`` will be created in
|
||||
# ``${CMAKE_CURRENT_BINARY_DIR}`` to receive the list of symbols.
|
||||
#
|
||||
# ``HEADERS_LIST_FILE``:
|
||||
# Required, expects a path to a file containing the list of header files to be
|
||||
# parsed.
|
||||
#
|
||||
# ``FILTER_PATTERN``:
|
||||
# Optional, expects a string. Only the lines containing the filter pattern
|
||||
# will be considered.
|
||||
#
|
||||
# ``COPY_TO``:
|
||||
# Optional, expects a string containing the path to where the file containing
|
||||
# the found symbols will be copied.
|
||||
#
|
||||
# This command extracts the symbols from the files listed in
|
||||
# ``headers_list`` and write them on the ``output`` file. If ``pattern``
|
||||
# is provided, then only the lines containing the string given in ``pattern``
|
||||
# will be considered. It is recommended to provide a ``FILTER_PATTERN`` to mark
|
||||
# the lines containing exported function declaration, since this function is
|
||||
# experimental and can return wrong symbols when parsing the header files.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# .. code-block:: cmake
|
||||
#
|
||||
# find_package(ABIMap)
|
||||
# extract_symbols("lib.symbols"
|
||||
# HEADERS_LIST_FILE "headers_list"
|
||||
# FILTER_PATTERN "API_FUNCTION"
|
||||
# )
|
||||
#
|
||||
# Where headers_list contains::
|
||||
#
|
||||
# header1.h;header2.h
|
||||
#
|
||||
# Where ``header1.h`` contains::
|
||||
#
|
||||
# API_FUNCTION int exported_func1(int a, int b);
|
||||
#
|
||||
# ``header2.h`` contains::
|
||||
#
|
||||
# API_FUNCTION int exported_func2(int a);
|
||||
#
|
||||
# int private_func2(int b);
|
||||
#
|
||||
# Will result in a file ``lib.symbols`` in ``${CMAKE_CURRENT_BINARY_DIR}`` containing::
|
||||
#
|
||||
# ``exported_func1;exported_func2``
|
||||
#
|
||||
|
||||
# Search for python which is required
|
||||
find_package(PythonInterp REQUIRED)
|
||||
|
||||
# Search for abimap tool used to generate the map files
|
||||
find_program(ABIMAP_EXECUTABLE NAMES abimap DOC "path to the abimap executable")
|
||||
mark_as_advanced(ABIMAP_EXECUTABLE)
|
||||
|
||||
if (NOT ABIMAP_EXECUTABLE AND UNIX)
|
||||
message(STATUS "Could not find `abimap` in PATH."
|
||||
" It can be found in PyPI as `abimap`"
|
||||
" (try `pip install abimap`)")
|
||||
else ()
|
||||
set(ABIMAP_FOUND TRUE)
|
||||
endif ()
|
||||
|
||||
# Define helper scripts
|
||||
set(_EXTRACT_SYMBOLS_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/ExtractSymbols.cmake)
|
||||
set(_GENERATE_MAP_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/GenerateMap.cmake)
|
||||
set(_GET_FILES_LIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/GetFilesList.cmake)
|
||||
|
||||
function(get_file_list _TARGET_NAME)
|
||||
|
||||
set(one_value_arguments
|
||||
COPY_TO
|
||||
)
|
||||
|
||||
set(multi_value_arguments
|
||||
DIRECTORIES
|
||||
FILES_PATTERNS
|
||||
)
|
||||
|
||||
cmake_parse_arguments(_get_files_list
|
||||
""
|
||||
"${one_value_arguments}"
|
||||
"${multi_value_arguments}"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
# The DIRS argument is required
|
||||
if (NOT DEFINED _get_files_list_DIRECTORIES)
|
||||
message(FATAL_ERROR "No directories paths provided. Provide a list of"
|
||||
" directories paths containing header files."
|
||||
)
|
||||
endif()
|
||||
|
||||
# The FILES_PATTERNS argument is required
|
||||
if (NOT DEFINED _get_files_list_FILES_PATTERNS)
|
||||
message(FATAL_ERROR "No matching expressions provided. Provide a list"
|
||||
" of matching patterns for the header files."
|
||||
)
|
||||
endif()
|
||||
|
||||
get_filename_component(_get_files_list_OUTPUT_PATH
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}"
|
||||
ABSOLUTE
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${_TARGET_NAME}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DOUTPUT_PATH="${_get_files_list_OUTPUT_PATH}"
|
||||
-DDIRECTORIES="${_get_files_list_DIRECTORIES}"
|
||||
-DFILES_PATTERNS="${_get_files_list_FILES_PATTERNS}"
|
||||
-P ${_GET_FILES_LIST_SCRIPT}
|
||||
COMMENT
|
||||
"Searching for files"
|
||||
)
|
||||
|
||||
if (DEFINED _get_files_list_COPY_TO)
|
||||
# Copy the generated file back to the COPY_TO
|
||||
add_custom_target(copy_headers_list_${TARGET_NAME} ALL
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E copy_if_different ${_TARGET_NAME} ${_get_files_list_COPY_TO}
|
||||
DEPENDS "${_TARGET_NAME}"
|
||||
COMMENT "Copying ${_TARGET_NAME} to ${_get_files_list_COPY_TO}"
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(extract_symbols _TARGET_NAME)
|
||||
|
||||
set(one_value_arguments
|
||||
FILTER_PATTERN
|
||||
HEADERS_LIST_FILE
|
||||
COPY_TO
|
||||
)
|
||||
|
||||
set(multi_value_arguments
|
||||
)
|
||||
|
||||
cmake_parse_arguments(_extract_symbols
|
||||
""
|
||||
"${one_value_arguments}"
|
||||
"${multi_value_arguments}"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
# The HEADERS_LIST_FILE argument is required
|
||||
if (NOT DEFINED _extract_symbols_HEADERS_LIST_FILE)
|
||||
message(FATAL_ERROR "No header files given. Provide a list of header"
|
||||
" files containing exported symbols."
|
||||
)
|
||||
endif()
|
||||
|
||||
get_filename_component(_extract_symbols_OUTPUT_PATH
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}"
|
||||
ABSOLUTE
|
||||
)
|
||||
|
||||
add_custom_target(${_TARGET_NAME}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DOUTPUT_PATH="${_extract_symbols_OUTPUT_PATH}"
|
||||
-DHEADERS_LIST_FILE="${_extract_symbols_HEADERS_LIST_FILE}"
|
||||
-DFILTER_PATTERN=${_extract_symbols_FILTER_PATTERN}
|
||||
-P ${_EXTRACT_SYMBOLS_SCRIPT}
|
||||
DEPENDS ${_extract_symbols_HEADERS_LIST_FILE}
|
||||
COMMENT "Extracting symbols from headers")
|
||||
|
||||
if (DEFINED _extract_symbols_COPY_TO)
|
||||
file(READ "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}" SYMBOL_CONTENT)
|
||||
string(REPLACE ";" "\n" SYMBOL_CONTENT_NEW "${SYMBOL_CONTENT}")
|
||||
file(WRITE "${_extract_symbols_COPY_TO}" "${SYMBOL_CONTENT_NEW}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(generate_map_file _TARGET_NAME)
|
||||
|
||||
set(options
|
||||
FINAL
|
||||
BREAK_ABI
|
||||
)
|
||||
|
||||
set(one_value_arguments
|
||||
RELEASE_NAME_VERSION
|
||||
SYMBOLS
|
||||
CURRENT_MAP
|
||||
COPY_TO
|
||||
)
|
||||
|
||||
set(multi_value_arguments
|
||||
)
|
||||
|
||||
cmake_parse_arguments(_generate_map_file
|
||||
"${options}"
|
||||
"${one_value_arguments}"
|
||||
"${multi_value_arguments}"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
if (NOT DEFINED _generate_map_file_SYMBOLS)
|
||||
message(FATAL_ERROR "No symbols file provided."
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED _generate_map_file_RELEASE_NAME_VERSION)
|
||||
message(FATAL_ERROR "Release name and version not provided."
|
||||
" (e.g. libname_1_0_0"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Set generated map file path
|
||||
get_filename_component(_generate_map_file_OUTPUT_PATH
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}"
|
||||
ABSOLUTE
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${_TARGET_NAME}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DABIMAP_EXECUTABLE=${ABIMAP_EXECUTABLE}
|
||||
-DSYMBOLS="${_generate_map_file_SYMBOLS}"
|
||||
-DCURRENT_MAP=${_generate_map_file_CURRENT_MAP}
|
||||
-DOUTPUT_PATH="${_generate_map_file_OUTPUT_PATH}"
|
||||
-DFINAL=${_generate_map_file_FINAL}
|
||||
-DBREAK_ABI=${_generate_map_file_BREAK_ABI}
|
||||
-DRELEASE_NAME_VERSION=${_generate_map_file_RELEASE_NAME_VERSION}
|
||||
-P ${_GENERATE_MAP_SCRIPT}
|
||||
DEPENDS ${_generate_map_file_SYMBOLS}
|
||||
COMMENT "Generating the map ${_TARGET_NAME}"
|
||||
)
|
||||
|
||||
if (DEFINED _generate_map_file_COPY_TO)
|
||||
# Copy the generated map back to the COPY_TO
|
||||
add_custom_target(copy_map_${_TARGET_NAME} ALL
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E copy_if_different ${_TARGET_NAME} ${_generate_map_file_COPY_TO}
|
||||
DEPENDS "${_TARGET_NAME}"
|
||||
COMMENT "Copying ${_TARGET_NAME} to ${_generate_map_file_COPY_TO}"
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -1,60 +1,66 @@
|
||||
# - Try to find Argp
|
||||
# - Try to find ARGP
|
||||
# Once done this will define
|
||||
#
|
||||
# ARGP_FOUND - system has Argp
|
||||
# ARGP_INCLUDE_DIRS - the Argp include directory
|
||||
# ARGP_LIBRARIES - Link these to use Argp
|
||||
# ARGP_DEFINITIONS - Compiler switches required for using Argp
|
||||
# ARGP_ROOT_DIR - Set this variable to the root installation of ARGP
|
||||
#
|
||||
# Copyright (c) 2010 Andreas Schneider <asn@cryptomilk.org>
|
||||
# Read-Only variables:
|
||||
# ARGP_FOUND - system has ARGP
|
||||
# ARGP_INCLUDE_DIR - the ARGP include directory
|
||||
# ARGP_LIBRARIES - Link these to use ARGP
|
||||
# ARGP_DEFINITIONS - Compiler switches required for using ARGP
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#=============================================================================
|
||||
# Copyright (c) 2011-2016 Andreas Schneider <asn@cryptomilk.org>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
#
|
||||
|
||||
set(_ARGP_ROOT_HINTS
|
||||
)
|
||||
|
||||
if (ARGP_LIBRARIES AND ARGP_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(ARGP_FOUND TRUE)
|
||||
else (ARGP_LIBRARIES AND ARGP_INCLUDE_DIRS)
|
||||
set(_ARGP_ROOT_PATHS
|
||||
"$ENV{PROGRAMFILES}/argp"
|
||||
)
|
||||
|
||||
find_path(ARGP_INCLUDE_DIR
|
||||
find_path(ARGP_ROOT_DIR
|
||||
NAMES
|
||||
argp.h
|
||||
include/argp.h
|
||||
HINTS
|
||||
${_ARGP_ROOT_HINTS}
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
)
|
||||
${_ARGP_ROOT_PATHS}
|
||||
)
|
||||
mark_as_advanced(ARGP_ROOT_DIR)
|
||||
|
||||
find_library(ARGP_LIBRARY
|
||||
find_path(ARGP_INCLUDE_DIR
|
||||
NAMES
|
||||
argp
|
||||
argp.h
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
${ARGP_ROOT_DIR}/include
|
||||
)
|
||||
|
||||
find_library(ARGP_LIBRARY
|
||||
NAMES
|
||||
argp
|
||||
PATHS
|
||||
${ARGP_ROOT_DIR}/lib
|
||||
)
|
||||
|
||||
if (ARGP_LIBRARY)
|
||||
set(ARGP_LIBRARIES
|
||||
${ARGP_LIBRARIES}
|
||||
${ARGP_LIBRARY}
|
||||
)
|
||||
endif (ARGP_LIBRARY)
|
||||
|
||||
set(ARGP_INCLUDE_DIRS
|
||||
${ARGP_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
if (ARGP_LIBRARY)
|
||||
set(ARGP_LIBRARIES
|
||||
${ARGP_LIBRARIES}
|
||||
${ARGP_LIBRARY}
|
||||
)
|
||||
endif (ARGP_LIBRARY)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Argp DEFAULT_MSG ARGP_LIBRARIES ARGP_INCLUDE_DIRS)
|
||||
|
||||
# show the ARGP_INCLUDE_DIRS and ARGP_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(ARGP_INCLUDE_DIRS ARGP_LIBRARIES)
|
||||
|
||||
endif (ARGP_LIBRARIES AND ARGP_INCLUDE_DIRS)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(ARGP DEFAULT_MSG ARGP_LIBRARIES ARGP_INCLUDE_DIR)
|
||||
|
||||
# show the ARGP_INCLUDE_DIR and ARGP_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(ARGP_INCLUDE_DIR ARGP_LIBRARIES)
|
||||
|
||||
@@ -35,6 +35,8 @@ find_path(GCRYPT_INCLUDE_DIR
|
||||
gcrypt.h
|
||||
HINTS
|
||||
${_GCRYPT_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
find_library(GCRYPT_LIBRARY
|
||||
@@ -44,13 +46,15 @@ find_library(GCRYPT_LIBRARY
|
||||
libgcrypt-11
|
||||
HINTS
|
||||
${_GCRYPT_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
set(GCRYPT_LIBRARIES ${GCRYPT_LIBRARY})
|
||||
|
||||
if (GCRYPT_INCLUDE_DIR)
|
||||
file(STRINGS "${GCRYPT_INCLUDE_DIR}/gcrypt.h" _gcrypt_version_str REGEX "^#define GCRYPT_VERSION \"[0-9]+.[0-9]+.[0-9]+\"")
|
||||
file(STRINGS "${GCRYPT_INCLUDE_DIR}/gcrypt.h" _gcrypt_version_str REGEX "^#define GCRYPT_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]")
|
||||
|
||||
string(REGEX REPLACE "^.*GCRYPT_VERSION.*([0-9]+.[0-9]+.[0-9]+).*" "\\1" GCRYPT_VERSION "${_gcrypt_version_str}")
|
||||
string(REGEX REPLACE "^.*GCRYPT_VERSION.*([0-9]+\\.[0-9]+\\.[0-9]+).*" "\\1" GCRYPT_VERSION "${_gcrypt_version_str}")
|
||||
endif (GCRYPT_INCLUDE_DIR)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
@@ -54,7 +54,8 @@ if (UNIX)
|
||||
OUTPUT_VARIABLE
|
||||
_GSSAPI_VENDOR_STRING)
|
||||
|
||||
if (_GSSAPI_VENDOR_STRING MATCHES ".*Massachusetts.*")
|
||||
if ((_GSSAPI_VENDOR_STRING MATCHES ".*Massachusetts.*") OR (_GSSAPI_VENDOR_STRING
|
||||
MATCHES ".*MITKerberosShim.*"))
|
||||
set(GSSAPI_FLAVOR_MIT TRUE)
|
||||
else()
|
||||
execute_process(
|
||||
|
||||
104
cmake/Modules/FindMbedTLS.cmake
Normal file
104
cmake/Modules/FindMbedTLS.cmake
Normal file
@@ -0,0 +1,104 @@
|
||||
# - Try to find mbedTLS
|
||||
# Once done this will define
|
||||
#
|
||||
# MBEDTLS_FOUND - system has mbedTLS
|
||||
# MBEDTLS_INCLUDE_DIRS - the mbedTLS include directory
|
||||
# MBEDTLS_LIBRARIES - Link these to use mbedTLS
|
||||
# MBEDTLS_DEFINITIONS - Compiler switches required for using mbedTLS
|
||||
#=============================================================================
|
||||
# Copyright (c) 2017 Sartura d.o.o.
|
||||
#
|
||||
# Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
#
|
||||
|
||||
|
||||
set(_MBEDTLS_ROOT_HINTS
|
||||
$ENV{MBEDTLS_ROOT_DIR}
|
||||
${MBEDTLS_ROOT_DIR})
|
||||
|
||||
set(_MBEDTLS_ROOT_PATHS
|
||||
"$ENV{PROGRAMFILES}/libmbedtls")
|
||||
|
||||
set(_MBEDTLS_ROOT_HINTS_AND_PATHS
|
||||
HINTS ${_MBEDTLS_ROOT_HINTS}
|
||||
PATHS ${_MBEDTLS_ROOT_PATHS})
|
||||
|
||||
|
||||
find_path(MBEDTLS_INCLUDE_DIR
|
||||
NAMES
|
||||
mbedtls/config.h
|
||||
HINTS
|
||||
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
find_library(MBEDTLS_SSL_LIBRARY
|
||||
NAMES
|
||||
mbedtls
|
||||
HINTS
|
||||
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
|
||||
)
|
||||
|
||||
find_library(MBEDTLS_CRYPTO_LIBRARY
|
||||
NAMES
|
||||
mbedcrypto
|
||||
HINTS
|
||||
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
|
||||
find_library(MBEDTLS_X509_LIBRARY
|
||||
NAMES
|
||||
mbedx509
|
||||
HINTS
|
||||
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
|
||||
set(MBEDTLS_LIBRARIES ${MBEDTLS_SSL_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY}
|
||||
${MBEDTLS_X509_LIBRARY})
|
||||
|
||||
if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
|
||||
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX
|
||||
"^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
|
||||
|
||||
string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+.[0-9]+.[0-9]+).*"
|
||||
"\\1" MBEDTLS_VERSION "${_mbedtls_version_str}")
|
||||
endif ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
if (MBEDTLS_VERSION)
|
||||
find_package_handle_standard_args(MbedTLS
|
||||
REQUIRED_VARS
|
||||
MBEDTLS_INCLUDE_DIR
|
||||
MBEDTLS_LIBRARIES
|
||||
VERSION_VAR
|
||||
MBEDTLS_VERSION
|
||||
FAIL_MESSAGE
|
||||
"Could NOT find mbedTLS, try to set the path to mbedTLS root folder
|
||||
in the system variable MBEDTLS_ROOT_DIR"
|
||||
)
|
||||
else (MBEDTLS_VERSION)
|
||||
find_package_handle_standard_args(MBedTLS
|
||||
"Could NOT find mbedTLS, try to set the path to mbedLS root folder in
|
||||
the system variable MBEDTLS_ROOT_DIR"
|
||||
MBEDTLS_INCLUDE_DIR
|
||||
MBEDTLS_LIBRARIES)
|
||||
endif (MBEDTLS_VERSION)
|
||||
|
||||
# show the MBEDTLS_INCLUDE_DIRS and MBEDTLS_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARIES)
|
||||
118
cmake/Modules/GenerateMap.cmake
Normal file
118
cmake/Modules/GenerateMap.cmake
Normal file
@@ -0,0 +1,118 @@
|
||||
#
|
||||
# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
#.rst:
|
||||
# GenerateMap
|
||||
# -----------
|
||||
#
|
||||
# This is a helper script for FindABImap.cmake.
|
||||
#
|
||||
# Generates a symbols version script using the abimap tool.
|
||||
# This script is run in build time to use the correct command depending on the
|
||||
# existence of the file provided ``CURRENT_MAP``.
|
||||
#
|
||||
# If the file exists, the ``abimap update`` subcommand is used to update the
|
||||
# existing map. Otherwise, the ``abimap new`` subcommand is used to create a new
|
||||
# map file.
|
||||
#
|
||||
# If the file provided in ``CURRENT_MAP`` exists, it is copied to the
|
||||
# ``OUTPUT_PATH`` before updating.
|
||||
# This is required because ``abimap`` do not generate output if no symbols were
|
||||
# changed when updating an existing file.
|
||||
#
|
||||
# Expected defined variables
|
||||
# --------------------------
|
||||
#
|
||||
# ``SYMBOLS``:
|
||||
# Required file containing the symbols to be used as input. Usually this is
|
||||
# the ``OUTPUT`` generated by ``extract_symbols()`` function provided in
|
||||
# FindABImap.cmake
|
||||
#
|
||||
# ``RELEASE_NAME_VERSION``:
|
||||
# Required, expects the library name and version information to be added to
|
||||
# the symbols in the format ``library_name_1_2_3``
|
||||
#
|
||||
# ``CURRENT_MAP``:
|
||||
# Required, expects the path to the current map file (or the path were it
|
||||
# should be)
|
||||
#
|
||||
# ``OUTPUT_PATH``:
|
||||
# Required, expects the output file path.
|
||||
#
|
||||
# ``ABIMAP_EXECUTABLE``:
|
||||
# Required, expects the path to the ``abimap`` tool.
|
||||
#
|
||||
# Optionally defined variables
|
||||
# ----------------------------
|
||||
#
|
||||
# ``FINAL``:
|
||||
# If defined, will mark the modified set of symbols in the symbol version
|
||||
# script as final, preventing later changes using ``abimap``.
|
||||
#
|
||||
# ``BREAK_ABI``:
|
||||
# If defined, the build will not fail if symbols were removed.
|
||||
# If defined and a symbol is removed, a new release is created containing
|
||||
# all symbols from all released versions. This makes an incompatible release.
|
||||
#
|
||||
|
||||
if (NOT DEFINED RELEASE_NAME_VERSION)
|
||||
message(SEND_ERROR "RELEASE_NAME_VERSION not defined")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED SYMBOLS)
|
||||
message(SEND_ERROR "SYMBOLS not defined")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED CURRENT_MAP)
|
||||
message(SEND_ERROR "CURRENT_MAP not defined")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED OUTPUT_PATH)
|
||||
message(SEND_ERROR "OUTPUT_PATH not defined")
|
||||
endif()
|
||||
|
||||
if (NOT ABIMAP_EXECUTABLE)
|
||||
message(SEND_ERROR "ABIMAP_EXECUTABLE not defined")
|
||||
endif()
|
||||
|
||||
set(ARGS_LIST)
|
||||
|
||||
if (FINAL)
|
||||
list(APPEND ARGS_LIST "--final")
|
||||
endif()
|
||||
|
||||
if (EXISTS ${CURRENT_MAP})
|
||||
if (BREAK_ABI)
|
||||
list(APPEND ARGS_LIST "--allow-abi-break")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E copy_if_different ${CURRENT_MAP} ${OUTPUT_PATH}
|
||||
COMMAND
|
||||
${ABIMAP_EXECUTABLE} update ${ARGS_LIST}
|
||||
-r ${RELEASE_NAME_VERSION}
|
||||
-i ${SYMBOLS}
|
||||
-o ${OUTPUT_PATH}
|
||||
${CURRENT_MAP}
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
else ()
|
||||
execute_process(
|
||||
COMMAND
|
||||
${ABIMAP_EXECUTABLE} new ${ARGS_LIST}
|
||||
-r ${RELEASE_NAME_VERSION}
|
||||
-i ${SYMBOLS}
|
||||
-o ${OUTPUT_PATH}
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT "${result}" STREQUAL "0")
|
||||
message(SEND_ERROR "Map generation failed")
|
||||
endif()
|
||||
59
cmake/Modules/GetFilesList.cmake
Normal file
59
cmake/Modules/GetFilesList.cmake
Normal file
@@ -0,0 +1,59 @@
|
||||
#
|
||||
# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
#.rst:
|
||||
# GetFilesList
|
||||
# ------------
|
||||
#
|
||||
# This is a helper script for FindABImap.cmake.
|
||||
#
|
||||
# Search in the provided directories for files matching the provided pattern.
|
||||
# The list of files is then written to the output file.
|
||||
#
|
||||
# Expected defined variables
|
||||
# --------------------------
|
||||
#
|
||||
# ``DIRECTORIES``:
|
||||
# Required, expects a list of directories paths.
|
||||
#
|
||||
# ``FILES_PATTERNS``:
|
||||
# Required, expects a list of patterns to be used to search files
|
||||
#
|
||||
# ``OUTPUT_PATH``:
|
||||
# Required, expects the output file path.
|
||||
|
||||
if (NOT DEFINED DIRECTORIES)
|
||||
message(SEND_ERROR "DIRECTORIES not defined")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED FILES_PATTERNS)
|
||||
message(SEND_ERROR "FILES_PATTERNS not defined")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED OUTPUT_PATH)
|
||||
message(SEND_ERROR "OUTPUT_PATH not defined")
|
||||
endif()
|
||||
|
||||
string(REPLACE " " ";" DIRECTORIES_LIST "${DIRECTORIES}")
|
||||
string(REPLACE " " ";" FILES_PATTERNS_LIST "${FILES_PATTERNS}")
|
||||
|
||||
# Create the list of expressions for the files
|
||||
set(glob_expressions)
|
||||
foreach(dir ${DIRECTORIES_LIST})
|
||||
foreach(exp ${FILES_PATTERNS_LIST})
|
||||
list(APPEND glob_expressions
|
||||
"${dir}/${exp}"
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# Create the list of files
|
||||
file(GLOB files ${glob_expressions})
|
||||
|
||||
# Write to the output
|
||||
file(WRITE ${OUTPUT_PATH} "${files}")
|
||||
23
cmake/Toolchain-cross-m32.cmake
Normal file
23
cmake/Toolchain-cross-m32.cmake
Normal file
@@ -0,0 +1,23 @@
|
||||
set(CMAKE_C_FLAGS "-m32" CACHE STRING "C compiler flags" FORCE)
|
||||
set(CMAKE_CXX_FLAGS "-m32" CACHE STRING "C++ compiler flags" FORCE)
|
||||
|
||||
set(LIB32 /usr/lib) # Fedora
|
||||
|
||||
if(EXISTS /usr/lib32)
|
||||
set(LIB32 /usr/lib32) # Arch, Solus
|
||||
endif()
|
||||
|
||||
set(CMAKE_SYSTEM_LIBRARY_PATH ${LIB32} CACHE STRING "system library search path" FORCE)
|
||||
set(CMAKE_LIBRARY_PATH ${LIB32} CACHE STRING "library search path" FORCE)
|
||||
|
||||
# this is probably unlikely to be needed, but just in case
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "executable linker flags" FORCE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "shared library linker flags" FORCE)
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "module linker flags" FORCE)
|
||||
|
||||
# on Fedora and Arch and similar, point pkgconfig at 32 bit .pc files. We have
|
||||
# to include the regular system .pc files as well (at the end), because some
|
||||
# are not always present in the 32 bit directory
|
||||
if(EXISTS ${LIB32}/pkgconfig)
|
||||
set(ENV{PKG_CONFIG_LIBDIR} ${LIB32}/pkgconfig:/usr/share/pkgconfig:/usr/lib/pkgconfig:/usr/lib64/pkgconfig)
|
||||
endiF()
|
||||
@@ -20,6 +20,9 @@
|
||||
/* Define to 1 if you have the <aprpa/inet.h> header file. */
|
||||
#cmakedefine HAVE_ARPA_INET_H 1
|
||||
|
||||
/* Define to 1 if you have the <glob.h> header file. */
|
||||
#cmakedefine HAVE_GLOB_H 1
|
||||
|
||||
/* Define to 1 if you have the <pty.h> header file. */
|
||||
#cmakedefine HAVE_PTY_H 1
|
||||
|
||||
@@ -35,12 +38,21 @@
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#cmakedefine HAVE_SYS_TIME_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/utime.h> header file. */
|
||||
#cmakedefine HAVE_SYS_UTIME_H 1
|
||||
|
||||
/* Define to 1 if you have the <io.h> header file. */
|
||||
#cmakedefine HAVE_IO_H 1
|
||||
|
||||
/* Define to 1 if you have the <termios.h> header file. */
|
||||
#cmakedefine HAVE_TERMIOS_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#cmakedefine HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#cmakedefine HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <openssl/aes.h> header file. */
|
||||
#cmakedefine HAVE_OPENSSL_AES_H 1
|
||||
|
||||
@@ -74,8 +86,26 @@
|
||||
/* Define to 1 if you have eliptic curve cryptography */
|
||||
#cmakedefine HAVE_ECC 1
|
||||
|
||||
/* Define to 1 if you have DSA */
|
||||
#cmakedefine HAVE_DSA 1
|
||||
|
||||
/*************************** FUNCTIONS ***************************/
|
||||
|
||||
/* Define to 1 if you have the `EVP_aes128_ctr' function. */
|
||||
#cmakedefine HAVE_OPENSSL_EVP_AES_CTR 1
|
||||
|
||||
/* Define to 1 if you have the `EVP_aes128_cbc' function. */
|
||||
#cmakedefine HAVE_OPENSSL_EVP_AES_CBC 1
|
||||
|
||||
/* Define to 1 if you have the `CRYPTO_THREADID_set_callback' function. */
|
||||
#cmakedefine HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK 1
|
||||
|
||||
/* Define to 1 if you have the `CRYPTO_ctr128_encrypt' function. */
|
||||
#cmakedefine HAVE_OPENSSL_CRYPTO_CTR128_ENCRYPT 1
|
||||
|
||||
/* Define to 1 if you have the `EVP_CIPHER_CTX_new' function. */
|
||||
#cmakedefine HAVE_OPENSSL_EVP_CIPHER_CTX_NEW 1
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#cmakedefine HAVE_SNPRINTF 1
|
||||
|
||||
@@ -130,6 +160,18 @@
|
||||
/* Define to 1 if you have the `_strtoui64' function. */
|
||||
#cmakedefine HAVE__STRTOUI64 1
|
||||
|
||||
/* Define to 1 if you have the `glob' function. */
|
||||
#cmakedefine HAVE_GLOB 1
|
||||
|
||||
/* Define to 1 if you have the `explicit_bzero' function. */
|
||||
#cmakedefine HAVE_EXPLICIT_BZERO 1
|
||||
|
||||
/* Define to 1 if you have the `memset_s' function. */
|
||||
#cmakedefine HAVE_MEMSET_S 1
|
||||
|
||||
/* Define to 1 if you have the `SecureZeroMemory' function. */
|
||||
#cmakedefine HAVE_SECURE_ZERO_MEMORY 1
|
||||
|
||||
/*************************** LIBRARIES ***************************/
|
||||
|
||||
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
||||
@@ -138,6 +180,9 @@
|
||||
/* Define to 1 if you have the `gcrypt' library (-lgcrypt). */
|
||||
#cmakedefine HAVE_LIBGCRYPT 1
|
||||
|
||||
/* Define to 1 if you have the 'mbedTLS' library (-lmbedtls). */
|
||||
#cmakedefine HAVE_LIBMBEDCRYPTO 1
|
||||
|
||||
/* Define to 1 if you have the `pthread' library (-lpthread). */
|
||||
#cmakedefine HAVE_PTHREAD 1
|
||||
|
||||
@@ -146,12 +191,16 @@
|
||||
#cmakedefine HAVE_GCC_THREAD_LOCAL_STORAGE 1
|
||||
#cmakedefine HAVE_MSC_THREAD_LOCAL_STORAGE 1
|
||||
|
||||
#cmakedefine HAVE_FALLTHROUGH_ATTRIBUTE 1
|
||||
|
||||
#cmakedefine HAVE_GCC_VOLATILE_MEMORY_PROTECTION 1
|
||||
#cmakedefine HAVE_GCC_NARG_MACRO 1
|
||||
|
||||
#cmakedefine HAVE_COMPILER__FUNC__ 1
|
||||
#cmakedefine HAVE_COMPILER__FUNCTION__ 1
|
||||
|
||||
#cmakedefine HAVE_GCC_BOUNDED_ATTRIBUTE 1
|
||||
|
||||
/* Define to 1 if you want to enable GSSAPI */
|
||||
#cmakedefine WITH_GSSAPI 1
|
||||
|
||||
@@ -161,15 +210,15 @@
|
||||
/* Define to 1 if you want to enable SFTP */
|
||||
#cmakedefine WITH_SFTP 1
|
||||
|
||||
/* Define to 1 if you want to enable SSH1 */
|
||||
#cmakedefine WITH_SSH1 1
|
||||
|
||||
/* Define to 1 if you want to enable server support */
|
||||
#cmakedefine WITH_SERVER 1
|
||||
|
||||
/* Define to 1 if you want to enable debug output for crypto functions */
|
||||
#cmakedefine DEBUG_CRYPTO 1
|
||||
|
||||
/* Define to 1 if you want to enable debug output for packet functions */
|
||||
#cmakedefine DEBUG_PACKET 1
|
||||
|
||||
/* Define to 1 if you want to enable pcap output support (experimental) */
|
||||
#cmakedefine WITH_PCAP 1
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ The ssh_userauth_publickey_auto() function also tries to authenticate using the
|
||||
SSH agent, if you have one running, or the "none" method otherwise.
|
||||
|
||||
If you wish to authenticate with public key by your own, follow these steps:
|
||||
- Retrieve the public key with ssh_import_pubkey_file().
|
||||
- Retrieve the public key with ssh_pki_import_pubkey_file().
|
||||
- Offer the public key to the SSH server using ssh_userauth_try_publickey().
|
||||
If the return value is SSH_AUTH_SUCCESS, the SSH server accepts to
|
||||
authenticate using the public key and you can go to the next step.
|
||||
@@ -305,7 +305,7 @@ int test_several_auth_methods(ssh_session session)
|
||||
int method, rc;
|
||||
|
||||
rc = ssh_userauth_none(session, NULL);
|
||||
if (rc != SSH_AUTH_SUCCESS) {
|
||||
if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_ERROR) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ If an error has been encountered, it returns a negative value:
|
||||
|
||||
@code
|
||||
char buffer[256];
|
||||
unsigned int nbytes;
|
||||
int nbytes;
|
||||
|
||||
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
|
||||
while (nbytes > 0)
|
||||
|
||||
@@ -158,7 +158,7 @@ you just connected to is known and safe to use (remember, SSH is about security
|
||||
authentication).
|
||||
|
||||
There are two ways of doing this:
|
||||
- The first way (recommended) is to use the ssh_is_server_known()
|
||||
- The first way (recommended) is to use the ssh_session_is_known_server()
|
||||
function. This function will look into the known host file
|
||||
(~/.ssh/known_hosts on UNIX), look for the server hostname's pattern,
|
||||
and determine whether this host is present or not in the list.
|
||||
@@ -185,74 +185,89 @@ examples/ directory:
|
||||
|
||||
int verify_knownhost(ssh_session session)
|
||||
{
|
||||
int state, hlen;
|
||||
unsigned char *hash = NULL;
|
||||
char *hexa;
|
||||
char buf[10];
|
||||
enum ssh_known_hosts_e state;
|
||||
unsigned char *hash = NULL;
|
||||
ssh_key srv_pubkey = NULL;
|
||||
size_t hlen;
|
||||
char buf[10];
|
||||
char *hexa;
|
||||
char *p;
|
||||
int cmp;
|
||||
int rc;
|
||||
|
||||
state = ssh_is_server_known(session);
|
||||
|
||||
hlen = ssh_get_pubkey_hash(session, &hash);
|
||||
if (hlen < 0)
|
||||
return -1;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case SSH_SERVER_KNOWN_OK:
|
||||
break; /* ok */
|
||||
|
||||
case SSH_SERVER_KNOWN_CHANGED:
|
||||
fprintf(stderr, "Host key for server changed: it is now:\n");
|
||||
ssh_print_hexa("Public key hash", hash, hlen);
|
||||
fprintf(stderr, "For security reasons, connection will be stopped\n");
|
||||
free(hash);
|
||||
return -1;
|
||||
|
||||
case SSH_SERVER_FOUND_OTHER:
|
||||
fprintf(stderr, "The host key for this server was not found but an other"
|
||||
"type of key exists.\n");
|
||||
fprintf(stderr, "An attacker might change the default server key to"
|
||||
"confuse your client into thinking the key does not exist\n");
|
||||
free(hash);
|
||||
return -1;
|
||||
|
||||
case SSH_SERVER_FILE_NOT_FOUND:
|
||||
fprintf(stderr, "Could not find known host file.\n");
|
||||
fprintf(stderr, "If you accept the host key here, the file will be"
|
||||
"automatically created.\n");
|
||||
/* fallback to SSH_SERVER_NOT_KNOWN behavior */
|
||||
|
||||
case SSH_SERVER_NOT_KNOWN:
|
||||
hexa = ssh_get_hexa(hash, hlen);
|
||||
fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
|
||||
fprintf(stderr, "Public key hash: %s\n", hexa);
|
||||
free(hexa);
|
||||
if (fgets(buf, sizeof(buf), stdin) == NULL)
|
||||
{
|
||||
free(hash);
|
||||
rc = ssh_get_server_publickey(session, &srv_pubkey);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (strncasecmp(buf, "yes", 3) != 0)
|
||||
{
|
||||
free(hash);
|
||||
return -1;
|
||||
}
|
||||
if (ssh_write_knownhost(session) < 0)
|
||||
{
|
||||
fprintf(stderr, "Error %s\n", strerror(errno));
|
||||
free(hash);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SSH_SERVER_ERROR:
|
||||
fprintf(stderr, "Error %s", ssh_get_error(session));
|
||||
free(hash);
|
||||
return -1;
|
||||
}
|
||||
rc = ssh_get_publickey_hash(srv_pubkey,
|
||||
SSH_PUBLICKEY_HASH_SHA1,
|
||||
&hash,
|
||||
&hlen);
|
||||
ssh_key_free(srv_pubkey);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(hash);
|
||||
return 0;
|
||||
state = ssh_session_is_known_server(session);
|
||||
switch (state) {
|
||||
case SSH_KNOWN_HOSTS_OK:
|
||||
/* OK */
|
||||
|
||||
break;
|
||||
case SSH_KNOWN_HOSTS_CHANGED:
|
||||
fprintf(stderr, "Host key for server changed: it is now:\n");
|
||||
ssh_print_hexa("Public key hash", hash, hlen);
|
||||
fprintf(stderr, "For security reasons, connection will be stopped\n");
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
|
||||
return -1;
|
||||
case SSH_KNOWN_HOSTS_OTHER:
|
||||
fprintf(stderr, "The host key for this server was not found but an other"
|
||||
"type of key exists.\n");
|
||||
fprintf(stderr, "An attacker might change the default server key to"
|
||||
"confuse your client into thinking the key does not exist\n");
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
|
||||
return -1;
|
||||
case SSH_KNOWN_HOSTS_NOT_FOUND:
|
||||
fprintf(stderr, "Could not find known host file.\n");
|
||||
fprintf(stderr, "If you accept the host key here, the file will be"
|
||||
"automatically created.\n");
|
||||
|
||||
/* FALL THROUGH to SSH_SERVER_NOT_KNOWN behavior */
|
||||
|
||||
case SSH_KNOWN_HOSTS_UNKNOWN:
|
||||
hexa = ssh_get_hexa(hash, hlen);
|
||||
fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
|
||||
fprintf(stderr, "Public key hash: %s\n", hexa);
|
||||
ssh_string_free_char(hexa);
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
p = fgets(buf, sizeof(buf), stdin);
|
||||
if (p == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmp = strncasecmp(buf, "yes", 3);
|
||||
if (cmp != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = ssh_session_update_known_hosts(session);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Error %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
case SSH_KNOWN_HOSTS_ERROR:
|
||||
fprintf(stderr, "Error %s", ssh_get_error(session));
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
return 0;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@@ -260,9 +275,10 @@ int verify_knownhost(ssh_session session)
|
||||
@see ssh_disconnect
|
||||
@see ssh_get_error
|
||||
@see ssh_get_error_code
|
||||
@see ssh_get_pubkey_hash
|
||||
@see ssh_is_server_known
|
||||
@see ssh_write_knownhost
|
||||
@see ssh_get_server_publickey
|
||||
@see ssh_get_publickey_hash
|
||||
@see ssh_session_is_known_server
|
||||
@see ssh_session_update_known_hosts
|
||||
|
||||
|
||||
@subsection auth Authenticating the user
|
||||
@@ -367,7 +383,7 @@ int show_remote_processes(ssh_session session)
|
||||
ssh_channel channel;
|
||||
int rc;
|
||||
char buffer[256];
|
||||
unsigned int nbytes;
|
||||
int nbytes;
|
||||
|
||||
channel = ssh_channel_new(session);
|
||||
if (channel == NULL)
|
||||
@@ -391,7 +407,7 @@ int show_remote_processes(ssh_session session)
|
||||
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
|
||||
while (nbytes > 0)
|
||||
{
|
||||
if (write(1, buffer, nbytes) != nbytes)
|
||||
if (write(1, buffer, nbytes) != (unsigned int) nbytes)
|
||||
{
|
||||
ssh_channel_close(channel);
|
||||
ssh_channel_free(channel);
|
||||
|
||||
@@ -19,16 +19,16 @@ the interesting functions as you go.
|
||||
|
||||
The libssh library provides:
|
||||
|
||||
- <strong>Key Exchange Methods</strong>: <i>curve25519-sha256@libssh.org, ecdh-sha2-nistp256</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
|
||||
- <strong>Hostkey Types</strong>: <i>ecdsa-sha2-nistp256</i>, ssh-dss, ssh-rsa
|
||||
- <strong>Ciphers</strong>: <i>aes256-ctr, aes192-ctr, aes128-ctr</i>, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, des-cbc-ssh1, blowfish-cbc, none
|
||||
- <strong>Key Exchange Methods</strong>: <i>curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
|
||||
- <strong>Hostkey Types</strong>: <i>ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521</i>, ssh-dss, ssh-rsa
|
||||
- <strong>Ciphers</strong>: <i>aes256-ctr, aes192-ctr, aes128-ctr</i>, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, blowfish-cbc, none
|
||||
- <strong>Compression Schemes</strong>: zlib, <i>zlib@openssh.com</i>, none
|
||||
- <strong>MAC hashes</strong>: hmac-sha1, none
|
||||
- <strong>MAC hashes</strong>: hmac-sha1, hmac-sha2-256, hmac-sha2-384, hmac-sha2-512, hmac-md5, none
|
||||
- <strong>Authentication</strong>: none, password, public-key, hostbased, keyboard-interactive, <i>gssapi-with-mic</i>
|
||||
- <strong>Channels</strong>: shell, exec (incl. SCP wrapper), direct-tcpip, subsystem, <i>auth-agent-req@openssh.com</i>
|
||||
- <strong>Global Requests</strong>: tcpip-forward, forwarded-tcpip
|
||||
- <strong>Channel Requests</strong>: x11, pty, <i>exit-status, signal, exit-signal, keepalive@openssh.com, auth-agent-req@openssh.com</i>
|
||||
- <strong>Subsystems</strong>: sftp(version 3), publickey(version 2), <i>OpenSSH Extensions</i>
|
||||
- <strong>Subsystems</strong>: sftp(version 3), <i>OpenSSH Extensions</i>
|
||||
- <strong>SFTP</strong>: <i>statvfs@openssh.com, fstatvfs@openssh.com</i>
|
||||
- <strong>Thread-safe</strong>: Just don't share sessions
|
||||
- <strong>Non-blocking</strong>: it can be used both blocking and non-blocking
|
||||
|
||||
@@ -253,7 +253,7 @@ int sftp_read_sync(ssh_session session, sftp_session sftp)
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
nwritten = write(fd, buf, nbytes);
|
||||
nwritten = write(fd, buffer, nbytes);
|
||||
if (nwritten != nbytes) {
|
||||
fprintf(stderr, "Error writing: %s\n",
|
||||
strerror(errno));
|
||||
@@ -282,7 +282,7 @@ sftp_async_read() waits for the data to come. To open a file in nonblocking mode
|
||||
call sftp_file_set_nonblocking() right after you opened it. Default is blocking mode.
|
||||
|
||||
The example below reads a very big file in asynchronous, nonblocking, mode. Each
|
||||
time the data are not ready yet, a counter is incrementer.
|
||||
time the data is not ready yet, a counter is incremented.
|
||||
|
||||
@code
|
||||
// Good chunk size
|
||||
|
||||
@@ -11,9 +11,9 @@ include_directories(
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
if (BSD OR SOLARIS OR OSX)
|
||||
find_package(Argp)
|
||||
endif (BSD OR SOLARIS OR OSX)
|
||||
if (ARGP_INCLUDE_DIR)
|
||||
include_directories(${ARGP_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT WIN32)
|
||||
add_executable(libssh_scp libssh_scp.c ${examples_SRCS})
|
||||
@@ -30,27 +30,27 @@ if (UNIX AND NOT WIN32)
|
||||
target_link_libraries(samplesftp ${LIBSSH_SHARED_LIBRARY})
|
||||
endif (WITH_SFTP)
|
||||
|
||||
add_executable(samplessh sample.c ${examples_SRCS})
|
||||
target_link_libraries(samplessh ${LIBSSH_SHARED_LIBRARY})
|
||||
add_executable(ssh-client ssh_client.c ${examples_SRCS})
|
||||
target_link_libraries(ssh-client ${LIBSSH_SHARED_LIBRARY})
|
||||
|
||||
if (WITH_SERVER)
|
||||
if (WITH_SERVER AND (ARGP_LIBRARY OR HAVE_ARGP_H))
|
||||
if (HAVE_LIBUTIL)
|
||||
add_executable(ssh_server_fork ssh_server_fork.c)
|
||||
target_link_libraries(ssh_server_fork ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES} util)
|
||||
target_link_libraries(ssh_server_fork ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY} util)
|
||||
endif (HAVE_LIBUTIL)
|
||||
|
||||
if (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
add_executable(samplesshd-cb samplesshd-cb.c)
|
||||
target_link_libraries(samplesshd-cb ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES})
|
||||
target_link_libraries(samplesshd-cb ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
|
||||
|
||||
add_executable(proxy proxy.c)
|
||||
target_link_libraries(proxy ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES})
|
||||
target_link_libraries(proxy ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
|
||||
endif (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
|
||||
add_executable(samplesshd-kbdint samplesshd-kbdint.c)
|
||||
target_link_libraries(samplesshd-kbdint ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES})
|
||||
target_link_libraries(samplesshd-kbdint ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
|
||||
|
||||
endif (WITH_SERVER)
|
||||
endif()
|
||||
endif (UNIX AND NOT WIN32)
|
||||
|
||||
add_executable(exec exec.c ${examples_SRCS})
|
||||
|
||||
@@ -17,11 +17,14 @@ The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include <libssh/libssh.h>
|
||||
#include "examples_common.h"
|
||||
|
||||
@@ -31,16 +34,14 @@ clients must be made or how a client should react.
|
||||
|
||||
int verify_knownhost(ssh_session session){
|
||||
char *hexa;
|
||||
int state;
|
||||
enum ssh_known_hosts_e state;
|
||||
char buf[10];
|
||||
unsigned char *hash = NULL;
|
||||
size_t hlen;
|
||||
ssh_key srv_pubkey;
|
||||
int rc;
|
||||
|
||||
state=ssh_is_server_known(session);
|
||||
|
||||
rc = ssh_get_publickey(session, &srv_pubkey);
|
||||
rc = ssh_get_server_publickey(session, &srv_pubkey);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -54,25 +55,28 @@ int verify_knownhost(ssh_session session){
|
||||
return -1;
|
||||
}
|
||||
|
||||
state = ssh_session_is_known_server(session);
|
||||
|
||||
switch(state){
|
||||
case SSH_SERVER_KNOWN_OK:
|
||||
case SSH_KNOWN_HOSTS_OK:
|
||||
break; /* ok */
|
||||
case SSH_SERVER_KNOWN_CHANGED:
|
||||
case SSH_KNOWN_HOSTS_CHANGED:
|
||||
fprintf(stderr,"Host key for server changed : server's one is now :\n");
|
||||
ssh_print_hexa("Public key hash",hash, hlen);
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
fprintf(stderr,"For security reason, connection will be stopped\n");
|
||||
return -1;
|
||||
case SSH_SERVER_FOUND_OTHER:
|
||||
case SSH_KNOWN_HOSTS_OTHER:
|
||||
fprintf(stderr,"The host key for this server was not found but an other type of key exists.\n");
|
||||
fprintf(stderr,"An attacker might change the default server key to confuse your client"
|
||||
"into thinking the key does not exist\n"
|
||||
"We advise you to rerun the client with -d or -r for more safety.\n");
|
||||
return -1;
|
||||
case SSH_SERVER_FILE_NOT_FOUND:
|
||||
case SSH_KNOWN_HOSTS_NOT_FOUND:
|
||||
fprintf(stderr,"Could not find known host file. If you accept the host key here,\n");
|
||||
fprintf(stderr,"the file will be automatically created.\n");
|
||||
/* fallback to SSH_SERVER_NOT_KNOWN behavior */
|
||||
FALL_THROUGH;
|
||||
case SSH_SERVER_NOT_KNOWN:
|
||||
hexa = ssh_get_hexa(hash, hlen);
|
||||
fprintf(stderr,"The server is unknown. Do you trust the host key ?\n");
|
||||
@@ -100,7 +104,7 @@ int verify_knownhost(ssh_session session){
|
||||
}
|
||||
|
||||
break;
|
||||
case SSH_SERVER_ERROR:
|
||||
case SSH_KNOWN_HOSTS_ERROR:
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
fprintf(stderr,"%s",ssh_get_error(session));
|
||||
return -1;
|
||||
|
||||
@@ -1,523 +0,0 @@
|
||||
/* client.c */
|
||||
/*
|
||||
Copyright 2003-2009 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_PTY_H
|
||||
#include <pty.h>
|
||||
#endif
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <libssh/callbacks.h>
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/sftp.h>
|
||||
|
||||
|
||||
#include "examples_common.h"
|
||||
#define MAXCMD 10
|
||||
|
||||
static char *host;
|
||||
static char *user;
|
||||
static char *cmds[MAXCMD];
|
||||
static struct termios terminal;
|
||||
|
||||
static char *pcap_file=NULL;
|
||||
|
||||
static char *proxycommand;
|
||||
|
||||
static int auth_callback(const char *prompt, char *buf, size_t len,
|
||||
int echo, int verify, void *userdata) {
|
||||
(void) verify;
|
||||
(void) userdata;
|
||||
|
||||
return ssh_getpass(prompt, buf, len, echo, verify);
|
||||
}
|
||||
|
||||
struct ssh_callbacks_struct cb = {
|
||||
.auth_function=auth_callback,
|
||||
.userdata=NULL
|
||||
};
|
||||
|
||||
static void add_cmd(char *cmd){
|
||||
int n;
|
||||
|
||||
for (n = 0; (n < MAXCMD) && cmds[n] != NULL; n++);
|
||||
|
||||
if (n == MAXCMD) {
|
||||
return;
|
||||
}
|
||||
cmds[n]=strdup(cmd);
|
||||
}
|
||||
|
||||
static void usage(){
|
||||
fprintf(stderr,"Usage : ssh [options] [login@]hostname\n"
|
||||
"sample client - libssh-%s\n"
|
||||
"Options :\n"
|
||||
" -l user : log in as user\n"
|
||||
" -p port : connect to port\n"
|
||||
" -d : use DSS to verify host public key\n"
|
||||
" -r : use RSA to verify host public key\n"
|
||||
#ifdef WITH_PCAP
|
||||
" -P file : create a pcap debugging file\n"
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
" -T proxycommand : command to execute as a socket proxy\n"
|
||||
#endif
|
||||
,
|
||||
ssh_version(0));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int opts(int argc, char **argv){
|
||||
int i;
|
||||
// for(i=0;i<argc;i++)
|
||||
// printf("%d : %s\n",i,argv[i]);
|
||||
/* insert your own arguments here */
|
||||
while((i=getopt(argc,argv,"T:P:"))!=-1){
|
||||
switch(i){
|
||||
case 'P':
|
||||
pcap_file=optarg;
|
||||
break;
|
||||
#ifndef _WIN32
|
||||
case 'T':
|
||||
proxycommand=optarg;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
fprintf(stderr,"unknown option %c\n",optopt);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
if(optind < argc)
|
||||
host=argv[optind++];
|
||||
while(optind < argc)
|
||||
add_cmd(argv[optind++]);
|
||||
if(host==NULL)
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_CFMAKERAW
|
||||
static void cfmakeraw(struct termios *termios_p){
|
||||
termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
|
||||
termios_p->c_oflag &= ~OPOST;
|
||||
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
||||
termios_p->c_cflag &= ~(CSIZE|PARENB);
|
||||
termios_p->c_cflag |= CS8;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void do_cleanup(int i) {
|
||||
/* unused variable */
|
||||
(void) i;
|
||||
|
||||
tcsetattr(0,TCSANOW,&terminal);
|
||||
}
|
||||
|
||||
static void do_exit(int i) {
|
||||
/* unused variable */
|
||||
(void) i;
|
||||
|
||||
do_cleanup(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ssh_channel chan;
|
||||
int signal_delayed=0;
|
||||
|
||||
static void sigwindowchanged(int i){
|
||||
(void) i;
|
||||
signal_delayed=1;
|
||||
}
|
||||
|
||||
static void setsignal(void){
|
||||
signal(SIGWINCH, sigwindowchanged);
|
||||
signal_delayed=0;
|
||||
}
|
||||
|
||||
static void sizechanged(void){
|
||||
struct winsize win = { 0, 0, 0, 0 };
|
||||
ioctl(1, TIOCGWINSZ, &win);
|
||||
ssh_channel_change_pty_size(chan,win.ws_col, win.ws_row);
|
||||
// printf("Changed pty size\n");
|
||||
setsignal();
|
||||
}
|
||||
|
||||
/* There are two flavors of select loop: the one based on
|
||||
* ssh_select and the one based on channel_select.
|
||||
* The ssh_select one permits you to give your own file descriptors to
|
||||
* follow. It is thus a complete select loop.
|
||||
* The second one only selects on channels. It is simplier to use
|
||||
* but doesn't permit you to fill in your own file descriptor. It is
|
||||
* more adapted if you can't use ssh_select as a main loop (because
|
||||
* you already have another main loop system).
|
||||
*/
|
||||
|
||||
#ifdef USE_CHANNEL_SELECT
|
||||
|
||||
/* channel_select base main loop, with a standard select(2)
|
||||
*/
|
||||
static void select_loop(ssh_session session,ssh_channel channel){
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
char buffer[4096];
|
||||
ssh_buffer readbuf=ssh_buffer_new();
|
||||
ssh_channel channels[2];
|
||||
int lus;
|
||||
int eof=0;
|
||||
int maxfd;
|
||||
int ret;
|
||||
while(channel){
|
||||
/* when a signal is caught, ssh_select will return
|
||||
* with SSH_EINTR, which means it should be started
|
||||
* again. It lets you handle the signal the faster you
|
||||
* can, like in this window changed example. Of course, if
|
||||
* your signal handler doesn't call libssh at all, you're
|
||||
* free to handle signals directly in sighandler.
|
||||
*/
|
||||
do{
|
||||
FD_ZERO(&fds);
|
||||
if(!eof)
|
||||
FD_SET(0,&fds);
|
||||
timeout.tv_sec=30;
|
||||
timeout.tv_usec=0;
|
||||
FD_SET(ssh_get_fd(session),&fds);
|
||||
maxfd=ssh_get_fd(session)+1;
|
||||
ret=select(maxfd,&fds,NULL,NULL,&timeout);
|
||||
if(ret==EINTR)
|
||||
continue;
|
||||
if(FD_ISSET(0,&fds)){
|
||||
lus=read(0,buffer,sizeof(buffer));
|
||||
if(lus)
|
||||
ssh_channel_write(channel,buffer,lus);
|
||||
else {
|
||||
eof=1;
|
||||
ssh_channel_send_eof(channel);
|
||||
}
|
||||
}
|
||||
if(FD_ISSET(ssh_get_fd(session),&fds)){
|
||||
ssh_set_fd_toread(session);
|
||||
}
|
||||
channels[0]=channel; // set the first channel we want to read from
|
||||
channels[1]=NULL;
|
||||
ret=ssh_channel_select(channels,NULL,NULL,NULL); // no specific timeout - just poll
|
||||
if(signal_delayed)
|
||||
sizechanged();
|
||||
} while (ret==EINTR || ret==SSH_EINTR);
|
||||
|
||||
// we already looked for input from stdin. Now, we are looking for input from the channel
|
||||
|
||||
if(channel && ssh_channel_is_closed(channel)){
|
||||
ssh_channel_free(channel);
|
||||
channel=NULL;
|
||||
channels[0]=NULL;
|
||||
}
|
||||
if(channels[0]){
|
||||
while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,0)>0){
|
||||
lus=channel_read_buffer(channel,readbuf,0,0);
|
||||
if(lus==-1){
|
||||
fprintf(stderr, "Error reading channel: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(lus==0){
|
||||
ssh_channel_free(channel);
|
||||
channel=channels[0]=NULL;
|
||||
} else
|
||||
if (write(1,ssh_buffer_get_begin(readbuf),lus) < 0) {
|
||||
fprintf(stderr, "Error writing to buffer\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,1)>0){ /* stderr */
|
||||
lus=channel_read_buffer(channel,readbuf,0,1);
|
||||
if(lus==-1){
|
||||
fprintf(stderr, "Error reading channel: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(lus==0){
|
||||
ssh_channel_free(channel);
|
||||
channel=channels[0]=NULL;
|
||||
} else
|
||||
if (write(2,ssh_buffer_get_begin(readbuf),lus) < 0) {
|
||||
fprintf(stderr, "Error writing to buffer\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(channel && ssh_channel_is_closed(channel)){
|
||||
ssh_channel_free(channel);
|
||||
channel=NULL;
|
||||
}
|
||||
}
|
||||
ssh_buffer_free(readbuf);
|
||||
}
|
||||
#else /* CHANNEL_SELECT */
|
||||
|
||||
static void select_loop(ssh_session session,ssh_channel channel){
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
char buffer[4096];
|
||||
/* channels will be set to the channels to poll.
|
||||
* outchannels will contain the result of the poll
|
||||
*/
|
||||
ssh_channel channels[2], outchannels[2];
|
||||
int lus;
|
||||
int eof=0;
|
||||
int maxfd;
|
||||
unsigned int r;
|
||||
int ret;
|
||||
while(channel){
|
||||
do{
|
||||
int fd;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
if(!eof)
|
||||
FD_SET(0,&fds);
|
||||
timeout.tv_sec=30;
|
||||
timeout.tv_usec=0;
|
||||
|
||||
fd = ssh_get_fd(session);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Error getting fd\n");
|
||||
return;
|
||||
}
|
||||
FD_SET(fd, &fds);
|
||||
maxfd = fd + 1;
|
||||
|
||||
channels[0]=channel; // set the first channel we want to read from
|
||||
channels[1]=NULL;
|
||||
ret=ssh_select(channels,outchannels,maxfd,&fds,&timeout);
|
||||
if(signal_delayed)
|
||||
sizechanged();
|
||||
if(ret==EINTR)
|
||||
continue;
|
||||
if(FD_ISSET(0,&fds)){
|
||||
lus=read(0,buffer,sizeof(buffer));
|
||||
if(lus)
|
||||
ssh_channel_write(channel,buffer,lus);
|
||||
else {
|
||||
eof=1;
|
||||
ssh_channel_send_eof(channel);
|
||||
}
|
||||
}
|
||||
if(channel && ssh_channel_is_closed(channel)){
|
||||
ssh_channel_free(channel);
|
||||
channel=NULL;
|
||||
channels[0]=NULL;
|
||||
}
|
||||
if(outchannels[0]){
|
||||
while(channel && ssh_channel_is_open(channel) && (r = ssh_channel_poll(channel,0))!=0){
|
||||
lus=ssh_channel_read(channel,buffer,sizeof(buffer) > r ? r : sizeof(buffer),0);
|
||||
if(lus==-1){
|
||||
fprintf(stderr, "Error reading channel: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(lus==0){
|
||||
ssh_channel_free(channel);
|
||||
channel=channels[0]=NULL;
|
||||
} else
|
||||
if (write(1,buffer,lus) < 0) {
|
||||
fprintf(stderr, "Error writing to buffer\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
while(channel && ssh_channel_is_open(channel) && (r = ssh_channel_poll(channel,1))!=0){ /* stderr */
|
||||
lus=ssh_channel_read(channel,buffer,sizeof(buffer) > r ? r : sizeof(buffer),1);
|
||||
if(lus==-1){
|
||||
fprintf(stderr, "Error reading channel: %s\n",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(lus==0){
|
||||
ssh_channel_free(channel);
|
||||
channel=channels[0]=NULL;
|
||||
} else
|
||||
if (write(2,buffer,lus) < 0) {
|
||||
fprintf(stderr, "Error writing to buffer\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(channel && ssh_channel_is_closed(channel)){
|
||||
ssh_channel_free(channel);
|
||||
channel=NULL;
|
||||
}
|
||||
} while (ret==EINTR || ret==SSH_EINTR);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void shell(ssh_session session){
|
||||
ssh_channel channel;
|
||||
struct termios terminal_local;
|
||||
int interactive=isatty(0);
|
||||
channel = ssh_channel_new(session);
|
||||
if(interactive){
|
||||
tcgetattr(0,&terminal_local);
|
||||
memcpy(&terminal,&terminal_local,sizeof(struct termios));
|
||||
}
|
||||
if(ssh_channel_open_session(channel)){
|
||||
printf("error opening channel : %s\n",ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
chan=channel;
|
||||
if(interactive){
|
||||
ssh_channel_request_pty(channel);
|
||||
sizechanged();
|
||||
}
|
||||
if(ssh_channel_request_shell(channel)){
|
||||
printf("Requesting shell : %s\n",ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(interactive){
|
||||
cfmakeraw(&terminal_local);
|
||||
tcsetattr(0,TCSANOW,&terminal_local);
|
||||
setsignal();
|
||||
}
|
||||
signal(SIGTERM,do_cleanup);
|
||||
select_loop(session,channel);
|
||||
if(interactive)
|
||||
do_cleanup(0);
|
||||
}
|
||||
|
||||
static void batch_shell(ssh_session session){
|
||||
ssh_channel channel;
|
||||
char buffer[1024];
|
||||
int i,s=0;
|
||||
for(i=0;i<MAXCMD && cmds[i];++i) {
|
||||
s+=snprintf(buffer+s,sizeof(buffer)-s,"%s ",cmds[i]);
|
||||
free(cmds[i]);
|
||||
cmds[i] = NULL;
|
||||
}
|
||||
channel=ssh_channel_new(session);
|
||||
ssh_channel_open_session(channel);
|
||||
if(ssh_channel_request_exec(channel,buffer)){
|
||||
printf("error executing \"%s\" : %s\n",buffer,ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
select_loop(session,channel);
|
||||
}
|
||||
|
||||
static int client(ssh_session session){
|
||||
int auth=0;
|
||||
char *banner;
|
||||
int state;
|
||||
if (user)
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0)
|
||||
return -1;
|
||||
if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0)
|
||||
return -1;
|
||||
if (proxycommand != NULL){
|
||||
if(ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, proxycommand))
|
||||
return -1;
|
||||
}
|
||||
ssh_options_parse_config(session, NULL);
|
||||
|
||||
if(ssh_connect(session)){
|
||||
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
|
||||
return -1;
|
||||
}
|
||||
state=verify_knownhost(session);
|
||||
if (state != 0)
|
||||
return -1;
|
||||
ssh_userauth_none(session, NULL);
|
||||
banner=ssh_get_issue_banner(session);
|
||||
if(banner){
|
||||
printf("%s\n",banner);
|
||||
free(banner);
|
||||
}
|
||||
auth=authenticate_console(session);
|
||||
if(auth != SSH_AUTH_SUCCESS){
|
||||
return -1;
|
||||
}
|
||||
if(!cmds[0])
|
||||
shell(session);
|
||||
else
|
||||
batch_shell(session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssh_pcap_file pcap;
|
||||
void set_pcap(ssh_session session);
|
||||
void set_pcap(ssh_session session){
|
||||
if(!pcap_file)
|
||||
return;
|
||||
pcap=ssh_pcap_file_new();
|
||||
if(!pcap)
|
||||
return;
|
||||
if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){
|
||||
printf("Error opening pcap file\n");
|
||||
ssh_pcap_file_free(pcap);
|
||||
pcap=NULL;
|
||||
return;
|
||||
}
|
||||
ssh_set_pcap_file(session,pcap);
|
||||
}
|
||||
|
||||
void cleanup_pcap(void);
|
||||
void cleanup_pcap(){
|
||||
if(pcap)
|
||||
ssh_pcap_file_free(pcap);
|
||||
pcap=NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
ssh_session session;
|
||||
|
||||
session = ssh_new();
|
||||
|
||||
ssh_callbacks_init(&cb);
|
||||
ssh_set_callbacks(session,&cb);
|
||||
|
||||
if(ssh_options_getopt(session, &argc, argv)) {
|
||||
fprintf(stderr, "error parsing command line :%s\n",
|
||||
ssh_get_error(session));
|
||||
usage();
|
||||
}
|
||||
opts(argc,argv);
|
||||
signal(SIGTERM, do_exit);
|
||||
|
||||
set_pcap(session);
|
||||
client(session);
|
||||
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
cleanup_pcap();
|
||||
|
||||
ssh_finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -22,9 +22,12 @@ program.
|
||||
#include <libssh/libssh.h>
|
||||
#include "examples_common.h"
|
||||
|
||||
int verbosity=0;
|
||||
const char *createcommand="rm -fr /tmp/libssh_tests && mkdir /tmp/libssh_tests && cd /tmp/libssh_tests && date > a && date > b && mkdir c && date > d";
|
||||
char *host=NULL;
|
||||
static int verbosity = 0;
|
||||
static const char *createcommand =
|
||||
"rm -fr /tmp/libssh_tests && mkdir /tmp/libssh_tests && "
|
||||
"cd /tmp/libssh_tests && date > a && date > b && mkdir c && date > d";
|
||||
static char *host = NULL;
|
||||
|
||||
static void usage(const char *argv0){
|
||||
fprintf(stderr,"Usage : %s [options] host\n"
|
||||
"sample tiny scp downloader client - libssh-%s\n"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <libssh/libssh.h>
|
||||
#include "examples_common.h"
|
||||
|
||||
#define LIMIT 0x100000000
|
||||
#define LIMIT 0x100000000UL
|
||||
|
||||
int main(void) {
|
||||
ssh_session session;
|
||||
|
||||
356
examples/ssh_client.c
Normal file
356
examples/ssh_client.c
Normal file
@@ -0,0 +1,356 @@
|
||||
/* client.c */
|
||||
/*
|
||||
Copyright 2003-2009 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_PTY_H
|
||||
#include <pty.h>
|
||||
#endif
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <libssh/callbacks.h>
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/sftp.h>
|
||||
|
||||
|
||||
#include "examples_common.h"
|
||||
#define MAXCMD 10
|
||||
|
||||
static char *host;
|
||||
static char *user;
|
||||
static char *cmds[MAXCMD];
|
||||
static struct termios terminal;
|
||||
|
||||
static char *pcap_file=NULL;
|
||||
|
||||
static char *proxycommand;
|
||||
|
||||
static int auth_callback(const char *prompt, char *buf, size_t len,
|
||||
int echo, int verify, void *userdata) {
|
||||
(void) verify;
|
||||
(void) userdata;
|
||||
|
||||
return ssh_getpass(prompt, buf, len, echo, verify);
|
||||
}
|
||||
|
||||
struct ssh_callbacks_struct cb = {
|
||||
.auth_function=auth_callback,
|
||||
.userdata=NULL
|
||||
};
|
||||
|
||||
static void add_cmd(char *cmd){
|
||||
int n;
|
||||
|
||||
for (n = 0; (n < MAXCMD) && cmds[n] != NULL; n++);
|
||||
|
||||
if (n == MAXCMD) {
|
||||
return;
|
||||
}
|
||||
cmds[n]=strdup(cmd);
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage : ssh [options] [login@]hostname\n"
|
||||
"sample client - libssh-%s\n"
|
||||
"Options :\n"
|
||||
" -l user : log in as user\n"
|
||||
" -p port : connect to port\n"
|
||||
" -d : use DSS to verify host public key\n"
|
||||
" -r : use RSA to verify host public key\n"
|
||||
#ifdef WITH_PCAP
|
||||
" -P file : create a pcap debugging file\n"
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
" -T proxycommand : command to execute as a socket proxy\n"
|
||||
#endif
|
||||
"\n",
|
||||
ssh_version(0));
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int opts(int argc, char **argv){
|
||||
int i;
|
||||
// for(i=0;i<argc;i++)
|
||||
// printf("%d : %s\n",i,argv[i]);
|
||||
/* insert your own arguments here */
|
||||
while((i=getopt(argc,argv,"T:P:"))!=-1){
|
||||
switch(i){
|
||||
case 'P':
|
||||
pcap_file=optarg;
|
||||
break;
|
||||
#ifndef _WIN32
|
||||
case 'T':
|
||||
proxycommand=optarg;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
fprintf(stderr,"unknown option %c\n",optopt);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
if(optind < argc)
|
||||
host=argv[optind++];
|
||||
while(optind < argc)
|
||||
add_cmd(argv[optind++]);
|
||||
if(host==NULL)
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_CFMAKERAW
|
||||
static void cfmakeraw(struct termios *termios_p){
|
||||
termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
|
||||
termios_p->c_oflag &= ~OPOST;
|
||||
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
||||
termios_p->c_cflag &= ~(CSIZE|PARENB);
|
||||
termios_p->c_cflag |= CS8;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void do_cleanup(int i) {
|
||||
/* unused variable */
|
||||
(void) i;
|
||||
|
||||
tcsetattr(0,TCSANOW,&terminal);
|
||||
}
|
||||
|
||||
static void do_exit(int i) {
|
||||
/* unused variable */
|
||||
(void) i;
|
||||
|
||||
do_cleanup(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ssh_channel chan;
|
||||
int signal_delayed=0;
|
||||
|
||||
static void sigwindowchanged(int i){
|
||||
(void) i;
|
||||
signal_delayed=1;
|
||||
}
|
||||
|
||||
static void setsignal(void){
|
||||
signal(SIGWINCH, sigwindowchanged);
|
||||
signal_delayed=0;
|
||||
}
|
||||
|
||||
static void sizechanged(void){
|
||||
struct winsize win = { 0, 0, 0, 0 };
|
||||
ioctl(1, TIOCGWINSZ, &win);
|
||||
ssh_channel_change_pty_size(chan,win.ws_col, win.ws_row);
|
||||
// printf("Changed pty size\n");
|
||||
setsignal();
|
||||
}
|
||||
|
||||
static void select_loop(ssh_session session,ssh_channel channel){
|
||||
ssh_connector connector_in, connector_out, connector_err;
|
||||
ssh_event event = ssh_event_new();
|
||||
|
||||
/* stdin */
|
||||
connector_in = ssh_connector_new(session);
|
||||
ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDOUT);
|
||||
ssh_connector_set_in_fd(connector_in, 0);
|
||||
ssh_event_add_connector(event, connector_in);
|
||||
|
||||
/* stdout */
|
||||
connector_out = ssh_connector_new(session);
|
||||
ssh_connector_set_out_fd(connector_out, 1);
|
||||
ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDOUT);
|
||||
ssh_event_add_connector(event, connector_out);
|
||||
|
||||
/* stderr */
|
||||
connector_err = ssh_connector_new(session);
|
||||
ssh_connector_set_out_fd(connector_err, 2);
|
||||
ssh_connector_set_in_channel(connector_err, channel, SSH_CONNECTOR_STDERR);
|
||||
ssh_event_add_connector(event, connector_err);
|
||||
|
||||
while(ssh_channel_is_open(channel)){
|
||||
if(signal_delayed)
|
||||
sizechanged();
|
||||
ssh_event_dopoll(event, 60000);
|
||||
}
|
||||
ssh_event_remove_connector(event, connector_in);
|
||||
ssh_event_remove_connector(event, connector_out);
|
||||
ssh_event_remove_connector(event, connector_err);
|
||||
|
||||
ssh_connector_free(connector_in);
|
||||
ssh_connector_free(connector_out);
|
||||
ssh_connector_free(connector_err);
|
||||
|
||||
ssh_event_free(event);
|
||||
ssh_channel_free(channel);
|
||||
}
|
||||
|
||||
static void shell(ssh_session session){
|
||||
ssh_channel channel;
|
||||
struct termios terminal_local;
|
||||
int interactive=isatty(0);
|
||||
channel = ssh_channel_new(session);
|
||||
if(interactive){
|
||||
tcgetattr(0,&terminal_local);
|
||||
memcpy(&terminal,&terminal_local,sizeof(struct termios));
|
||||
}
|
||||
if(ssh_channel_open_session(channel)){
|
||||
printf("error opening channel : %s\n",ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
chan=channel;
|
||||
if(interactive){
|
||||
ssh_channel_request_pty(channel);
|
||||
sizechanged();
|
||||
}
|
||||
if(ssh_channel_request_shell(channel)){
|
||||
printf("Requesting shell : %s\n",ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
if(interactive){
|
||||
cfmakeraw(&terminal_local);
|
||||
tcsetattr(0,TCSANOW,&terminal_local);
|
||||
setsignal();
|
||||
}
|
||||
signal(SIGTERM,do_cleanup);
|
||||
select_loop(session,channel);
|
||||
if(interactive)
|
||||
do_cleanup(0);
|
||||
}
|
||||
|
||||
static void batch_shell(ssh_session session){
|
||||
ssh_channel channel;
|
||||
char buffer[1024];
|
||||
int i,s=0;
|
||||
for(i=0;i<MAXCMD && cmds[i];++i) {
|
||||
s+=snprintf(buffer+s,sizeof(buffer)-s,"%s ",cmds[i]);
|
||||
free(cmds[i]);
|
||||
cmds[i] = NULL;
|
||||
}
|
||||
channel=ssh_channel_new(session);
|
||||
ssh_channel_open_session(channel);
|
||||
if(ssh_channel_request_exec(channel,buffer)){
|
||||
printf("error executing \"%s\" : %s\n",buffer,ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
select_loop(session,channel);
|
||||
}
|
||||
|
||||
static int client(ssh_session session){
|
||||
int auth=0;
|
||||
char *banner;
|
||||
int state;
|
||||
if (user)
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0)
|
||||
return -1;
|
||||
if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0)
|
||||
return -1;
|
||||
if (proxycommand != NULL){
|
||||
if(ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, proxycommand))
|
||||
return -1;
|
||||
}
|
||||
ssh_options_parse_config(session, NULL);
|
||||
|
||||
if(ssh_connect(session)){
|
||||
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
|
||||
return -1;
|
||||
}
|
||||
state=verify_knownhost(session);
|
||||
if (state != 0)
|
||||
return -1;
|
||||
ssh_userauth_none(session, NULL);
|
||||
banner=ssh_get_issue_banner(session);
|
||||
if(banner){
|
||||
printf("%s\n",banner);
|
||||
free(banner);
|
||||
}
|
||||
auth=authenticate_console(session);
|
||||
if(auth != SSH_AUTH_SUCCESS){
|
||||
return -1;
|
||||
}
|
||||
if(!cmds[0])
|
||||
shell(session);
|
||||
else
|
||||
batch_shell(session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssh_pcap_file pcap;
|
||||
void set_pcap(ssh_session session);
|
||||
void set_pcap(ssh_session session){
|
||||
if(!pcap_file)
|
||||
return;
|
||||
pcap=ssh_pcap_file_new();
|
||||
if(!pcap)
|
||||
return;
|
||||
if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){
|
||||
printf("Error opening pcap file\n");
|
||||
ssh_pcap_file_free(pcap);
|
||||
pcap=NULL;
|
||||
return;
|
||||
}
|
||||
ssh_set_pcap_file(session,pcap);
|
||||
}
|
||||
|
||||
void cleanup_pcap(void);
|
||||
void cleanup_pcap(){
|
||||
if(pcap)
|
||||
ssh_pcap_file_free(pcap);
|
||||
pcap=NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
ssh_session session;
|
||||
|
||||
session = ssh_new();
|
||||
|
||||
ssh_callbacks_init(&cb);
|
||||
ssh_set_callbacks(session,&cb);
|
||||
|
||||
if(ssh_options_getopt(session, &argc, argv)) {
|
||||
fprintf(stderr, "error parsing command line :%s\n",
|
||||
ssh_get_error(session));
|
||||
usage();
|
||||
}
|
||||
opts(argc,argv);
|
||||
signal(SIGTERM, do_exit);
|
||||
|
||||
set_pcap(session);
|
||||
client(session);
|
||||
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
cleanup_pcap();
|
||||
|
||||
ssh_finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -14,9 +14,9 @@ The goal is to show the API in action.
|
||||
#include "config.h"
|
||||
|
||||
#include <libssh/callbacks.h>
|
||||
#include <libssh/poll.h>
|
||||
#include <libssh/server.h>
|
||||
|
||||
#include <poll.h>
|
||||
#ifdef HAVE_ARGP_H
|
||||
#include <argp.h>
|
||||
#endif
|
||||
@@ -621,6 +621,7 @@ int main(int argc, char **argv) {
|
||||
ssh_session session;
|
||||
ssh_event event;
|
||||
struct sigaction sa;
|
||||
int rc;
|
||||
|
||||
/* Set up SIGCHLD handler. */
|
||||
sa.sa_handler = sigchld_handler;
|
||||
@@ -631,8 +632,17 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssh_init();
|
||||
rc = ssh_init();
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "ssh_init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sshbind = ssh_bind_new();
|
||||
if (sshbind == NULL) {
|
||||
fprintf(stderr, "ssh_bind_new failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ARGP_H
|
||||
argp_parse(&argp, argc, argv, 0, 0, sshbind);
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
project(headers C)
|
||||
project(libssh-headers-x C)
|
||||
|
||||
add_subdirectory(libssh)
|
||||
|
||||
@@ -15,13 +15,6 @@ if (WITH_SFTP)
|
||||
)
|
||||
endif (WITH_SFTP)
|
||||
|
||||
if (WITH_SSH1)
|
||||
set(libssh_HDRS
|
||||
${libssh_HDRS}
|
||||
ssh1.h
|
||||
)
|
||||
endif (WITH_SSH1)
|
||||
|
||||
if (WITH_SERVER)
|
||||
set(libssh_HDRS
|
||||
${libssh_HDRS}
|
||||
|
||||
@@ -81,16 +81,16 @@ struct ssh_agent_struct {
|
||||
*
|
||||
* @return An allocated ssh agent structure or NULL on error.
|
||||
*/
|
||||
struct ssh_agent_struct *agent_new(struct ssh_session_struct *session);
|
||||
struct ssh_agent_struct *ssh_agent_new(struct ssh_session_struct *session);
|
||||
|
||||
void agent_close(struct ssh_agent_struct *agent);
|
||||
void ssh_agent_close(struct ssh_agent_struct *agent);
|
||||
|
||||
/**
|
||||
* @brief Free an allocated ssh agent structure.
|
||||
*
|
||||
* @param agent The ssh agent structure to free.
|
||||
*/
|
||||
void agent_free(struct ssh_agent_struct *agent);
|
||||
void ssh_agent_free(struct ssh_agent_struct *agent);
|
||||
|
||||
/**
|
||||
* @brief Check if the ssh agent is running.
|
||||
@@ -99,7 +99,7 @@ void agent_free(struct ssh_agent_struct *agent);
|
||||
*
|
||||
* @return 1 if it is running, 0 if not.
|
||||
*/
|
||||
int agent_is_running(struct ssh_session_struct *session);
|
||||
int ssh_agent_is_running(struct ssh_session_struct *session);
|
||||
|
||||
int ssh_agent_get_ident_count(struct ssh_session_struct *session);
|
||||
|
||||
@@ -115,4 +115,3 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
#endif
|
||||
|
||||
#endif /* __AGENT_H */
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
|
||||
@@ -49,20 +49,6 @@ ssh_kbdint ssh_kbdint_new(void);
|
||||
void ssh_kbdint_clean(ssh_kbdint kbd);
|
||||
void ssh_kbdint_free(ssh_kbdint kbd);
|
||||
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
void ssh_auth1_handler(ssh_session session, uint8_t type);
|
||||
|
||||
/* auth1.c */
|
||||
int ssh_userauth1_none(ssh_session session, const char *username);
|
||||
int ssh_userauth1_offer_pubkey(ssh_session session, const char *username,
|
||||
int type, ssh_string pubkey);
|
||||
int ssh_userauth1_password(ssh_session session, const char *username,
|
||||
const char *password);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/** @internal
|
||||
* States of authentication in the client-side. They describe
|
||||
* what was the last response from the server
|
||||
@@ -104,8 +90,6 @@ enum ssh_auth_service_state_e {
|
||||
SSH_AUTH_SERVICE_ACCEPTED,
|
||||
/** Access to service denied (fatal) */
|
||||
SSH_AUTH_SERVICE_DENIED,
|
||||
/** Specific to SSH1 */
|
||||
SSH_AUTH_SERVICE_USER_SENT
|
||||
};
|
||||
|
||||
#endif /* AUTH_H_ */
|
||||
|
||||
@@ -23,11 +23,12 @@
|
||||
|
||||
#include "libssh/libcrypto.h"
|
||||
#include "libssh/libgcrypt.h"
|
||||
#include "libssh/libmbedcrypto.h"
|
||||
|
||||
bignum make_string_bn(ssh_string string);
|
||||
void make_string_bn_inplace(ssh_string string, bignum bnout);
|
||||
ssh_string make_bignum_string(bignum num);
|
||||
void ssh_print_bignum(const char *which,bignum num);
|
||||
bignum ssh_make_string_bn(ssh_string string);
|
||||
void ssh_make_string_bn_inplace(ssh_string string, bignum bnout);
|
||||
ssh_string ssh_make_bignum_string(bignum num);
|
||||
void ssh_print_bignum(const char *which, const bignum num);
|
||||
|
||||
|
||||
#endif /* BIGNUM_H_ */
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
typedef struct BlowfishContext {
|
||||
uint32_t S[4][256]; /* S-Boxes */
|
||||
uint32_t P[BLF_N + 2]; /* Subkeys */
|
||||
} blf_ctx;
|
||||
} ssh_blf_ctx;
|
||||
|
||||
/* Raw access to customized Blowfish
|
||||
* blf_key is just:
|
||||
@@ -61,24 +61,24 @@ typedef struct BlowfishContext {
|
||||
* Blowfish_expand0state( state, key, keylen )
|
||||
*/
|
||||
|
||||
void Blowfish_encipher(blf_ctx *, uint32_t *, uint32_t *);
|
||||
void Blowfish_decipher(blf_ctx *, uint32_t *, uint32_t *);
|
||||
void Blowfish_initstate(blf_ctx *);
|
||||
void Blowfish_expand0state(blf_ctx *, const uint8_t *, uint16_t);
|
||||
void Blowfish_encipher(ssh_blf_ctx *, uint32_t *, uint32_t *);
|
||||
void Blowfish_decipher(ssh_blf_ctx *, uint32_t *, uint32_t *);
|
||||
void Blowfish_initstate(ssh_blf_ctx *);
|
||||
void Blowfish_expand0state(ssh_blf_ctx *, const uint8_t *, uint16_t);
|
||||
void Blowfish_expandstate
|
||||
(blf_ctx *, const uint8_t *, uint16_t, const uint8_t *, uint16_t);
|
||||
(ssh_blf_ctx *, const uint8_t *, uint16_t, const uint8_t *, uint16_t);
|
||||
|
||||
/* Standard Blowfish */
|
||||
|
||||
void blf_key(blf_ctx *, const uint8_t *, uint16_t);
|
||||
void blf_enc(blf_ctx *, uint32_t *, uint16_t);
|
||||
void blf_dec(blf_ctx *, uint32_t *, uint16_t);
|
||||
void ssh_blf_key(ssh_blf_ctx *, const uint8_t *, uint16_t);
|
||||
void ssh_blf_enc(ssh_blf_ctx *, uint32_t *, uint16_t);
|
||||
void ssh_blf_dec(ssh_blf_ctx *, uint32_t *, uint16_t);
|
||||
|
||||
void blf_ecb_encrypt(blf_ctx *, uint8_t *, uint32_t);
|
||||
void blf_ecb_decrypt(blf_ctx *, uint8_t *, uint32_t);
|
||||
void ssh_blf_ecb_encrypt(ssh_blf_ctx *, uint8_t *, uint32_t);
|
||||
void ssh_blf_ecb_decrypt(ssh_blf_ctx *, uint8_t *, uint32_t);
|
||||
|
||||
void blf_cbc_encrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t);
|
||||
void blf_cbc_decrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t);
|
||||
void ssh_blf_cbc_encrypt(ssh_blf_ctx *, uint8_t *, uint8_t *, uint32_t);
|
||||
void ssh_blf_cbc_decrypt(ssh_blf_ctx *, uint8_t *, uint8_t *, uint32_t);
|
||||
|
||||
/* Converts uint8_t to uint32_t */
|
||||
uint32_t Blowfish_stream2word(const uint8_t *, uint16_t , uint16_t *);
|
||||
|
||||
@@ -41,18 +41,17 @@ struct ssh_buffer_struct {
|
||||
|
||||
#define SSH_BUFFER_PACK_END ((uint32_t) 0x4f65feb3)
|
||||
|
||||
LIBSSH_API void ssh_buffer_free(ssh_buffer buffer);
|
||||
LIBSSH_API void *ssh_buffer_get_begin(ssh_buffer buffer);
|
||||
LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer);
|
||||
LIBSSH_API ssh_buffer ssh_buffer_new(void);
|
||||
void ssh_buffer_set_secure(ssh_buffer buffer);
|
||||
int buffer_add_ssh_string(ssh_buffer buffer, ssh_string string);
|
||||
int buffer_add_u8(ssh_buffer buffer, uint8_t data);
|
||||
int buffer_add_u16(ssh_buffer buffer, uint16_t data);
|
||||
int buffer_add_u32(ssh_buffer buffer, uint32_t data);
|
||||
int buffer_add_u64(ssh_buffer buffer, uint64_t data);
|
||||
int ssh_buffer_add_data(ssh_buffer buffer, const void *data, uint32_t len);
|
||||
int ssh_buffer_add_ssh_string(ssh_buffer buffer, ssh_string string);
|
||||
int ssh_buffer_add_u8(ssh_buffer buffer, uint8_t data);
|
||||
int ssh_buffer_add_u16(ssh_buffer buffer, uint16_t data);
|
||||
int ssh_buffer_add_u32(ssh_buffer buffer, uint32_t data);
|
||||
int ssh_buffer_add_u64(ssh_buffer buffer, uint64_t data);
|
||||
|
||||
int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len);
|
||||
|
||||
void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len);
|
||||
int ssh_buffer_allocate_size(struct ssh_buffer_struct *buffer, uint32_t len);
|
||||
int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
const char *format,
|
||||
int argc,
|
||||
@@ -74,27 +73,19 @@ int _ssh_buffer_unpack(struct ssh_buffer_struct *buffer,
|
||||
#define ssh_buffer_unpack(buffer, format, ...) \
|
||||
_ssh_buffer_unpack((buffer), (format), __VA_NARG__(__VA_ARGS__), __VA_ARGS__, SSH_BUFFER_PACK_END)
|
||||
|
||||
int buffer_prepend_data(ssh_buffer buffer, const void *data, uint32_t len);
|
||||
int buffer_add_buffer(ssh_buffer buffer, ssh_buffer source);
|
||||
int ssh_buffer_reinit(ssh_buffer buffer);
|
||||
|
||||
/* buffer_get_rest returns a pointer to the current position into the buffer */
|
||||
void *buffer_get_rest(ssh_buffer buffer);
|
||||
/* buffer_get_rest_len returns the number of bytes which can be read */
|
||||
uint32_t buffer_get_rest_len(ssh_buffer buffer);
|
||||
int ssh_buffer_prepend_data(ssh_buffer buffer, const void *data, uint32_t len);
|
||||
int ssh_buffer_add_buffer(ssh_buffer buffer, ssh_buffer source);
|
||||
|
||||
/* buffer_read_*() returns the number of bytes read, except for ssh strings */
|
||||
int buffer_get_u8(ssh_buffer buffer, uint8_t *data);
|
||||
int buffer_get_u32(ssh_buffer buffer, uint32_t *data);
|
||||
int buffer_get_u64(ssh_buffer buffer, uint64_t *data);
|
||||
int ssh_buffer_get_u8(ssh_buffer buffer, uint8_t *data);
|
||||
int ssh_buffer_get_u32(ssh_buffer buffer, uint32_t *data);
|
||||
int ssh_buffer_get_u64(ssh_buffer buffer, uint64_t *data);
|
||||
|
||||
uint32_t buffer_get_data(ssh_buffer buffer, void *data, uint32_t requestedlen);
|
||||
/* buffer_get_ssh_string() is an exception. if the String read is too large or invalid, it will answer NULL. */
|
||||
ssh_string buffer_get_ssh_string(ssh_buffer buffer);
|
||||
/* gets a string out of a SSH-1 mpint */
|
||||
ssh_string buffer_get_mpint(ssh_buffer buffer);
|
||||
/* buffer_pass_bytes acts as if len bytes have been read (used for padding) */
|
||||
uint32_t buffer_pass_bytes_end(ssh_buffer buffer, uint32_t len);
|
||||
uint32_t buffer_pass_bytes(ssh_buffer buffer, uint32_t len);
|
||||
/* ssh_buffer_get_ssh_string() is an exception. if the String read is too large or invalid, it will answer NULL. */
|
||||
ssh_string ssh_buffer_get_ssh_string(ssh_buffer buffer);
|
||||
|
||||
/* ssh_buffer_pass_bytes acts as if len bytes have been read (used for padding) */
|
||||
uint32_t ssh_buffer_pass_bytes_end(ssh_buffer buffer, uint32_t len);
|
||||
uint32_t ssh_buffer_pass_bytes(ssh_buffer buffer, uint32_t len);
|
||||
|
||||
#endif /* BUFFER_H_ */
|
||||
|
||||
@@ -124,6 +124,18 @@ typedef void (*ssh_global_request_callback) (ssh_session session,
|
||||
typedef ssh_channel (*ssh_channel_open_request_x11_callback) (ssh_session session,
|
||||
const char * originator_address, int originator_port, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Handles an SSH new channel open "auth-agent" request. This happens when the server
|
||||
* sends back an "auth-agent" connection attempt. This is a client-side API
|
||||
* @param session current session handler
|
||||
* @param userdata Userdata to be passed to the callback function.
|
||||
* @returns a valid ssh_channel handle if the request is to be allowed
|
||||
* @returns NULL if the request should not be allowed
|
||||
* @warning The channel pointer returned by this callback must be closed by the application.
|
||||
*/
|
||||
typedef ssh_channel (*ssh_channel_open_request_auth_agent_callback) (ssh_session session,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* The structure to replace libssh functions with appropriate callbacks.
|
||||
*/
|
||||
@@ -154,6 +166,9 @@ struct ssh_callbacks_struct {
|
||||
/** This function will be called when an incoming X11 request is received.
|
||||
*/
|
||||
ssh_channel_open_request_x11_callback channel_open_request_x11_function;
|
||||
/** This function will be called when an incoming "auth-agent" request is received.
|
||||
*/
|
||||
ssh_channel_open_request_auth_agent_callback channel_open_request_auth_agent_function;
|
||||
};
|
||||
typedef struct ssh_callbacks_struct *ssh_callbacks;
|
||||
|
||||
@@ -420,6 +435,69 @@ typedef struct ssh_socket_callbacks_struct *ssh_socket_callbacks;
|
||||
((p)-> c != NULL) \
|
||||
)
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Iterate through a list of callback structures
|
||||
*
|
||||
* This tests for their validity and executes them. The userdata argument is
|
||||
* automatically passed through.
|
||||
*
|
||||
* @param list list of callbacks
|
||||
*
|
||||
* @param cbtype type of the callback
|
||||
*
|
||||
* @param c callback name
|
||||
*
|
||||
* @param va_args parameters to be passed
|
||||
*/
|
||||
#define ssh_callbacks_execute_list(list, cbtype, c, ...) \
|
||||
do { \
|
||||
struct ssh_iterator *i = ssh_list_get_iterator(list); \
|
||||
cbtype cb; \
|
||||
while (i != NULL){ \
|
||||
cb = ssh_iterator_value(cbtype, i); \
|
||||
if (ssh_callbacks_exists(cb, c)) \
|
||||
cb-> c (__VA_ARGS__, cb->userdata); \
|
||||
i = i->next; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief iterate through a list of callback structures.
|
||||
*
|
||||
* This tests for their validity and give control back to the calling code to
|
||||
* execute them. Caller can decide to break the loop or continue executing the
|
||||
* callbacks with different parameters
|
||||
*
|
||||
* @code
|
||||
* ssh_callbacks_iterate(channel->callbacks, ssh_channel_callbacks,
|
||||
* channel_eof_function){
|
||||
* rc = ssh_callbacks_iterate_exec(session, channel);
|
||||
* if (rc != SSH_OK){
|
||||
* break;
|
||||
* }
|
||||
* }
|
||||
* ssh_callbacks_iterate_end();
|
||||
* @endcode
|
||||
*/
|
||||
#define ssh_callbacks_iterate(_cb_list, _cb_type, _cb_name) \
|
||||
do { \
|
||||
struct ssh_iterator *_cb_i = ssh_list_get_iterator(_cb_list); \
|
||||
_cb_type _cb; \
|
||||
for (; _cb_i != NULL; _cb_i = _cb_i->next) { \
|
||||
_cb = ssh_iterator_value(_cb_type, _cb_i); \
|
||||
if (ssh_callbacks_exists(_cb, _cb_name))
|
||||
|
||||
#define ssh_callbacks_iterate_exec(_cb_name, ...) \
|
||||
_cb->_cb_name(__VA_ARGS__, _cb->userdata)
|
||||
|
||||
#define ssh_callbacks_iterate_end() \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/** @brief Prototype for a packet callback, to be called when a new packet arrives
|
||||
* @param session The current session of the packet
|
||||
* @param type packet type (see ssh2.h)
|
||||
@@ -679,6 +757,22 @@ typedef int (*ssh_channel_subsystem_request_callback) (ssh_session session,
|
||||
const char *subsystem,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* @brief SSH channel write will not block (flow control).
|
||||
*
|
||||
* @param channel the channel
|
||||
*
|
||||
* @param[in] bytes size of the remote window in bytes. Writing as much data
|
||||
* will not block.
|
||||
*
|
||||
* @param[in] userdata Userdata to be passed to the callback function.
|
||||
*
|
||||
* @returns 0 default return value (other return codes may be added in future).
|
||||
*/
|
||||
typedef int (*ssh_channel_write_wontblock_callback) (ssh_session session,
|
||||
ssh_channel channel,
|
||||
size_t bytes,
|
||||
void *userdata);
|
||||
|
||||
struct ssh_channel_callbacks_struct {
|
||||
/** DON'T SET THIS use ssh_callbacks_init() instead. */
|
||||
@@ -743,6 +837,10 @@ struct ssh_channel_callbacks_struct {
|
||||
* (like sftp).
|
||||
*/
|
||||
ssh_channel_subsystem_request_callback channel_subsystem_request_function;
|
||||
/** This function will be called when the channel write is guaranteed
|
||||
* not to block.
|
||||
*/
|
||||
ssh_channel_write_wontblock_callback channel_write_wontblock_function;
|
||||
};
|
||||
|
||||
typedef struct ssh_channel_callbacks_struct *ssh_channel_callbacks;
|
||||
@@ -767,10 +865,46 @@ typedef struct ssh_channel_callbacks_struct *ssh_channel_callbacks;
|
||||
* @param cb The callback structure itself.
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error.
|
||||
* @warning this function will not replace existing callbacks but set the
|
||||
* new one atop of them.
|
||||
*/
|
||||
LIBSSH_API int ssh_set_channel_callbacks(ssh_channel channel,
|
||||
ssh_channel_callbacks cb);
|
||||
|
||||
/**
|
||||
* @brief Add channel callback functions
|
||||
*
|
||||
* This function will add channel callback functions to the channel callback
|
||||
* list.
|
||||
* Callbacks missing from a callback structure will be probed in the next
|
||||
* on the list.
|
||||
*
|
||||
* @param channel The channel to set the callback structure.
|
||||
*
|
||||
* @param cb The callback structure itself.
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error.
|
||||
*
|
||||
* @see ssh_set_channel_callbacks
|
||||
*/
|
||||
LIBSSH_API int ssh_add_channel_callbacks(ssh_channel channel,
|
||||
ssh_channel_callbacks cb);
|
||||
|
||||
/**
|
||||
* @brief Remove a channel callback.
|
||||
*
|
||||
* The channel has been added with ssh_add_channel_callbacks or
|
||||
* ssh_set_channel_callbacks in this case.
|
||||
*
|
||||
* @param channel The channel to remove the callback structure from.
|
||||
*
|
||||
* @param cb The callback structure to remove
|
||||
*
|
||||
* @returns SSH_OK on success, SSH_ERROR on error.
|
||||
*/
|
||||
LIBSSH_API int ssh_remove_channel_callbacks(ssh_channel channel,
|
||||
ssh_channel_callbacks cb);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @group libssh_threads
|
||||
|
||||
41
include/libssh/chacha.h
Normal file
41
include/libssh/chacha.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* $OpenBSD: chacha.h,v 1.3 2014/05/02 03:27:54 djm Exp $ */
|
||||
|
||||
/*
|
||||
chacha-merged.c version 20080118
|
||||
D. J. Bernstein
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#ifndef CHACHA_H
|
||||
#define CHACHA_H
|
||||
|
||||
struct chacha_ctx {
|
||||
uint32_t input[16];
|
||||
};
|
||||
|
||||
#define CHACHA_MINKEYLEN 16
|
||||
#define CHACHA_NONCELEN 8
|
||||
#define CHACHA_CTRLEN 8
|
||||
#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN)
|
||||
#define CHACHA_BLOCKLEN 64
|
||||
|
||||
void chacha_keysetup(struct chacha_ctx *x, const uint8_t *k, uint32_t kbits)
|
||||
#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE
|
||||
__attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN)))
|
||||
#endif
|
||||
;
|
||||
void chacha_ivsetup(struct chacha_ctx *x, const uint8_t *iv, const uint8_t *ctr)
|
||||
#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE
|
||||
__attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN)))
|
||||
__attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN)))
|
||||
#endif
|
||||
;
|
||||
void chacha_encrypt_bytes(struct chacha_ctx *x, const uint8_t *m,
|
||||
uint8_t *c, uint32_t bytes)
|
||||
#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE
|
||||
__attribute__((__bounded__(__buffer__, 2, 4)))
|
||||
__attribute__((__bounded__(__buffer__, 3, 4)))
|
||||
#endif
|
||||
;
|
||||
|
||||
#endif /* CHACHA_H */
|
||||
@@ -71,10 +71,10 @@ struct ssh_channel_struct {
|
||||
ssh_buffer stdout_buffer;
|
||||
ssh_buffer stderr_buffer;
|
||||
void *userarg;
|
||||
int version;
|
||||
int exit_status;
|
||||
enum ssh_channel_request_state_e request_state;
|
||||
ssh_channel_callbacks callbacks;
|
||||
struct ssh_list *callbacks; /* list of ssh_channel_callbacks */
|
||||
|
||||
/* counters */
|
||||
ssh_counter counter;
|
||||
};
|
||||
@@ -99,20 +99,5 @@ int ssh_channel_flush(ssh_channel channel);
|
||||
uint32_t ssh_channel_new_id(ssh_session session);
|
||||
ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id);
|
||||
void ssh_channel_do_free(ssh_channel channel);
|
||||
#ifdef WITH_SSH1
|
||||
SSH_PACKET_CALLBACK(ssh_packet_data1);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_close1);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_exist_status1);
|
||||
|
||||
/* channels1.c */
|
||||
int channel_open_session1(ssh_channel channel);
|
||||
int channel_request_pty_size1(ssh_channel channel, const char *terminal,
|
||||
int cols, int rows);
|
||||
int channel_change_pty_size1(ssh_channel channel, int cols, int rows);
|
||||
int channel_request_shell1(ssh_channel channel);
|
||||
int channel_request_exec1(ssh_channel channel, const char *cmd);
|
||||
int channel_write1(ssh_channel channel, const void *data, int len);
|
||||
ssh_channel ssh_get_channel1(ssh_session session);
|
||||
#endif
|
||||
|
||||
#endif /* CHANNELS_H_ */
|
||||
|
||||
@@ -55,14 +55,38 @@ enum ssh_key_exchange_e {
|
||||
SSH_KEX_DH_GROUP14_SHA1,
|
||||
/* ecdh-sha2-nistp256 */
|
||||
SSH_KEX_ECDH_SHA2_NISTP256,
|
||||
/* ecdh-sha2-nistp384 */
|
||||
SSH_KEX_ECDH_SHA2_NISTP384,
|
||||
/* ecdh-sha2-nistp521 */
|
||||
SSH_KEX_ECDH_SHA2_NISTP521,
|
||||
/* curve25519-sha256@libssh.org */
|
||||
SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG
|
||||
SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG,
|
||||
/* curve25519-sha256 */
|
||||
SSH_KEX_CURVE25519_SHA256
|
||||
};
|
||||
|
||||
enum ssh_cipher_e {
|
||||
SSH_NO_CIPHER=0,
|
||||
SSH_BLOWFISH_CBC,
|
||||
SSH_3DES_CBC,
|
||||
SSH_AES128_CBC,
|
||||
SSH_AES192_CBC,
|
||||
SSH_AES256_CBC,
|
||||
SSH_AES128_CTR,
|
||||
SSH_AES192_CTR,
|
||||
SSH_AES256_CTR
|
||||
};
|
||||
|
||||
struct ssh_crypto_struct {
|
||||
bignum e,f,x,k,y;
|
||||
#ifdef HAVE_ECDH
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
EC_KEY *ecdh_privkey;
|
||||
#elif defined HAVE_GCRYPT_ECC
|
||||
gcry_sexp_t ecdh_privkey;
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
mbedtls_ecp_keypair *ecdh_privkey;
|
||||
#endif
|
||||
ssh_string ecdh_client_pubkey;
|
||||
ssh_string ecdh_server_pubkey;
|
||||
#endif
|
||||
@@ -85,8 +109,7 @@ struct ssh_crypto_struct {
|
||||
struct ssh_cipher_struct *in_cipher, *out_cipher; /* the cipher structures/objects */
|
||||
enum ssh_hmac_e in_hmac, out_hmac; /* the MAC algorithms used */
|
||||
|
||||
ssh_string server_pubkey;
|
||||
const char *server_pubkey_type;
|
||||
ssh_key server_pubkey;
|
||||
int do_compress_out; /* idem */
|
||||
int do_compress_in; /* don't set them, set the option instead */
|
||||
int delayed_compress_in; /* Use of zlib@openssh.org */
|
||||
@@ -104,14 +127,24 @@ struct ssh_crypto_struct {
|
||||
struct ssh_cipher_struct {
|
||||
const char *name; /* ssh name of the algorithm */
|
||||
unsigned int blocksize; /* blocksize of the algo */
|
||||
unsigned int keylen; /* length of the key structure */
|
||||
enum ssh_cipher_e ciphertype;
|
||||
uint32_t lenfield_blocksize; /* blocksize of the packet length field */
|
||||
size_t keylen; /* length of the key structure */
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_cipher_hd_t *key;
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
void *key; /* a key buffer allocated for the algo */
|
||||
void *IV;
|
||||
struct ssh_3des_key_schedule *des3_key;
|
||||
struct ssh_aes_key_schedule *aes_key;
|
||||
const EVP_CIPHER *cipher;
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
mbedtls_cipher_context_t encrypt_ctx;
|
||||
mbedtls_cipher_context_t decrypt_ctx;
|
||||
mbedtls_cipher_type_t type;
|
||||
#endif
|
||||
struct chacha20_poly1305_keysched *chacha20_schedule;
|
||||
unsigned int keysize; /* bytes of key used. != keylen */
|
||||
size_t tag_size; /* overhead required for tag */
|
||||
/* sets the new key for immediate use */
|
||||
int (*set_encrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV);
|
||||
int (*set_decrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV);
|
||||
@@ -119,7 +152,15 @@ struct ssh_cipher_struct {
|
||||
unsigned long len);
|
||||
void (*decrypt)(struct ssh_cipher_struct *cipher, void *in, void *out,
|
||||
unsigned long len);
|
||||
void (*aead_encrypt)(struct ssh_cipher_struct *cipher, void *in, void *out,
|
||||
size_t len, uint8_t *mac, uint64_t seq);
|
||||
int (*aead_decrypt_length)(struct ssh_cipher_struct *cipher, void *in,
|
||||
uint8_t *out, size_t len, uint64_t seq);
|
||||
int (*aead_decrypt)(struct ssh_cipher_struct *cipher, void *complete_packet, uint8_t *out,
|
||||
size_t encrypted_size, uint64_t seq);
|
||||
void (*cleanup)(struct ssh_cipher_struct *cipher);
|
||||
};
|
||||
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
const struct ssh_cipher_struct *ssh_get_chacha20poly1305_cipher(void);
|
||||
|
||||
#endif /* _CRYPTO_H_ */
|
||||
|
||||
@@ -25,27 +25,37 @@
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
|
||||
int dh_generate_e(ssh_session session);
|
||||
int dh_generate_f(ssh_session session);
|
||||
int dh_generate_x(ssh_session session);
|
||||
int dh_generate_y(ssh_session session);
|
||||
int ssh_dh_generate_e(ssh_session session);
|
||||
int ssh_dh_generate_f(ssh_session session);
|
||||
int ssh_dh_generate_x(ssh_session session);
|
||||
int ssh_dh_generate_y(ssh_session session);
|
||||
|
||||
int ssh_crypto_init(void);
|
||||
void ssh_crypto_finalize(void);
|
||||
int ssh_dh_init(void);
|
||||
void ssh_dh_finalize(void);
|
||||
|
||||
ssh_string dh_get_e(ssh_session session);
|
||||
ssh_string dh_get_f(ssh_session session);
|
||||
int dh_import_f(ssh_session session,ssh_string f_string);
|
||||
int dh_import_e(ssh_session session, ssh_string e_string);
|
||||
void dh_import_pubkey(ssh_session session,ssh_string pubkey_string);
|
||||
int dh_build_k(ssh_session session);
|
||||
ssh_string ssh_dh_get_e(ssh_session session);
|
||||
ssh_string ssh_dh_get_f(ssh_session session);
|
||||
int ssh_dh_import_f(ssh_session session,ssh_string f_string);
|
||||
int ssh_dh_import_e(ssh_session session, ssh_string e_string);
|
||||
|
||||
int ssh_dh_import_pubkey_blob(ssh_session session, ssh_string pubkey_blob);
|
||||
int ssh_dh_import_next_pubkey_blob(ssh_session session, ssh_string pubkey_blob);
|
||||
|
||||
int ssh_dh_build_k(ssh_session session);
|
||||
int ssh_client_dh_init(ssh_session session);
|
||||
int ssh_client_dh_reply(ssh_session session, ssh_buffer packet);
|
||||
|
||||
int make_sessionid(ssh_session session);
|
||||
ssh_key ssh_dh_get_current_server_publickey(ssh_session session);
|
||||
int ssh_dh_get_current_server_publickey_blob(ssh_session session,
|
||||
ssh_string *pubkey_blob);
|
||||
ssh_key ssh_dh_get_next_server_publickey(ssh_session session);
|
||||
int ssh_dh_get_next_server_publickey_blob(ssh_session session,
|
||||
ssh_string *pubkey_blob);
|
||||
|
||||
int ssh_make_sessionid(ssh_session session);
|
||||
/* add data for the final cookie */
|
||||
int hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
|
||||
int hashbufout_add_cookie(ssh_session session);
|
||||
int generate_session_keys(ssh_session session);
|
||||
int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
|
||||
int ssh_hashbufout_add_cookie(ssh_session session);
|
||||
int ssh_generate_session_keys(ssh_session session);
|
||||
|
||||
#endif /* DH_H_ */
|
||||
|
||||
@@ -33,9 +33,21 @@
|
||||
#endif /* HAVE_OPENSSL_ECDH_H */
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
int ssh_client_ecdh_init(ssh_session session);
|
||||
#ifdef HAVE_GCRYPT_ECC
|
||||
#define HAVE_ECDH 1
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBMBEDCRYPTO
|
||||
#define HAVE_ECDH 1
|
||||
#endif
|
||||
|
||||
/* Common functions. */
|
||||
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet);
|
||||
|
||||
/* Backend-specific functions. */
|
||||
int ssh_client_ecdh_init(ssh_session session);
|
||||
int ecdh_build_k(ssh_session session);
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet);
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
@@ -28,7 +28,7 @@ typedef struct
|
||||
fe25519 t;
|
||||
} ge25519;
|
||||
|
||||
const ge25519 ge25519_base;
|
||||
extern const ge25519 ge25519_base;
|
||||
|
||||
int ge25519_unpackneg_vartime(ge25519 *r, const unsigned char p[32]);
|
||||
|
||||
|
||||
@@ -32,16 +32,14 @@ struct ssh_kex_struct {
|
||||
};
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_kexinit);
|
||||
#ifdef WITH_SSH1
|
||||
SSH_PACKET_CALLBACK(ssh_packet_publickey1);
|
||||
#endif
|
||||
|
||||
int ssh_send_kex(ssh_session session, int server_kex);
|
||||
void ssh_list_kex(struct ssh_kex_struct *kex);
|
||||
int set_client_kex(ssh_session session);
|
||||
int ssh_set_client_kex(ssh_session session);
|
||||
int ssh_kex_select_methods(ssh_session session);
|
||||
int verify_existing_algo(int algo, const char *name);
|
||||
char **space_tokenize(const char *chain);
|
||||
int ssh_verify_existing_algo(enum ssh_kex_types_e algo, const char *name);
|
||||
char *ssh_keep_known_algos(enum ssh_kex_types_e algo, const char *list);
|
||||
char **ssh_space_tokenize(const char *chain);
|
||||
int ssh_get_kex1(ssh_session session);
|
||||
char *ssh_find_matching(const char *in_d, const char *what_d);
|
||||
const char *ssh_kex_get_supported_method(uint32_t algo);
|
||||
|
||||
@@ -34,6 +34,9 @@ struct ssh_public_key_struct {
|
||||
#elif HAVE_LIBCRYPTO
|
||||
DSA *dsa_pub;
|
||||
RSA *rsa_pub;
|
||||
#elif HAVE_LIBMBEDCRYPTO
|
||||
mbedtls_pk_context *rsa_pub;
|
||||
void *dsa_pub;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -45,6 +48,9 @@ struct ssh_private_key_struct {
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
DSA *dsa_priv;
|
||||
RSA *rsa_priv;
|
||||
#elif HAVE_LIBMBEDCRYPTO
|
||||
mbedtls_pk_context *rsa_priv;
|
||||
void *dsa_priv;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef KNOWNHOSTS_H_
|
||||
#define KNOWNHOSTS_H_
|
||||
#ifndef SSH_KNOWNHOSTS_H_
|
||||
#define SSH_KNOWNHOSTS_H_
|
||||
|
||||
char **ssh_knownhosts_algorithms(ssh_session session);
|
||||
struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session);
|
||||
|
||||
#endif /* KNOWNHOSTS_H_ */
|
||||
#endif /* SSH_KNOWNHOSTS_H_ */
|
||||
|
||||
@@ -30,15 +30,13 @@
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/hmac.h>
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
#include <openssl/evp.h>
|
||||
#endif
|
||||
|
||||
typedef SHA_CTX* SHACTX;
|
||||
typedef SHA256_CTX* SHA256CTX;
|
||||
typedef SHA512_CTX* SHA384CTX;
|
||||
typedef SHA512_CTX* SHA512CTX;
|
||||
typedef MD5_CTX* MD5CTX;
|
||||
typedef EVP_MD_CTX* SHACTX;
|
||||
typedef EVP_MD_CTX* SHA256CTX;
|
||||
typedef EVP_MD_CTX* SHA384CTX;
|
||||
typedef EVP_MD_CTX* SHA512CTX;
|
||||
typedef EVP_MD_CTX* MD5CTX;
|
||||
typedef HMAC_CTX* HMACCTX;
|
||||
#ifdef HAVE_ECC
|
||||
typedef EVP_MD_CTX *EVPCTX;
|
||||
@@ -69,13 +67,18 @@ typedef BIGNUM* bignum;
|
||||
typedef BN_CTX* bignum_CTX;
|
||||
|
||||
#define bignum_new() BN_new()
|
||||
#define bignum_free(num) BN_clear_free(num)
|
||||
#define bignum_safe_free(num) do { \
|
||||
if ((num) != NULL) { \
|
||||
BN_clear_free((num)); \
|
||||
(num)=NULL; \
|
||||
} \
|
||||
} while(0)
|
||||
#define bignum_set_word(bn,n) BN_set_word(bn,n)
|
||||
#define bignum_bin2bn(bn,datalen,data) BN_bin2bn(bn,datalen,data)
|
||||
#define bignum_bn2dec(num) BN_bn2dec(num)
|
||||
#define bignum_dec2bn(bn,data) BN_dec2bn(data,bn)
|
||||
#define bignum_bn2hex(num) BN_bn2hex(num)
|
||||
#define bignum_rand(rnd, bits, top, bottom) BN_rand(rnd,bits,top,bottom)
|
||||
#define bignum_rand(rnd, bits) BN_rand(rnd, bits, 0, 1)
|
||||
#define bignum_ctx_new() BN_CTX_new()
|
||||
#define bignum_ctx_free(num) BN_CTX_free(num)
|
||||
#define bignum_mod_exp(dest,generator,exp,modulo,ctx) BN_mod_exp(dest,generator,exp,modulo,ctx)
|
||||
@@ -85,20 +88,6 @@ typedef BN_CTX* bignum_CTX;
|
||||
#define bignum_bn2bin(num,ptr) BN_bn2bin(num,ptr)
|
||||
#define bignum_cmp(num1,num2) BN_cmp(num1,num2)
|
||||
|
||||
SHA256CTX sha256_init(void);
|
||||
void sha256_update(SHA256CTX c, const void *data, unsigned long len);
|
||||
void sha256_final(unsigned char *md, SHA256CTX c);
|
||||
|
||||
SHA384CTX sha384_init(void);
|
||||
void sha384_update(SHA384CTX c, const void *data, unsigned long len);
|
||||
void sha384_final(unsigned char *md, SHA384CTX c);
|
||||
|
||||
SHA512CTX sha512_init(void);
|
||||
void sha512_update(SHA512CTX c, const void *data, unsigned long len);
|
||||
void sha512_final(unsigned char *md, SHA512CTX c);
|
||||
|
||||
struct ssh_cipher_struct *ssh_get_ciphertab(void);
|
||||
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
#endif /* LIBCRYPTO_H_ */
|
||||
|
||||
@@ -32,7 +32,7 @@ typedef gcry_md_hd_t SHA384CTX;
|
||||
typedef gcry_md_hd_t SHA512CTX;
|
||||
typedef gcry_md_hd_t MD5CTX;
|
||||
typedef gcry_md_hd_t HMACCTX;
|
||||
typedef void *EVPCTX;
|
||||
typedef gcry_md_hd_t EVPCTX;
|
||||
#define SHA_DIGEST_LENGTH 20
|
||||
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
|
||||
#define MD5_DIGEST_LEN 16
|
||||
@@ -51,16 +51,26 @@ typedef void *EVPCTX;
|
||||
|
||||
typedef gcry_mpi_t bignum;
|
||||
|
||||
/* Constants for curves. */
|
||||
#define NID_gcrypt_nistp256 0
|
||||
#define NID_gcrypt_nistp384 1
|
||||
#define NID_gcrypt_nistp521 2
|
||||
|
||||
/* missing gcrypt functions */
|
||||
int my_gcry_dec2bn(bignum *bn, const char *data);
|
||||
char *my_gcry_bn2dec(bignum bn);
|
||||
int ssh_gcry_dec2bn(bignum *bn, const char *data);
|
||||
char *ssh_gcry_bn2dec(bignum bn);
|
||||
|
||||
#define bignum_new() gcry_mpi_new(0)
|
||||
#define bignum_free(num) gcry_mpi_release(num)
|
||||
#define bignum_safe_free(num) do { \
|
||||
if ((num) != NULL) { \
|
||||
gcry_mpi_release((num)); \
|
||||
(num)=NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
#define bignum_set_word(bn,n) gcry_mpi_set_ui(bn,n)
|
||||
#define bignum_bin2bn(bn,datalen,data) gcry_mpi_scan(data,GCRYMPI_FMT_USG,bn,datalen,NULL)
|
||||
#define bignum_bn2dec(num) my_gcry_bn2dec(num)
|
||||
#define bignum_dec2bn(num, data) my_gcry_dec2bn(data, num)
|
||||
#define bignum_bn2dec(num) ssh_gcry_bn2dec(num)
|
||||
#define bignum_dec2bn(num, data) ssh_gcry_dec2bn(data, num)
|
||||
#define bignum_bn2hex(num,data) gcry_mpi_aprint(GCRYMPI_FMT_HEX,data,NULL,num)
|
||||
#define bignum_hex2bn(num,datalen,data) gcry_mpi_scan(num,GCRYMPI_FMT_HEX,data,datalen,NULL)
|
||||
#define bignum_rand(num,bits) gcry_mpi_randomize(num,bits,GCRY_STRONG_RANDOM),gcry_mpi_set_bit(num,bits-1),gcry_mpi_set_bit(num,0)
|
||||
@@ -71,8 +81,16 @@ char *my_gcry_bn2dec(bignum bn);
|
||||
#define bignum_bn2bin(num,datalen,data) gcry_mpi_print(GCRYMPI_FMT_USG,data,datalen,NULL,num)
|
||||
#define bignum_cmp(num1,num2) gcry_mpi_cmp(num1,num2)
|
||||
|
||||
/* Helper functions for data conversions. */
|
||||
|
||||
/* Extract an MPI from the given s-expression SEXP named NAME which is
|
||||
encoded using INFORMAT and store it in a newly allocated ssh_string
|
||||
encoded using OUTFORMAT. */
|
||||
ssh_string ssh_sexp_extract_mpi(const gcry_sexp_t sexp,
|
||||
const char *name,
|
||||
enum gcry_mpi_format informat,
|
||||
enum gcry_mpi_format outformat);
|
||||
|
||||
#endif /* HAVE_LIBGCRYPT */
|
||||
|
||||
struct ssh_cipher_struct *ssh_get_ciphertab(void);
|
||||
|
||||
#endif /* LIBGCRYPT_H_ */
|
||||
|
||||
113
include/libssh/libmbedcrypto.h
Normal file
113
include/libssh/libmbedcrypto.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2017 Sartura d.o.o.
|
||||
*
|
||||
* Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef LIBMBEDCRYPTO_H_
|
||||
#define LIBMBEDCRYPTO_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_LIBMBEDCRYPTO
|
||||
|
||||
#include <mbedtls/md.h>
|
||||
#include <mbedtls/bignum.h>
|
||||
#include <mbedtls/pk.h>
|
||||
#include <mbedtls/cipher.h>
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
|
||||
typedef mbedtls_md_context_t *SHACTX;
|
||||
typedef mbedtls_md_context_t *SHA256CTX;
|
||||
typedef mbedtls_md_context_t *SHA384CTX;
|
||||
typedef mbedtls_md_context_t *SHA512CTX;
|
||||
typedef mbedtls_md_context_t *MD5CTX;
|
||||
typedef mbedtls_md_context_t *HMACCTX;
|
||||
typedef mbedtls_md_context_t *EVPCTX;
|
||||
|
||||
#define SHA_DIGEST_LENGTH 20
|
||||
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
|
||||
#define MD5_DIGEST_LEN 16
|
||||
#define SHA256_DIGEST_LENGTH 32
|
||||
#define SHA256_DIGEST_LEN SHA256_DIGEST_LENGTH
|
||||
#define SHA384_DIGEST_LENGTH 48
|
||||
#define SHA384_DIGEST_LEN SHA384_DIGEST_LENGTH
|
||||
#define SHA512_DIGEST_LENGTH 64
|
||||
#define SHA512_DIGEST_LEN SHA512_DIGEST_LENGTH
|
||||
|
||||
#ifndef EVP_MAX_MD_SIZE
|
||||
#define EVP_MAX_MD_SIZE 64
|
||||
#endif
|
||||
|
||||
#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE
|
||||
|
||||
typedef mbedtls_mpi *bignum;
|
||||
|
||||
/* Constants for curves */
|
||||
#define NID_mbedtls_nistp256 0
|
||||
#define NID_mbedtls_nistp384 1
|
||||
#define NID_mbedtls_nistp521 2
|
||||
|
||||
struct mbedtls_ecdsa_sig {
|
||||
bignum r;
|
||||
bignum s;
|
||||
};
|
||||
|
||||
bignum ssh_mbedcry_bn_new(void);
|
||||
void ssh_mbedcry_bn_free(bignum num);
|
||||
char *ssh_mbedcry_bn2num(bignum num, int radix);
|
||||
int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom);
|
||||
int ssh_mbedcry_is_bit_set(bignum num, size_t pos);
|
||||
|
||||
#define bignum_new() ssh_mbedcry_bn_new()
|
||||
#define bignum_safe_free(num) do { \
|
||||
if ((num) != NULL) { \
|
||||
ssh_mbedcry_bn_free(num); \
|
||||
(num)=NULL; \
|
||||
} \
|
||||
} while(0)
|
||||
#define bignum_set_word(bn, n) mbedtls_mpi_lset(bn, n) /* TODO fix
|
||||
overflow/underflow */
|
||||
#define bignum_bin2bn(data, datalen, bn) mbedtls_mpi_read_binary(bn, data, \
|
||||
datalen)
|
||||
#define bignum_bn2dec(num) ssh_mbedcry_bn2num(num, 10)
|
||||
#define bignum_dec2bn(data, bn) mbedtls_mpi_read_string(bn, 10, data)
|
||||
#define bignum_bn2hex(num) ssh_mbedcry_bn2num(num, 16)
|
||||
#define bignum_rand(rnd, bits) ssh_mbedcry_rand((rnd), (bits), 0, 1)
|
||||
#define bignum_mod_exp(dest, generator, exp, modulo, ctx) \
|
||||
mbedtls_mpi_exp_mod(dest, generator, exp, modulo, NULL)
|
||||
#define bignum_num_bytes(num) mbedtls_mpi_size(num)
|
||||
#define bignum_num_bits(num) mbedtls_mpi_bitlen(num)
|
||||
#define bignum_is_bit_set(num, bit) ssh_mbedcry_is_bit_set(num, bit)
|
||||
#define bignum_bn2bin(num, ptr) mbedtls_mpi_write_binary(num, ptr, \
|
||||
mbedtls_mpi_size(num))
|
||||
#define bignum_cmp(num1, num2) mbedtls_mpi_cmp_mpi(num1, num2)
|
||||
|
||||
mbedtls_entropy_context ssh_mbedtls_entropy;
|
||||
mbedtls_ctr_drbg_context ssh_mbedtls_ctr_drbg;
|
||||
|
||||
int ssh_mbedtls_random(void *where, int len, int strong);
|
||||
|
||||
ssh_string make_ecpoint_string(const mbedtls_ecp_group *g, const
|
||||
mbedtls_ecp_point *p);
|
||||
|
||||
#endif /* HAVE_LIBMBEDCRYPTO */
|
||||
#endif /* LIBMBEDCRYPTO_H_ */
|
||||
@@ -58,6 +58,7 @@
|
||||
#else /* _MSC_VER */
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -78,7 +79,7 @@
|
||||
/* libssh version */
|
||||
#define LIBSSH_VERSION_MAJOR 0
|
||||
#define LIBSSH_VERSION_MINOR 7
|
||||
#define LIBSSH_VERSION_MICRO 0
|
||||
#define LIBSSH_VERSION_MICRO 90
|
||||
|
||||
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
|
||||
LIBSSH_VERSION_MINOR, \
|
||||
@@ -122,6 +123,7 @@ typedef struct ssh_scp_struct* ssh_scp;
|
||||
typedef struct ssh_session_struct* ssh_session;
|
||||
typedef struct ssh_string_struct* ssh_string;
|
||||
typedef struct ssh_event_struct* ssh_event;
|
||||
typedef struct ssh_connector_struct * ssh_connector;
|
||||
typedef void* ssh_gssapi_creds;
|
||||
|
||||
/* Socket type */
|
||||
@@ -188,7 +190,8 @@ enum ssh_channel_type_e {
|
||||
SSH_CHANNEL_SESSION,
|
||||
SSH_CHANNEL_DIRECT_TCPIP,
|
||||
SSH_CHANNEL_FORWARDED_TCPIP,
|
||||
SSH_CHANNEL_X11
|
||||
SSH_CHANNEL_X11,
|
||||
SSH_CHANNEL_AUTH_AGENT
|
||||
};
|
||||
|
||||
enum ssh_channel_requests_e {
|
||||
@@ -206,6 +209,7 @@ enum ssh_global_requests_e {
|
||||
SSH_GLOBAL_REQUEST_UNKNOWN=0,
|
||||
SSH_GLOBAL_REQUEST_TCPIP_FORWARD,
|
||||
SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD,
|
||||
SSH_GLOBAL_REQUEST_KEEPALIVE
|
||||
};
|
||||
|
||||
enum ssh_publickey_state_e {
|
||||
@@ -234,6 +238,15 @@ enum ssh_server_known_e {
|
||||
SSH_SERVER_FILE_NOT_FOUND
|
||||
};
|
||||
|
||||
enum ssh_known_hosts_e {
|
||||
SSH_KNOWN_HOSTS_ERROR = -2,
|
||||
SSH_KNOWN_HOSTS_NOT_FOUND = -1,
|
||||
SSH_KNOWN_HOSTS_UNKNOWN = 0,
|
||||
SSH_KNOWN_HOSTS_OK,
|
||||
SSH_KNOWN_HOSTS_CHANGED,
|
||||
SSH_KNOWN_HOSTS_OTHER,
|
||||
};
|
||||
|
||||
#ifndef MD5_DIGEST_LEN
|
||||
#define MD5_DIGEST_LEN 16
|
||||
#endif
|
||||
@@ -253,7 +266,9 @@ enum ssh_keytypes_e{
|
||||
SSH_KEYTYPE_RSA,
|
||||
SSH_KEYTYPE_RSA1,
|
||||
SSH_KEYTYPE_ECDSA,
|
||||
SSH_KEYTYPE_ED25519
|
||||
SSH_KEYTYPE_ED25519,
|
||||
SSH_KEYTYPE_DSS_CERT01,
|
||||
SSH_KEYTYPE_RSA_CERT01
|
||||
};
|
||||
|
||||
enum ssh_keycmp_e {
|
||||
@@ -261,6 +276,16 @@ enum ssh_keycmp_e {
|
||||
SSH_KEY_CMP_PRIVATE
|
||||
};
|
||||
|
||||
#define SSH_ADDRSTRLEN 46
|
||||
|
||||
struct ssh_knownhosts_entry {
|
||||
char *hostname;
|
||||
char *unparsed;
|
||||
ssh_key publickey;
|
||||
char *comment;
|
||||
};
|
||||
|
||||
|
||||
/* Error return codes */
|
||||
#define SSH_OK 0 /* No error */
|
||||
#define SSH_ERROR -1 /* Error of some kind */
|
||||
@@ -345,6 +370,12 @@ enum ssh_options_e {
|
||||
SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS,
|
||||
SSH_OPTIONS_HMAC_C_S,
|
||||
SSH_OPTIONS_HMAC_S_C,
|
||||
SSH_OPTIONS_PASSWORD_AUTH,
|
||||
SSH_OPTIONS_PUBKEY_AUTH,
|
||||
SSH_OPTIONS_KBDINT_AUTH,
|
||||
SSH_OPTIONS_GSSAPI_AUTH,
|
||||
SSH_OPTIONS_GLOBAL_KNOWNHOSTS,
|
||||
SSH_OPTIONS_NODELAY,
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -368,6 +399,15 @@ enum ssh_scp_request_types {
|
||||
SSH_SCP_REQUEST_WARNING
|
||||
};
|
||||
|
||||
enum ssh_connector_flags_e {
|
||||
/** Only the standard stream of the channel */
|
||||
SSH_CONNECTOR_STDOUT = 1,
|
||||
/** Only the exception stream of the channel */
|
||||
SSH_CONNECTOR_STDERR = 2,
|
||||
/** Merge both standard and exception streams */
|
||||
SSH_CONNECTOR_BOTH = 3
|
||||
};
|
||||
|
||||
LIBSSH_API int ssh_blocking_flush(ssh_session session, int timeout);
|
||||
LIBSSH_API ssh_channel ssh_channel_accept_x11(ssh_channel channel, int timeout_ms);
|
||||
LIBSSH_API int ssh_channel_change_pty_size(ssh_channel channel,int cols,int rows);
|
||||
@@ -397,10 +437,12 @@ LIBSSH_API int ssh_channel_request_pty_size(ssh_channel channel, const char *ter
|
||||
int cols, int rows);
|
||||
LIBSSH_API int ssh_channel_request_shell(ssh_channel channel);
|
||||
LIBSSH_API int ssh_channel_request_send_signal(ssh_channel channel, const char *signum);
|
||||
LIBSSH_API int ssh_channel_request_send_break(ssh_channel channel, uint32_t length);
|
||||
LIBSSH_API int ssh_channel_request_sftp(ssh_channel channel);
|
||||
LIBSSH_API int ssh_channel_request_subsystem(ssh_channel channel, const char *subsystem);
|
||||
LIBSSH_API int ssh_channel_request_x11(ssh_channel channel, int single_connection, const char *protocol,
|
||||
const char *cookie, int screen_number);
|
||||
LIBSSH_API int ssh_channel_request_auth_agent(ssh_channel channel);
|
||||
LIBSSH_API int ssh_channel_send_eof(ssh_channel channel);
|
||||
LIBSSH_API int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans, ssh_channel *exceptchans, struct
|
||||
timeval * timeout);
|
||||
@@ -408,11 +450,26 @@ LIBSSH_API void ssh_channel_set_blocking(ssh_channel channel, int blocking);
|
||||
LIBSSH_API void ssh_channel_set_counter(ssh_channel channel,
|
||||
ssh_counter counter);
|
||||
LIBSSH_API int ssh_channel_write(ssh_channel channel, const void *data, uint32_t len);
|
||||
LIBSSH_API int ssh_channel_write_stderr(ssh_channel channel,
|
||||
const void *data,
|
||||
uint32_t len);
|
||||
LIBSSH_API uint32_t ssh_channel_window_size(ssh_channel channel);
|
||||
|
||||
LIBSSH_API char *ssh_basename (const char *path);
|
||||
LIBSSH_API void ssh_clean_pubkey_hash(unsigned char **hash);
|
||||
LIBSSH_API int ssh_connect(ssh_session session);
|
||||
|
||||
LIBSSH_API ssh_connector ssh_connector_new(ssh_session session);
|
||||
LIBSSH_API void ssh_connector_free(ssh_connector connector);
|
||||
LIBSSH_API int ssh_connector_set_in_channel(ssh_connector connector,
|
||||
ssh_channel channel,
|
||||
enum ssh_connector_flags_e flags);
|
||||
LIBSSH_API int ssh_connector_set_out_channel(ssh_connector connector,
|
||||
ssh_channel channel,
|
||||
enum ssh_connector_flags_e flags);
|
||||
LIBSSH_API void ssh_connector_set_in_fd(ssh_connector connector, socket_t fd);
|
||||
LIBSSH_API void ssh_connector_set_out_fd(ssh_connector connector, socket_t fd);
|
||||
|
||||
LIBSSH_API const char *ssh_copyright(void);
|
||||
LIBSSH_API void ssh_disconnect(ssh_session session);
|
||||
LIBSSH_API char *ssh_dirname (const char *path);
|
||||
@@ -439,7 +496,7 @@ LIBSSH_API char *ssh_get_hexa(const unsigned char *what, size_t len);
|
||||
LIBSSH_API char *ssh_get_issue_banner(ssh_session session);
|
||||
LIBSSH_API int ssh_get_openssh_version(ssh_session session);
|
||||
|
||||
LIBSSH_API int ssh_get_publickey(ssh_session session, ssh_key *key);
|
||||
LIBSSH_API int ssh_get_server_publickey(ssh_session session, ssh_key *key);
|
||||
|
||||
enum ssh_publickey_hash_type {
|
||||
SSH_PUBLICKEY_HASH_SHA1,
|
||||
@@ -455,6 +512,7 @@ SSH_DEPRECATED LIBSSH_API int ssh_get_pubkey_hash(ssh_session session, unsigned
|
||||
SSH_DEPRECATED LIBSSH_API ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms);
|
||||
SSH_DEPRECATED LIBSSH_API int ssh_forward_cancel(ssh_session session, const char *address, int port);
|
||||
SSH_DEPRECATED LIBSSH_API int ssh_forward_listen(ssh_session session, const char *address, int port, int *bound_port);
|
||||
SSH_DEPRECATED LIBSSH_API int ssh_get_publickey(ssh_session session, ssh_key *key);
|
||||
|
||||
|
||||
LIBSSH_API int ssh_get_random(void *where,int len,int strong);
|
||||
@@ -466,6 +524,29 @@ LIBSSH_API int ssh_is_blocking(ssh_session session);
|
||||
LIBSSH_API int ssh_is_connected(ssh_session session);
|
||||
LIBSSH_API int ssh_is_server_known(ssh_session session);
|
||||
|
||||
/* KNOWN HOSTS */
|
||||
LIBSSH_API void ssh_knownhosts_entry_free(struct ssh_knownhosts_entry *entry);
|
||||
#define SSH_KNOWNHOSTS_ENTRY_FREE(e) do { \
|
||||
if ((e) != NULL) { \
|
||||
ssh_knownhosts_entry_free(e); \
|
||||
e = NULL; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
LIBSSH_API int ssh_known_hosts_parse_line(const char *host,
|
||||
const char *line,
|
||||
struct ssh_knownhosts_entry **entry);
|
||||
LIBSSH_API enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session);
|
||||
|
||||
LIBSSH_API int ssh_session_export_known_hosts_entry(ssh_session session,
|
||||
char **pentry_string);
|
||||
LIBSSH_API int ssh_session_update_known_hosts(ssh_session session);
|
||||
|
||||
LIBSSH_API enum ssh_known_hosts_e
|
||||
ssh_session_get_known_hosts_entry(ssh_session session,
|
||||
struct ssh_knownhosts_entry **pentry);
|
||||
LIBSSH_API enum ssh_known_hosts_e ssh_session_is_known_server(ssh_session session);
|
||||
|
||||
/* LOGGING */
|
||||
LIBSSH_API int ssh_set_log_level(int level);
|
||||
LIBSSH_API int ssh_get_log_level(void);
|
||||
@@ -547,12 +628,21 @@ LIBSSH_API int ssh_pki_export_privkey_file(const ssh_key privkey,
|
||||
void *auth_data,
|
||||
const char *filename);
|
||||
|
||||
LIBSSH_API int ssh_pki_copy_cert_to_privkey(const ssh_key cert_key,
|
||||
ssh_key privkey);
|
||||
|
||||
LIBSSH_API int ssh_pki_import_pubkey_base64(const char *b64_key,
|
||||
enum ssh_keytypes_e type,
|
||||
ssh_key *pkey);
|
||||
LIBSSH_API int ssh_pki_import_pubkey_file(const char *filename,
|
||||
ssh_key *pkey);
|
||||
|
||||
LIBSSH_API int ssh_pki_import_cert_base64(const char *b64_cert,
|
||||
enum ssh_keytypes_e type,
|
||||
ssh_key *pkey);
|
||||
LIBSSH_API int ssh_pki_import_cert_file(const char *filename,
|
||||
ssh_key *pkey);
|
||||
|
||||
LIBSSH_API int ssh_pki_export_privkey_to_pubkey(const ssh_key privkey,
|
||||
ssh_key *pkey);
|
||||
LIBSSH_API int ssh_pki_export_pubkey_base64(const ssh_key key,
|
||||
@@ -588,6 +678,7 @@ LIBSSH_API int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socke
|
||||
fd_set *readfds, struct timeval *timeout);
|
||||
LIBSSH_API int ssh_service_request(ssh_session session, const char *service);
|
||||
LIBSSH_API int ssh_set_agent_channel(ssh_session session, ssh_channel channel);
|
||||
LIBSSH_API int ssh_set_agent_socket(ssh_session session, socket_t fd);
|
||||
LIBSSH_API void ssh_set_blocking(ssh_session session, int blocking);
|
||||
LIBSSH_API void ssh_set_counters(ssh_session session, ssh_counter scounter,
|
||||
ssh_counter rcounter);
|
||||
@@ -629,6 +720,7 @@ LIBSSH_API int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i
|
||||
LIBSSH_API int ssh_userauth_gssapi(ssh_session session);
|
||||
LIBSSH_API const char *ssh_version(int req_version);
|
||||
LIBSSH_API int ssh_write_knownhost(ssh_session session);
|
||||
LIBSSH_API char *ssh_dump_knownhost(ssh_session session);
|
||||
|
||||
LIBSSH_API void ssh_string_burn(ssh_string str);
|
||||
LIBSSH_API ssh_string ssh_string_copy(ssh_string str);
|
||||
@@ -652,9 +744,11 @@ LIBSSH_API ssh_event ssh_event_new(void);
|
||||
LIBSSH_API int ssh_event_add_fd(ssh_event event, socket_t fd, short events,
|
||||
ssh_event_callback cb, void *userdata);
|
||||
LIBSSH_API int ssh_event_add_session(ssh_event event, ssh_session session);
|
||||
LIBSSH_API int ssh_event_add_connector(ssh_event event, ssh_connector connector);
|
||||
LIBSSH_API int ssh_event_dopoll(ssh_event event, int timeout);
|
||||
LIBSSH_API int ssh_event_remove_fd(ssh_event event, socket_t fd);
|
||||
LIBSSH_API int ssh_event_remove_session(ssh_event event, ssh_session session);
|
||||
LIBSSH_API int ssh_event_remove_connector(ssh_event event, ssh_connector connector);
|
||||
LIBSSH_API void ssh_event_free(ssh_event event);
|
||||
LIBSSH_API const char* ssh_get_clientbanner(ssh_session session);
|
||||
LIBSSH_API const char* ssh_get_serverbanner(ssh_session session);
|
||||
@@ -664,6 +758,14 @@ LIBSSH_API const char* ssh_get_cipher_out(ssh_session session);
|
||||
LIBSSH_API const char* ssh_get_hmac_in(ssh_session session);
|
||||
LIBSSH_API const char* ssh_get_hmac_out(ssh_session session);
|
||||
|
||||
LIBSSH_API ssh_buffer ssh_buffer_new(void);
|
||||
LIBSSH_API void ssh_buffer_free(ssh_buffer buffer);
|
||||
LIBSSH_API int ssh_buffer_reinit(ssh_buffer buffer);
|
||||
LIBSSH_API int ssh_buffer_add_data(ssh_buffer buffer, const void *data, uint32_t len);
|
||||
LIBSSH_API uint32_t ssh_buffer_get_data(ssh_buffer buffer, void *data, uint32_t requestedlen);
|
||||
LIBSSH_API void *ssh_buffer_get(ssh_buffer buffer);
|
||||
LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer);
|
||||
|
||||
#ifndef LIBSSH_LEGACY_0_4
|
||||
#include "libssh/legacy.h"
|
||||
#endif
|
||||
@@ -672,4 +774,3 @@ LIBSSH_API const char* ssh_get_hmac_out(ssh_session session);
|
||||
}
|
||||
#endif
|
||||
#endif /* _LIBSSH_H */
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
|
||||
@@ -194,6 +194,43 @@ public:
|
||||
ssh_throw(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Authenticate through the "keyboard-interactive" method.
|
||||
* @param[in] The username to authenticate. You can specify NULL if ssh_option_set_username() has been used. You cannot try two different logins in a row.
|
||||
* @param[in] Undocumented. Set it to NULL.
|
||||
* @throws SshException on error
|
||||
* @returns SSH_AUTH_SUCCESS, SSH_AUTH_PARTIAL, SSH_AUTH_DENIED, SSH_AUTH_ERROR, SSH_AUTH_INFO, SSH_AUTH_AGAIN
|
||||
* @see ssh_userauth_kbdint
|
||||
*/
|
||||
int userauthKbdint(const char* username, const char* submethods){
|
||||
int ret=ssh_userauth_kbdint(c_session,NULL,NULL);
|
||||
ssh_throw(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief Get the number of prompts (questions) the server has given.
|
||||
* @returns The number of prompts.
|
||||
* @see ssh_userauth_kbdint_getnprompts
|
||||
*/
|
||||
int userauthKbdintGetNPrompts(){
|
||||
return ssh_userauth_kbdint_getnprompts(c_session);
|
||||
}
|
||||
|
||||
/** @brief Set the answer for a question from a message block..
|
||||
* @param[in] index The number of the ith prompt.
|
||||
* @param[in] The answer to give to the server. The answer MUST be encoded UTF-8. It is up to the server how to interpret the value and validate it. However, if you read the answer in some other encoding, you MUST convert it to UTF-8.
|
||||
* @throws SshException on error
|
||||
* @returns 0 on success, < 0 on error
|
||||
* @see ssh_userauth_kbdint_setanswer
|
||||
*/
|
||||
int userauthKbdintSetAnswer(unsigned int i, const char* answer){
|
||||
int ret=ssh_userauth_kbdint_setanswer(c_session, i, answer);
|
||||
ssh_throw(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Authenticates using the password method.
|
||||
* @param[in] password password to use for authentication
|
||||
* @throws SshException on error
|
||||
@@ -228,8 +265,7 @@ public:
|
||||
ssh_throw(ret);
|
||||
return ret;
|
||||
}
|
||||
int userauthPrivatekeyFile(const char *filename,
|
||||
const char *passphrase);
|
||||
|
||||
/** @brief Returns the available authentication methods from the server
|
||||
* @throws SshException on error
|
||||
* @returns Bitfield of available methods.
|
||||
@@ -281,8 +317,12 @@ public:
|
||||
*/
|
||||
std::string getIssueBanner(){
|
||||
char *banner=ssh_get_issue_banner(c_session);
|
||||
std::string ret= std::string(banner);
|
||||
::free(banner);
|
||||
std::string ret;
|
||||
if (banner)
|
||||
{
|
||||
ret= std::string(banner);
|
||||
::free(banner);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/** @brief returns the OpenSSH version (server) if possible
|
||||
@@ -303,12 +343,12 @@ public:
|
||||
* @throws SshException on error
|
||||
* @returns Integer value depending on the knowledge of the
|
||||
* server key
|
||||
* @see ssh_is_server_known
|
||||
* @see ssh_session_update_known_hosts
|
||||
*/
|
||||
int isServerKnown(){
|
||||
int ret=ssh_is_server_known(c_session);
|
||||
ssh_throw(ret);
|
||||
return ret;
|
||||
int state = ssh_session_is_known_server(c_session);
|
||||
ssh_throw(state);
|
||||
return state;
|
||||
}
|
||||
void log(int priority, const char *format, ...){
|
||||
char buffer[1024];
|
||||
@@ -378,11 +418,14 @@ public:
|
||||
return_throwable;
|
||||
}
|
||||
|
||||
private:
|
||||
ssh_session c_session;
|
||||
ssh_session getCSession(){
|
||||
return c_session;
|
||||
}
|
||||
|
||||
protected:
|
||||
ssh_session c_session;
|
||||
|
||||
private:
|
||||
/* No copy constructor, no = operator */
|
||||
Session(const Session &);
|
||||
Session& operator=(const Session &);
|
||||
@@ -481,12 +524,12 @@ public:
|
||||
ssh_throw(err);
|
||||
return err;
|
||||
}
|
||||
int read(void *dest, size_t count, bool is_stderr){
|
||||
int read(void *dest, size_t count){
|
||||
int err;
|
||||
/* handle int overflow */
|
||||
if(count > 0x7fffffff)
|
||||
count = 0x7fffffff;
|
||||
err=ssh_channel_read_timeout(channel,dest,count,is_stderr,-1);
|
||||
err=ssh_channel_read_timeout(channel,dest,count,false,-1);
|
||||
ssh_throw(err);
|
||||
return err;
|
||||
}
|
||||
@@ -584,16 +627,24 @@ public:
|
||||
ssh_throw(ret);
|
||||
return ret;
|
||||
}
|
||||
private:
|
||||
|
||||
ssh_session getCSession(){
|
||||
return session->getCSession();
|
||||
}
|
||||
|
||||
ssh_channel getCChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
protected:
|
||||
Session *session;
|
||||
ssh_channel channel;
|
||||
|
||||
private:
|
||||
Channel (Session &session, ssh_channel c_channel){
|
||||
this->channel=c_channel;
|
||||
this->session=&session;
|
||||
}
|
||||
Session *session;
|
||||
ssh_channel channel;
|
||||
/* No copy and no = operator */
|
||||
Channel(const Channel &);
|
||||
Channel &operator=(const Channel &);
|
||||
|
||||
@@ -29,19 +29,10 @@ int ssh_file_readaccess_ok(const char *file);
|
||||
|
||||
char *ssh_path_expand_tilde(const char *d);
|
||||
char *ssh_path_expand_escape(ssh_session session, const char *s);
|
||||
int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2);
|
||||
int ssh_analyze_banner(ssh_session session, int server);
|
||||
int ssh_is_ipaddr_v4(const char *str);
|
||||
int ssh_is_ipaddr(const char *str);
|
||||
|
||||
#ifndef HAVE_NTOHLL
|
||||
/* macro for byte ordering */
|
||||
uint64_t ntohll(uint64_t);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_HTONLL
|
||||
#define htonll(x) ntohll((x))
|
||||
#endif
|
||||
|
||||
/* list processing */
|
||||
|
||||
struct ssh_list {
|
||||
@@ -63,6 +54,7 @@ struct ssh_list *ssh_list_new(void);
|
||||
void ssh_list_free(struct ssh_list *list);
|
||||
struct ssh_iterator *ssh_list_get_iterator(const struct ssh_list *list);
|
||||
struct ssh_iterator *ssh_list_find(const struct ssh_list *list, void *value);
|
||||
size_t ssh_list_count(const struct ssh_list *list);
|
||||
int ssh_list_append(struct ssh_list *list, const void *data);
|
||||
int ssh_list_prepend(struct ssh_list *list, const void *data);
|
||||
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator);
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
#define _OPTIONS_H
|
||||
|
||||
int ssh_config_parse_file(ssh_session session, const char *filename);
|
||||
int ssh_options_set_algo(ssh_session session, int algo, const char *list);
|
||||
int ssh_options_set_algo(ssh_session session,
|
||||
enum ssh_kex_types_e algo,
|
||||
const char *list);
|
||||
int ssh_options_apply(ssh_session session);
|
||||
|
||||
#endif /* _OPTIONS_H */
|
||||
|
||||
@@ -43,18 +43,7 @@ enum ssh_packet_state_e {
|
||||
PACKET_STATE_PROCESSING
|
||||
};
|
||||
|
||||
int packet_send(ssh_session session);
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
int packet_send1(ssh_session session) ;
|
||||
void ssh_packet_set_default_callbacks1(ssh_session session);
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_disconnect1);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_smsg_success1);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_smsg_failure1);
|
||||
int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user);
|
||||
|
||||
#endif
|
||||
int ssh_packet_send(ssh_session session);
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_unimplemented);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback);
|
||||
@@ -78,12 +67,13 @@ void ssh_packet_set_default_callbacks(ssh_session session);
|
||||
void ssh_packet_process(ssh_session session, uint8_t type);
|
||||
|
||||
/* PACKET CRYPT */
|
||||
uint32_t packet_decrypt_len(ssh_session session, char *crypted);
|
||||
int packet_decrypt(ssh_session session, void *packet, unsigned int len);
|
||||
unsigned char *packet_encrypt(ssh_session session,
|
||||
void *packet,
|
||||
unsigned int len);
|
||||
int packet_hmac_verify(ssh_session session,ssh_buffer buffer,
|
||||
unsigned char *mac, enum ssh_hmac_e type);
|
||||
uint32_t ssh_packet_decrypt_len(ssh_session session, uint8_t *destination, uint8_t *source);
|
||||
int ssh_packet_decrypt(ssh_session session, uint8_t *destination, uint8_t *source,
|
||||
size_t start, size_t encrypted_size);
|
||||
unsigned char *ssh_packet_encrypt(ssh_session session,
|
||||
void *packet,
|
||||
unsigned int len);
|
||||
int ssh_packet_hmac_verify(ssh_session session,ssh_buffer buffer,
|
||||
unsigned char *mac, enum ssh_hmac_e type);
|
||||
|
||||
#endif /* PACKET_H_ */
|
||||
|
||||
@@ -43,4 +43,3 @@ int ssh_pcap_context_write(ssh_pcap_context,enum ssh_pcap_direction direction, v
|
||||
|
||||
#endif /* WITH_PCAP */
|
||||
#endif /* PCAP_H_ */
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
|
||||
@@ -47,7 +47,11 @@ struct ssh_key_struct {
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_t dsa;
|
||||
gcry_sexp_t rsa;
|
||||
void *ecdsa;
|
||||
gcry_sexp_t ecdsa;
|
||||
#elif HAVE_LIBMBEDCRYPTO
|
||||
mbedtls_pk_context *rsa;
|
||||
mbedtls_ecdsa_context *ecdsa;
|
||||
void *dsa;
|
||||
#elif HAVE_LIBCRYPTO
|
||||
DSA *dsa;
|
||||
RSA *rsa;
|
||||
@@ -60,6 +64,7 @@ struct ssh_key_struct {
|
||||
ed25519_pubkey *ed25519_pubkey;
|
||||
ed25519_privkey *ed25519_privkey;
|
||||
void *cert;
|
||||
enum ssh_keytypes_e cert_type;
|
||||
};
|
||||
|
||||
struct ssh_signature_struct {
|
||||
@@ -68,7 +73,7 @@ struct ssh_signature_struct {
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_t dsa_sig;
|
||||
gcry_sexp_t rsa_sig;
|
||||
void *ecdsa_sig;
|
||||
gcry_sexp_t ecdsa_sig;
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
DSA_SIG *dsa_sig;
|
||||
ssh_string rsa_sig;
|
||||
@@ -77,6 +82,9 @@ struct ssh_signature_struct {
|
||||
# else
|
||||
void *ecdsa_sig;
|
||||
# endif
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
ssh_string rsa_sig;
|
||||
struct mbedtls_ecdsa_sig ecdsa_sig;
|
||||
#endif
|
||||
ed25519_signature *ed25519_sig;
|
||||
};
|
||||
@@ -107,10 +115,10 @@ int ssh_pki_export_pubkey_blob(const ssh_key key,
|
||||
ssh_string *pblob);
|
||||
int ssh_pki_import_pubkey_blob(const ssh_string key_blob,
|
||||
ssh_key *pkey);
|
||||
int ssh_pki_export_pubkey_rsa1(const ssh_key key,
|
||||
const char *host,
|
||||
char *rsa1,
|
||||
size_t rsa1_len);
|
||||
|
||||
int ssh_pki_import_cert_blob(const ssh_string cert_blob,
|
||||
ssh_key *pkey);
|
||||
|
||||
|
||||
/* SSH Signing Functions */
|
||||
ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf,
|
||||
|
||||
@@ -43,11 +43,6 @@ int bcrypt_pbkdf(const char *pass,
|
||||
/* Magic defined in OpenSSH/PROTOCOL.key */
|
||||
#define OPENSSH_AUTH_MAGIC "openssh-key-v1"
|
||||
|
||||
#define ssh_pki_log(...) \
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, __func__, __VA_ARGS__)
|
||||
void _ssh_pki_log(const char *function,
|
||||
const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
|
||||
|
||||
int pki_key_ecdsa_nid_from_name(const char *name);
|
||||
const char *pki_key_ecdsa_nid_to_name(int nid);
|
||||
|
||||
@@ -85,10 +80,6 @@ int pki_pubkey_build_rsa(ssh_key key,
|
||||
ssh_string n);
|
||||
int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e);
|
||||
ssh_string pki_publickey_to_blob(const ssh_key key);
|
||||
int pki_export_pubkey_rsa1(const ssh_key key,
|
||||
const char *host,
|
||||
char *rsa1,
|
||||
size_t rsa1_len);
|
||||
|
||||
/* SSH Signature Functions */
|
||||
ssh_string pki_signature_to_blob(const ssh_signature sign);
|
||||
|
||||
@@ -155,5 +155,7 @@ int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, struct ssh_socket_struct *s);
|
||||
void ssh_poll_ctx_remove(ssh_poll_ctx ctx, ssh_poll_handle p);
|
||||
int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout);
|
||||
ssh_poll_ctx ssh_poll_get_default_ctx(ssh_session session);
|
||||
int ssh_event_add_poll(ssh_event event, ssh_poll_handle p);
|
||||
void ssh_event_remove_poll(ssh_event event, ssh_poll_handle p);
|
||||
|
||||
#endif /* POLL_H_ */
|
||||
|
||||
21
include/libssh/poly1305.h
Normal file
21
include/libssh/poly1305.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Public Domain poly1305 from Andrew Moon
|
||||
* poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
|
||||
*/
|
||||
|
||||
#ifndef POLY1305_H
|
||||
#define POLY1305_H
|
||||
|
||||
#define POLY1305_KEYLEN 32
|
||||
#define POLY1305_TAGLEN 16
|
||||
|
||||
void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen,
|
||||
const uint8_t key[POLY1305_KEYLEN])
|
||||
#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE
|
||||
__attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN)))
|
||||
__attribute__((__bounded__(__buffer__, 2, 3)))
|
||||
__attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN)))
|
||||
#endif
|
||||
;
|
||||
|
||||
#endif /* POLY1305_H */
|
||||
@@ -29,7 +29,8 @@
|
||||
#ifndef _LIBSSH_PRIV_H
|
||||
#define _LIBSSH_PRIV_H
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(HAVE_STRTOULL)
|
||||
# if defined(HAVE___STRTOULL)
|
||||
@@ -43,6 +44,20 @@
|
||||
# endif
|
||||
#endif /* !defined(HAVE_STRTOULL) */
|
||||
|
||||
#ifdef HAVE_BYTESWAP_H
|
||||
#include <byteswap.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifndef bswap_32
|
||||
#define bswap_32(x) \
|
||||
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
|
||||
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/* Imitate define of inttypes.h */
|
||||
@@ -60,11 +75,16 @@
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# include <stdio.h>
|
||||
# include <stdarg.h> /* va_copy define check */
|
||||
|
||||
/* On Microsoft compilers define inline to __inline on all others use inline */
|
||||
# undef inline
|
||||
# define inline __inline
|
||||
|
||||
# ifndef va_copy
|
||||
# define va_copy(dest, src) (dest = src)
|
||||
# endif
|
||||
|
||||
# define strcasecmp _stricmp
|
||||
# define strncasecmp _strnicmp
|
||||
# if ! defined(HAVE_ISBLANK)
|
||||
@@ -130,12 +150,11 @@ int gettimeofday(struct timeval *__p, void *__t);
|
||||
#ifndef ERROR_BUFFERLEN
|
||||
#define ERROR_BUFFERLEN 1024
|
||||
#endif
|
||||
#ifndef CLIENTBANNER1
|
||||
#define CLIENTBANNER1 "SSH-1.5-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
|
||||
#endif
|
||||
#ifndef CLIENTBANNER2
|
||||
#define CLIENTBANNER2 "SSH-2.0-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
|
||||
#endif
|
||||
|
||||
#ifndef CLIENT_BANNER_SSH2
|
||||
#define CLIENT_BANNER_SSH2 "SSH-2.0-libssh_" SSH_STRINGIFY(LIBSSH_VERSION)
|
||||
#endif /* CLIENT_BANNER_SSH2 */
|
||||
|
||||
#ifndef KBDINT_MAX_PROMPT
|
||||
#define KBDINT_MAX_PROMPT 256 /* more than openssh's :) */
|
||||
#endif
|
||||
@@ -170,10 +189,6 @@ int gettimeofday(struct timeval *__p, void *__t);
|
||||
# define LIBSSH_MEM_PROTECTION
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
/* forward declarations */
|
||||
struct ssh_common_struct;
|
||||
struct ssh_kex_struct;
|
||||
@@ -244,10 +259,18 @@ int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen);
|
||||
/* match.c */
|
||||
int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
|
||||
/* connector.c */
|
||||
int ssh_connector_set_event(ssh_connector connector, ssh_event event);
|
||||
int ssh_connector_remove_event(ssh_connector connector);
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/** Free memory space */
|
||||
#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
|
||||
|
||||
@@ -260,33 +283,9 @@ int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
/** Get the size of an array */
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
/*
|
||||
* See http://llvm.org/bugs/show_bug.cgi?id=15495
|
||||
*/
|
||||
#if defined(HAVE_GCC_VOLATILE_MEMORY_PROTECTION)
|
||||
/** Overwrite a string with '\0' */
|
||||
# define BURN_STRING(x) do { \
|
||||
if ((x) != NULL) \
|
||||
memset((x), '\0', strlen((x))); __asm__ volatile("" : : "r"(&(x)) : "memory"); \
|
||||
} while(0)
|
||||
|
||||
/** Overwrite the buffer with '\0' */
|
||||
# define BURN_BUFFER(x, size) do { \
|
||||
if ((x) != NULL) \
|
||||
memset((x), '\0', (size)); __asm__ volatile("" : : "r"(&(x)) : "memory"); \
|
||||
} while(0)
|
||||
#else /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
|
||||
/** Overwrite a string with '\0' */
|
||||
# define BURN_STRING(x) do { \
|
||||
if ((x) != NULL) memset((x), '\0', strlen((x))); \
|
||||
} while(0)
|
||||
|
||||
/** Overwrite the buffer with '\0' */
|
||||
# define BURN_BUFFER(x, size) do { \
|
||||
if ((x) != NULL) \
|
||||
memset((x), '\0', (size)); \
|
||||
} while(0)
|
||||
#endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
|
||||
#ifndef HAVE_EXPLICIT_BZERO
|
||||
void explicit_bzero(void *s, size_t n);
|
||||
#endif /* !HAVE_EXPLICIT_BZERO */
|
||||
|
||||
/**
|
||||
* This is a hack to fix warnings. The idea is to use this everywhere that we
|
||||
@@ -346,5 +345,32 @@ int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
|
||||
#define CLOSE_SOCKET(s) do { if ((s) != SSH_INVALID_SOCKET) { _XCLOSESOCKET(s); (s) = SSH_INVALID_SOCKET;} } while(0)
|
||||
|
||||
#ifndef HAVE_HTONLL
|
||||
# ifdef WORDS_BIGENDIAN
|
||||
# define htonll(x) (x)
|
||||
# else
|
||||
# define htonll(x) \
|
||||
(((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_NTOHLL
|
||||
# ifdef WORDS_BIGENDIAN
|
||||
# define ntohll(x) (x)
|
||||
# else
|
||||
# define ntohll(x) \
|
||||
(((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FALL_THROUGH
|
||||
# ifdef HAVE_FALLTHROUGH_ATTRIBUTE
|
||||
# define FALL_THROUGH __attribute__ ((fallthrough))
|
||||
# else /* HAVE_FALLTHROUGH_ATTRIBUTE */
|
||||
# define FALL_THROUGH
|
||||
# endif /* HAVE_FALLTHROUGH_ATTRIBUTE */
|
||||
#endif /* FALL_THROUGH */
|
||||
|
||||
void ssh_agent_state_free(void *data);
|
||||
|
||||
#endif /* _LIBSSH_PRIV_H */
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
@@ -45,7 +45,8 @@ enum ssh_bind_options_e {
|
||||
SSH_BIND_OPTIONS_BANNER,
|
||||
SSH_BIND_OPTIONS_LOG_VERBOSITY,
|
||||
SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
|
||||
SSH_BIND_OPTIONS_ECDSAKEY
|
||||
SSH_BIND_OPTIONS_ECDSAKEY,
|
||||
SSH_BIND_OPTIONS_IMPORT_KEY
|
||||
};
|
||||
|
||||
typedef struct ssh_bind_struct* ssh_bind;
|
||||
@@ -186,6 +187,24 @@ LIBSSH_API ssh_gssapi_creds ssh_gssapi_get_creds(ssh_session session);
|
||||
*/
|
||||
LIBSSH_API int ssh_handle_key_exchange(ssh_session session);
|
||||
|
||||
/**
|
||||
* @brief Initialize the set of key exchange, hostkey, ciphers, MACs, and
|
||||
* compression algorithms for the given ssh_session.
|
||||
*
|
||||
* The selection of algorithms and keys used are determined by the
|
||||
* options that are currently set in the given ssh_session structure.
|
||||
* May only be called before the initial key exchange has begun.
|
||||
*
|
||||
* @param session The session structure to initialize.
|
||||
*
|
||||
* @see ssh_handle_key_exchange
|
||||
* @see ssh_options_set
|
||||
*
|
||||
* @return SSH_OK if initialization succeeds.
|
||||
*/
|
||||
|
||||
LIBSSH_API int ssh_server_init_kex(ssh_session session);
|
||||
|
||||
/**
|
||||
* @brief Free a ssh servers bind.
|
||||
*
|
||||
@@ -193,6 +212,23 @@ LIBSSH_API int ssh_handle_key_exchange(ssh_session session);
|
||||
*/
|
||||
LIBSSH_API void ssh_bind_free(ssh_bind ssh_bind_o);
|
||||
|
||||
/**
|
||||
* @brief Set the acceptable authentication methods to be sent to the client.
|
||||
*
|
||||
*
|
||||
* @param[in] session The server session
|
||||
*
|
||||
* @param[in] auth_methods The authentication methods we will support, which
|
||||
* can be bitwise-or'd.
|
||||
*
|
||||
* Supported methods are:
|
||||
*
|
||||
* SSH_AUTH_METHOD_PASSWORD
|
||||
* SSH_AUTH_METHOD_PUBLICKEY
|
||||
* SSH_AUTH_METHOD_HOSTBASED
|
||||
* SSH_AUTH_METHOD_INTERACTIVE
|
||||
* SSH_AUTH_METHOD_GSSAPI_MIC
|
||||
*/
|
||||
LIBSSH_API void ssh_set_auth_methods(ssh_session session, int auth_methods);
|
||||
|
||||
/**********************************************************
|
||||
@@ -316,9 +352,6 @@ LIBSSH_API int ssh_channel_request_send_exit_signal(ssh_channel channel,
|
||||
int core,
|
||||
const char *errmsg,
|
||||
const char *lang);
|
||||
LIBSSH_API int ssh_channel_write_stderr(ssh_channel channel,
|
||||
const void *data,
|
||||
uint32_t len);
|
||||
|
||||
LIBSSH_API int ssh_send_keepalive(ssh_session session);
|
||||
|
||||
|
||||
@@ -79,6 +79,13 @@ enum ssh_pending_call_e {
|
||||
/* Don't block at all */
|
||||
#define SSH_TIMEOUT_NONBLOCKING 0
|
||||
|
||||
/* options flags */
|
||||
/* Authentication with *** allowed */
|
||||
#define SSH_OPT_FLAG_PASSWORD_AUTH 0x1
|
||||
#define SSH_OPT_FLAG_PUBKEY_AUTH 0x2
|
||||
#define SSH_OPT_FLAG_KBDINT_AUTH 0x4
|
||||
#define SSH_OPT_FLAG_GSSAPI_AUTH 0x8
|
||||
|
||||
/* members that are common to ssh_session and ssh_bind */
|
||||
struct ssh_common_struct {
|
||||
struct error_struct error;
|
||||
@@ -150,7 +157,7 @@ struct ssh_session_struct {
|
||||
/* keyb interactive data */
|
||||
struct ssh_kbdint_struct *kbdint;
|
||||
struct ssh_gssapi_struct *gssapi;
|
||||
int version; /* 1 or 2 */
|
||||
|
||||
/* server host keys */
|
||||
struct {
|
||||
ssh_key rsa_key;
|
||||
@@ -182,6 +189,7 @@ struct ssh_session_struct {
|
||||
char *bindaddr; /* bind the client to an ip addr */
|
||||
char *sshdir;
|
||||
char *knownhosts;
|
||||
char *global_knownhosts;
|
||||
char *wanted_methods[10];
|
||||
char *ProxyCommand;
|
||||
char *custombanner;
|
||||
@@ -190,12 +198,12 @@ struct ssh_session_struct {
|
||||
unsigned int port;
|
||||
socket_t fd;
|
||||
int StrictHostKeyChecking;
|
||||
int ssh2;
|
||||
int ssh1;
|
||||
char compressionlevel;
|
||||
char *gss_server_identity;
|
||||
char *gss_client_identity;
|
||||
int gss_delegate_creds;
|
||||
int flags;
|
||||
int nodelay;
|
||||
} opts;
|
||||
/* counters */
|
||||
ssh_counter socket_counter;
|
||||
|
||||
@@ -788,6 +788,22 @@ LIBSSH_API sftp_statvfs_t sftp_fstatvfs(sftp_file file);
|
||||
*/
|
||||
LIBSSH_API void sftp_statvfs_free(sftp_statvfs_t statvfs_o);
|
||||
|
||||
/**
|
||||
* @brief Synchronize a file's in-core state with storage device
|
||||
*
|
||||
* This calls the "fsync@openssh.com" extention. You should check if the
|
||||
* extensions is supported using:
|
||||
*
|
||||
* @code
|
||||
* int supported = sftp_extension_supported(sftp, "fsync@openssh.com", "1");
|
||||
* @endcode
|
||||
*
|
||||
* @param file The opened sftp file handle to sync
|
||||
*
|
||||
* @return 0 on success, < 0 on error with ssh and sftp error set.
|
||||
*/
|
||||
LIBSSH_API int sftp_fsync(sftp_file file);
|
||||
|
||||
/**
|
||||
* @brief Canonicalize a sftp path.
|
||||
*
|
||||
@@ -847,18 +863,18 @@ LIBSSH_API void sftp_client_message_set_filename(sftp_client_message msg, const
|
||||
LIBSSH_API const char *sftp_client_message_get_data(sftp_client_message msg);
|
||||
LIBSSH_API uint32_t sftp_client_message_get_flags(sftp_client_message msg);
|
||||
LIBSSH_API int sftp_send_client_message(sftp_session sftp, sftp_client_message msg);
|
||||
int sftp_reply_name(sftp_client_message msg, const char *name,
|
||||
LIBSSH_API int sftp_reply_name(sftp_client_message msg, const char *name,
|
||||
sftp_attributes attr);
|
||||
int sftp_reply_handle(sftp_client_message msg, ssh_string handle);
|
||||
ssh_string sftp_handle_alloc(sftp_session sftp, void *info);
|
||||
int sftp_reply_attr(sftp_client_message msg, sftp_attributes attr);
|
||||
void *sftp_handle(sftp_session sftp, ssh_string handle);
|
||||
int sftp_reply_status(sftp_client_message msg, uint32_t status, const char *message);
|
||||
int sftp_reply_names_add(sftp_client_message msg, const char *file,
|
||||
LIBSSH_API int sftp_reply_handle(sftp_client_message msg, ssh_string handle);
|
||||
LIBSSH_API ssh_string sftp_handle_alloc(sftp_session sftp, void *info);
|
||||
LIBSSH_API int sftp_reply_attr(sftp_client_message msg, sftp_attributes attr);
|
||||
LIBSSH_API void *sftp_handle(sftp_session sftp, ssh_string handle);
|
||||
LIBSSH_API int sftp_reply_status(sftp_client_message msg, uint32_t status, const char *message);
|
||||
LIBSSH_API int sftp_reply_names_add(sftp_client_message msg, const char *file,
|
||||
const char *longname, sftp_attributes attr);
|
||||
int sftp_reply_names(sftp_client_message msg);
|
||||
int sftp_reply_data(sftp_client_message msg, const void *data, int len);
|
||||
void sftp_handle_remove(sftp_session sftp, void *handle);
|
||||
LIBSSH_API int sftp_reply_names(sftp_client_message msg);
|
||||
LIBSSH_API int sftp_reply_data(sftp_client_message msg, const void *data, int len);
|
||||
LIBSSH_API void sftp_handle_remove(sftp_session sftp, void *handle);
|
||||
|
||||
/* SFTP commands and constants */
|
||||
#define SSH_FXP_INIT 1
|
||||
@@ -962,6 +978,16 @@ void sftp_handle_remove(sftp_session sftp, void *handle);
|
||||
#define SSH_FXF_EXCL 0x20
|
||||
#define SSH_FXF_TEXT 0x40
|
||||
|
||||
/* file type flags */
|
||||
#define SSH_S_IFMT 00170000
|
||||
#define SSH_S_IFSOCK 0140000
|
||||
#define SSH_S_IFLNK 0120000
|
||||
#define SSH_S_IFREG 0100000
|
||||
#define SSH_S_IFBLK 0060000
|
||||
#define SSH_S_IFDIR 0040000
|
||||
#define SSH_S_IFCHR 0020000
|
||||
#define SSH_S_IFIFO 0010000
|
||||
|
||||
/* rename flags */
|
||||
#define SSH_FXF_RENAME_OVERWRITE 0x00000001
|
||||
#define SSH_FXF_RENAME_ATOMIC 0x00000002
|
||||
@@ -991,10 +1017,9 @@ void sftp_handle_remove(sftp_session sftp, void *handle);
|
||||
#define SSH_FXE_STATVFS_ST_NOSUID 0x2 /* no setuid */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} ;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SFTP_H */
|
||||
|
||||
/** @} */
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
#ifndef __SSH1_H
|
||||
#define __SSH1_H
|
||||
|
||||
#define SSH_MSG_NONE 0 /* no message */
|
||||
#define SSH_MSG_DISCONNECT 1 /* cause (string) */
|
||||
#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */
|
||||
#define SSH_CMSG_SESSION_KEY 3 /* key (BIGNUM) */
|
||||
#define SSH_CMSG_USER 4 /* user (string) */
|
||||
#define SSH_CMSG_AUTH_RHOSTS 5 /* user (string) */
|
||||
#define SSH_CMSG_AUTH_RSA 6 /* modulus (BIGNUM) */
|
||||
#define SSH_SMSG_AUTH_RSA_CHALLENGE 7 /* int (BIGNUM) */
|
||||
#define SSH_CMSG_AUTH_RSA_RESPONSE 8 /* int (BIGNUM) */
|
||||
#define SSH_CMSG_AUTH_PASSWORD 9 /* pass (string) */
|
||||
#define SSH_CMSG_REQUEST_PTY 10 /* TERM, tty modes */
|
||||
#define SSH_CMSG_WINDOW_SIZE 11 /* row,col,xpix,ypix */
|
||||
#define SSH_CMSG_EXEC_SHELL 12 /* */
|
||||
#define SSH_CMSG_EXEC_CMD 13 /* cmd (string) */
|
||||
#define SSH_SMSG_SUCCESS 14 /* */
|
||||
#define SSH_SMSG_FAILURE 15 /* */
|
||||
#define SSH_CMSG_STDIN_DATA 16 /* data (string) */
|
||||
#define SSH_SMSG_STDOUT_DATA 17 /* data (string) */
|
||||
#define SSH_SMSG_STDERR_DATA 18 /* data (string) */
|
||||
#define SSH_CMSG_EOF 19 /* */
|
||||
#define SSH_SMSG_EXITSTATUS 20 /* status (int) */
|
||||
#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* channel (int) */
|
||||
#define SSH_MSG_CHANNEL_OPEN_FAILURE 22 /* channel (int) */
|
||||
#define SSH_MSG_CHANNEL_DATA 23 /* ch,data (int,str) */
|
||||
#define SSH_MSG_CHANNEL_CLOSE 24 /* channel (int) */
|
||||
#define SSH_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* channel (int) */
|
||||
/* SSH_CMSG_X11_REQUEST_FORWARDING 26 OBSOLETE */
|
||||
#define SSH_SMSG_X11_OPEN 27 /* channel (int) */
|
||||
#define SSH_CMSG_PORT_FORWARD_REQUEST 28 /* p,host,hp (i,s,i) */
|
||||
#define SSH_MSG_PORT_OPEN 29 /* ch,h,p (i,s,i) */
|
||||
#define SSH_CMSG_AGENT_REQUEST_FORWARDING 30 /* */
|
||||
#define SSH_SMSG_AGENT_OPEN 31 /* port (int) */
|
||||
#define SSH_MSG_IGNORE 32 /* string */
|
||||
#define SSH_CMSG_EXIT_CONFIRMATION 33 /* */
|
||||
#define SSH_CMSG_X11_REQUEST_FORWARDING 34 /* proto,data (s,s) */
|
||||
#define SSH_CMSG_AUTH_RHOSTS_RSA 35 /* user,mod (s,mpi) */
|
||||
#define SSH_MSG_DEBUG 36 /* string */
|
||||
#define SSH_CMSG_REQUEST_COMPRESSION 37 /* level 1-9 (int) */
|
||||
#define SSH_CMSG_MAX_PACKET_SIZE 38 /* size 4k-1024k (int) */
|
||||
#define SSH_CMSG_AUTH_TIS 39 /* we use this for s/key */
|
||||
#define SSH_SMSG_AUTH_TIS_CHALLENGE 40 /* challenge (string) */
|
||||
#define SSH_CMSG_AUTH_TIS_RESPONSE 41 /* response (string) */
|
||||
#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */
|
||||
#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */
|
||||
#define SSH_CMSG_HAVE_KERBEROS_TGT 44 /* credentials (s) */
|
||||
#define SSH_CMSG_HAVE_AFS_TOKEN 65 /* token (s) */
|
||||
|
||||
/* protocol version 1.5 overloads some version 1.3 message types */
|
||||
#define SSH_MSG_CHANNEL_INPUT_EOF SSH_MSG_CHANNEL_CLOSE
|
||||
#define SSH_MSG_CHANNEL_OUTPUT_CLOSE SSH_MSG_CHANNEL_CLOSE_CONFIRMATION
|
||||
|
||||
/*
|
||||
* Authentication methods. New types can be added, but old types should not
|
||||
* be removed for compatibility. The maximum allowed value is 31.
|
||||
*/
|
||||
#define SSH_AUTH_RHOSTS 1
|
||||
#define SSH_AUTH_RSA 2
|
||||
#define SSH_AUTH_PASSWORD 3
|
||||
#define SSH_AUTH_RHOSTS_RSA 4
|
||||
#define SSH_AUTH_TIS 5
|
||||
#define SSH_AUTH_KERBEROS 6
|
||||
#define SSH_PASS_KERBEROS_TGT 7
|
||||
/* 8 to 15 are reserved */
|
||||
#define SSH_PASS_AFS_TOKEN 21
|
||||
|
||||
/* Protocol flags. These are bit masks. */
|
||||
#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */
|
||||
#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */
|
||||
|
||||
/* cipher flags. they are bit numbers */
|
||||
#define SSH_CIPHER_NONE 0 /* No encryption */
|
||||
#define SSH_CIPHER_IDEA 1 /* IDEA in CFB mode */
|
||||
#define SSH_CIPHER_DES 2 /* DES in CBC mode */
|
||||
#define SSH_CIPHER_3DES 3 /* Triple-DES in CBC mode */
|
||||
#define SSH_CIPHER_RC4 5 /* RC4 */
|
||||
#define SSH_CIPHER_BLOWFISH 6
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,8 +24,40 @@
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/callbacks.h>
|
||||
|
||||
#if HAVE_PTHREAD
|
||||
|
||||
#include <pthread.h>
|
||||
#define SSH_MUTEX pthread_mutex_t
|
||||
|
||||
#if defined _GNU_SOURCE
|
||||
#define SSH_MUTEX_STATIC_INIT PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
|
||||
#else
|
||||
#define SSH_MUTEX_STATIC_INIT PTHREAD_MUTEX_INITIALIZER
|
||||
#endif
|
||||
|
||||
#elif (defined _WIN32) || (defined _WIN64)
|
||||
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
#define SSH_MUTEX CRITICAL_SECTION *
|
||||
#define SSH_MUTEX_STATIC_INIT NULL
|
||||
|
||||
#else
|
||||
|
||||
# define SSH_MUTEX void *
|
||||
#define SSH_MUTEX_STATIC_INIT NULL
|
||||
|
||||
#endif
|
||||
|
||||
int ssh_threads_init(void);
|
||||
void ssh_threads_finalize(void);
|
||||
const char *ssh_threads_get_type(void);
|
||||
|
||||
void ssh_mutex_lock(SSH_MUTEX *mutex);
|
||||
void ssh_mutex_unlock(SSH_MUTEX *mutex);
|
||||
|
||||
struct ssh_threads_callbacks_struct *ssh_threads_get_default(void);
|
||||
int crypto_thread_init(struct ssh_threads_callbacks_struct *user_callbacks);
|
||||
void crypto_thread_finalize(void);
|
||||
|
||||
#endif /* THREADS_H_ */
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/libcrypto.h"
|
||||
#include "libssh/libgcrypt.h"
|
||||
#include "libssh/libmbedcrypto.h"
|
||||
|
||||
enum ssh_mac_e {
|
||||
SSH_MAC_SHA1=1,
|
||||
@@ -38,7 +39,8 @@ enum ssh_hmac_e {
|
||||
SSH_HMAC_SHA256,
|
||||
SSH_HMAC_SHA384,
|
||||
SSH_HMAC_SHA512,
|
||||
SSH_HMAC_MD5
|
||||
SSH_HMAC_MD5,
|
||||
SSH_HMAC_AEAD_POLY1305
|
||||
};
|
||||
|
||||
enum ssh_des_e {
|
||||
@@ -51,6 +53,8 @@ struct ssh_hmac_struct {
|
||||
enum ssh_hmac_e hmac_type;
|
||||
};
|
||||
|
||||
struct ssh_cipher_struct;
|
||||
|
||||
typedef struct ssh_mac_ctx_struct *ssh_mac_ctx;
|
||||
MD5CTX md5_init(void);
|
||||
void md5_update(MD5CTX c, const void *data, unsigned long len);
|
||||
@@ -90,15 +94,18 @@ void hmac_update(HMACCTX c, const void *data, unsigned long len);
|
||||
void hmac_final(HMACCTX ctx,unsigned char *hashmacbuf,unsigned int *len);
|
||||
size_t hmac_digest_len(enum ssh_hmac_e type);
|
||||
|
||||
int crypt_set_algorithms(ssh_session session, enum ssh_des_e des_type);
|
||||
int crypt_set_algorithms_client(ssh_session session);
|
||||
int crypt_set_algorithms_server(ssh_session session);
|
||||
struct ssh_crypto_struct *crypto_new(void);
|
||||
void crypto_free(struct ssh_crypto_struct *crypto);
|
||||
|
||||
void ssh_reseed(void);
|
||||
int ssh_crypto_init(void);
|
||||
void ssh_crypto_finalize(void);
|
||||
|
||||
void ssh_cipher_clear(struct ssh_cipher_struct *cipher);
|
||||
struct ssh_hmac_struct *ssh_get_hmactab(void);
|
||||
struct ssh_cipher_struct *ssh_get_ciphertab(void);
|
||||
const char *ssh_hmac_type_to_string(enum ssh_hmac_e hmac_type);
|
||||
|
||||
#endif /* WRAPPER_H_ */
|
||||
|
||||
@@ -11,3 +11,5 @@ set(LIBSSH_LIBRARY @LIB_INSTALL_DIR@/@LIBSSH_LIBRARY_NAME@)
|
||||
set(LIBSSH_LIBRARIES @LIB_INSTALL_DIR@/@LIBSSH_LIBRARY_NAME@)
|
||||
|
||||
set(LIBSSH_THREADS_LIBRARY @LIB_INSTALL_DIR@/@LIBSSH_THREADS_LIBRARY_NAME@)
|
||||
|
||||
mark_as_advanced(LIBSSH_LIBRARIES LIBSSH_INCLUDE_DIR)
|
||||
|
||||
@@ -63,7 +63,7 @@ function clean_build_dir() {
|
||||
|
||||
function usage () {
|
||||
echo "Usage: `basename $0` [--prefix /install_prefix|--build [debug|final]|--clean|--verbose|--libsuffix (32|64)|--help|--clang|--cmakedir /directory|--make
|
||||
(gmake|make)|--ccompiler (gcc|cc)|--withstaticlib|--unittesting|--clientunittesting|--withssh1|--withserver]"
|
||||
(gmake|make)|--ccompiler(gcc|cc)|--withstaticlib|--unittesting|--clientunittesting|--withserver|--withoutsymbolversioning]"
|
||||
cleanup_and_exit
|
||||
}
|
||||
|
||||
@@ -137,17 +137,20 @@ while test -n "$1"; do
|
||||
OPTIONS="${OPTIONS} -DWITH_STATIC_LIB=ON"
|
||||
;;
|
||||
*-unittesting)
|
||||
OPTIONS="${OPTIONS} -DWITH_TESTING=ON"
|
||||
OPTIONS="${OPTIONS} -DUNIT_TESTING=ON"
|
||||
;;
|
||||
*-clientunittesting)
|
||||
OPTIONS="${OPTIONS} -DWITH_CLIENT_TESTING=ON"
|
||||
;;
|
||||
*-withssh1)
|
||||
OPTIONS="${OPTIONS} -DWITH_SSH1=ON"
|
||||
OPTIONS="${OPTIONS} -DCLIENT_TESTING=ON"
|
||||
;;
|
||||
*-withserver)
|
||||
OPTIONS="${OPTIONS} -DWITH_SERVER=ON"
|
||||
;;
|
||||
*-withoutsymbolversioning)
|
||||
OPTIONS="${OPTIONS} -DWITH_SYMBOL_VERSIONING=OFF"
|
||||
;;
|
||||
*-finalrelease)
|
||||
OPTIONS="${OPTIONS} -DWITH_FINAL=ON"
|
||||
;;
|
||||
----noarg)
|
||||
echo "$ARG does not take an argument"
|
||||
cleanup_and_exit
|
||||
|
||||
1
src/ABI/current
Normal file
1
src/ABI/current
Normal file
@@ -0,0 +1 @@
|
||||
4.5.0
|
||||
411
src/ABI/libssh-4.5.0.symbols
Normal file
411
src/ABI/libssh-4.5.0.symbols
Normal file
@@ -0,0 +1,411 @@
|
||||
ssh_set_server_callbacks
|
||||
ssh_set_callbacks
|
||||
ssh_set_channel_callbacks
|
||||
ssh_add_channel_callbacks
|
||||
ssh_remove_channel_callbacks
|
||||
ssh_threads_set_callbacks
|
||||
ssh_threads_get_pthread
|
||||
ssh_threads_get_noop
|
||||
ssh_set_log_callback
|
||||
ssh_get_log_callback
|
||||
ssh_auth_list
|
||||
ssh_userauth_offer_pubkey
|
||||
ssh_userauth_pubkey
|
||||
ssh_userauth_agent_pubkey
|
||||
ssh_userauth_autopubkey
|
||||
ssh_userauth_privatekey_file
|
||||
buffer_free
|
||||
buffer_get
|
||||
buffer_get_len
|
||||
buffer_new
|
||||
channel_accept_x11
|
||||
channel_change_pty_size
|
||||
channel_forward_accept
|
||||
channel_close
|
||||
channel_forward_cancel
|
||||
channel_forward_listen
|
||||
channel_free
|
||||
channel_get_exit_status
|
||||
channel_get_session
|
||||
channel_is_closed
|
||||
channel_is_eof
|
||||
channel_is_open
|
||||
channel_new
|
||||
channel_open_forward
|
||||
channel_open_session
|
||||
channel_poll
|
||||
channel_read
|
||||
channel_read_buffer
|
||||
channel_read_nonblocking
|
||||
channel_request_env
|
||||
channel_request_exec
|
||||
channel_request_pty
|
||||
channel_request_pty_size
|
||||
channel_request_shell
|
||||
channel_request_send_signal
|
||||
channel_request_sftp
|
||||
channel_request_subsystem
|
||||
channel_request_x11
|
||||
channel_send_eof
|
||||
channel_select
|
||||
channel_set_blocking
|
||||
channel_write
|
||||
privatekey_free
|
||||
privatekey_from_file
|
||||
publickey_free
|
||||
ssh_publickey_to_file
|
||||
publickey_from_file
|
||||
publickey_from_privatekey
|
||||
publickey_to_string
|
||||
ssh_try_publickey_from_file
|
||||
ssh_privatekey_type
|
||||
ssh_get_pubkey
|
||||
ssh_message_retrieve
|
||||
ssh_message_auth_publickey
|
||||
string_burn
|
||||
string_copy
|
||||
string_data
|
||||
string_fill
|
||||
string_free
|
||||
string_from_char
|
||||
string_len
|
||||
string_new
|
||||
string_to_char
|
||||
ssh_blocking_flush
|
||||
ssh_channel_accept_x11
|
||||
ssh_channel_change_pty_size
|
||||
ssh_channel_close
|
||||
ssh_channel_free
|
||||
ssh_channel_get_exit_status
|
||||
ssh_channel_get_session
|
||||
ssh_channel_is_closed
|
||||
ssh_channel_is_eof
|
||||
ssh_channel_is_open
|
||||
ssh_channel_new
|
||||
ssh_channel_open_auth_agent
|
||||
ssh_channel_open_forward
|
||||
ssh_channel_open_session
|
||||
ssh_channel_open_x11
|
||||
ssh_channel_poll
|
||||
ssh_channel_poll_timeout
|
||||
ssh_channel_read
|
||||
ssh_channel_read_timeout
|
||||
ssh_channel_read_nonblocking
|
||||
ssh_channel_request_env
|
||||
ssh_channel_request_exec
|
||||
ssh_channel_request_pty
|
||||
ssh_channel_request_pty_size
|
||||
ssh_channel_request_shell
|
||||
ssh_channel_request_send_signal
|
||||
ssh_channel_request_send_break
|
||||
ssh_channel_request_sftp
|
||||
ssh_channel_request_subsystem
|
||||
ssh_channel_request_x11
|
||||
ssh_channel_request_auth_agent
|
||||
ssh_channel_send_eof
|
||||
ssh_channel_select
|
||||
ssh_channel_set_blocking
|
||||
ssh_channel_set_counter
|
||||
ssh_channel_write
|
||||
ssh_channel_write_stderr
|
||||
ssh_channel_window_size
|
||||
ssh_basename
|
||||
ssh_clean_pubkey_hash
|
||||
ssh_connect
|
||||
ssh_connector_new
|
||||
ssh_connector_free
|
||||
ssh_connector_set_in_channel
|
||||
ssh_connector_set_out_channel
|
||||
ssh_connector_set_in_fd
|
||||
ssh_connector_set_out_fd
|
||||
ssh_copyright
|
||||
ssh_disconnect
|
||||
ssh_dirname
|
||||
ssh_finalize
|
||||
ssh_channel_accept_forward
|
||||
ssh_channel_cancel_forward
|
||||
ssh_channel_listen_forward
|
||||
ssh_free
|
||||
ssh_get_disconnect_message
|
||||
ssh_get_error
|
||||
ssh_get_error_code
|
||||
ssh_get_fd
|
||||
ssh_get_hexa
|
||||
ssh_get_issue_banner
|
||||
ssh_get_openssh_version
|
||||
ssh_get_server_publickey
|
||||
ssh_get_publickey_hash
|
||||
ssh_get_pubkey_hash
|
||||
ssh_forward_accept
|
||||
ssh_forward_cancel
|
||||
ssh_forward_listen
|
||||
ssh_get_publickey
|
||||
ssh_get_random
|
||||
ssh_get_version
|
||||
ssh_get_status
|
||||
ssh_get_poll_flags
|
||||
ssh_init
|
||||
ssh_is_blocking
|
||||
ssh_is_connected
|
||||
ssh_is_server_known
|
||||
ssh_knownhosts_entry_free
|
||||
ssh_known_hosts_parse_line
|
||||
ssh_session_has_known_hosts_entry
|
||||
ssh_session_export_known_hosts_entry
|
||||
ssh_session_update_known_hosts
|
||||
ssh_session_is_known_server
|
||||
ssh_set_log_level
|
||||
ssh_get_log_level
|
||||
ssh_get_log_userdata
|
||||
ssh_set_log_userdata
|
||||
_ssh_log
|
||||
ssh_log
|
||||
ssh_message_channel_request_open_reply_accept
|
||||
ssh_message_channel_request_reply_success
|
||||
ssh_message_free
|
||||
ssh_message_get
|
||||
ssh_message_subtype
|
||||
ssh_message_type
|
||||
ssh_mkdir
|
||||
ssh_new
|
||||
ssh_options_copy
|
||||
ssh_options_getopt
|
||||
ssh_options_parse_config
|
||||
ssh_options_set
|
||||
ssh_options_get
|
||||
ssh_options_get_port
|
||||
ssh_pcap_file_close
|
||||
ssh_pcap_file_free
|
||||
ssh_pcap_file_new
|
||||
ssh_pcap_file_open
|
||||
ssh_key_new
|
||||
ssh_key_free
|
||||
ssh_key_type
|
||||
ssh_key_type_to_char
|
||||
ssh_key_type_from_name
|
||||
ssh_key_is_public
|
||||
ssh_key_is_private
|
||||
ssh_key_cmp
|
||||
ssh_pki_generate
|
||||
ssh_pki_import_privkey_base64
|
||||
ssh_pki_import_privkey_file
|
||||
ssh_pki_export_privkey_file
|
||||
ssh_pki_copy_cert_to_privkey
|
||||
ssh_pki_import_pubkey_base64
|
||||
ssh_pki_import_pubkey_file
|
||||
ssh_pki_import_cert_base64
|
||||
ssh_pki_import_cert_file
|
||||
ssh_pki_export_privkey_to_pubkey
|
||||
ssh_pki_export_pubkey_base64
|
||||
ssh_pki_export_pubkey_file
|
||||
ssh_pki_key_ecdsa_name
|
||||
ssh_print_hexa
|
||||
ssh_send_ignore
|
||||
ssh_send_debug
|
||||
ssh_gssapi_set_creds
|
||||
ssh_scp_accept_request
|
||||
ssh_scp_close
|
||||
ssh_scp_deny_request
|
||||
ssh_scp_free
|
||||
ssh_scp_init
|
||||
ssh_scp_leave_directory
|
||||
ssh_scp_new
|
||||
ssh_scp_pull_request
|
||||
ssh_scp_push_directory
|
||||
ssh_scp_push_file
|
||||
ssh_scp_push_file64
|
||||
ssh_scp_read
|
||||
ssh_scp_request_get_filename
|
||||
ssh_scp_request_get_permissions
|
||||
ssh_scp_request_get_size
|
||||
ssh_scp_request_get_size64
|
||||
ssh_scp_request_get_warning
|
||||
ssh_scp_write
|
||||
ssh_select
|
||||
ssh_service_request
|
||||
ssh_set_agent_channel
|
||||
ssh_set_agent_socket
|
||||
ssh_set_blocking
|
||||
ssh_set_counters
|
||||
ssh_set_fd_except
|
||||
ssh_set_fd_toread
|
||||
ssh_set_fd_towrite
|
||||
ssh_silent_disconnect
|
||||
ssh_set_pcap_file
|
||||
ssh_userauth_none
|
||||
ssh_userauth_list
|
||||
ssh_userauth_try_publickey
|
||||
ssh_userauth_publickey
|
||||
ssh_userauth_agent
|
||||
ssh_userauth_publickey_auto
|
||||
ssh_userauth_password
|
||||
ssh_userauth_kbdint
|
||||
ssh_userauth_kbdint_getinstruction
|
||||
ssh_userauth_kbdint_getname
|
||||
ssh_userauth_kbdint_getnprompts
|
||||
ssh_userauth_kbdint_getprompt
|
||||
ssh_userauth_kbdint_getnanswers
|
||||
ssh_userauth_kbdint_getanswer
|
||||
ssh_userauth_kbdint_setanswer
|
||||
ssh_userauth_gssapi
|
||||
ssh_version
|
||||
ssh_write_knownhost
|
||||
ssh_dump_knownhost
|
||||
ssh_string_burn
|
||||
ssh_string_copy
|
||||
ssh_string_data
|
||||
ssh_string_fill
|
||||
ssh_string_free
|
||||
ssh_string_from_char
|
||||
ssh_string_len
|
||||
ssh_string_new
|
||||
ssh_string_get_char
|
||||
ssh_string_to_char
|
||||
ssh_string_free_char
|
||||
ssh_getpass
|
||||
ssh_event_new
|
||||
ssh_event_add_fd
|
||||
ssh_event_add_session
|
||||
ssh_event_add_connector
|
||||
ssh_event_dopoll
|
||||
ssh_event_remove_fd
|
||||
ssh_event_remove_session
|
||||
ssh_event_remove_connector
|
||||
ssh_event_free
|
||||
ssh_get_clientbanner
|
||||
ssh_get_serverbanner
|
||||
ssh_get_kex_algo
|
||||
ssh_get_cipher_in
|
||||
ssh_get_cipher_out
|
||||
ssh_get_hmac_in
|
||||
ssh_get_hmac_out
|
||||
ssh_buffer_new
|
||||
ssh_buffer_free
|
||||
ssh_buffer_reinit
|
||||
ssh_buffer_add_data
|
||||
ssh_buffer_get_data
|
||||
ssh_buffer_get
|
||||
ssh_buffer_get_len
|
||||
ssh_bind_new
|
||||
ssh_bind_options_set
|
||||
ssh_bind_listen
|
||||
ssh_bind_set_callbacks
|
||||
ssh_bind_set_blocking
|
||||
ssh_bind_get_fd
|
||||
ssh_bind_set_fd
|
||||
ssh_bind_fd_toaccept
|
||||
ssh_bind_accept
|
||||
ssh_bind_accept_fd
|
||||
ssh_gssapi_get_creds
|
||||
ssh_handle_key_exchange
|
||||
ssh_server_init_kex
|
||||
ssh_bind_free
|
||||
ssh_set_auth_methods
|
||||
ssh_message_reply_default
|
||||
ssh_message_auth_user
|
||||
ssh_message_auth_password
|
||||
ssh_message_auth_pubkey
|
||||
ssh_message_auth_kbdint_is_response
|
||||
ssh_message_auth_publickey_state
|
||||
ssh_message_auth_reply_success
|
||||
ssh_message_auth_reply_pk_ok
|
||||
ssh_message_auth_reply_pk_ok_simple
|
||||
ssh_message_auth_set_methods
|
||||
ssh_message_auth_interactive_request
|
||||
ssh_message_service_reply_success
|
||||
ssh_message_service_service
|
||||
ssh_message_global_request_reply_success
|
||||
ssh_set_message_callback
|
||||
ssh_execute_message_callbacks
|
||||
ssh_message_channel_request_open_originator
|
||||
ssh_message_channel_request_open_originator_port
|
||||
ssh_message_channel_request_open_destination
|
||||
ssh_message_channel_request_open_destination_port
|
||||
ssh_message_channel_request_channel
|
||||
ssh_message_channel_request_pty_term
|
||||
ssh_message_channel_request_pty_width
|
||||
ssh_message_channel_request_pty_height
|
||||
ssh_message_channel_request_pty_pxwidth
|
||||
ssh_message_channel_request_pty_pxheight
|
||||
ssh_message_channel_request_env_name
|
||||
ssh_message_channel_request_env_value
|
||||
ssh_message_channel_request_command
|
||||
ssh_message_channel_request_subsystem
|
||||
ssh_message_channel_request_x11_single_connection
|
||||
ssh_message_channel_request_x11_auth_protocol
|
||||
ssh_message_channel_request_x11_auth_cookie
|
||||
ssh_message_channel_request_x11_screen_number
|
||||
ssh_message_global_request_address
|
||||
ssh_message_global_request_port
|
||||
ssh_channel_open_reverse_forward
|
||||
ssh_channel_request_send_exit_status
|
||||
ssh_channel_request_send_exit_signal
|
||||
ssh_send_keepalive
|
||||
ssh_accept
|
||||
channel_write_stderr
|
||||
sftp_new
|
||||
sftp_new_channel
|
||||
sftp_free
|
||||
sftp_init
|
||||
sftp_get_error
|
||||
sftp_extensions_get_count
|
||||
sftp_extensions_get_name
|
||||
sftp_extensions_get_data
|
||||
sftp_extension_supported
|
||||
sftp_opendir
|
||||
sftp_readdir
|
||||
sftp_dir_eof
|
||||
sftp_stat
|
||||
sftp_lstat
|
||||
sftp_fstat
|
||||
sftp_attributes_free
|
||||
sftp_closedir
|
||||
sftp_close
|
||||
sftp_open
|
||||
sftp_file_set_nonblocking
|
||||
sftp_file_set_blocking
|
||||
sftp_read
|
||||
sftp_async_read_begin
|
||||
sftp_async_read
|
||||
sftp_write
|
||||
sftp_seek
|
||||
sftp_seek64
|
||||
sftp_tell
|
||||
sftp_tell64
|
||||
sftp_rewind
|
||||
sftp_unlink
|
||||
sftp_rmdir
|
||||
sftp_mkdir
|
||||
sftp_rename
|
||||
sftp_setstat
|
||||
sftp_chown
|
||||
sftp_chmod
|
||||
sftp_utimes
|
||||
sftp_symlink
|
||||
sftp_readlink
|
||||
sftp_statvfs
|
||||
sftp_fstatvfs
|
||||
sftp_statvfs_free
|
||||
sftp_fsync
|
||||
sftp_canonicalize_path
|
||||
sftp_server_version
|
||||
sftp_server_new
|
||||
sftp_server_init
|
||||
sftp_get_client_message
|
||||
sftp_client_message_free
|
||||
sftp_client_message_get_type
|
||||
sftp_client_message_get_filename
|
||||
sftp_client_message_set_filename
|
||||
sftp_client_message_get_data
|
||||
sftp_client_message_get_flags
|
||||
sftp_send_client_message
|
||||
sftp_reply_name
|
||||
sftp_reply_handle
|
||||
sftp_handle_alloc
|
||||
sftp_reply_attr
|
||||
sftp_handle
|
||||
sftp_reply_status
|
||||
sftp_reply_names_add
|
||||
sftp_reply_names
|
||||
sftp_reply_data
|
||||
sftp_handle_remove
|
||||
@@ -1,12 +1,10 @@
|
||||
project(libssh-library C)
|
||||
|
||||
set(LIBSSH_PUBLIC_INCLUDE_DIRS
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
${libssh_SOURCE_DIR}/include
|
||||
CACHE INTERNAL "libssh public include directories"
|
||||
)
|
||||
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${CMAKE_BINARY_DIR}
|
||||
${libssh_BINARY_DIR}
|
||||
)
|
||||
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
@@ -39,6 +37,17 @@ if (OPENSSL_CRYPTO_LIBRARY)
|
||||
)
|
||||
endif (OPENSSL_CRYPTO_LIBRARY)
|
||||
|
||||
if (MBEDTLS_CRYPTO_LIBRARY)
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
${MBEDTLS_INCLUDE_DIR}
|
||||
)
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
${LIBSSH_LINK_LIBRARIES}
|
||||
${MBEDTLS_CRYPTO_LIBRARY}
|
||||
)
|
||||
endif (MBEDTLS_CRYPTO_LIBRARY)
|
||||
|
||||
if (GCRYPT_LIBRARY)
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
@@ -54,7 +63,7 @@ endif (GCRYPT_LIBRARY)
|
||||
if (WITH_ZLIB)
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
@@ -115,6 +124,7 @@ set(libssh_SRCS
|
||||
client.c
|
||||
config.c
|
||||
connect.c
|
||||
connector.c
|
||||
curve25519.c
|
||||
dh.c
|
||||
ecdh.c
|
||||
@@ -123,8 +133,8 @@ set(libssh_SRCS
|
||||
init.c
|
||||
kex.c
|
||||
known_hosts.c
|
||||
knownhosts.c
|
||||
legacy.c
|
||||
libcrypto.c
|
||||
log.c
|
||||
match.c
|
||||
messages.c
|
||||
@@ -146,24 +156,63 @@ set(libssh_SRCS
|
||||
wrapper.c
|
||||
external/bcrypt_pbkdf.c
|
||||
external/blowfish.c
|
||||
external/chacha.c
|
||||
external/ed25519.c
|
||||
external/fe25519.c
|
||||
external/ge25519.c
|
||||
external/poly1305.c
|
||||
external/sc25519.c
|
||||
chachapoly.c
|
||||
)
|
||||
|
||||
if (CMAKE_USE_PTHREADS_INIT)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
threads/noop.c
|
||||
threads/pthread.c
|
||||
)
|
||||
elseif (CMAKE_USE_WIN32_THREADS_INIT)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
threads/noop.c
|
||||
threads/winlocks.c
|
||||
)
|
||||
else()
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
threads/noop.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if (WITH_GCRYPT)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
threads/libgcrypt.c
|
||||
libgcrypt.c
|
||||
gcrypt_missing.c
|
||||
pki_gcrypt.c
|
||||
ecdh_gcrypt.c
|
||||
)
|
||||
elseif (WITH_MBEDTLS)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
threads/mbedtls.c
|
||||
libmbedcrypto.c
|
||||
mbedcrypto_missing.c
|
||||
pki_mbedcrypto.c
|
||||
ecdh_mbedcrypto.c
|
||||
)
|
||||
else (WITH_GCRYPT)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
threads/libcrypto.c
|
||||
pki_crypto.c
|
||||
ecdh_crypto.c
|
||||
libcrypto.c
|
||||
)
|
||||
if(OPENSSL_VERSION VERSION_LESS "1.1.0")
|
||||
set(libssh_SRCS ${libssh_SRCS} libcrypto-compat.c)
|
||||
endif()
|
||||
endif (WITH_GCRYPT)
|
||||
|
||||
if (WITH_SFTP)
|
||||
@@ -180,17 +229,6 @@ if (WITH_SFTP)
|
||||
endif (WITH_SERVER)
|
||||
endif (WITH_SFTP)
|
||||
|
||||
if (WITH_SSH1)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
auth1.c
|
||||
channels1.c
|
||||
crc32.c
|
||||
kex1.c
|
||||
packet1.c
|
||||
)
|
||||
endif (WITH_SSH1)
|
||||
|
||||
if (WITH_SERVER)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
@@ -225,10 +263,52 @@ include_directories(
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
# Set the path to the default map file
|
||||
set(MAP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.map")
|
||||
|
||||
if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
||||
# Get the list of header files
|
||||
get_file_list("dev_header_list"
|
||||
DIRECTORIES "${LIBSSH_PUBLIC_INCLUDE_DIRS}/libssh"
|
||||
FILES_PATTERNS "*.h")
|
||||
|
||||
# Extract the symbols marked as "LIBSSH_API" from the header files
|
||||
extract_symbols("${PROJECT_NAME}_dev.symbols"
|
||||
HEADERS_LIST_FILE "dev_header_list"
|
||||
FILTER_PATTERN "LIBSSH_API")
|
||||
|
||||
if (WITH_ABI_BREAK)
|
||||
set(ALLOW_ABI_BREAK "BREAK_ABI")
|
||||
endif()
|
||||
|
||||
# Generate the symbol version map file
|
||||
generate_map_file("${PROJECT_NAME}_dev.map"
|
||||
SYMBOLS "${PROJECT_NAME}_dev.symbols"
|
||||
RELEASE_NAME_VERSION ${PROJECT_NAME}_AFTER_${LIBRARY_VERSION}
|
||||
CURRENT_MAP ${MAP_PATH}
|
||||
${ALLOW_ABI_BREAK})
|
||||
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
${PROJECT_NAME}_dev.map
|
||||
)
|
||||
endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
||||
|
||||
add_library(${LIBSSH_SHARED_LIBRARY} SHARED ${libssh_SRCS})
|
||||
|
||||
target_link_libraries(${LIBSSH_SHARED_LIBRARY} ${LIBSSH_LINK_LIBRARIES})
|
||||
|
||||
if (WITH_SYMBOL_VERSIONING)
|
||||
if (ABIMAP_FOUND)
|
||||
# Change path to devel map file
|
||||
set(MAP_PATH "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_dev.map")
|
||||
endif (ABIMAP_FOUND)
|
||||
|
||||
set_target_properties(${LIBSSH_SHARED_LIBRARY}
|
||||
PROPERTIES LINK_FLAGS
|
||||
"-Wl,--version-script,\"${MAP_PATH}\"")
|
||||
endif (WITH_SYMBOL_VERSIONING)
|
||||
|
||||
set_target_properties(
|
||||
${LIBSSH_SHARED_LIBRARY}
|
||||
PROPERTIES
|
||||
@@ -300,6 +380,4 @@ if (WITH_STATIC_LIB)
|
||||
)
|
||||
endif (WITH_STATIC_LIB)
|
||||
|
||||
if (Threads_FOUND)
|
||||
add_subdirectory(threads)
|
||||
endif (Threads_FOUND)
|
||||
message(STATUS "Threads_FOUND=${Threads_FOUND}")
|
||||
|
||||
171
src/agent.c
171
src/agent.c
@@ -143,7 +143,7 @@ static size_t atomicio(struct ssh_agent_struct *agent, void *buf, size_t n, int
|
||||
}
|
||||
}
|
||||
|
||||
ssh_agent agent_new(struct ssh_session_struct *session) {
|
||||
ssh_agent ssh_agent_new(struct ssh_session_struct *session) {
|
||||
ssh_agent agent = NULL;
|
||||
|
||||
agent = malloc(sizeof(struct ssh_agent_struct));
|
||||
@@ -185,24 +185,41 @@ int ssh_set_agent_channel(ssh_session session, ssh_channel channel){
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @brief sets the SSH agent socket.
|
||||
* The SSH agent will be used to authenticate this client using
|
||||
* the given socket to communicate with the ssh-agent. The caller
|
||||
* is responsible for connecting to the socket prior to calling
|
||||
* this function.
|
||||
* @returns SSH_OK in case of success
|
||||
* SSH_ERROR in case of an error
|
||||
*/
|
||||
int ssh_set_agent_socket(ssh_session session, socket_t fd){
|
||||
if (!session)
|
||||
return SSH_ERROR;
|
||||
if (!session->agent){
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED, "Session has no active agent");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
void agent_close(struct ssh_agent_struct *agent) {
|
||||
ssh_socket_set_fd(session->agent->sock, fd);
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
void ssh_agent_close(struct ssh_agent_struct *agent) {
|
||||
if (agent == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getenv("SSH_AUTH_SOCK")) {
|
||||
ssh_socket_close(agent->sock);
|
||||
}
|
||||
ssh_socket_close(agent->sock);
|
||||
}
|
||||
|
||||
void agent_free(ssh_agent agent) {
|
||||
void ssh_agent_free(ssh_agent agent) {
|
||||
if (agent) {
|
||||
if (agent->ident) {
|
||||
ssh_buffer_free(agent->ident);
|
||||
}
|
||||
if (agent->sock) {
|
||||
agent_close(agent);
|
||||
ssh_agent_close(agent);
|
||||
ssh_socket_free(agent->sock);
|
||||
}
|
||||
SAFE_FREE(agent);
|
||||
@@ -256,13 +273,13 @@ static int agent_talk(struct ssh_session_struct *session,
|
||||
uint32_t len = 0;
|
||||
uint8_t payload[1024] = {0};
|
||||
|
||||
len = buffer_get_rest_len(request);
|
||||
len = ssh_buffer_get_len(request);
|
||||
SSH_LOG(SSH_LOG_TRACE, "Request length: %u", len);
|
||||
agent_put_u32(payload, len);
|
||||
|
||||
/* send length and then the request packet */
|
||||
if (atomicio(session->agent, payload, 4, 0) == 4) {
|
||||
if (atomicio(session->agent, buffer_get_rest(request), len, 0)
|
||||
if (atomicio(session->agent, ssh_buffer_get(request), len, 0)
|
||||
!= len) {
|
||||
SSH_LOG(SSH_LOG_WARN, "atomicio sending request failed: %s",
|
||||
strerror(errno));
|
||||
@@ -314,30 +331,16 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) {
|
||||
ssh_buffer request = NULL;
|
||||
ssh_buffer reply = NULL;
|
||||
unsigned int type = 0;
|
||||
unsigned int c1 = 0, c2 = 0;
|
||||
uint8_t buf[4] = {0};
|
||||
int rc;
|
||||
|
||||
switch (session->version) {
|
||||
case 1:
|
||||
c1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
|
||||
c2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
|
||||
break;
|
||||
case 2:
|
||||
c1 = SSH2_AGENTC_REQUEST_IDENTITIES;
|
||||
c2 = SSH2_AGENT_IDENTITIES_ANSWER;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* send message to the agent requesting the list of identities */
|
||||
request = ssh_buffer_new();
|
||||
if (request == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return -1;
|
||||
}
|
||||
if (buffer_add_u8(request, c1) < 0) {
|
||||
if (ssh_buffer_add_u8(request, SSH2_AGENTC_REQUEST_IDENTITIES) < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
ssh_buffer_free(request);
|
||||
return -1;
|
||||
@@ -358,29 +361,32 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) {
|
||||
ssh_buffer_free(request);
|
||||
|
||||
/* get message type and verify the answer */
|
||||
rc = buffer_get_u8(reply, (uint8_t *) &type);
|
||||
rc = ssh_buffer_get_u8(reply, (uint8_t *) &type);
|
||||
if (rc != sizeof(uint8_t)) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Bad authentication reply size: %d", rc);
|
||||
ssh_buffer_free(reply);
|
||||
return -1;
|
||||
}
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
type = bswap_32(type);
|
||||
#endif
|
||||
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Answer type: %d, expected answer: %d",
|
||||
type, c2);
|
||||
type, SSH2_AGENT_IDENTITIES_ANSWER);
|
||||
|
||||
if (agent_failed(type)) {
|
||||
ssh_buffer_free(reply);
|
||||
return 0;
|
||||
} else if (type != c2) {
|
||||
} else if (type != SSH2_AGENT_IDENTITIES_ANSWER) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Bad authentication reply message type: %d", type);
|
||||
"Bad authentication reply message type: %u", type);
|
||||
ssh_buffer_free(reply);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer_get_u32(reply, (uint32_t *) buf);
|
||||
ssh_buffer_get_u32(reply, (uint32_t *) buf);
|
||||
session->agent->count = agent_get_u32(buf);
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Agent count: %d",
|
||||
session->agent->count);
|
||||
@@ -422,49 +428,45 @@ ssh_key ssh_agent_get_next_ident(struct ssh_session_struct *session,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch(session->version) {
|
||||
case 1:
|
||||
return NULL;
|
||||
case 2:
|
||||
/* get the blob */
|
||||
blob = buffer_get_ssh_string(session->agent->ident);
|
||||
if (blob == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
/* get the blob */
|
||||
blob = ssh_buffer_get_ssh_string(session->agent->ident);
|
||||
if (blob == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get the comment */
|
||||
tmp = buffer_get_ssh_string(session->agent->ident);
|
||||
if (tmp == NULL) {
|
||||
ssh_string_free(blob);
|
||||
/* get the comment */
|
||||
tmp = ssh_buffer_get_ssh_string(session->agent->ident);
|
||||
if (tmp == NULL) {
|
||||
ssh_string_free(blob);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (comment) {
|
||||
*comment = ssh_string_to_char(tmp);
|
||||
} else {
|
||||
ssh_string_free(blob);
|
||||
ssh_string_free(tmp);
|
||||
if (comment) {
|
||||
*comment = ssh_string_to_char(tmp);
|
||||
} else {
|
||||
ssh_string_free(blob);
|
||||
ssh_string_free(tmp);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
ssh_string_free(tmp);
|
||||
return NULL;
|
||||
}
|
||||
ssh_string_free(tmp);
|
||||
|
||||
/* get key from blob */
|
||||
rc = ssh_pki_import_pubkey_blob(blob, &key);
|
||||
ssh_string_free(blob);
|
||||
if (rc == SSH_ERROR) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
/* get key from blob */
|
||||
rc = ssh_pki_import_pubkey_blob(blob, &key);
|
||||
if (rc == SSH_ERROR) {
|
||||
/* Try again as a cert. */
|
||||
rc = ssh_pki_import_cert_blob(blob, &key);
|
||||
}
|
||||
ssh_string_free(blob);
|
||||
if (rc == SSH_ERROR) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
int agent_is_running(ssh_session session) {
|
||||
int ssh_agent_is_running(ssh_session session) {
|
||||
if (session == NULL || session->agent == NULL) {
|
||||
return 0;
|
||||
}
|
||||
@@ -490,8 +492,8 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
ssh_buffer reply;
|
||||
ssh_string key_blob;
|
||||
ssh_string sig_blob;
|
||||
int type = SSH2_AGENT_FAILURE;
|
||||
int flags = 0;
|
||||
unsigned int type = 0;
|
||||
unsigned int flags = 0;
|
||||
uint32_t dlen;
|
||||
int rc;
|
||||
|
||||
@@ -501,7 +503,7 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
}
|
||||
|
||||
/* create request */
|
||||
if (buffer_add_u8(request, SSH2_AGENTC_SIGN_REQUEST) < 0) {
|
||||
if (ssh_buffer_add_u8(request, SSH2_AGENTC_SIGN_REQUEST) < 0) {
|
||||
ssh_buffer_free(request);
|
||||
return NULL;
|
||||
}
|
||||
@@ -512,8 +514,23 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* make sure it already can contain all the expected content:
|
||||
* - 1 x uint8_t
|
||||
* - 2 x uint32_t
|
||||
* - 1 x ssh_string (uint8_t + data)
|
||||
*/
|
||||
rc = ssh_buffer_allocate_size(request,
|
||||
sizeof(uint8_t) * 2 +
|
||||
sizeof(uint32_t) * 2 +
|
||||
ssh_string_len(key_blob));
|
||||
if (rc < 0) {
|
||||
ssh_buffer_free(request);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* adds len + blob */
|
||||
rc = buffer_add_ssh_string(request, key_blob);
|
||||
rc = ssh_buffer_add_ssh_string(request, key_blob);
|
||||
ssh_string_free(key_blob);
|
||||
if (rc < 0) {
|
||||
ssh_buffer_free(request);
|
||||
@@ -521,17 +538,17 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
}
|
||||
|
||||
/* Add data */
|
||||
dlen = buffer_get_rest_len(data);
|
||||
if (buffer_add_u32(request, htonl(dlen)) < 0) {
|
||||
dlen = ssh_buffer_get_len(data);
|
||||
if (ssh_buffer_add_u32(request, htonl(dlen)) < 0) {
|
||||
ssh_buffer_free(request);
|
||||
return NULL;
|
||||
}
|
||||
if (ssh_buffer_add_data(request, buffer_get_rest(data), dlen) < 0) {
|
||||
if (ssh_buffer_add_data(request, ssh_buffer_get(data), dlen) < 0) {
|
||||
ssh_buffer_free(request);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (buffer_add_u32(request, htonl(flags)) < 0) {
|
||||
if (ssh_buffer_add_u32(request, htonl(flags)) < 0) {
|
||||
ssh_buffer_free(request);
|
||||
return NULL;
|
||||
}
|
||||
@@ -551,27 +568,31 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
ssh_buffer_free(request);
|
||||
|
||||
/* check if reply is valid */
|
||||
if (buffer_get_u8(reply, (uint8_t *) &type) != sizeof(uint8_t)) {
|
||||
if (ssh_buffer_get_u8(reply, (uint8_t *) &type) != sizeof(uint8_t)) {
|
||||
ssh_buffer_free(reply);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
type = bswap_32(type);
|
||||
#endif
|
||||
|
||||
if (agent_failed(type)) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Agent reports failure in signing the key");
|
||||
ssh_buffer_free(reply);
|
||||
return NULL;
|
||||
} else if (type != SSH2_AGENT_SIGN_RESPONSE) {
|
||||
ssh_set_error(session, SSH_FATAL, "Bad authentication response: %d", type);
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Bad authentication response: %u",
|
||||
type);
|
||||
ssh_buffer_free(reply);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sig_blob = buffer_get_ssh_string(reply);
|
||||
sig_blob = ssh_buffer_get_ssh_string(reply);
|
||||
ssh_buffer_free(reply);
|
||||
|
||||
return sig_blob;
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
769
src/auth.c
769
src/auth.c
File diff suppressed because it is too large
Load Diff
229
src/auth1.c
229
src/auth1.c
@@ -1,229 +0,0 @@
|
||||
/*
|
||||
* auth1.c - authentication with SSH-1 protocol
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2005-2008 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/ssh1.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/string.h"
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
|
||||
static int ssh_auth_status_termination(void *s){
|
||||
ssh_session session=s;
|
||||
if(session->auth_state != SSH_AUTH_STATE_NONE ||
|
||||
session->session_state == SSH_SESSION_STATE_ERROR)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wait_auth1_status(ssh_session session) {
|
||||
/* wait for a packet */
|
||||
if (ssh_handle_packets_termination(session,SSH_TIMEOUT_USER,
|
||||
ssh_auth_status_termination, session) != SSH_OK){
|
||||
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,"Auth state : %d",session->auth_state);
|
||||
|
||||
switch(session->auth_state) {
|
||||
case SSH_AUTH_STATE_SUCCESS:
|
||||
return SSH_AUTH_SUCCESS;
|
||||
case SSH_AUTH_STATE_FAILED:
|
||||
return SSH_AUTH_DENIED;
|
||||
default:
|
||||
return SSH_AUTH_AGAIN;
|
||||
}
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
void ssh_auth1_handler(ssh_session session, uint8_t type){
|
||||
if(session->session_state != SSH_SESSION_STATE_AUTHENTICATING){
|
||||
ssh_set_error(session,SSH_FATAL,"SSH_SMSG_SUCCESS or FAILED received in wrong state");
|
||||
return;
|
||||
}
|
||||
if(type==SSH_SMSG_SUCCESS){
|
||||
session->auth_state=SSH_AUTH_STATE_SUCCESS;
|
||||
session->session_state=SSH_SESSION_STATE_AUTHENTICATED;
|
||||
} else if(type==SSH_SMSG_FAILURE)
|
||||
session->auth_state=SSH_AUTH_STATE_FAILED;
|
||||
}
|
||||
|
||||
static int send_username(ssh_session session, const char *username) {
|
||||
ssh_string user = NULL;
|
||||
int rc;
|
||||
/* returns SSH_AUTH_SUCCESS or SSH_AUTH_DENIED */
|
||||
if(session->auth_service_state == SSH_AUTH_SERVICE_USER_SENT) {
|
||||
if(session->auth_state == SSH_AUTH_STATE_FAILED)
|
||||
return SSH_AUTH_DENIED;
|
||||
if(session->auth_state == SSH_AUTH_STATE_SUCCESS)
|
||||
return SSH_AUTH_SUCCESS;
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
if (session->auth_service_state == SSH_AUTH_SERVICE_SENT)
|
||||
goto pending;
|
||||
if (!username) {
|
||||
if(!(username = session->opts.username)) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
||||
session->auth_service_state = SSH_AUTH_SERVICE_DENIED;
|
||||
return SSH_ERROR;
|
||||
} else {
|
||||
username = session->opts.username;
|
||||
}
|
||||
}
|
||||
}
|
||||
user = ssh_string_from_char(username);
|
||||
if (user == NULL) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
if (buffer_add_u8(session->out_buffer, SSH_CMSG_USER) < 0) {
|
||||
ssh_string_free(user);
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
if (buffer_add_ssh_string(session->out_buffer, user) < 0) {
|
||||
ssh_string_free(user);
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
ssh_string_free(user);
|
||||
session->auth_state=SSH_AUTH_STATE_NONE;
|
||||
session->auth_service_state = SSH_AUTH_SERVICE_SENT;
|
||||
if (packet_send(session) == SSH_ERROR) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
pending:
|
||||
rc = wait_auth1_status(session);
|
||||
switch (rc){
|
||||
case SSH_AUTH_SUCCESS:
|
||||
session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT;
|
||||
session->auth_state=SSH_AUTH_STATE_SUCCESS;
|
||||
ssh_set_error(session, SSH_NO_ERROR, "Authentication successful");
|
||||
return SSH_AUTH_SUCCESS;
|
||||
case SSH_AUTH_DENIED:
|
||||
session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT;
|
||||
ssh_set_error(session,SSH_REQUEST_DENIED,"Password authentication necessary for user %s",username);
|
||||
return SSH_AUTH_DENIED;
|
||||
case SSH_AUTH_AGAIN:
|
||||
return SSH_AUTH_AGAIN;
|
||||
default:
|
||||
session->auth_service_state = SSH_AUTH_SERVICE_NONE;
|
||||
session->auth_state=SSH_AUTH_STATE_ERROR;
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* use the "none" authentication question */
|
||||
int ssh_userauth1_none(ssh_session session, const char *username){
|
||||
return send_username(session, username);
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* \todo implement ssh1 public key
|
||||
*/
|
||||
int ssh_userauth1_offer_pubkey(ssh_session session, const char *username,
|
||||
int type, ssh_string pubkey) {
|
||||
(void) session;
|
||||
(void) username;
|
||||
(void) type;
|
||||
(void) pubkey;
|
||||
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
int ssh_userauth1_password(ssh_session session, const char *username,
|
||||
const char *password) {
|
||||
ssh_string pwd = NULL;
|
||||
int rc;
|
||||
|
||||
rc = send_username(session, username);
|
||||
if (rc != SSH_AUTH_DENIED) {
|
||||
return rc;
|
||||
}
|
||||
if (session->pending_call_state == SSH_PENDING_CALL_AUTH_PASSWORD)
|
||||
goto pending;
|
||||
/* we trick a bit here. A known flaw in SSH1 protocol is that it's
|
||||
* easy to guess password sizes.
|
||||
* not that sure ...
|
||||
*/
|
||||
|
||||
/* XXX fix me here ! */
|
||||
/* cisco IOS doesn't like when a password is followed by zeroes and random pad. */
|
||||
if(1 || strlen(password) >= 128) {
|
||||
/* not risky to disclose the size of such a big password .. */
|
||||
pwd = ssh_string_from_char(password);
|
||||
if (pwd == NULL) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
} else {
|
||||
char buf[128] = {0};
|
||||
/* fill the password string from random things. the strcpy
|
||||
* ensure there is at least a nul byte after the password.
|
||||
* most implementation won't see the garbage at end.
|
||||
* why garbage ? because nul bytes will be compressed by
|
||||
* gzip and disclose password len.
|
||||
*/
|
||||
pwd = ssh_string_new(sizeof(buf));
|
||||
if (pwd == NULL) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
ssh_get_random(buf, sizeof(buf), 0);
|
||||
strcpy(buf, password);
|
||||
ssh_string_fill(pwd, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
if (buffer_add_u8(session->out_buffer, SSH_CMSG_AUTH_PASSWORD) < 0) {
|
||||
ssh_string_burn(pwd);
|
||||
ssh_string_free(pwd);
|
||||
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
if (buffer_add_ssh_string(session->out_buffer, pwd) < 0) {
|
||||
ssh_string_burn(pwd);
|
||||
ssh_string_free(pwd);
|
||||
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
ssh_string_burn(pwd);
|
||||
ssh_string_free(pwd);
|
||||
session->auth_state=SSH_AUTH_STATE_NONE;
|
||||
session->pending_call_state = SSH_PENDING_CALL_AUTH_PASSWORD;
|
||||
if (packet_send(session) == SSH_ERROR) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
pending:
|
||||
rc = wait_auth1_status(session);
|
||||
if (rc != SSH_AUTH_AGAIN)
|
||||
session->pending_call_state = SSH_PENDING_CALL_NONE;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* WITH_SSH1 */
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
@@ -22,9 +22,9 @@
|
||||
*/
|
||||
|
||||
/* just the dirtiest part of code i ever made */
|
||||
#include <string.h>
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/buffer.h"
|
||||
@@ -288,5 +288,3 @@ unsigned char *bin_to_base64(const unsigned char *source, int len) {
|
||||
|
||||
return base64;
|
||||
}
|
||||
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
|
||||
26
src/bignum.c
26
src/bignum.c
@@ -19,13 +19,15 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/bignum.h"
|
||||
#include "libssh/string.h"
|
||||
|
||||
ssh_string make_bignum_string(bignum num) {
|
||||
ssh_string ssh_make_bignum_string(bignum num) {
|
||||
ssh_string ptr = NULL;
|
||||
int pad = 0;
|
||||
unsigned int len = bignum_num_bytes(num);
|
||||
@@ -58,12 +60,14 @@ ssh_string make_bignum_string(bignum num) {
|
||||
bignum_bn2bin(num, len, ptr->data + pad);
|
||||
#elif HAVE_LIBCRYPTO
|
||||
bignum_bn2bin(num, ptr->data + pad);
|
||||
#elif HAVE_LIBMBEDCRYPTO
|
||||
bignum_bn2bin(num, ptr->data + pad);
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bignum make_string_bn(ssh_string string){
|
||||
bignum ssh_make_string_bn(ssh_string string){
|
||||
bignum bn = NULL;
|
||||
unsigned int len = ssh_string_len(string);
|
||||
|
||||
@@ -76,12 +80,15 @@ bignum make_string_bn(ssh_string string){
|
||||
bignum_bin2bn(string->data, len, &bn);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bn = bignum_bin2bn(string->data, len, NULL);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
bn = bignum_new();
|
||||
bignum_bin2bn(string->data, len, bn);
|
||||
#endif
|
||||
|
||||
return bn;
|
||||
}
|
||||
|
||||
void make_string_bn_inplace(ssh_string string, bignum bnout) {
|
||||
void ssh_make_string_bn_inplace(ssh_string string, bignum bnout) {
|
||||
unsigned int len = ssh_string_len(string);
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
/* XXX: FIXME as needed for LIBGCRYPT ECDSA codepaths. */
|
||||
@@ -89,19 +96,30 @@ void make_string_bn_inplace(ssh_string string, bignum bnout) {
|
||||
(void) bnout;
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bignum_bin2bn(string->data, len, bnout);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
bignum_bin2bn(string->data, len, bnout);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* prints the bignum on stderr */
|
||||
void ssh_print_bignum(const char *which, bignum num) {
|
||||
void ssh_print_bignum(const char *which, const bignum num) {
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
unsigned char *hex = NULL;
|
||||
bignum_bn2hex(num, &hex);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
char *hex = NULL;
|
||||
hex = bignum_bn2hex(num);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
char *hex = NULL;
|
||||
hex = bignum_bn2hex(num);
|
||||
#endif
|
||||
fprintf(stderr, "%s value: ", which);
|
||||
fprintf(stderr, "%s\n", (hex == NULL) ? "(null)" : (char *) hex);
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
SAFE_FREE(hex);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
OPENSSL_free(hex);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
SAFE_FREE(hex);
|
||||
#endif
|
||||
}
|
||||
|
||||
63
src/bind.c
63
src/bind.c
@@ -149,9 +149,10 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
|
||||
|
||||
if (sshbind->ecdsakey == NULL &&
|
||||
sshbind->dsakey == NULL &&
|
||||
sshbind->rsakey == NULL) {
|
||||
sshbind->rsakey == NULL &&
|
||||
sshbind->ed25519key == NULL) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"ECDSA, DSA, or RSA host key file must be set");
|
||||
"ECDSA, ED25519, DSA, or RSA host key file must be set");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -178,6 +179,7 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DSA
|
||||
if (sshbind->dsa == NULL && sshbind->dsakey != NULL) {
|
||||
rc = ssh_pki_import_privkey_file(sshbind->dsakey,
|
||||
NULL,
|
||||
@@ -199,6 +201,7 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sshbind->rsa == NULL && sshbind->rsakey != NULL) {
|
||||
rc = ssh_pki_import_privkey_file(sshbind->rsakey,
|
||||
@@ -212,8 +215,7 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (ssh_key_type(sshbind->rsa) != SSH_KEYTYPE_RSA &&
|
||||
ssh_key_type(sshbind->rsa) != SSH_KEYTYPE_RSA1) {
|
||||
if (ssh_key_type(sshbind->rsa) != SSH_KEYTYPE_RSA) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"The RSA host key has the wrong type");
|
||||
ssh_key_free(sshbind->rsa);
|
||||
@@ -222,6 +224,27 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
|
||||
}
|
||||
}
|
||||
|
||||
if (sshbind->ed25519 == NULL && sshbind->ed25519key != NULL) {
|
||||
rc = ssh_pki_import_privkey_file(sshbind->ed25519key,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&sshbind->ed25519);
|
||||
if (rc == SSH_ERROR || rc == SSH_EOF) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"Failed to import private ED25519 host key");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (ssh_key_type(sshbind->ed25519) != SSH_KEYTYPE_ED25519) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"The ED25519 host key has the wrong type");
|
||||
ssh_key_free(sshbind->ed25519);
|
||||
sshbind->ed25519 = NULL;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
@@ -230,14 +253,14 @@ int ssh_bind_listen(ssh_bind sshbind) {
|
||||
socket_t fd;
|
||||
int rc;
|
||||
|
||||
if (ssh_init() < 0) {
|
||||
ssh_set_error(sshbind, SSH_FATAL, "ssh_init() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = ssh_bind_import_keys(sshbind);
|
||||
if (rc != SSH_OK) {
|
||||
return SSH_ERROR;
|
||||
if (sshbind->rsa == NULL &&
|
||||
sshbind->dsa == NULL &&
|
||||
sshbind->ecdsa == NULL &&
|
||||
sshbind->ed25519 == NULL) {
|
||||
rc = ssh_bind_import_keys(sshbind);
|
||||
if (rc != SSH_OK) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (sshbind->bindfd == SSH_INVALID_SOCKET) {
|
||||
@@ -252,6 +275,7 @@ int ssh_bind_listen(ssh_bind sshbind) {
|
||||
sshbind->dsa = NULL;
|
||||
ssh_key_free(sshbind->rsa);
|
||||
sshbind->rsa = NULL;
|
||||
/* XXX should this clear also other structures that were allocated */
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -264,6 +288,7 @@ int ssh_bind_listen(ssh_bind sshbind) {
|
||||
sshbind->dsa = NULL;
|
||||
ssh_key_free(sshbind->rsa);
|
||||
sshbind->rsa = NULL;
|
||||
/* XXX should this clear also other structures that were allocated */
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -390,7 +415,6 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
}
|
||||
|
||||
session->server = 1;
|
||||
session->version = 2;
|
||||
|
||||
/* copy options */
|
||||
for (i = 0; i < 10; i++) {
|
||||
@@ -430,9 +454,14 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
* where keys can be imported) on this ssh_bind and are instead
|
||||
* only using ssh_bind_accept_fd to manage sockets ourselves.
|
||||
*/
|
||||
rc = ssh_bind_import_keys(sshbind);
|
||||
if (rc != SSH_OK) {
|
||||
return SSH_ERROR;
|
||||
if (sshbind->rsa == NULL &&
|
||||
sshbind->dsa == NULL &&
|
||||
sshbind->ecdsa == NULL &&
|
||||
sshbind->ed25519 == NULL) {
|
||||
rc = ssh_bind_import_keys(sshbind);
|
||||
if (rc != SSH_OK) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_ECC
|
||||
@@ -444,6 +473,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_DSA
|
||||
if (sshbind->dsa) {
|
||||
session->srv.dsa_key = ssh_key_dup(sshbind->dsa);
|
||||
if (session->srv.dsa_key == NULL) {
|
||||
@@ -451,6 +481,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (sshbind->rsa) {
|
||||
session->srv.rsa_key = ssh_key_dup(sshbind->rsa);
|
||||
if (session->srv.rsa_key == NULL) {
|
||||
|
||||
403
src/buffer.c
403
src/buffer.c
@@ -21,9 +21,9 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -84,12 +84,12 @@ static void buffer_verify(ssh_buffer buf){
|
||||
* @return A newly initialized SSH buffer, NULL on error.
|
||||
*/
|
||||
struct ssh_buffer_struct *ssh_buffer_new(void) {
|
||||
struct ssh_buffer_struct *buf = malloc(sizeof(struct ssh_buffer_struct));
|
||||
|
||||
struct ssh_buffer_struct *buf =
|
||||
calloc(1, sizeof(struct ssh_buffer_struct));
|
||||
if (buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset(buf, 0, sizeof(struct ssh_buffer_struct));
|
||||
|
||||
buffer_verify(buf);
|
||||
return buf;
|
||||
}
|
||||
@@ -107,10 +107,10 @@ void ssh_buffer_free(struct ssh_buffer_struct *buffer) {
|
||||
|
||||
if (buffer->data) {
|
||||
/* burn the data */
|
||||
BURN_BUFFER(buffer->data, buffer->allocated);
|
||||
explicit_bzero(buffer->data, buffer->allocated);
|
||||
SAFE_FREE(buffer->data);
|
||||
}
|
||||
BURN_BUFFER(buffer, sizeof(struct ssh_buffer_struct));
|
||||
explicit_bzero(buffer, sizeof(struct ssh_buffer_struct));
|
||||
SAFE_FREE(buffer);
|
||||
}
|
||||
|
||||
@@ -127,38 +127,40 @@ void ssh_buffer_set_secure(ssh_buffer buffer){
|
||||
}
|
||||
|
||||
static int realloc_buffer(struct ssh_buffer_struct *buffer, size_t needed) {
|
||||
size_t smallest = 1;
|
||||
char *new;
|
||||
size_t smallest = 1;
|
||||
char *new;
|
||||
|
||||
buffer_verify(buffer);
|
||||
buffer_verify(buffer);
|
||||
|
||||
/* Find the smallest power of two which is greater or equal to needed */
|
||||
while(smallest <= needed) {
|
||||
if (smallest == 0) {
|
||||
return -1;
|
||||
}
|
||||
smallest <<= 1;
|
||||
}
|
||||
needed = smallest;
|
||||
if (buffer->secure){
|
||||
new = malloc(needed);
|
||||
if (new == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(new, buffer->data,buffer->used);
|
||||
BURN_BUFFER(buffer->data, buffer->used);
|
||||
SAFE_FREE(buffer->data);
|
||||
} else {
|
||||
new = realloc(buffer->data, needed);
|
||||
if (new == NULL) {
|
||||
buffer->data = NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
buffer->data = new;
|
||||
buffer->allocated = needed;
|
||||
buffer_verify(buffer);
|
||||
return 0;
|
||||
/* Find the smallest power of two which is greater or equal to needed */
|
||||
while(smallest <= needed) {
|
||||
if (smallest == 0) {
|
||||
return -1;
|
||||
}
|
||||
smallest <<= 1;
|
||||
}
|
||||
needed = smallest;
|
||||
if (buffer->secure){
|
||||
new = malloc(needed);
|
||||
if (new == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (buffer->used > 0) {
|
||||
memcpy(new, buffer->data,buffer->used);
|
||||
explicit_bzero(buffer->data, buffer->used);
|
||||
SAFE_FREE(buffer->data);
|
||||
}
|
||||
} else {
|
||||
new = realloc(buffer->data, needed);
|
||||
if (new == NULL) {
|
||||
buffer->data = NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
buffer->data = new;
|
||||
buffer->allocated = needed;
|
||||
buffer_verify(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
@@ -177,15 +179,13 @@ static void buffer_shift(ssh_buffer buffer){
|
||||
|
||||
if (buffer->secure){
|
||||
void *ptr = buffer->data + buffer->used;
|
||||
BURN_BUFFER(ptr, burn_pos);
|
||||
explicit_bzero(ptr, burn_pos);
|
||||
}
|
||||
|
||||
buffer_verify(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Reinitialize a SSH buffer.
|
||||
*
|
||||
* @param[in] buffer The buffer to reinitialize.
|
||||
@@ -194,22 +194,24 @@ static void buffer_shift(ssh_buffer buffer){
|
||||
*/
|
||||
int ssh_buffer_reinit(struct ssh_buffer_struct *buffer)
|
||||
{
|
||||
buffer_verify(buffer);
|
||||
BURN_BUFFER(buffer->data, buffer->used);
|
||||
buffer->used = 0;
|
||||
buffer->pos = 0;
|
||||
if(buffer->allocated > 127) {
|
||||
if (realloc_buffer(buffer, 127) < 0) {
|
||||
return -1;
|
||||
buffer_verify(buffer);
|
||||
if (buffer->used > 0) {
|
||||
explicit_bzero(buffer->data, buffer->used);
|
||||
}
|
||||
}
|
||||
buffer_verify(buffer);
|
||||
return 0;
|
||||
buffer->used = 0;
|
||||
buffer->pos = 0;
|
||||
|
||||
if (buffer->allocated > 127) {
|
||||
if (realloc_buffer(buffer, 127) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
buffer_verify(buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Add data at the tail of a buffer.
|
||||
*
|
||||
* @param[in] buffer The buffer to add the data.
|
||||
@@ -246,6 +248,72 @@ int ssh_buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Ensure the buffer has at least a certain preallocated size.
|
||||
*
|
||||
* @param[in] buffer The buffer to enlarge.
|
||||
*
|
||||
* @param[in] len The length to ensure as allocated.
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
int ssh_buffer_allocate_size(struct ssh_buffer_struct *buffer,
|
||||
uint32_t len)
|
||||
{
|
||||
buffer_verify(buffer);
|
||||
|
||||
if (buffer->allocated < len) {
|
||||
if (buffer->pos > 0) {
|
||||
buffer_shift(buffer);
|
||||
}
|
||||
if (realloc_buffer(buffer, len) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
buffer_verify(buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Allocate space for data at the tail of a buffer.
|
||||
*
|
||||
* @param[in] buffer The buffer to add the data.
|
||||
*
|
||||
* @param[in] len The length of the data to add.
|
||||
*
|
||||
* @return Pointer on the allocated space
|
||||
* NULL on error.
|
||||
*/
|
||||
void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len)
|
||||
{
|
||||
void *ptr;
|
||||
buffer_verify(buffer);
|
||||
|
||||
if (buffer->used + len < len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (buffer->allocated < (buffer->used + len)) {
|
||||
if (buffer->pos > 0) {
|
||||
buffer_shift(buffer);
|
||||
}
|
||||
|
||||
if (realloc_buffer(buffer, buffer->used + len) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ptr = buffer->data + buffer->used;
|
||||
buffer->used+=len;
|
||||
buffer_verify(buffer);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
@@ -257,7 +325,7 @@ int ssh_buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
int buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
|
||||
int ssh_buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
|
||||
struct ssh_string_struct *string) {
|
||||
uint32_t len = 0;
|
||||
|
||||
@@ -284,7 +352,7 @@ int buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
|
||||
*
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data)
|
||||
int ssh_buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -307,7 +375,7 @@ int buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data)
|
||||
*
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data)
|
||||
int ssh_buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -330,7 +398,7 @@ int buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data)
|
||||
*
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int buffer_add_u64(struct ssh_buffer_struct *buffer, uint64_t data)
|
||||
int ssh_buffer_add_u64(struct ssh_buffer_struct *buffer, uint64_t data)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -353,7 +421,7 @@ int buffer_add_u64(struct ssh_buffer_struct *buffer, uint64_t data)
|
||||
*
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int buffer_add_u8(struct ssh_buffer_struct *buffer,uint8_t data)
|
||||
int ssh_buffer_add_u8(struct ssh_buffer_struct *buffer,uint8_t data)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -378,7 +446,7 @@ int buffer_add_u8(struct ssh_buffer_struct *buffer,uint8_t data)
|
||||
*
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data,
|
||||
int ssh_buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data,
|
||||
uint32_t len) {
|
||||
buffer_verify(buffer);
|
||||
|
||||
@@ -419,14 +487,14 @@ int buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data,
|
||||
*
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int buffer_add_buffer(struct ssh_buffer_struct *buffer,
|
||||
int ssh_buffer_add_buffer(struct ssh_buffer_struct *buffer,
|
||||
struct ssh_buffer_struct *source)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ssh_buffer_add_data(buffer,
|
||||
buffer_get_rest(source),
|
||||
buffer_get_rest_len(source));
|
||||
ssh_buffer_get(source),
|
||||
ssh_buffer_get_len(source));
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -435,63 +503,28 @@ int buffer_add_buffer(struct ssh_buffer_struct *buffer,
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a pointer on the head of a buffer.
|
||||
*
|
||||
* @param[in] buffer The buffer to get the head pointer.
|
||||
*
|
||||
* @return A data pointer on the head. It doesn't take the position
|
||||
* into account.
|
||||
*
|
||||
* @warning Don't expect data to be nul-terminated.
|
||||
*
|
||||
* @see buffer_get_rest()
|
||||
* @see buffer_get_len()
|
||||
*/
|
||||
void *ssh_buffer_get_begin(struct ssh_buffer_struct *buffer){
|
||||
return buffer->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Get a pointer to the head of a buffer at the current position.
|
||||
*
|
||||
* @param[in] buffer The buffer to get the head pointer.
|
||||
*
|
||||
* @return A pointer to the data from current position.
|
||||
*
|
||||
* @see buffer_get_rest_len()
|
||||
* @see buffer_get()
|
||||
* @see ssh_buffer_get_len()
|
||||
*/
|
||||
void *buffer_get_rest(struct ssh_buffer_struct *buffer){
|
||||
void *ssh_buffer_get(struct ssh_buffer_struct *buffer){
|
||||
return buffer->data + buffer->pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the length of the buffer, not counting position.
|
||||
*
|
||||
* @param[in] buffer The buffer to get the length from.
|
||||
*
|
||||
* @return The length of the buffer.
|
||||
*
|
||||
* @see buffer_get()
|
||||
*/
|
||||
uint32_t ssh_buffer_get_len(struct ssh_buffer_struct *buffer){
|
||||
return buffer->used;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Get the length of the buffer from the current position.
|
||||
*
|
||||
* @param[in] buffer The buffer to get the length from.
|
||||
*
|
||||
* @return The length of the buffer.
|
||||
*
|
||||
* @see buffer_get_rest()
|
||||
* @see ssh_buffer_get()
|
||||
*/
|
||||
uint32_t buffer_get_rest_len(struct ssh_buffer_struct *buffer){
|
||||
uint32_t ssh_buffer_get_len(struct ssh_buffer_struct *buffer){
|
||||
buffer_verify(buffer);
|
||||
return buffer->used - buffer->pos;
|
||||
}
|
||||
@@ -509,7 +542,7 @@ uint32_t buffer_get_rest_len(struct ssh_buffer_struct *buffer){
|
||||
*
|
||||
* @return The new size of the buffer.
|
||||
*/
|
||||
uint32_t buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
|
||||
uint32_t ssh_buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
|
||||
buffer_verify(buffer);
|
||||
|
||||
if (buffer->pos + len < len || buffer->used < buffer->pos + len) {
|
||||
@@ -537,7 +570,7 @@ uint32_t buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
|
||||
*
|
||||
* @return The new size of the buffer.
|
||||
*/
|
||||
uint32_t buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){
|
||||
uint32_t ssh_buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){
|
||||
buffer_verify(buffer);
|
||||
|
||||
if (buffer->used < len) {
|
||||
@@ -550,8 +583,6 @@ uint32_t buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Get the remaining data out of the buffer and adjust the read pointer.
|
||||
*
|
||||
* @param[in] buffer The buffer to read.
|
||||
@@ -562,13 +593,17 @@ uint32_t buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){
|
||||
*
|
||||
* @returns 0 if there is not enough data in buffer, len otherwise.
|
||||
*/
|
||||
uint32_t buffer_get_data(struct ssh_buffer_struct *buffer, void *data, uint32_t len){
|
||||
uint32_t ssh_buffer_get_data(struct ssh_buffer_struct *buffer, void *data, uint32_t len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Check for a integer overflow first, then check if not enough data is in
|
||||
* the buffer.
|
||||
*/
|
||||
if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
|
||||
return 0;
|
||||
rc = ssh_buffer_validate_length(buffer, len);
|
||||
if (rc != SSH_OK) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(data,buffer->data+buffer->pos,len);
|
||||
buffer->pos+=len;
|
||||
@@ -583,23 +618,27 @@ uint32_t buffer_get_data(struct ssh_buffer_struct *buffer, void *data, uint32_t
|
||||
*
|
||||
* @param[in] buffer The buffer to read.
|
||||
*
|
||||
* @param[in] data A pointer to a uint8_t where to store the data.
|
||||
* @param[in] data A pointer to a uint8_t where to store the data.
|
||||
*
|
||||
* @returns 0 if there is not enough data in buffer, 1 otherwise.
|
||||
*/
|
||||
int buffer_get_u8(struct ssh_buffer_struct *buffer, uint8_t *data){
|
||||
return buffer_get_data(buffer,data,sizeof(uint8_t));
|
||||
int ssh_buffer_get_u8(struct ssh_buffer_struct *buffer, uint8_t *data){
|
||||
return ssh_buffer_get_data(buffer,data,sizeof(uint8_t));
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* \brief gets a 32 bits unsigned int out of the buffer. Adjusts the read pointer.
|
||||
* \param buffer Buffer to read
|
||||
* \param data pointer to a uint32_t where to store the data
|
||||
* \returns 0 if there is not enough data in buffer
|
||||
* \returns 4 otherwise.
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief gets a 32 bits unsigned int out of the buffer. Adjusts the read pointer.
|
||||
*
|
||||
* @param[in] buffer The buffer to read.
|
||||
*
|
||||
* @param[in] data A pointer to a uint32_t where to store the data.
|
||||
*
|
||||
* @returns 0 if there is not enough data in buffer, 4 otherwise.
|
||||
*/
|
||||
int buffer_get_u32(struct ssh_buffer_struct *buffer, uint32_t *data){
|
||||
return buffer_get_data(buffer,data,sizeof(uint32_t));
|
||||
int ssh_buffer_get_u32(struct ssh_buffer_struct *buffer, uint32_t *data){
|
||||
return ssh_buffer_get_data(buffer,data,sizeof(uint32_t));
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
@@ -613,8 +652,26 @@ int buffer_get_u32(struct ssh_buffer_struct *buffer, uint32_t *data){
|
||||
*
|
||||
* @returns 0 if there is not enough data in buffer, 8 otherwise.
|
||||
*/
|
||||
int buffer_get_u64(struct ssh_buffer_struct *buffer, uint64_t *data){
|
||||
return buffer_get_data(buffer,data,sizeof(uint64_t));
|
||||
int ssh_buffer_get_u64(struct ssh_buffer_struct *buffer, uint64_t *data){
|
||||
return ssh_buffer_get_data(buffer,data,sizeof(uint64_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Valdiates that the given length can be obtained from the buffer.
|
||||
*
|
||||
* @param[in] buffer The buffer to read from.
|
||||
*
|
||||
* @param[in] len The length to be checked.
|
||||
*
|
||||
* @return SSH_OK if the length is valid, SSH_ERROR otherwise.
|
||||
*/
|
||||
int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len)
|
||||
{
|
||||
if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -626,24 +683,26 @@ int buffer_get_u64(struct ssh_buffer_struct *buffer, uint64_t *data){
|
||||
*
|
||||
* @returns The SSH String, NULL on error.
|
||||
*/
|
||||
struct ssh_string_struct *buffer_get_ssh_string(struct ssh_buffer_struct *buffer) {
|
||||
struct ssh_string_struct *ssh_buffer_get_ssh_string(struct ssh_buffer_struct *buffer) {
|
||||
uint32_t stringlen;
|
||||
uint32_t hostlen;
|
||||
struct ssh_string_struct *str = NULL;
|
||||
int rc;
|
||||
|
||||
if (buffer_get_u32(buffer, &stringlen) == 0) {
|
||||
if (ssh_buffer_get_u32(buffer, &stringlen) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
hostlen = ntohl(stringlen);
|
||||
/* verify if there is enough space in buffer to get it */
|
||||
if (buffer->pos + hostlen < hostlen || buffer->pos + hostlen > buffer->used) {
|
||||
rc = ssh_buffer_validate_length(buffer, hostlen);
|
||||
if (rc != SSH_OK) {
|
||||
return NULL; /* it is indeed */
|
||||
}
|
||||
str = ssh_string_new(hostlen);
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (buffer_get_data(buffer, ssh_string_data(str), hostlen) != hostlen) {
|
||||
if (ssh_buffer_get_data(buffer, ssh_string_data(str), hostlen) != hostlen) {
|
||||
/* should never happen */
|
||||
SAFE_FREE(str);
|
||||
return NULL;
|
||||
@@ -652,41 +711,6 @@ struct ssh_string_struct *buffer_get_ssh_string(struct ssh_buffer_struct *buffer
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Get a mpint out of the buffer and adjusts the read pointer.
|
||||
*
|
||||
* @note This function is SSH-1 only.
|
||||
*
|
||||
* @param[in] buffer The buffer to read.
|
||||
*
|
||||
* @returns The SSH String containing the mpint, NULL on error.
|
||||
*/
|
||||
struct ssh_string_struct *buffer_get_mpint(struct ssh_buffer_struct *buffer) {
|
||||
uint16_t bits;
|
||||
uint32_t len;
|
||||
struct ssh_string_struct *str = NULL;
|
||||
|
||||
if (buffer_get_data(buffer, &bits, sizeof(uint16_t)) != sizeof(uint16_t)) {
|
||||
return NULL;
|
||||
}
|
||||
bits = ntohs(bits);
|
||||
len = (bits + 7) / 8;
|
||||
if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
|
||||
return NULL;
|
||||
}
|
||||
str = ssh_string_new(len);
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (buffer_get_data(buffer, ssh_string_data(str), len) != len) {
|
||||
SAFE_FREE(str);
|
||||
return NULL;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief Add multiple values in a buffer on a single function call
|
||||
* @param[in] buffer The buffer to add to
|
||||
@@ -725,32 +749,32 @@ int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
switch(*p) {
|
||||
case 'b':
|
||||
o.byte = (uint8_t)va_arg(ap, unsigned int);
|
||||
rc = buffer_add_u8(buffer, o.byte);
|
||||
rc = ssh_buffer_add_u8(buffer, o.byte);
|
||||
break;
|
||||
case 'w':
|
||||
o.word = (uint16_t)va_arg(ap, unsigned int);
|
||||
o.word = htons(o.word);
|
||||
rc = buffer_add_u16(buffer, o.word);
|
||||
rc = ssh_buffer_add_u16(buffer, o.word);
|
||||
break;
|
||||
case 'd':
|
||||
o.dword = va_arg(ap, uint32_t);
|
||||
o.dword = htonl(o.dword);
|
||||
rc = buffer_add_u32(buffer, o.dword);
|
||||
rc = ssh_buffer_add_u32(buffer, o.dword);
|
||||
break;
|
||||
case 'q':
|
||||
o.qword = va_arg(ap, uint64_t);
|
||||
o.qword = htonll(o.qword);
|
||||
rc = buffer_add_u64(buffer, o.qword);
|
||||
rc = ssh_buffer_add_u64(buffer, o.qword);
|
||||
break;
|
||||
case 'S':
|
||||
o.string = va_arg(ap, ssh_string);
|
||||
rc = buffer_add_ssh_string(buffer, o.string);
|
||||
rc = ssh_buffer_add_ssh_string(buffer, o.string);
|
||||
o.string = NULL;
|
||||
break;
|
||||
case 's':
|
||||
cstring = va_arg(ap, char *);
|
||||
len = strlen(cstring);
|
||||
rc = buffer_add_u32(buffer, htonl(len));
|
||||
rc = ssh_buffer_add_u32(buffer, htonl(len));
|
||||
if (rc == SSH_OK){
|
||||
rc = ssh_buffer_add_data(buffer, cstring, len);
|
||||
}
|
||||
@@ -767,12 +791,12 @@ int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
break;
|
||||
case 'B':
|
||||
b = va_arg(ap, bignum);
|
||||
o.string = make_bignum_string(b);
|
||||
o.string = ssh_make_bignum_string(b);
|
||||
if(o.string == NULL){
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
rc = buffer_add_ssh_string(buffer, o.string);
|
||||
rc = ssh_buffer_add_ssh_string(buffer, o.string);
|
||||
SAFE_FREE(o.string);
|
||||
break;
|
||||
case 't':
|
||||
@@ -867,11 +891,12 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
char **cstring;
|
||||
void **data;
|
||||
} o;
|
||||
size_t len, rlen;
|
||||
uint32_t u32len;
|
||||
size_t len, rlen, max_len;
|
||||
va_list ap_copy;
|
||||
int count;
|
||||
|
||||
max_len = ssh_buffer_get_len(buffer);
|
||||
|
||||
/* copy the argument list in case a rollback is needed */
|
||||
va_copy(ap_copy, ap);
|
||||
|
||||
@@ -885,52 +910,60 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
switch (*p) {
|
||||
case 'b':
|
||||
o.byte = va_arg(ap, uint8_t *);
|
||||
rlen = buffer_get_u8(buffer, o.byte);
|
||||
rlen = ssh_buffer_get_u8(buffer, o.byte);
|
||||
rc = rlen==1 ? SSH_OK : SSH_ERROR;
|
||||
break;
|
||||
case 'w':
|
||||
o.word = va_arg(ap, uint16_t *);
|
||||
rlen = buffer_get_data(buffer, o.word, sizeof(uint16_t));
|
||||
rlen = ssh_buffer_get_data(buffer, o.word, sizeof(uint16_t));
|
||||
*o.word = ntohs(*o.word);
|
||||
rc = rlen==2 ? SSH_OK : SSH_ERROR;
|
||||
break;
|
||||
case 'd':
|
||||
o.dword = va_arg(ap, uint32_t *);
|
||||
rlen = buffer_get_u32(buffer, o.dword);
|
||||
rlen = ssh_buffer_get_u32(buffer, o.dword);
|
||||
*o.dword = ntohl(*o.dword);
|
||||
rc = rlen==4 ? SSH_OK : SSH_ERROR;
|
||||
break;
|
||||
case 'q':
|
||||
o.qword = va_arg(ap, uint64_t*);
|
||||
rlen = buffer_get_u64(buffer, o.qword);
|
||||
rlen = ssh_buffer_get_u64(buffer, o.qword);
|
||||
*o.qword = ntohll(*o.qword);
|
||||
rc = rlen==8 ? SSH_OK : SSH_ERROR;
|
||||
break;
|
||||
case 'S':
|
||||
o.string = va_arg(ap, ssh_string *);
|
||||
*o.string = buffer_get_ssh_string(buffer);
|
||||
*o.string = ssh_buffer_get_ssh_string(buffer);
|
||||
rc = *o.string != NULL ? SSH_OK : SSH_ERROR;
|
||||
o.string = NULL;
|
||||
break;
|
||||
case 's':
|
||||
case 's': {
|
||||
uint32_t u32len = 0;
|
||||
|
||||
o.cstring = va_arg(ap, char **);
|
||||
*o.cstring = NULL;
|
||||
rc = buffer_get_u32(buffer, &u32len);
|
||||
rc = ssh_buffer_get_u32(buffer, &u32len);
|
||||
if (rc != 4){
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
len = ntohl(u32len);
|
||||
if (len > UINT_MAX - 1){
|
||||
if (len > max_len - 1) {
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_validate_length(buffer, len);
|
||||
if (rc != SSH_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
*o.cstring = malloc(len + 1);
|
||||
if (*o.cstring == NULL){
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
rlen = buffer_get_data(buffer, *o.cstring, len);
|
||||
rlen = ssh_buffer_get_data(buffer, *o.cstring, len);
|
||||
if (rlen != len){
|
||||
SAFE_FREE(*o.cstring);
|
||||
rc = SSH_ERROR;
|
||||
@@ -940,8 +973,18 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
o.cstring = NULL;
|
||||
rc = SSH_OK;
|
||||
break;
|
||||
}
|
||||
case 'P':
|
||||
len = va_arg(ap, size_t);
|
||||
if (len > max_len - 1) {
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_validate_length(buffer, len);
|
||||
if (rc != SSH_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
o.data = va_arg(ap, void **);
|
||||
count++;
|
||||
@@ -951,7 +994,7 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
rlen = buffer_get_data(buffer, *o.data, len);
|
||||
rlen = ssh_buffer_get_data(buffer, *o.data, len);
|
||||
if (rlen != len){
|
||||
SAFE_FREE(*o.data);
|
||||
rc = SSH_ERROR;
|
||||
@@ -1053,5 +1096,3 @@ int _ssh_buffer_unpack(struct ssh_buffer_struct *buffer,
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
@@ -25,7 +25,10 @@
|
||||
|
||||
#include "libssh/callbacks.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
|
||||
#define is_callback_valid(session, cb) \
|
||||
(cb->size <= 0 || cb->size > 1024 * sizeof(void *))
|
||||
|
||||
/* LEGACY */
|
||||
static void ssh_legacy_log_callback(int priority,
|
||||
@@ -47,12 +50,12 @@ int ssh_set_callbacks(ssh_session session, ssh_callbacks cb) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if(cb->size <= 0 || cb->size > 1024 * sizeof(void *)){
|
||||
ssh_set_error(session,SSH_FATAL,
|
||||
"Invalid callback passed in (badly initialized)");
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (is_callback_valid(session, cb)) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid callback passed in (badly initialized)");
|
||||
return SSH_ERROR;
|
||||
};
|
||||
session->common.callbacks = cb;
|
||||
|
||||
/* LEGACY */
|
||||
@@ -64,35 +67,80 @@ int ssh_set_callbacks(ssh_session session, ssh_callbacks cb) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ssh_set_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb) {
|
||||
ssh_session session = NULL;
|
||||
if (channel == NULL || cb == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
session = channel->session;
|
||||
static int ssh_add_set_channel_callbacks(ssh_channel channel,
|
||||
ssh_channel_callbacks cb,
|
||||
int prepend)
|
||||
{
|
||||
ssh_session session = NULL;
|
||||
int rc;
|
||||
|
||||
if(cb->size <= 0 || cb->size > 1024 * sizeof(void *)){
|
||||
ssh_set_error(session,SSH_FATAL,
|
||||
"Invalid channel callback passed in (badly initialized)");
|
||||
if (channel == NULL || cb == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
session = channel->session;
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
channel->callbacks = cb;
|
||||
if (is_callback_valid(session, cb)) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid callback passed in (badly initialized)");
|
||||
return SSH_ERROR;
|
||||
};
|
||||
if (channel->callbacks == NULL) {
|
||||
channel->callbacks = ssh_list_new();
|
||||
if (channel->callbacks == NULL){
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
if (prepend) {
|
||||
rc = ssh_list_prepend(channel->callbacks, cb);
|
||||
} else {
|
||||
rc = ssh_list_append(channel->callbacks, cb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ssh_set_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb)
|
||||
{
|
||||
return ssh_add_set_channel_callbacks(channel, cb, 1);
|
||||
}
|
||||
|
||||
int ssh_add_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb)
|
||||
{
|
||||
return ssh_add_set_channel_callbacks(channel, cb, 0);
|
||||
}
|
||||
|
||||
int ssh_remove_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb)
|
||||
{
|
||||
struct ssh_iterator *it;
|
||||
|
||||
if (channel == NULL || channel->callbacks == NULL){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
it = ssh_list_find(channel->callbacks, cb);
|
||||
if (it == NULL){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
ssh_list_remove(channel->callbacks, it);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
|
||||
int ssh_set_server_callbacks(ssh_session session, ssh_server_callbacks cb){
|
||||
if (session == NULL || cb == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if(cb->size <= 0 || cb->size > 1024 * sizeof(void *)){
|
||||
ssh_set_error(session,SSH_FATAL,
|
||||
"Invalid callback passed in (badly initialized)");
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (is_callback_valid(session, cb)) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid callback passed in (badly initialized)");
|
||||
return SSH_ERROR;
|
||||
};
|
||||
session->server_callbacks = cb;
|
||||
|
||||
return 0;
|
||||
|
||||
212
src/chachapoly.c
Normal file
212
src/chachapoly.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2015 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/chacha.h"
|
||||
#include "libssh/poly1305.h"
|
||||
#include "libssh/misc.h"
|
||||
|
||||
/* size of the keys k1 and k2 as defined in specs */
|
||||
#define CHACHA20_KEYLEN 32
|
||||
struct chacha20_poly1305_keysched {
|
||||
/* key used for encrypting the length field*/
|
||||
struct chacha_ctx k1;
|
||||
/* key used for encrypting the packets */
|
||||
struct chacha_ctx k2;
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct ssh_packet_header {
|
||||
uint32_t length;
|
||||
uint8_t payload[];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static const uint8_t zero_block_counter[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static const uint8_t payload_block_counter[8] = {1, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
static int chacha20_set_encrypt_key(struct ssh_cipher_struct *cipher,
|
||||
void *key,
|
||||
void *IV)
|
||||
{
|
||||
struct chacha20_poly1305_keysched *sched;
|
||||
uint8_t *u8key = key;
|
||||
(void)IV;
|
||||
|
||||
if (cipher->chacha20_schedule == NULL) {
|
||||
sched = malloc(sizeof *sched);
|
||||
if (sched == NULL){
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
sched = cipher->chacha20_schedule;
|
||||
}
|
||||
|
||||
chacha_keysetup(&sched->k2, u8key, CHACHA20_KEYLEN * 8);
|
||||
chacha_keysetup(&sched->k1, u8key + CHACHA20_KEYLEN, CHACHA20_KEYLEN * 8);
|
||||
cipher->chacha20_schedule = sched;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief encrypts an outgoing packet with chacha20 and authenticate it
|
||||
* with poly1305.
|
||||
*/
|
||||
static void chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len,
|
||||
uint8_t *tag,
|
||||
uint64_t seq)
|
||||
{
|
||||
struct ssh_packet_header *in_packet = in, *out_packet = out;
|
||||
uint8_t poly1305_ctx[POLY1305_KEYLEN] = {0};
|
||||
struct chacha20_poly1305_keysched *keys = cipher->chacha20_schedule;
|
||||
|
||||
seq = htonll(seq);
|
||||
/* step 1, prepare the poly1305 key */
|
||||
chacha_ivsetup(&keys->k2, (uint8_t *)&seq, zero_block_counter);
|
||||
chacha_encrypt_bytes(&keys->k2,
|
||||
poly1305_ctx,
|
||||
poly1305_ctx,
|
||||
POLY1305_KEYLEN);
|
||||
|
||||
/* step 2, encrypt length field */
|
||||
chacha_ivsetup(&keys->k1, (uint8_t *)&seq, zero_block_counter);
|
||||
chacha_encrypt_bytes(&keys->k1,
|
||||
(uint8_t *)&in_packet->length,
|
||||
(uint8_t *)&out_packet->length,
|
||||
sizeof(uint32_t));
|
||||
|
||||
/* step 3, encrypt packet payload */
|
||||
chacha_ivsetup(&keys->k2, (uint8_t *)&seq, payload_block_counter);
|
||||
chacha_encrypt_bytes(&keys->k2,
|
||||
in_packet->payload,
|
||||
out_packet->payload,
|
||||
len - sizeof(uint32_t));
|
||||
|
||||
/* ssh_print_hexa("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx)); */
|
||||
/* step 4, compute the MAC */
|
||||
poly1305_auth(tag, (uint8_t *)out_packet, len, poly1305_ctx);
|
||||
/* ssh_print_hexa("poly1305 src", (uint8_t *)out_packet, len);
|
||||
ssh_print_hexa("poly1305 tag", tag, POLY1305_TAGLEN); */
|
||||
}
|
||||
|
||||
static int chacha20_poly1305_aead_decrypt_length(
|
||||
struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
uint8_t *out,
|
||||
size_t len,
|
||||
uint64_t seq)
|
||||
{
|
||||
struct chacha20_poly1305_keysched *keys = cipher->chacha20_schedule;
|
||||
|
||||
if (len < sizeof(uint32_t)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
seq = htonll(seq);
|
||||
|
||||
chacha_ivsetup(&keys->k1, (uint8_t *)&seq, zero_block_counter);
|
||||
chacha_encrypt_bytes(&keys->k1,
|
||||
in,
|
||||
(uint8_t *)out,
|
||||
sizeof(uint32_t));
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static int chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
void *complete_packet,
|
||||
uint8_t *out,
|
||||
size_t encrypted_size,
|
||||
uint64_t seq)
|
||||
{
|
||||
uint8_t poly1305_ctx[POLY1305_KEYLEN] = {0};
|
||||
uint8_t tag[POLY1305_TAGLEN] = {0};
|
||||
struct chacha20_poly1305_keysched *keys = cipher->chacha20_schedule;
|
||||
uint8_t *mac = (uint8_t *)complete_packet + sizeof(uint32_t) + encrypted_size;
|
||||
int cmp;
|
||||
|
||||
seq = htonll(seq);
|
||||
|
||||
ZERO_STRUCT(poly1305_ctx);
|
||||
chacha_ivsetup(&keys->k2, (uint8_t *)&seq, zero_block_counter);
|
||||
chacha_encrypt_bytes(&keys->k2,
|
||||
poly1305_ctx,
|
||||
poly1305_ctx,
|
||||
POLY1305_KEYLEN);
|
||||
#if 0
|
||||
ssh_print_hexa("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx));
|
||||
#endif
|
||||
|
||||
poly1305_auth(tag, (uint8_t *)complete_packet, encrypted_size +
|
||||
sizeof(uint32_t), poly1305_ctx);
|
||||
#if 0
|
||||
ssh_print_hexa("poly1305 src",
|
||||
(uint8_t*)complete_packet,
|
||||
encrypted_size + 4);
|
||||
ssh_print_hexa("poly1305 tag", tag, POLY1305_TAGLEN);
|
||||
ssh_print_hexa("received tag", mac, POLY1305_TAGLEN);
|
||||
#endif
|
||||
|
||||
cmp = memcmp(tag, mac, POLY1305_TAGLEN);
|
||||
if(cmp != 0) {
|
||||
/* mac error */
|
||||
SSH_LOG(SSH_LOG_PACKET,"poly1305 verify error");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
chacha_ivsetup(&keys->k2, (uint8_t *)&seq, payload_block_counter);
|
||||
chacha_encrypt_bytes(&keys->k2,
|
||||
(uint8_t *)complete_packet + sizeof(uint32_t),
|
||||
out,
|
||||
encrypted_size);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static void chacha20_cleanup(struct ssh_cipher_struct *cipher) {
|
||||
SAFE_FREE(cipher->chacha20_schedule);
|
||||
}
|
||||
|
||||
const struct ssh_cipher_struct chacha20poly1305_cipher = {
|
||||
.name = "chacha20-poly1305@openssh.com",
|
||||
.blocksize = 8,
|
||||
.lenfield_blocksize = 4,
|
||||
.keylen = sizeof(struct chacha20_poly1305_keysched),
|
||||
.keysize = 512,
|
||||
.tag_size = POLY1305_TAGLEN,
|
||||
.set_encrypt_key = chacha20_set_encrypt_key,
|
||||
.set_decrypt_key = chacha20_set_encrypt_key,
|
||||
.aead_encrypt = chacha20_poly1305_aead_encrypt,
|
||||
.aead_decrypt_length = chacha20_poly1305_aead_decrypt_length,
|
||||
.aead_decrypt = chacha20_poly1305_aead_decrypt,
|
||||
.cleanup = chacha20_cleanup
|
||||
};
|
||||
|
||||
const struct ssh_cipher_struct *ssh_get_chacha20poly1305_cipher(void)
|
||||
{
|
||||
return &chacha20poly1305_cipher;
|
||||
}
|
||||
403
src/channels.c
403
src/channels.c
@@ -22,9 +22,9 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
@@ -106,7 +106,6 @@ ssh_channel ssh_channel_new(ssh_session session) {
|
||||
}
|
||||
|
||||
channel->session = session;
|
||||
channel->version = session->version;
|
||||
channel->exit_status = -1;
|
||||
channel->flags = SSH_CHANNEL_FLAG_NOT_BOUND;
|
||||
|
||||
@@ -286,14 +285,14 @@ static int channel_open(ssh_channel channel, const char *type, int window,
|
||||
}
|
||||
|
||||
if (payload != NULL) {
|
||||
if (buffer_add_buffer(session->out_buffer, payload) < 0) {
|
||||
if (ssh_buffer_add_buffer(session->out_buffer, payload) < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
|
||||
return err;
|
||||
}
|
||||
}
|
||||
channel->state = SSH_CHANNEL_STATE_OPENING;
|
||||
if (packet_send(session) == SSH_ERROR) {
|
||||
if (ssh_packet_send(session) == SSH_ERROR) {
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -346,13 +345,6 @@ static int grow_window(ssh_session session, ssh_channel channel, int minimumsize
|
||||
uint32_t new_window = minimumsize > WINDOWBASE ? minimumsize : WINDOWBASE;
|
||||
int rc;
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
if (session->version == 1){
|
||||
channel->remote_window = new_window;
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
#endif
|
||||
if(new_window <= channel->local_window){
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
"growing window (channel %d:%d) to %d bytes : not needed (%d bytes)",
|
||||
@@ -374,7 +366,7 @@ static int grow_window(ssh_session session, ssh_channel channel, int minimumsize
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (packet_send(session) == SSH_ERROR) {
|
||||
if (ssh_packet_send(session) == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -398,8 +390,6 @@ error:
|
||||
*
|
||||
* @brief Parse a channel-related packet to resolve it to a ssh_channel.
|
||||
*
|
||||
* This works on SSH1 sessions too.
|
||||
*
|
||||
* @param[in] session The current SSH session.
|
||||
*
|
||||
* @param[in] packet The buffer to parse packet from. The read pointer will
|
||||
@@ -412,11 +402,7 @@ static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet) {
|
||||
ssh_channel channel;
|
||||
uint32_t chan;
|
||||
int rc;
|
||||
#ifdef WITH_SSH1
|
||||
/* With SSH1, the channel is always the first one */
|
||||
if(session->version==1)
|
||||
return ssh_get_channel1(session);
|
||||
#endif
|
||||
|
||||
rc = ssh_buffer_unpack(packet,"d",&chan);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
@@ -492,10 +478,10 @@ SSH_PACKET_CALLBACK(channel_rcv_data){
|
||||
if (is_stderr) {
|
||||
uint32_t ignore;
|
||||
/* uint32 data type code. we can ignore it */
|
||||
buffer_get_u32(packet, &ignore);
|
||||
ssh_buffer_get_u32(packet, &ignore);
|
||||
}
|
||||
|
||||
str = buffer_get_ssh_string(packet);
|
||||
str = ssh_buffer_get_ssh_string(packet);
|
||||
if (str == NULL) {
|
||||
SSH_LOG(SSH_LOG_PACKET, "Invalid data packet!");
|
||||
|
||||
@@ -538,31 +524,38 @@ SSH_PACKET_CALLBACK(channel_rcv_data){
|
||||
|
||||
ssh_string_free(str);
|
||||
|
||||
if(ssh_callbacks_exists(channel->callbacks, channel_data_function)) {
|
||||
if(is_stderr) {
|
||||
buf = channel->stderr_buffer;
|
||||
} else {
|
||||
buf = channel->stdout_buffer;
|
||||
}
|
||||
rest = channel->callbacks->channel_data_function(channel->session,
|
||||
channel,
|
||||
buffer_get_rest(buf),
|
||||
buffer_get_rest_len(buf),
|
||||
is_stderr,
|
||||
channel->callbacks->userdata);
|
||||
if(rest > 0) {
|
||||
if (channel->counter != NULL) {
|
||||
channel->counter->in_bytes += rest;
|
||||
}
|
||||
buffer_pass_bytes(buf, rest);
|
||||
}
|
||||
if (channel->local_window + buffer_get_rest_len(buf) < WINDOWLIMIT) {
|
||||
if (grow_window(session, channel, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (is_stderr) {
|
||||
buf = channel->stderr_buffer;
|
||||
} else {
|
||||
buf = channel->stdout_buffer;
|
||||
}
|
||||
|
||||
ssh_callbacks_iterate(channel->callbacks,
|
||||
ssh_channel_callbacks,
|
||||
channel_data_function) {
|
||||
if (ssh_buffer_get(buf) == NULL) {
|
||||
break;
|
||||
}
|
||||
rest = ssh_callbacks_iterate_exec(channel_data_function,
|
||||
channel->session,
|
||||
channel,
|
||||
ssh_buffer_get(buf),
|
||||
ssh_buffer_get_len(buf),
|
||||
is_stderr);
|
||||
if (rest > 0) {
|
||||
if (channel->counter != NULL) {
|
||||
channel->counter->in_bytes += rest;
|
||||
}
|
||||
ssh_buffer_pass_bytes(buf, rest);
|
||||
}
|
||||
}
|
||||
ssh_callbacks_iterate_end();
|
||||
|
||||
if (channel->local_window + ssh_buffer_get_len(buf) < WINDOWLIMIT) {
|
||||
if (grow_window(session, channel, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
@@ -585,11 +578,11 @@ SSH_PACKET_CALLBACK(channel_rcv_eof) {
|
||||
/* channel->remote_window = 0; */
|
||||
channel->remote_eof = 1;
|
||||
|
||||
if(ssh_callbacks_exists(channel->callbacks, channel_eof_function)) {
|
||||
channel->callbacks->channel_eof_function(channel->session,
|
||||
channel,
|
||||
channel->callbacks->userdata);
|
||||
}
|
||||
ssh_callbacks_execute_list(channel->callbacks,
|
||||
ssh_channel_callbacks,
|
||||
channel_eof_function,
|
||||
channel->session,
|
||||
channel);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
@@ -612,9 +605,9 @@ SSH_PACKET_CALLBACK(channel_rcv_close) {
|
||||
channel->remote_channel);
|
||||
|
||||
if ((channel->stdout_buffer &&
|
||||
buffer_get_rest_len(channel->stdout_buffer) > 0) ||
|
||||
ssh_buffer_get_len(channel->stdout_buffer) > 0) ||
|
||||
(channel->stderr_buffer &&
|
||||
buffer_get_rest_len(channel->stderr_buffer) > 0)) {
|
||||
ssh_buffer_get_len(channel->stderr_buffer) > 0)) {
|
||||
channel->delayed_close = 1;
|
||||
} else {
|
||||
channel->state = SSH_CHANNEL_STATE_CLOSED;
|
||||
@@ -629,11 +622,12 @@ SSH_PACKET_CALLBACK(channel_rcv_close) {
|
||||
* buffer because the eof is ignored until the buffer is empty.
|
||||
*/
|
||||
|
||||
if(ssh_callbacks_exists(channel->callbacks, channel_close_function)) {
|
||||
channel->callbacks->channel_close_function(channel->session,
|
||||
channel,
|
||||
channel->callbacks->userdata);
|
||||
}
|
||||
ssh_callbacks_execute_list(channel->callbacks,
|
||||
ssh_channel_callbacks,
|
||||
channel_close_function,
|
||||
channel->session,
|
||||
channel);
|
||||
|
||||
channel->flags |= SSH_CHANNEL_FLAG_CLOSED_REMOTE;
|
||||
if(channel->flags & SSH_CHANNEL_FLAG_FREED_LOCAL)
|
||||
ssh_channel_do_free(channel);
|
||||
@@ -664,18 +658,16 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
|
||||
}
|
||||
|
||||
if (strcmp(request,"exit-status") == 0) {
|
||||
uint32_t exit_status = 0;
|
||||
SAFE_FREE(request);
|
||||
rc = ssh_buffer_unpack(packet, "d", &channel->exit_status);
|
||||
SSH_LOG(SSH_LOG_PACKET, "received exit-status %d", channel->exit_status);
|
||||
|
||||
SAFE_FREE(request);
|
||||
rc = ssh_buffer_unpack(packet, "d", &exit_status);
|
||||
SSH_LOG(SSH_LOG_PACKET, "received exit-status %d", channel->exit_status);
|
||||
|
||||
if(ssh_callbacks_exists(channel->callbacks, channel_exit_status_function)) {
|
||||
channel->callbacks->channel_exit_status_function(channel->session,
|
||||
channel,
|
||||
channel->exit_status,
|
||||
channel->callbacks->userdata);
|
||||
}
|
||||
ssh_callbacks_execute_list(channel->callbacks,
|
||||
ssh_channel_callbacks,
|
||||
channel_exit_status_function,
|
||||
channel->session,
|
||||
channel,
|
||||
channel->exit_status);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
@@ -694,13 +686,13 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Remote connection sent a signal SIG %s", sig);
|
||||
if(ssh_callbacks_exists(channel->callbacks, channel_signal_function)) {
|
||||
channel->callbacks->channel_signal_function(channel->session,
|
||||
channel,
|
||||
sig,
|
||||
channel->callbacks->userdata);
|
||||
}
|
||||
SAFE_FREE(sig);
|
||||
ssh_callbacks_execute_list(channel->callbacks,
|
||||
ssh_channel_callbacks,
|
||||
channel_signal_function,
|
||||
channel->session,
|
||||
channel,
|
||||
sig);
|
||||
SAFE_FREE(sig);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
@@ -714,7 +706,7 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
|
||||
|
||||
SAFE_FREE(request);
|
||||
|
||||
rc = ssh_buffer_unpack(packet, "sbs",
|
||||
rc = ssh_buffer_unpack(packet, "sbss",
|
||||
&sig, /* signal name */
|
||||
&core_dumped, /* core dumped */
|
||||
&errmsg, /* error message */
|
||||
@@ -730,12 +722,15 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Remote connection closed by signal SIG %s %s", sig, core);
|
||||
if(ssh_callbacks_exists(channel->callbacks, channel_exit_signal_function)) {
|
||||
channel->callbacks->channel_exit_signal_function(channel->session,
|
||||
channel,
|
||||
sig, core_dumped, errmsg, lang,
|
||||
channel->callbacks->userdata);
|
||||
}
|
||||
ssh_callbacks_execute_list(channel->callbacks,
|
||||
ssh_channel_callbacks,
|
||||
channel_exit_signal_function,
|
||||
channel->session,
|
||||
channel,
|
||||
sig,
|
||||
core_dumped,
|
||||
errmsg,
|
||||
lang);
|
||||
|
||||
SAFE_FREE(lang);
|
||||
SAFE_FREE(errmsg);
|
||||
@@ -754,7 +749,7 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
|
||||
if (rc != SSH_OK) {
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
packet_send(session);
|
||||
ssh_packet_send(session);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
@@ -762,10 +757,11 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
|
||||
if (strcmp(request, "auth-agent-req@openssh.com") == 0) {
|
||||
SAFE_FREE(request);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "Received an auth-agent-req request");
|
||||
if(ssh_callbacks_exists(channel->callbacks, channel_auth_agent_req_function)) {
|
||||
channel->callbacks->channel_auth_agent_req_function(channel->session, channel,
|
||||
channel->callbacks->userdata);
|
||||
}
|
||||
ssh_callbacks_execute_list(channel->callbacks,
|
||||
ssh_channel_callbacks,
|
||||
channel_auth_agent_req_function,
|
||||
channel->session,
|
||||
channel);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
@@ -864,12 +860,6 @@ int ssh_channel_open_session(ssh_channel channel) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
if (channel->session->version == 1) {
|
||||
return channel_open_session1(channel);
|
||||
}
|
||||
#endif
|
||||
|
||||
return channel_open(channel,
|
||||
"session",
|
||||
CHANNEL_INITIAL_WINDOW,
|
||||
@@ -897,12 +887,6 @@ int ssh_channel_open_auth_agent(ssh_channel channel){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
if (channel->session->version == 1) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
return channel_open(channel,
|
||||
"auth-agent@openssh.com",
|
||||
CHANNEL_INITIAL_WINDOW,
|
||||
@@ -1030,6 +1014,9 @@ void ssh_channel_do_free(ssh_channel channel){
|
||||
}
|
||||
ssh_buffer_free(channel->stdout_buffer);
|
||||
ssh_buffer_free(channel->stderr_buffer);
|
||||
if (channel->callbacks != NULL){
|
||||
ssh_list_free(channel->callbacks);
|
||||
}
|
||||
|
||||
/* debug trick to catch use after frees */
|
||||
memset(channel, 'X', sizeof(struct ssh_channel_struct));
|
||||
@@ -1084,7 +1071,7 @@ int ssh_channel_send_eof(ssh_channel channel){
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = packet_send(session);
|
||||
rc = ssh_packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Sent a EOF on client channel (%d:%d)",
|
||||
channel->local_channel,
|
||||
@@ -1143,7 +1130,7 @@ int ssh_channel_close(ssh_channel channel){
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = packet_send(session);
|
||||
rc = ssh_packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Sent a close on client channel (%d:%d)",
|
||||
channel->local_channel,
|
||||
@@ -1247,16 +1234,10 @@ static int channel_write_common(ssh_channel channel,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (channel->session->session_state == SSH_SESSION_STATE_ERROR) {
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#ifdef WITH_SSH1
|
||||
if (channel->version == 1) {
|
||||
rc = channel_write1(channel, data, len);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
if (ssh_waitsession_unblocked(session) == 0){
|
||||
rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT,
|
||||
ssh_waitsession_unblocked, session);
|
||||
@@ -1278,7 +1259,7 @@ static int channel_write_common(ssh_channel channel,
|
||||
ssh_channel_waitwindow_termination,channel);
|
||||
if (rc == SSH_ERROR ||
|
||||
!ssh_channel_waitwindow_termination(channel) ||
|
||||
channel->session->session_state == SSH_SESSION_STATE_ERROR ||
|
||||
session->session_state == SSH_SESSION_STATE_ERROR ||
|
||||
channel->state == SSH_CHANNEL_STATE_CLOSED)
|
||||
goto out;
|
||||
continue;
|
||||
@@ -1320,7 +1301,7 @@ static int channel_write_common(ssh_channel channel,
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = packet_send(session);
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -1351,6 +1332,23 @@ error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the remote window size.
|
||||
*
|
||||
* This is the maximum amounts of bytes the remote side expects us to send
|
||||
* before growing the window again.
|
||||
*
|
||||
* @param[in] channel The channel to query.
|
||||
*
|
||||
* @return The remote window size
|
||||
*
|
||||
* @warning A nonzero return value does not guarantee the socket is ready
|
||||
* to send that much data. Buffering may happen in the local SSH
|
||||
* packet buffer, so beware of really big window sizes.
|
||||
*
|
||||
* @warning A zero return value means ssh_channel_write (default settings)
|
||||
* will block until the window grows back.
|
||||
*/
|
||||
uint32_t ssh_channel_window_size(ssh_channel channel) {
|
||||
return channel->remote_window;
|
||||
}
|
||||
@@ -1416,9 +1414,9 @@ int ssh_channel_is_eof(ssh_channel channel) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if ((channel->stdout_buffer &&
|
||||
buffer_get_rest_len(channel->stdout_buffer) > 0) ||
|
||||
ssh_buffer_get_len(channel->stdout_buffer) > 0) ||
|
||||
(channel->stderr_buffer &&
|
||||
buffer_get_rest_len(channel->stderr_buffer) > 0)) {
|
||||
ssh_buffer_get_len(channel->stderr_buffer) > 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1447,8 +1445,6 @@ void ssh_channel_set_blocking(ssh_channel channel, int blocking) {
|
||||
* @internal
|
||||
*
|
||||
* @brief handle a SSH_CHANNEL_SUCCESS packet and set the channel state.
|
||||
*
|
||||
* This works on SSH1 sessions too.
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_channel_success){
|
||||
ssh_channel channel;
|
||||
@@ -1479,8 +1475,6 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_success){
|
||||
* @internal
|
||||
*
|
||||
* @brief Handle a SSH_CHANNEL_FAILURE packet and set the channel state.
|
||||
*
|
||||
* This works on SSH1 sessions too.
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_channel_failure){
|
||||
ssh_channel channel;
|
||||
@@ -1542,14 +1536,14 @@ static int channel_request(ssh_channel channel, const char *request,
|
||||
}
|
||||
|
||||
if (buffer != NULL) {
|
||||
if (ssh_buffer_add_data(session->out_buffer, buffer_get_rest(buffer),
|
||||
buffer_get_rest_len(buffer)) < 0) {
|
||||
if (ssh_buffer_add_data(session->out_buffer, ssh_buffer_get(buffer),
|
||||
ssh_buffer_get_len(buffer)) < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
channel->request_state = SSH_CHANNEL_REQ_STATE_PENDING;
|
||||
if (packet_send(session) == SSH_ERROR) {
|
||||
if (ssh_packet_send(session) == SSH_ERROR) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1633,13 +1627,6 @@ int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal,
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
if (channel->version==1) {
|
||||
rc = channel_request_pty_size1(channel,terminal, col, row);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
switch(channel->request_state){
|
||||
case SSH_CHANNEL_REQ_STATE_NONE:
|
||||
break;
|
||||
@@ -1711,14 +1698,6 @@ int ssh_channel_change_pty_size(ssh_channel channel, int cols, int rows) {
|
||||
ssh_buffer buffer = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
if (channel->version == 1) {
|
||||
rc = channel_change_pty_size1(channel,cols,rows);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
buffer = ssh_buffer_new();
|
||||
if (buffer == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
@@ -1757,12 +1736,8 @@ int ssh_channel_request_shell(ssh_channel channel) {
|
||||
if(channel == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#ifdef WITH_SSH1
|
||||
if (channel->version == 1) {
|
||||
return channel_request_shell1(channel);
|
||||
}
|
||||
#endif
|
||||
return channel_request(channel, "shell", NULL, 1);
|
||||
|
||||
return channel_request(channel, "shell", NULL, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1827,9 +1802,14 @@ static char *generate_cookie(void) {
|
||||
static const char *hex = "0123456789abcdef";
|
||||
char s[36];
|
||||
unsigned char rnd[16];
|
||||
int ok;
|
||||
int i;
|
||||
|
||||
ssh_get_random(rnd,sizeof(rnd),0);
|
||||
ok = ssh_get_random(rnd, sizeof(rnd), 0);
|
||||
if (!ok) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
s[i*2] = hex[rnd[i] & 0x0f];
|
||||
s[i*2+1] = hex[rnd[i] >> 4];
|
||||
@@ -1983,6 +1963,25 @@ ssh_channel ssh_channel_accept_x11(ssh_channel channel, int timeout_ms) {
|
||||
return ssh_channel_accept(channel->session, SSH_CHANNEL_X11, timeout_ms, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send an "auth-agent-req" channel request over an existing session channel.
|
||||
*
|
||||
* This client-side request will enable forwarding the agent over an secure tunnel.
|
||||
* When the server is ready to open one authentication agent channel, an
|
||||
* ssh_channel_open_request_auth_agent_callback event will be generated.
|
||||
*
|
||||
* @param[in] channel The channel to send signal.
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR if an error occurred
|
||||
*/
|
||||
int ssh_channel_request_auth_agent(ssh_channel channel) {
|
||||
if (channel == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return channel_request(channel, "auth-agent-req@openssh.com", NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
@@ -2082,8 +2081,8 @@ static int global_request(ssh_session session, const char *request,
|
||||
|
||||
if (buffer != NULL) {
|
||||
rc = ssh_buffer_add_data(session->out_buffer,
|
||||
buffer_get_rest(buffer),
|
||||
buffer_get_rest_len(buffer));
|
||||
ssh_buffer_get(buffer),
|
||||
ssh_buffer_get_len(buffer));
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
rc = SSH_ERROR;
|
||||
@@ -2092,7 +2091,7 @@ static int global_request(ssh_session session, const char *request,
|
||||
}
|
||||
|
||||
session->global_req_state = SSH_CHANNEL_REQ_STATE_PENDING;
|
||||
rc = packet_send(session);
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
return rc;
|
||||
}
|
||||
@@ -2205,6 +2204,11 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* DEPRECATED */
|
||||
int ssh_forward_listen(ssh_session session, const char *address, int port, int *bound_port) {
|
||||
return ssh_channel_listen_forward(session, address, port, bound_port);
|
||||
}
|
||||
|
||||
/* DEPRECATED */
|
||||
ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms) {
|
||||
return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms, NULL);
|
||||
@@ -2272,6 +2276,7 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* DEPRECATED */
|
||||
int ssh_forward_cancel(ssh_session session, const char *address, int port) {
|
||||
return ssh_channel_cancel_forward(session, address, port);
|
||||
}
|
||||
@@ -2373,11 +2378,6 @@ int ssh_channel_request_exec(ssh_channel channel, const char *cmd) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
if (channel->version == 1) {
|
||||
return channel_request_exec1(channel, cmd);
|
||||
}
|
||||
#endif
|
||||
switch(channel->request_state){
|
||||
case SSH_CHANNEL_REQ_STATE_NONE:
|
||||
break;
|
||||
@@ -2448,12 +2448,6 @@ int ssh_channel_request_send_signal(ssh_channel channel, const char *sig) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
if (channel->version == 1) {
|
||||
return SSH_ERROR; // TODO: Add support for SSH-v1 if possible.
|
||||
}
|
||||
#endif
|
||||
|
||||
buffer = ssh_buffer_new();
|
||||
if (buffer == NULL) {
|
||||
ssh_set_error_oom(channel->session);
|
||||
@@ -2473,6 +2467,49 @@ error:
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send a break signal to the server (as described in RFC 4335).
|
||||
*
|
||||
* Sends a break signal to the remote process.
|
||||
* Note, that remote system may not support breaks.
|
||||
* In such a case this request will be silently ignored.
|
||||
* Only SSH-v2 is supported.
|
||||
*
|
||||
* @param[in] channel The channel to send the break to.
|
||||
*
|
||||
* @param[in] length The break-length in milliseconds to send.
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR if an error occurred
|
||||
* (including attempts to send signal via SSH-v1 session).
|
||||
*/
|
||||
int ssh_channel_request_send_break(ssh_channel channel, uint32_t length) {
|
||||
ssh_buffer buffer = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
if (channel == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
buffer = ssh_buffer_new();
|
||||
if (buffer == NULL) {
|
||||
ssh_set_error_oom(channel->session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(buffer, "d", length);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(channel->session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = channel_request(channel, "break", buffer, 0);
|
||||
|
||||
error:
|
||||
ssh_buffer_free(buffer);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read data from a channel into a buffer.
|
||||
*
|
||||
@@ -2561,7 +2598,7 @@ struct ssh_channel_read_termination_struct {
|
||||
|
||||
static int ssh_channel_read_termination(void *s){
|
||||
struct ssh_channel_read_termination_struct *ctx = s;
|
||||
if (buffer_get_rest_len(ctx->buffer) >= ctx->count ||
|
||||
if (ssh_buffer_get_len(ctx->buffer) >= ctx->count ||
|
||||
ctx->channel->remote_eof ||
|
||||
ctx->channel->session->session_state == SSH_SESSION_STATE_ERROR)
|
||||
return 1;
|
||||
@@ -2658,11 +2695,11 @@ int ssh_channel_read_timeout(ssh_channel channel,
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Read (%d) buffered : %d bytes. Window: %d",
|
||||
count,
|
||||
buffer_get_rest_len(stdbuf),
|
||||
ssh_buffer_get_len(stdbuf),
|
||||
channel->local_window);
|
||||
|
||||
if (count > buffer_get_rest_len(stdbuf) + channel->local_window) {
|
||||
if (grow_window(session, channel, count - buffer_get_rest_len(stdbuf)) < 0) {
|
||||
if (count > ssh_buffer_get_len(stdbuf) + channel->local_window) {
|
||||
if (grow_window(session, channel, count - ssh_buffer_get_len(stdbuf)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -2685,17 +2722,17 @@ int ssh_channel_read_timeout(ssh_channel channel,
|
||||
if (rc == SSH_ERROR){
|
||||
return rc;
|
||||
}
|
||||
if (channel->session->session_state == SSH_SESSION_STATE_ERROR){
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (channel->remote_eof && buffer_get_rest_len(stdbuf) == 0) {
|
||||
if (channel->remote_eof && ssh_buffer_get_len(stdbuf) == 0) {
|
||||
return 0;
|
||||
}
|
||||
len = buffer_get_rest_len(stdbuf);
|
||||
len = ssh_buffer_get_len(stdbuf);
|
||||
/* Read count bytes if len is greater, everything otherwise */
|
||||
len = (len > count ? count : len);
|
||||
memcpy(dest, buffer_get_rest(stdbuf), len);
|
||||
buffer_pass_bytes(stdbuf,len);
|
||||
memcpy(dest, ssh_buffer_get(stdbuf), len);
|
||||
ssh_buffer_pass_bytes(stdbuf,len);
|
||||
if (channel->counter != NULL) {
|
||||
channel->counter->in_bytes += len;
|
||||
}
|
||||
@@ -2750,7 +2787,7 @@ int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count
|
||||
to_read = ssh_channel_poll(channel, is_stderr);
|
||||
|
||||
if (to_read <= 0) {
|
||||
if (channel->session->session_state == SSH_SESSION_STATE_ERROR){
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -2795,7 +2832,7 @@ int ssh_channel_poll(ssh_channel channel, int is_stderr){
|
||||
stdbuf = channel->stderr_buffer;
|
||||
}
|
||||
|
||||
if (buffer_get_rest_len(stdbuf) == 0 && channel->remote_eof == 0) {
|
||||
if (ssh_buffer_get_len(stdbuf) == 0 && channel->remote_eof == 0) {
|
||||
if (channel->session->session_state == SSH_SESSION_STATE_ERROR){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -2804,15 +2841,15 @@ int ssh_channel_poll(ssh_channel channel, int is_stderr){
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer_get_rest_len(stdbuf) > 0){
|
||||
return buffer_get_rest_len(stdbuf);
|
||||
if (ssh_buffer_get_len(stdbuf) > 0){
|
||||
return ssh_buffer_get_len(stdbuf);
|
||||
}
|
||||
|
||||
if (channel->remote_eof) {
|
||||
return SSH_EOF;
|
||||
}
|
||||
|
||||
return buffer_get_rest_len(stdbuf);
|
||||
return ssh_buffer_get_len(stdbuf);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2859,7 +2896,7 @@ int ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr){
|
||||
rc = SSH_ERROR;
|
||||
goto end;
|
||||
}
|
||||
rc = buffer_get_rest_len(stdbuf);
|
||||
rc = ssh_buffer_get_len(stdbuf);
|
||||
if(rc > 0)
|
||||
goto end;
|
||||
if (channel->remote_eof)
|
||||
@@ -2948,8 +2985,8 @@ static int channel_protocol_select(ssh_channel *rchans, ssh_channel *wchans,
|
||||
ssh_handle_packets(chan->session, SSH_TIMEOUT_NONBLOCKING);
|
||||
}
|
||||
|
||||
if ((chan->stdout_buffer && buffer_get_rest_len(chan->stdout_buffer) > 0) ||
|
||||
(chan->stderr_buffer && buffer_get_rest_len(chan->stderr_buffer) > 0) ||
|
||||
if ((chan->stdout_buffer && ssh_buffer_get_len(chan->stdout_buffer) > 0) ||
|
||||
(chan->stderr_buffer && ssh_buffer_get_len(chan->stderr_buffer) > 0) ||
|
||||
chan->remote_eof) {
|
||||
rout[j] = chan;
|
||||
j++;
|
||||
@@ -3050,18 +3087,18 @@ int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans,
|
||||
}
|
||||
|
||||
/* Prepare the outgoing temporary arrays */
|
||||
rchans = malloc(sizeof(ssh_channel ) * (count_ptrs(readchans) + 1));
|
||||
rchans = calloc(count_ptrs(readchans) + 1, sizeof(ssh_channel));
|
||||
if (rchans == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
wchans = malloc(sizeof(ssh_channel ) * (count_ptrs(writechans) + 1));
|
||||
wchans = calloc(count_ptrs(writechans) + 1, sizeof(ssh_channel));
|
||||
if (wchans == NULL) {
|
||||
SAFE_FREE(rchans);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
echans = malloc(sizeof(ssh_channel ) * (count_ptrs(exceptchans) + 1));
|
||||
echans = calloc(count_ptrs(exceptchans) + 1, sizeof(ssh_channel));
|
||||
if (echans == NULL) {
|
||||
SAFE_FREE(rchans);
|
||||
SAFE_FREE(wchans);
|
||||
@@ -3155,7 +3192,6 @@ void ssh_channel_set_counter(ssh_channel channel,
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_SERVER
|
||||
/**
|
||||
* @brief Blocking write on a channel stderr.
|
||||
*
|
||||
@@ -3173,6 +3209,8 @@ int ssh_channel_write_stderr(ssh_channel channel, const void *data, uint32_t len
|
||||
return channel_write_common(channel, data, len, 1);
|
||||
}
|
||||
|
||||
#if WITH_SERVER
|
||||
|
||||
/**
|
||||
* @brief Open a TCP/IP reverse forwarding channel.
|
||||
*
|
||||
@@ -3327,12 +3365,6 @@ int ssh_channel_request_send_exit_status(ssh_channel channel, int exit_status) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
if (channel->version == 1) {
|
||||
return SSH_ERROR; // TODO: Add support for SSH-v1 if possible.
|
||||
}
|
||||
#endif
|
||||
|
||||
buffer = ssh_buffer_new();
|
||||
if (buffer == NULL) {
|
||||
ssh_set_error_oom(channel->session);
|
||||
@@ -3382,11 +3414,6 @@ int ssh_channel_request_send_exit_signal(ssh_channel channel, const char *sig,
|
||||
ssh_set_error_invalid(channel->session);
|
||||
return rc;
|
||||
}
|
||||
#ifdef WITH_SSH1
|
||||
if (channel->version == 1) {
|
||||
return SSH_ERROR; // TODO: Add support for SSH-v1 if possible.
|
||||
}
|
||||
#endif
|
||||
|
||||
buffer = ssh_buffer_new();
|
||||
if (buffer == NULL) {
|
||||
@@ -3414,5 +3441,3 @@ error:
|
||||
#endif
|
||||
|
||||
/* @} */
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
396
src/channels1.c
396
src/channels1.c
@@ -1,396 +0,0 @@
|
||||
/*
|
||||
* channels1.c - Support for SSH-1 type channels
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2009 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifndef _WIN32
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/ssh1.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/channels.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
|
||||
/*
|
||||
* This is a big hack. In fact, SSH1 doesn't make a clever use of channels.
|
||||
* The whole packets concerning shells are sent outside of a channel.
|
||||
* Thus, an inside limitation of this behavior is that you can't only
|
||||
* request one shell.
|
||||
* The question is still how they managed to embed two "channel" into one
|
||||
* protocol.
|
||||
*/
|
||||
|
||||
int channel_open_session1(ssh_channel chan) {
|
||||
ssh_session session;
|
||||
|
||||
if (chan == NULL) {
|
||||
return -1;
|
||||
}
|
||||
session = chan->session;
|
||||
|
||||
/*
|
||||
* We guess we are requesting an *exec* channel. It can only have one exec
|
||||
* channel. So we abort with an error if we need more than one.
|
||||
*/
|
||||
if (session->exec_channel_opened) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"SSH1 supports only one execution channel. "
|
||||
"One has already been opened");
|
||||
return -1;
|
||||
}
|
||||
session->exec_channel_opened = 1;
|
||||
chan->request_state = SSH_CHANNEL_REQ_STATE_ACCEPTED;
|
||||
chan->state = SSH_CHANNEL_STATE_OPEN;
|
||||
chan->local_maxpacket = 32000;
|
||||
chan->local_window = 64000;
|
||||
SSH_LOG(SSH_LOG_PACKET, "Opened a SSH1 channel session");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 10 SSH_CMSG_REQUEST_PTY
|
||||
*
|
||||
* string TERM environment variable value (e.g. vt100)
|
||||
* 32-bit int terminal height, rows (e.g., 24)
|
||||
* 32-bit int terminal width, columns (e.g., 80)
|
||||
* 32-bit int terminal width, pixels (0 if no graphics) (e.g., 480)
|
||||
* 32-bit int terminal height, pixels (0 if no graphics) (e.g., 640)
|
||||
* n bytes tty modes encoded in binary
|
||||
* Some day, someone should have a look at that nasty tty encoded. It's
|
||||
* much simplier under ssh2. I just hope the defaults values are ok ...
|
||||
*/
|
||||
|
||||
int channel_request_pty_size1(ssh_channel channel, const char *terminal, int col,
|
||||
int row) {
|
||||
ssh_session session;
|
||||
ssh_string str = NULL;
|
||||
|
||||
if (channel == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
session = channel->session;
|
||||
|
||||
if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE &&
|
||||
channel->request_state != SSH_CHANNEL_REQ_STATE_ACCEPTED){
|
||||
ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
str = ssh_string_from_char(terminal);
|
||||
if (str == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffer_add_u8(session->out_buffer, SSH_CMSG_REQUEST_PTY) < 0 ||
|
||||
buffer_add_ssh_string(session->out_buffer, str) < 0) {
|
||||
ssh_string_free(str);
|
||||
return -1;
|
||||
}
|
||||
ssh_string_free(str);
|
||||
|
||||
if (buffer_add_u32(session->out_buffer, ntohl(row)) < 0 ||
|
||||
buffer_add_u32(session->out_buffer, ntohl(col)) < 0 ||
|
||||
buffer_add_u32(session->out_buffer, 0) < 0 || /* x */
|
||||
buffer_add_u32(session->out_buffer, 0) < 0 || /* y */
|
||||
buffer_add_u8(session->out_buffer, 0) < 0) { /* tty things */
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_FUNCTIONS, "Opening a ssh1 pty");
|
||||
channel->request_state = SSH_CHANNEL_REQ_STATE_PENDING;
|
||||
if (packet_send(session) == SSH_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING) {
|
||||
ssh_handle_packets(session, SSH_TIMEOUT_INFINITE);
|
||||
}
|
||||
|
||||
switch(channel->request_state){
|
||||
case SSH_CHANNEL_REQ_STATE_ERROR:
|
||||
case SSH_CHANNEL_REQ_STATE_PENDING:
|
||||
case SSH_CHANNEL_REQ_STATE_NONE:
|
||||
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
|
||||
return SSH_ERROR;
|
||||
case SSH_CHANNEL_REQ_STATE_ACCEPTED:
|
||||
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
|
||||
SSH_LOG(SSH_LOG_RARE, "PTY: Success");
|
||||
return SSH_OK;
|
||||
case SSH_CHANNEL_REQ_STATE_DENIED:
|
||||
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Server denied PTY allocation");
|
||||
SSH_LOG(SSH_LOG_RARE, "PTY: denied\n");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
// Not reached
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
int channel_change_pty_size1(ssh_channel channel, int cols, int rows) {
|
||||
ssh_session session;
|
||||
|
||||
if (channel == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
session = channel->session;
|
||||
|
||||
if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
|
||||
ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (buffer_add_u8(session->out_buffer, SSH_CMSG_WINDOW_SIZE) < 0 ||
|
||||
buffer_add_u32(session->out_buffer, ntohl(rows)) < 0 ||
|
||||
buffer_add_u32(session->out_buffer, ntohl(cols)) < 0 ||
|
||||
buffer_add_u32(session->out_buffer, 0) < 0 ||
|
||||
buffer_add_u32(session->out_buffer, 0) < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
channel->request_state=SSH_CHANNEL_REQ_STATE_PENDING;
|
||||
if (packet_send(session) == SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "Change pty size send");
|
||||
while(channel->request_state==SSH_CHANNEL_REQ_STATE_PENDING){
|
||||
ssh_handle_packets(session, SSH_TIMEOUT_INFINITE);
|
||||
}
|
||||
switch(channel->request_state){
|
||||
case SSH_CHANNEL_REQ_STATE_ERROR:
|
||||
case SSH_CHANNEL_REQ_STATE_PENDING:
|
||||
case SSH_CHANNEL_REQ_STATE_NONE:
|
||||
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
|
||||
return SSH_ERROR;
|
||||
case SSH_CHANNEL_REQ_STATE_ACCEPTED:
|
||||
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "pty size changed");
|
||||
return SSH_OK;
|
||||
case SSH_CHANNEL_REQ_STATE_DENIED:
|
||||
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
|
||||
SSH_LOG(SSH_LOG_RARE, "pty size change denied");
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED, "pty size change denied");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
// Not reached
|
||||
return SSH_ERROR;
|
||||
|
||||
}
|
||||
|
||||
int channel_request_shell1(ssh_channel channel) {
|
||||
ssh_session session;
|
||||
|
||||
if (channel == NULL) {
|
||||
return -1;
|
||||
}
|
||||
session = channel->session;
|
||||
|
||||
if (buffer_add_u8(session->out_buffer,SSH_CMSG_EXEC_SHELL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (packet_send(session) == SSH_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_RARE, "Launched a shell");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int channel_request_exec1(ssh_channel channel, const char *cmd) {
|
||||
ssh_session session;
|
||||
ssh_string command = NULL;
|
||||
|
||||
if (channel == NULL) {
|
||||
return -1;
|
||||
}
|
||||
session = channel->session;
|
||||
|
||||
command = ssh_string_from_char(cmd);
|
||||
if (command == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffer_add_u8(session->out_buffer, SSH_CMSG_EXEC_CMD) < 0 ||
|
||||
buffer_add_ssh_string(session->out_buffer, command) < 0) {
|
||||
ssh_string_free(command);
|
||||
return -1;
|
||||
}
|
||||
ssh_string_free(command);
|
||||
|
||||
if(packet_send(session) == SSH_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_RARE, "Executing %s ...", cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_data1){
|
||||
ssh_channel channel = ssh_get_channel1(session);
|
||||
ssh_string str = NULL;
|
||||
int is_stderr=(type==SSH_SMSG_STDOUT_DATA ? 0 : 1);
|
||||
(void)user;
|
||||
|
||||
if (channel == NULL) {
|
||||
return SSH_PACKET_NOT_USED;
|
||||
}
|
||||
|
||||
str = buffer_get_ssh_string(packet);
|
||||
if (str == NULL) {
|
||||
SSH_LOG(SSH_LOG_FUNCTIONS, "Invalid data packet !\n");
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
"Adding %" PRIdS " bytes data in %d",
|
||||
ssh_string_len(str), is_stderr);
|
||||
|
||||
if (channel_default_bufferize(channel, ssh_string_data(str), ssh_string_len(str),
|
||||
is_stderr) < 0) {
|
||||
ssh_string_free(str);
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
ssh_string_free(str);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_close1){
|
||||
ssh_channel channel = ssh_get_channel1(session);
|
||||
uint32_t status;
|
||||
int rc;
|
||||
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
if (channel == NULL) {
|
||||
return SSH_PACKET_NOT_USED;
|
||||
}
|
||||
|
||||
buffer_get_u32(packet, &status);
|
||||
/*
|
||||
* It's much more than a channel closing. spec says it's the last
|
||||
* message sent by server (strange)
|
||||
*/
|
||||
|
||||
/* actually status is lost somewhere */
|
||||
channel->state = SSH_CHANNEL_STATE_CLOSED;
|
||||
channel->remote_eof = 1;
|
||||
|
||||
rc = buffer_add_u8(session->out_buffer, SSH_CMSG_EXIT_CONFIRMATION);
|
||||
if (rc < 0) {
|
||||
return SSH_PACKET_NOT_USED;
|
||||
}
|
||||
packet_send(session);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_exist_status1){
|
||||
ssh_channel channel = ssh_get_channel1(session);
|
||||
uint32_t status;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
if (channel == NULL) {
|
||||
return SSH_PACKET_NOT_USED;
|
||||
}
|
||||
|
||||
buffer_get_u32(packet, &status);
|
||||
channel->state = SSH_CHANNEL_STATE_CLOSED;
|
||||
channel->remote_eof = 1;
|
||||
channel->exit_status = ntohl(status);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
|
||||
int channel_write1(ssh_channel channel, const void *data, int len) {
|
||||
ssh_session session;
|
||||
int origlen = len;
|
||||
int effectivelen;
|
||||
const unsigned char *ptr=data;
|
||||
|
||||
if (channel == NULL) {
|
||||
return -1;
|
||||
}
|
||||
session = channel->session;
|
||||
|
||||
while (len > 0) {
|
||||
if (buffer_add_u8(session->out_buffer, SSH_CMSG_STDIN_DATA) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
effectivelen = len > 32000 ? 32000 : len;
|
||||
|
||||
if (buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 ||
|
||||
ssh_buffer_add_data(session->out_buffer, ptr, effectivelen) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr += effectivelen;
|
||||
len -= effectivelen;
|
||||
|
||||
if (packet_send(session) == SSH_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
ssh_handle_packets(session, SSH_TIMEOUT_NONBLOCKING);
|
||||
if (channel->counter != NULL) {
|
||||
channel->counter->out_bytes += effectivelen;
|
||||
}
|
||||
}
|
||||
if (ssh_blocking_flush(session,SSH_TIMEOUT_USER) == SSH_ERROR)
|
||||
return -1;
|
||||
return origlen;
|
||||
}
|
||||
|
||||
ssh_channel ssh_get_channel1(ssh_session session){
|
||||
struct ssh_iterator *it;
|
||||
|
||||
if (session == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* With SSH1, the channel is always the first one */
|
||||
if(session->channels != NULL){
|
||||
it = ssh_list_get_iterator(session->channels);
|
||||
if(it)
|
||||
return ssh_iterator_value(ssh_channel, it);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif /* WITH_SSH1 */
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
406
src/client.c
406
src/client.c
@@ -21,9 +21,9 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
@@ -90,52 +90,74 @@ static void socket_callback_connected(int code, int errno_code, void *user){
|
||||
* @param user is a pointer to session
|
||||
* @returns Number of bytes processed, or zero if the banner is not complete.
|
||||
*/
|
||||
static int callback_receive_banner(const void *data, size_t len, void *user) {
|
||||
char *buffer = (char *)data;
|
||||
ssh_session session=(ssh_session) user;
|
||||
char *str = NULL;
|
||||
size_t i;
|
||||
int ret=0;
|
||||
static int callback_receive_banner(const void *data, size_t len, void *user)
|
||||
{
|
||||
char *buffer = (char *)data;
|
||||
ssh_session session=(ssh_session) user;
|
||||
char *str = NULL;
|
||||
size_t i;
|
||||
int ret=0;
|
||||
|
||||
if(session->session_state != SSH_SESSION_STATE_SOCKET_CONNECTED){
|
||||
ssh_set_error(session,SSH_FATAL,"Wrong state in callback_receive_banner : %d",session->session_state);
|
||||
if (session->session_state != SSH_SESSION_STATE_SOCKET_CONNECTED) {
|
||||
ssh_set_error(session,SSH_FATAL,
|
||||
"Wrong state in callback_receive_banner : %d",
|
||||
session->session_state);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
for(i=0;i<len;++i){
|
||||
#ifdef WITH_PCAP
|
||||
if(session->pcap_ctx && buffer[i] == '\n'){
|
||||
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_IN,buffer,i+1,i+1);
|
||||
}
|
||||
#endif
|
||||
if(buffer[i]=='\r') {
|
||||
buffer[i]='\0';
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (buffer[i]=='\n') {
|
||||
buffer[i] = '\0';
|
||||
str = strdup(buffer);
|
||||
if (str == NULL) {
|
||||
return SSH_ERROR;
|
||||
for (i = 0; i < len; ++i) {
|
||||
#ifdef WITH_PCAP
|
||||
if (session->pcap_ctx && buffer[i] == '\n') {
|
||||
ssh_pcap_context_write(session->pcap_ctx,
|
||||
SSH_PCAP_DIR_IN,
|
||||
buffer,i+1,
|
||||
i+1);
|
||||
}
|
||||
/* number of bytes read */
|
||||
ret = i + 1;
|
||||
session->serverbanner = str;
|
||||
session->session_state=SSH_SESSION_STATE_BANNER_RECEIVED;
|
||||
SSH_LOG(SSH_LOG_PACKET,"Received banner: %s",str);
|
||||
session->ssh_connection_callback(session);
|
||||
#endif
|
||||
if (buffer[i] == '\r') {
|
||||
buffer[i] = '\0';
|
||||
}
|
||||
if (buffer[i] == '\n') {
|
||||
int cmp;
|
||||
|
||||
return ret;
|
||||
}
|
||||
if(i>127){
|
||||
/* Too big banner */
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
ssh_set_error(session,SSH_FATAL,"Receiving banner: too large banner");
|
||||
buffer[i] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* The server MAY send other lines of data... */
|
||||
cmp = strncmp(buffer, "SSH-", 4);
|
||||
if (cmp == 0) {
|
||||
str = strdup(buffer);
|
||||
if (str == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
/* number of bytes read */
|
||||
ret = i + 1;
|
||||
session->serverbanner = str;
|
||||
session->session_state = SSH_SESSION_STATE_BANNER_RECEIVED;
|
||||
SSH_LOG(SSH_LOG_PACKET, "Received banner: %s", str);
|
||||
session->ssh_connection_callback(session);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"ssh_protocol_version_exchange: %s",
|
||||
buffer);
|
||||
ret = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* According to RFC 4253 the max banner length is 255 */
|
||||
if (i > 255) {
|
||||
/* Too big banner */
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Receiving banner: too large banner");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
@@ -147,46 +169,69 @@ static int callback_receive_banner(const void *data, size_t len, void *user) {
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
int ssh_send_banner(ssh_session session, int server) {
|
||||
const char *banner = NULL;
|
||||
char buffer[128] = {0};
|
||||
int err=SSH_ERROR;
|
||||
int ssh_send_banner(ssh_session session, int server)
|
||||
{
|
||||
const char *banner = CLIENT_BANNER_SSH2;
|
||||
const char *terminator = "\r\n";
|
||||
/* The maximum banner length is 255 for SSH2 */
|
||||
char buffer[256] = {0};
|
||||
size_t len;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2;
|
||||
if (server == 1) {
|
||||
if (session->opts.custombanner == NULL){
|
||||
len = strlen(banner);
|
||||
session->serverbanner = strdup(banner);
|
||||
if (session->serverbanner == NULL) {
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
len = strlen(session->opts.custombanner);
|
||||
session->serverbanner = malloc(len + 8 + 1);
|
||||
if(session->serverbanner == NULL) {
|
||||
goto end;
|
||||
}
|
||||
snprintf(session->serverbanner,
|
||||
len + 8 + 1,
|
||||
"SSH-2.0-%s",
|
||||
session->opts.custombanner);
|
||||
}
|
||||
|
||||
if (server) {
|
||||
if(session->opts.custombanner == NULL){
|
||||
session->serverbanner = strdup(banner);
|
||||
snprintf(buffer,
|
||||
sizeof(buffer),
|
||||
"%s%s",
|
||||
session->serverbanner,
|
||||
terminator);
|
||||
} else {
|
||||
session->serverbanner = malloc(strlen(session->opts.custombanner) + 9);
|
||||
if(!session->serverbanner)
|
||||
goto end;
|
||||
strcpy(session->serverbanner, "SSH-2.0-");
|
||||
strcat(session->serverbanner, session->opts.custombanner);
|
||||
}
|
||||
if (session->serverbanner == NULL) {
|
||||
goto end;
|
||||
}
|
||||
snprintf(buffer, 128, "%s\n", session->serverbanner);
|
||||
} else {
|
||||
session->clientbanner = strdup(banner);
|
||||
if (session->clientbanner == NULL) {
|
||||
goto end;
|
||||
}
|
||||
snprintf(buffer, 128, "%s\n", session->clientbanner);
|
||||
}
|
||||
session->clientbanner = strdup(banner);
|
||||
if (session->clientbanner == NULL) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (ssh_socket_write(session->socket, buffer, strlen(buffer)) == SSH_ERROR) {
|
||||
goto end;
|
||||
}
|
||||
snprintf(buffer,
|
||||
sizeof(buffer),
|
||||
"%s%s",
|
||||
session->clientbanner,
|
||||
terminator);
|
||||
}
|
||||
|
||||
rc = ssh_socket_write(session->socket, buffer, strlen(buffer));
|
||||
if (rc == SSH_ERROR) {
|
||||
goto end;
|
||||
}
|
||||
#ifdef WITH_PCAP
|
||||
if(session->pcap_ctx)
|
||||
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,buffer,strlen(buffer),strlen(buffer));
|
||||
if (session->pcap_ctx != NULL) {
|
||||
ssh_pcap_context_write(session->pcap_ctx,
|
||||
SSH_PCAP_DIR_OUT,
|
||||
buffer,
|
||||
strlen(buffer),
|
||||
strlen(buffer));
|
||||
}
|
||||
#endif
|
||||
err=SSH_OK;
|
||||
end:
|
||||
|
||||
return err;
|
||||
rc = SSH_OK;
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
@@ -209,10 +254,13 @@ static int dh_handshake(ssh_session session) {
|
||||
break;
|
||||
#ifdef HAVE_ECDH
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
case SSH_KEX_ECDH_SHA2_NISTP384:
|
||||
case SSH_KEX_ECDH_SHA2_NISTP521:
|
||||
rc = ssh_client_ecdh_init(session);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_CURVE25519
|
||||
case SSH_KEX_CURVE25519_SHA256:
|
||||
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
|
||||
rc = ssh_client_curve25519_init(session);
|
||||
break;
|
||||
@@ -283,7 +331,7 @@ int ssh_service_request(ssh_session session, const char *service) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
session->auth_service_state=SSH_AUTH_SERVICE_SENT;
|
||||
if (packet_send(session) == SSH_ERROR) {
|
||||
if (ssh_packet_send(session) == SSH_ERROR) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Sending SSH2_MSG_SERVICE_REQUEST failed.");
|
||||
return SSH_ERROR;
|
||||
@@ -308,8 +356,6 @@ pending:
|
||||
rc=SSH_AGAIN;
|
||||
break;
|
||||
case SSH_AUTH_SERVICE_NONE:
|
||||
case SSH_AUTH_SERVICE_USER_SENT:
|
||||
/* Invalid state, SSH1 specific */
|
||||
rc=SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
@@ -329,113 +375,86 @@ pending:
|
||||
* @brief A function to be called each time a step has been done in the
|
||||
* connection.
|
||||
*/
|
||||
static void ssh_client_connection_callback(ssh_session session){
|
||||
int ssh1,ssh2;
|
||||
static void ssh_client_connection_callback(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
|
||||
switch(session->session_state){
|
||||
case SSH_SESSION_STATE_NONE:
|
||||
case SSH_SESSION_STATE_CONNECTING:
|
||||
case SSH_SESSION_STATE_SOCKET_CONNECTED:
|
||||
break;
|
||||
case SSH_SESSION_STATE_BANNER_RECEIVED:
|
||||
if (session->serverbanner == NULL) {
|
||||
goto error;
|
||||
}
|
||||
set_status(session, 0.4f);
|
||||
SSH_LOG(SSH_LOG_RARE,
|
||||
"SSH server banner: %s", session->serverbanner);
|
||||
switch(session->session_state) {
|
||||
case SSH_SESSION_STATE_NONE:
|
||||
case SSH_SESSION_STATE_CONNECTING:
|
||||
break;
|
||||
case SSH_SESSION_STATE_SOCKET_CONNECTED:
|
||||
ssh_set_fd_towrite(session);
|
||||
ssh_send_banner(session, 0);
|
||||
|
||||
/* Here we analyze the different protocols the server allows. */
|
||||
if (ssh_analyze_banner(session, 0, &ssh1, &ssh2) < 0) {
|
||||
goto error;
|
||||
}
|
||||
/* Here we decide which version of the protocol to use. */
|
||||
if (ssh2 && session->opts.ssh2) {
|
||||
session->version = 2;
|
||||
#ifdef WITH_SSH1
|
||||
} else if(ssh1 && session->opts.ssh1) {
|
||||
session->version = 1;
|
||||
#endif
|
||||
} else if(ssh1 && !session->opts.ssh1){
|
||||
#ifdef WITH_SSH1
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"SSH-1 protocol not available (configure session to allow SSH-1)");
|
||||
goto error;
|
||||
#else
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"SSH-1 protocol not available (libssh compiled without SSH-1 support)");
|
||||
goto error;
|
||||
#endif
|
||||
} else {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"No version of SSH protocol usable (banner: %s)",
|
||||
session->serverbanner);
|
||||
goto error;
|
||||
}
|
||||
/* from now, the packet layer is handling incoming packets */
|
||||
if(session->version==2)
|
||||
session->socket_callbacks.data=ssh_packet_socket_callback;
|
||||
#ifdef WITH_SSH1
|
||||
else
|
||||
session->socket_callbacks.data=ssh_packet_socket_callback1;
|
||||
#endif
|
||||
ssh_packet_set_default_callbacks(session);
|
||||
session->session_state=SSH_SESSION_STATE_INITIAL_KEX;
|
||||
ssh_send_banner(session, 0);
|
||||
set_status(session, 0.5f);
|
||||
break;
|
||||
case SSH_SESSION_STATE_INITIAL_KEX:
|
||||
/* TODO: This state should disappear in favor of get_key handle */
|
||||
#ifdef WITH_SSH1
|
||||
if(session->version==1){
|
||||
if (ssh_get_kex1(session) < 0)
|
||||
goto error;
|
||||
set_status(session,0.6f);
|
||||
session->connected = 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case SSH_SESSION_STATE_KEXINIT_RECEIVED:
|
||||
set_status(session,0.6f);
|
||||
ssh_list_kex(&session->next_crypto->server_kex);
|
||||
if (set_client_kex(session) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (ssh_kex_select_methods(session) == SSH_ERROR)
|
||||
goto error;
|
||||
if (ssh_send_kex(session, 0) < 0) {
|
||||
goto error;
|
||||
}
|
||||
set_status(session,0.8f);
|
||||
session->session_state=SSH_SESSION_STATE_DH;
|
||||
if (dh_handshake(session) == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case SSH_SESSION_STATE_BANNER_RECEIVED:
|
||||
if (session->serverbanner == NULL) {
|
||||
goto error;
|
||||
}
|
||||
set_status(session, 0.4f);
|
||||
SSH_LOG(SSH_LOG_RARE,
|
||||
"SSH server banner: %s", session->serverbanner);
|
||||
|
||||
/* Here we analyze the different protocols the server allows. */
|
||||
rc = ssh_analyze_banner(session, 0);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"No version of SSH protocol usable (banner: %s)",
|
||||
session->serverbanner);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_packet_register_socket_callback(session, session->socket);
|
||||
|
||||
ssh_packet_set_default_callbacks(session);
|
||||
session->session_state = SSH_SESSION_STATE_INITIAL_KEX;
|
||||
set_status(session, 0.5f);
|
||||
|
||||
break;
|
||||
case SSH_SESSION_STATE_INITIAL_KEX:
|
||||
/* TODO: This state should disappear in favor of get_key handle */
|
||||
break;
|
||||
case SSH_SESSION_STATE_KEXINIT_RECEIVED:
|
||||
set_status(session,0.6f);
|
||||
ssh_list_kex(&session->next_crypto->server_kex);
|
||||
if (ssh_set_client_kex(session) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (ssh_kex_select_methods(session) == SSH_ERROR)
|
||||
goto error;
|
||||
if (ssh_send_kex(session, 0) < 0) {
|
||||
goto error;
|
||||
}
|
||||
set_status(session,0.8f);
|
||||
session->session_state=SSH_SESSION_STATE_DH;
|
||||
if (dh_handshake(session) == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case SSH_SESSION_STATE_DH:
|
||||
if(session->dh_handshake_state==DH_STATE_FINISHED){
|
||||
set_status(session,1.0f);
|
||||
session->connected = 1;
|
||||
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
|
||||
session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
|
||||
else
|
||||
session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
|
||||
}
|
||||
break;
|
||||
case SSH_SESSION_STATE_AUTHENTICATING:
|
||||
break;
|
||||
case SSH_SESSION_STATE_ERROR:
|
||||
goto error;
|
||||
default:
|
||||
ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state);
|
||||
}
|
||||
case SSH_SESSION_STATE_DH:
|
||||
if(session->dh_handshake_state==DH_STATE_FINISHED){
|
||||
set_status(session,1.0f);
|
||||
session->connected = 1;
|
||||
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
|
||||
session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
|
||||
else
|
||||
session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
|
||||
}
|
||||
break;
|
||||
case SSH_SESSION_STATE_AUTHENTICATING:
|
||||
break;
|
||||
case SSH_SESSION_STATE_ERROR:
|
||||
goto error;
|
||||
default:
|
||||
ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state);
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
error:
|
||||
ssh_socket_close(session->socket);
|
||||
session->alive = 0;
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
ssh_socket_close(session->socket);
|
||||
session->alive = 0;
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
|
||||
}
|
||||
|
||||
@@ -486,9 +505,6 @@ int ssh_connect(ssh_session session) {
|
||||
session->alive = 0;
|
||||
session->client = 1;
|
||||
|
||||
if (ssh_init() < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (session->opts.fd == SSH_INVALID_SOCKET &&
|
||||
session->opts.host == NULL &&
|
||||
session->opts.ProxyCommand == NULL) {
|
||||
@@ -634,19 +650,22 @@ void ssh_disconnect(ssh_session session) {
|
||||
|
||||
if (session->socket != NULL && ssh_socket_is_open(session->socket)) {
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bds",
|
||||
"bdss",
|
||||
SSH2_MSG_DISCONNECT,
|
||||
SSH2_DISCONNECT_BY_APPLICATION,
|
||||
"Bye Bye");
|
||||
"Bye Bye",
|
||||
""); /* language tag */
|
||||
if (rc != SSH_OK){
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
packet_send(session);
|
||||
ssh_packet_send(session);
|
||||
ssh_socket_close(session->socket);
|
||||
}
|
||||
error:
|
||||
session->recv_seq = 0;
|
||||
session->send_seq = 0;
|
||||
session->alive = 0;
|
||||
if (session->socket != NULL){
|
||||
ssh_socket_reset(session->socket);
|
||||
@@ -662,6 +681,13 @@ error:
|
||||
crypto_free(session->current_crypto);
|
||||
session->current_crypto=NULL;
|
||||
}
|
||||
if (session->next_crypto) {
|
||||
crypto_free(session->next_crypto);
|
||||
session->next_crypto = crypto_new();
|
||||
if (session->next_crypto == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
}
|
||||
}
|
||||
if (session->in_buffer) {
|
||||
ssh_buffer_reinit(session->in_buffer);
|
||||
}
|
||||
@@ -695,10 +721,10 @@ error:
|
||||
}
|
||||
|
||||
const char *ssh_copyright(void) {
|
||||
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2014 Aris Adamantiadis, Andreas Schneider, "
|
||||
"and libssh contributors. Distributed under the LGPL, please refer to COPYING "
|
||||
"file for information about your rights";
|
||||
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2018 "
|
||||
"Aris Adamantiadis, Andreas Schneider "
|
||||
"and libssh contributors. "
|
||||
"Distributed under the LGPL, please refer to COPYING "
|
||||
"file for information about your rights";
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
345
src/config.c
345
src/config.c
@@ -27,20 +27,32 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_GLOB_H
|
||||
# include <glob.h>
|
||||
#endif
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/options.h"
|
||||
|
||||
#define MAX_LINE_SIZE 1024
|
||||
|
||||
enum ssh_config_opcode_e {
|
||||
/* Unknown opcode */
|
||||
SOC_UNKNOWN = -3,
|
||||
/* Known and not applicable to libssh */
|
||||
SOC_NA = -2,
|
||||
/* Known but not supported by current libssh version */
|
||||
SOC_UNSUPPORTED = -1,
|
||||
SOC_HOST,
|
||||
SOC_MATCH,
|
||||
SOC_HOSTNAME,
|
||||
SOC_PORT,
|
||||
SOC_USERNAME,
|
||||
SOC_IDENTITY,
|
||||
SOC_CIPHERS,
|
||||
SOC_MACS,
|
||||
SOC_COMPRESSION,
|
||||
SOC_TIMEOUT,
|
||||
SOC_PROTOCOL,
|
||||
@@ -50,6 +62,18 @@ enum ssh_config_opcode_e {
|
||||
SOC_GSSAPISERVERIDENTITY,
|
||||
SOC_GSSAPICLIENTIDENTITY,
|
||||
SOC_GSSAPIDELEGATECREDENTIALS,
|
||||
SOC_INCLUDE,
|
||||
SOC_BINDADDRESS,
|
||||
SOC_GLOBALKNOWNHOSTSFILE,
|
||||
SOC_LOGLEVEL,
|
||||
SOC_HOSTKEYALGORITHMS,
|
||||
SOC_KEXALGORITHMS,
|
||||
SOC_GSSAPIAUTHENTICATION,
|
||||
SOC_KBDINTERACTIVEAUTHENTICATION,
|
||||
SOC_PASSWORDAUTHENTICATION,
|
||||
SOC_PUBKEYAUTHENTICATION,
|
||||
|
||||
SOC_END /* Keep this one last in the list */
|
||||
};
|
||||
|
||||
struct ssh_config_keyword_table_s {
|
||||
@@ -59,11 +83,13 @@ struct ssh_config_keyword_table_s {
|
||||
|
||||
static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
||||
{ "host", SOC_HOST },
|
||||
{ "match", SOC_MATCH },
|
||||
{ "hostname", SOC_HOSTNAME },
|
||||
{ "port", SOC_PORT },
|
||||
{ "user", SOC_USERNAME },
|
||||
{ "identityfile", SOC_IDENTITY },
|
||||
{ "ciphers", SOC_CIPHERS },
|
||||
{ "macs", SOC_MACS },
|
||||
{ "compression", SOC_COMPRESSION },
|
||||
{ "connecttimeout", SOC_TIMEOUT },
|
||||
{ "protocol", SOC_PROTOCOL },
|
||||
@@ -71,11 +97,96 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
||||
{ "userknownhostsfile", SOC_KNOWNHOSTS },
|
||||
{ "proxycommand", SOC_PROXYCOMMAND },
|
||||
{ "gssapiserveridentity", SOC_GSSAPISERVERIDENTITY },
|
||||
{ "gssapiserveridentity", SOC_GSSAPICLIENTIDENTITY },
|
||||
{ "gssapiclientidentity", SOC_GSSAPICLIENTIDENTITY },
|
||||
{ "gssapidelegatecredentials", SOC_GSSAPIDELEGATECREDENTIALS },
|
||||
{ NULL, SOC_UNSUPPORTED }
|
||||
{ "include", SOC_INCLUDE },
|
||||
{ "bindaddress", SOC_BINDADDRESS},
|
||||
{ "globalknownhostsfile", SOC_GLOBALKNOWNHOSTSFILE},
|
||||
{ "loglevel", SOC_LOGLEVEL},
|
||||
{ "hostkeyalgorithms", SOC_HOSTKEYALGORITHMS},
|
||||
{ "kexalgorithms", SOC_KEXALGORITHMS},
|
||||
{ "mac", SOC_UNSUPPORTED}, /* SSHv1 */
|
||||
{ "gssapiauthentication", SOC_GSSAPIAUTHENTICATION},
|
||||
{ "kbdinteractiveauthentication", SOC_KBDINTERACTIVEAUTHENTICATION},
|
||||
{ "passwordauthentication", SOC_PASSWORDAUTHENTICATION},
|
||||
{ "pubkeyauthentication", SOC_PUBKEYAUTHENTICATION},
|
||||
{ "addkeystoagent", SOC_UNSUPPORTED},
|
||||
{ "addressfamily", SOC_UNSUPPORTED},
|
||||
{ "batchmode", SOC_UNSUPPORTED},
|
||||
{ "canonicaldomains", SOC_UNSUPPORTED},
|
||||
{ "canonicalizefallbacklocal", SOC_UNSUPPORTED},
|
||||
{ "canonicalizehostname", SOC_UNSUPPORTED},
|
||||
{ "canonicalizemaxdots", SOC_UNSUPPORTED},
|
||||
{ "canonicalizepermittedcnames", SOC_UNSUPPORTED},
|
||||
{ "certificatefile", SOC_UNSUPPORTED},
|
||||
{ "challengeresponseauthentication", SOC_UNSUPPORTED},
|
||||
{ "checkhostip", SOC_UNSUPPORTED},
|
||||
{ "cipher", SOC_UNSUPPORTED}, /* SSHv1 */
|
||||
{ "compressionlevel", SOC_UNSUPPORTED}, /* SSHv1 */
|
||||
{ "connectionattempts", SOC_UNSUPPORTED},
|
||||
{ "enablesshkeysign", SOC_UNSUPPORTED},
|
||||
{ "fingerprinthash", SOC_UNSUPPORTED},
|
||||
{ "forwardagent", SOC_UNSUPPORTED},
|
||||
{ "gssapikeyexchange", SOC_UNSUPPORTED},
|
||||
{ "gssapirenewalforcesrekey", SOC_UNSUPPORTED},
|
||||
{ "gssapitrustdns", SOC_UNSUPPORTED},
|
||||
{ "hashknownhosts", SOC_UNSUPPORTED},
|
||||
{ "hostbasedauthentication", SOC_UNSUPPORTED},
|
||||
{ "hostbasedkeytypes", SOC_UNSUPPORTED},
|
||||
{ "hostkeyalias", SOC_UNSUPPORTED},
|
||||
{ "identitiesonly", SOC_UNSUPPORTED},
|
||||
{ "identityagent", SOC_UNSUPPORTED},
|
||||
{ "ipqos", SOC_UNSUPPORTED},
|
||||
{ "kbdinteractivedevices", SOC_UNSUPPORTED},
|
||||
{ "nohostauthenticationforlocalhost", SOC_UNSUPPORTED},
|
||||
{ "numberofpasswordprompts", SOC_UNSUPPORTED},
|
||||
{ "pkcs11provider", SOC_UNSUPPORTED},
|
||||
{ "preferredauthentications", SOC_UNSUPPORTED},
|
||||
{ "proxyjump", SOC_UNSUPPORTED},
|
||||
{ "proxyusefdpass", SOC_UNSUPPORTED},
|
||||
{ "pubkeyacceptedtypes", SOC_UNSUPPORTED},
|
||||
{ "rekeylimit", SOC_UNSUPPORTED},
|
||||
{ "remotecommand", SOC_UNSUPPORTED},
|
||||
{ "revokedhostkeys", SOC_UNSUPPORTED},
|
||||
{ "rhostsrsaauthentication", SOC_UNSUPPORTED},
|
||||
{ "rsaauthentication", SOC_UNSUPPORTED}, /* SSHv1 */
|
||||
{ "serveralivecountmax", SOC_UNSUPPORTED},
|
||||
{ "serveraliveinterval", SOC_UNSUPPORTED},
|
||||
{ "streamlocalbindmask", SOC_UNSUPPORTED},
|
||||
{ "streamlocalbindunlink", SOC_UNSUPPORTED},
|
||||
{ "syslogfacility", SOC_UNSUPPORTED},
|
||||
{ "tcpkeepalive", SOC_UNSUPPORTED},
|
||||
{ "updatehostkeys", SOC_UNSUPPORTED},
|
||||
{ "useprivilegedport", SOC_UNSUPPORTED},
|
||||
{ "verifyhostkeydns", SOC_UNSUPPORTED},
|
||||
{ "visualhostkey", SOC_UNSUPPORTED},
|
||||
{ "clearallforwardings", SOC_NA},
|
||||
{ "controlmaster", SOC_NA},
|
||||
{ "controlpersist", SOC_NA},
|
||||
{ "controlpath", SOC_NA},
|
||||
{ "dynamicforward", SOC_NA},
|
||||
{ "escapechar", SOC_NA},
|
||||
{ "exitonforwardfailure", SOC_NA},
|
||||
{ "forwardx11", SOC_NA},
|
||||
{ "forwardx11timeout", SOC_NA},
|
||||
{ "forwardx11trusted", SOC_NA},
|
||||
{ "gatewayports", SOC_NA},
|
||||
{ "ignoreunknown", SOC_NA},
|
||||
{ "localcommand", SOC_NA},
|
||||
{ "localforward", SOC_NA},
|
||||
{ "permitlocalcommand", SOC_NA},
|
||||
{ "remoteforward", SOC_NA},
|
||||
{ "requesttty", SOC_NA},
|
||||
{ "sendenv", SOC_NA},
|
||||
{ "tunnel", SOC_NA},
|
||||
{ "tunneldevice", SOC_NA},
|
||||
{ "xauthlocation", SOC_NA},
|
||||
{ NULL, SOC_UNKNOWN }
|
||||
};
|
||||
|
||||
static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
unsigned int count, int *parsing, int seen[]);
|
||||
|
||||
static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
|
||||
int i;
|
||||
|
||||
@@ -85,7 +196,7 @@ static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
|
||||
}
|
||||
}
|
||||
|
||||
return SOC_UNSUPPORTED;
|
||||
return SOC_UNKNOWN;
|
||||
}
|
||||
|
||||
static char *ssh_config_get_cmd(char **str) {
|
||||
@@ -140,9 +251,9 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ssh_config_get_int(char **str, int notfound) {
|
||||
static long ssh_config_get_long(char **str, long notfound) {
|
||||
char *p, *endp;
|
||||
int i;
|
||||
long i;
|
||||
|
||||
p = ssh_config_get_token(str);
|
||||
if (p && *p) {
|
||||
@@ -184,8 +295,63 @@ static int ssh_config_get_yesno(char **str, int notfound) {
|
||||
return notfound;
|
||||
}
|
||||
|
||||
static void local_parse_file(ssh_session session, const char *filename, int *parsing, int seen[]) {
|
||||
FILE *f;
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
unsigned int count = 0;
|
||||
|
||||
if ((f = fopen(filename, "r")) == NULL) {
|
||||
SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
|
||||
filename);
|
||||
return;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Reading additional configuration data from %s", filename);
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
count++;
|
||||
if (ssh_config_parse_line(session, line, count, parsing, seen) < 0) {
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GLOB
|
||||
static void local_parse_glob(ssh_session session,
|
||||
const char *fileglob,
|
||||
int *parsing,
|
||||
int seen[])
|
||||
{
|
||||
glob_t globbuf = {
|
||||
.gl_flags = 0,
|
||||
};
|
||||
int rt;
|
||||
u_int i;
|
||||
|
||||
rt = glob(fileglob, GLOB_TILDE, NULL, &globbuf);
|
||||
if (rt == GLOB_NOMATCH) {
|
||||
globfree(&globbuf);
|
||||
return;
|
||||
} else if (rt != 0) {
|
||||
SSH_LOG(SSH_LOG_RARE, "Glob error: %s",
|
||||
fileglob);
|
||||
globfree(&globbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < globbuf.gl_pathc; i++) {
|
||||
local_parse_file(session, globbuf.gl_pathv[i], parsing, seen);
|
||||
}
|
||||
|
||||
globfree(&globbuf);
|
||||
}
|
||||
#endif /* HAVE_GLOB */
|
||||
|
||||
static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
unsigned int count, int *parsing) {
|
||||
unsigned int count, int *parsing, int seen[]) {
|
||||
enum ssh_config_opcode_e opcode;
|
||||
const char *p;
|
||||
char *s, *x;
|
||||
@@ -193,6 +359,7 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
char *lowerhost;
|
||||
size_t len;
|
||||
int i;
|
||||
long l;
|
||||
|
||||
x = s = strdup(line);
|
||||
if (s == NULL) {
|
||||
@@ -216,42 +383,63 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
}
|
||||
|
||||
opcode = ssh_config_get_opcode(keyword);
|
||||
if (*parsing == 1 && opcode != SOC_HOST && opcode != SOC_UNSUPPORTED && opcode != SOC_INCLUDE) {
|
||||
if (seen[opcode] != 0) {
|
||||
SAFE_FREE(x);
|
||||
return 0;
|
||||
}
|
||||
seen[opcode] = 1;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case SOC_HOST:
|
||||
case SOC_INCLUDE: /* recursive include of other files */
|
||||
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
#ifdef HAVE_GLOB
|
||||
local_parse_glob(session, p, parsing, seen);
|
||||
#else
|
||||
local_parse_file(session, p, parsing, seen);
|
||||
#endif /* HAVE_GLOB */
|
||||
}
|
||||
break;
|
||||
case SOC_HOST: {
|
||||
int ok = 0;
|
||||
|
||||
*parsing = 0;
|
||||
lowerhost = (session->opts.host) ? ssh_lowercase(session->opts.host) : NULL;
|
||||
for (p = ssh_config_get_str_tok(&s, NULL);
|
||||
p != NULL && p[0] != '\0';
|
||||
p = ssh_config_get_str_tok(&s, NULL)) {
|
||||
char *z = ssh_path_expand_escape(session, p);
|
||||
int ok;
|
||||
|
||||
if (z == NULL) {
|
||||
z = strdup(p);
|
||||
if (ok >= 0) {
|
||||
ok = match_hostname(lowerhost, p, strlen(p));
|
||||
if (ok < 0) {
|
||||
*parsing = 0;
|
||||
} else if (ok > 0) {
|
||||
*parsing = 1;
|
||||
}
|
||||
}
|
||||
ok = match_hostname(lowerhost, z, strlen(z));
|
||||
if (ok) {
|
||||
*parsing = 1;
|
||||
}
|
||||
free(z);
|
||||
}
|
||||
SAFE_FREE(lowerhost);
|
||||
break;
|
||||
}
|
||||
case SOC_HOSTNAME:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, p);
|
||||
char *z = ssh_path_expand_escape(session, p);
|
||||
if (z == NULL) {
|
||||
z = strdup(p);
|
||||
}
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, z);
|
||||
free(z);
|
||||
}
|
||||
break;
|
||||
case SOC_PORT:
|
||||
if (session->opts.port == 0) {
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
|
||||
}
|
||||
break;
|
||||
case SOC_USERNAME:
|
||||
if (session->opts.username == NULL) {
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
@@ -273,6 +461,13 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, p);
|
||||
}
|
||||
break;
|
||||
case SOC_MACS:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_HMAC_C_S, p);
|
||||
ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, p);
|
||||
}
|
||||
break;
|
||||
case SOC_COMPRESSION:
|
||||
i = ssh_config_get_yesno(&s, -1);
|
||||
if (i >= 0 && *parsing) {
|
||||
@@ -294,14 +489,11 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
return -1;
|
||||
}
|
||||
i = 0;
|
||||
ssh_options_set(session, SSH_OPTIONS_SSH1, &i);
|
||||
ssh_options_set(session, SSH_OPTIONS_SSH2, &i);
|
||||
|
||||
for (a = strtok(b, ","); a; a = strtok(NULL, ",")) {
|
||||
switch (atoi(a)) {
|
||||
case 1:
|
||||
i = 1;
|
||||
ssh_options_set(session, SSH_OPTIONS_SSH1, &i);
|
||||
break;
|
||||
case 2:
|
||||
i = 1;
|
||||
@@ -315,9 +507,9 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
}
|
||||
break;
|
||||
case SOC_TIMEOUT:
|
||||
i = ssh_config_get_int(&s, -1);
|
||||
if (i >= 0 && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &i);
|
||||
l = ssh_config_get_long(&s, -1);
|
||||
if (l >= 0 && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &l);
|
||||
}
|
||||
break;
|
||||
case SOC_STRICTHOSTKEYCHECK:
|
||||
@@ -356,12 +548,94 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
ssh_options_set(session, SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS, &i);
|
||||
}
|
||||
break;
|
||||
case SOC_BINDADDRESS:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_BINDADDR, p);
|
||||
}
|
||||
break;
|
||||
case SOC_GLOBALKNOWNHOSTSFILE:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, p);
|
||||
}
|
||||
break;
|
||||
case SOC_LOGLEVEL:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
int value = -1;
|
||||
|
||||
if (strcasecmp(p, "quiet") == 0) {
|
||||
value = SSH_LOG_NONE;
|
||||
} else if (strcasecmp(p, "fatal") == 0 ||
|
||||
strcasecmp(p, "error")== 0 ||
|
||||
strcasecmp(p, "info") == 0) {
|
||||
value = SSH_LOG_WARN;
|
||||
} else if (strcasecmp(p, "verbose") == 0) {
|
||||
value = SSH_LOG_INFO;
|
||||
} else if (strcasecmp(p, "DEBUG") == 0 ||
|
||||
strcasecmp(p, "DEBUG1") == 0) {
|
||||
value = SSH_LOG_DEBUG;
|
||||
} else if (strcasecmp(p, "DEBUG2") == 0 ||
|
||||
strcasecmp(p, "DEBUG3") == 0) {
|
||||
value = SSH_LOG_TRACE;
|
||||
}
|
||||
if (value != -1) {
|
||||
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SOC_HOSTKEYALGORITHMS:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, p);
|
||||
}
|
||||
break;
|
||||
case SOC_KEXALGORITHMS:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, p);
|
||||
}
|
||||
break;
|
||||
case SOC_GSSAPIAUTHENTICATION:
|
||||
case SOC_KBDINTERACTIVEAUTHENTICATION:
|
||||
case SOC_PASSWORDAUTHENTICATION:
|
||||
case SOC_PUBKEYAUTHENTICATION:
|
||||
i = ssh_config_get_yesno(&s, 0);
|
||||
if (i>=0 && *parsing) {
|
||||
switch(opcode){
|
||||
case SOC_GSSAPIAUTHENTICATION:
|
||||
ssh_options_set(session, SSH_OPTIONS_GSSAPI_AUTH, &i);
|
||||
break;
|
||||
case SOC_KBDINTERACTIVEAUTHENTICATION:
|
||||
ssh_options_set(session, SSH_OPTIONS_KBDINT_AUTH, &i);
|
||||
break;
|
||||
case SOC_PASSWORDAUTHENTICATION:
|
||||
ssh_options_set(session, SSH_OPTIONS_PASSWORD_AUTH, &i);
|
||||
break;
|
||||
case SOC_PUBKEYAUTHENTICATION:
|
||||
ssh_options_set(session, SSH_OPTIONS_PUBKEY_AUTH, &i);
|
||||
break;
|
||||
/* make gcc happy */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SOC_NA:
|
||||
SSH_LOG(SSH_LOG_INFO, "Unapplicable option: %s, line: %d\n",
|
||||
keyword, count);
|
||||
break;
|
||||
case SOC_UNSUPPORTED:
|
||||
SSH_LOG(SSH_LOG_RARE, "Unsupported option: %s, line: %d\n",
|
||||
SSH_LOG(SSH_LOG_RARE, "Unsupported option: %s, line: %d",
|
||||
keyword, count);
|
||||
break;
|
||||
case SOC_UNKNOWN:
|
||||
SSH_LOG(SSH_LOG_WARN, "Unknown option: %s, line: %d\n",
|
||||
keyword, count);
|
||||
break;
|
||||
default:
|
||||
ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d\n",
|
||||
ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d",
|
||||
opcode);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
@@ -374,10 +648,11 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
|
||||
/* ssh_config_parse_file */
|
||||
int ssh_config_parse_file(ssh_session session, const char *filename) {
|
||||
char line[1024] = {0};
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
unsigned int count = 0;
|
||||
FILE *f;
|
||||
int parsing;
|
||||
int seen[SOC_END - SOC_UNSUPPORTED] = {0};
|
||||
|
||||
if ((f = fopen(filename, "r")) == NULL) {
|
||||
return 0;
|
||||
@@ -388,7 +663,7 @@ int ssh_config_parse_file(ssh_session session, const char *filename) {
|
||||
parsing = 1;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
count++;
|
||||
if (ssh_config_parse_line(session, line, count, &parsing) < 0) {
|
||||
if (ssh_config_parse_line(session, line, count, &parsing, seen) < 0) {
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
@@ -203,7 +204,7 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host,
|
||||
}
|
||||
|
||||
/* s is connected ? */
|
||||
SSH_LOG(SSH_LOG_PACKET, "Socket connected with timeout\n");
|
||||
SSH_LOG(SSH_LOG_PACKET, "Socket connected with timeout");
|
||||
ret = ssh_socket_set_blocking(s);
|
||||
if (ret < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
@@ -216,6 +217,12 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host,
|
||||
return s;
|
||||
}
|
||||
|
||||
static int set_tcp_nodelay(socket_t socket)
|
||||
{
|
||||
int opt = 1;
|
||||
return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
@@ -252,7 +259,7 @@ socket_t ssh_connect_host(ssh_session session, const char *host,
|
||||
struct addrinfo *bind_ai;
|
||||
struct addrinfo *bind_itr;
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s\n", bind_addr);
|
||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
||||
|
||||
rc = getai(bind_addr, 0, &bind_ai);
|
||||
if (rc != 0) {
|
||||
@@ -346,7 +353,7 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
struct addrinfo *bind_ai;
|
||||
struct addrinfo *bind_itr;
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s\n", bind_addr);
|
||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
||||
|
||||
rc = getai(bind_addr, 0, &bind_ai);
|
||||
if (rc != 0) {
|
||||
@@ -387,6 +394,18 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (session->opts.nodelay) {
|
||||
/* For winsock, socket options are only effective before connect */
|
||||
rc = set_tcp_nodelay(s);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set TCP_NODELAY on socket: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
|
||||
if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
|
||||
@@ -518,5 +537,3 @@ out:
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
636
src/connector.c
Normal file
636
src/connector.c
Normal file
@@ -0,0 +1,636 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2015 by Aris Adamantiadis <aris@badcode.be>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/poll.h"
|
||||
#include "libssh/callbacks.h"
|
||||
#include "libssh/session.h"
|
||||
#include <stdlib.h>
|
||||
#define CHUNKSIZE 4096
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef HAVE_IO_H
|
||||
# include <io.h>
|
||||
# undef open
|
||||
# define open _open
|
||||
# undef close
|
||||
# define close _close
|
||||
# undef read
|
||||
# define read _read
|
||||
# undef unlink
|
||||
# define unlink _unlink
|
||||
# endif /* HAVE_IO_H */
|
||||
#endif
|
||||
|
||||
struct ssh_connector_struct {
|
||||
ssh_session session;
|
||||
|
||||
ssh_channel in_channel;
|
||||
ssh_channel out_channel;
|
||||
|
||||
socket_t in_fd;
|
||||
socket_t out_fd;
|
||||
|
||||
ssh_poll_handle in_poll;
|
||||
ssh_poll_handle out_poll;
|
||||
|
||||
ssh_event event;
|
||||
|
||||
int in_available;
|
||||
int out_wontblock;
|
||||
|
||||
struct ssh_channel_callbacks_struct in_channel_cb;
|
||||
struct ssh_channel_callbacks_struct out_channel_cb;
|
||||
|
||||
enum ssh_connector_flags_e in_flags;
|
||||
enum ssh_connector_flags_e out_flags;
|
||||
};
|
||||
|
||||
static int ssh_connector_channel_data_cb(ssh_session session,
|
||||
ssh_channel channel,
|
||||
void *data,
|
||||
uint32_t len,
|
||||
int is_stderr,
|
||||
void *userdata);
|
||||
static int ssh_connector_channel_write_wontblock_cb(ssh_session session,
|
||||
ssh_channel channel,
|
||||
size_t bytes,
|
||||
void *userdata);
|
||||
|
||||
ssh_connector ssh_connector_new(ssh_session session)
|
||||
{
|
||||
ssh_connector connector;
|
||||
|
||||
connector = calloc(1, sizeof(struct ssh_connector_struct));
|
||||
if (connector == NULL){
|
||||
ssh_set_error_oom(session);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
connector->session = session;
|
||||
connector->in_fd = SSH_INVALID_SOCKET;
|
||||
connector->out_fd = SSH_INVALID_SOCKET;
|
||||
|
||||
ssh_callbacks_init(&connector->in_channel_cb);
|
||||
ssh_callbacks_init(&connector->out_channel_cb);
|
||||
|
||||
connector->in_channel_cb.userdata = connector;
|
||||
connector->in_channel_cb.channel_data_function = ssh_connector_channel_data_cb;
|
||||
|
||||
connector->out_channel_cb.userdata = connector;
|
||||
connector->out_channel_cb.channel_write_wontblock_function =
|
||||
ssh_connector_channel_write_wontblock_cb;
|
||||
|
||||
return connector;
|
||||
}
|
||||
|
||||
void ssh_connector_free (ssh_connector connector)
|
||||
{
|
||||
if (connector->in_channel != NULL) {
|
||||
ssh_remove_channel_callbacks(connector->in_channel,
|
||||
&connector->in_channel_cb);
|
||||
}
|
||||
if (connector->out_channel != NULL) {
|
||||
ssh_remove_channel_callbacks(connector->out_channel,
|
||||
&connector->out_channel_cb);
|
||||
}
|
||||
|
||||
if (connector->event != NULL){
|
||||
ssh_connector_remove_event(connector);
|
||||
}
|
||||
|
||||
if (connector->in_poll != NULL) {
|
||||
ssh_poll_free(connector->in_poll);
|
||||
connector->in_poll = NULL;
|
||||
}
|
||||
|
||||
if (connector->out_poll != NULL) {
|
||||
ssh_poll_free(connector->out_poll);
|
||||
connector->out_poll = NULL;
|
||||
}
|
||||
|
||||
free(connector);
|
||||
}
|
||||
|
||||
int ssh_connector_set_in_channel(ssh_connector connector,
|
||||
ssh_channel channel,
|
||||
enum ssh_connector_flags_e flags)
|
||||
{
|
||||
connector->in_channel = channel;
|
||||
connector->in_fd = SSH_INVALID_SOCKET;
|
||||
connector->in_flags = flags;
|
||||
|
||||
/* Fallback to default value for invalid flags */
|
||||
if (!(flags & SSH_CONNECTOR_STDOUT) && !(flags & SSH_CONNECTOR_STDERR)) {
|
||||
connector->in_flags = SSH_CONNECTOR_STDOUT;
|
||||
}
|
||||
|
||||
return ssh_add_channel_callbacks(channel, &connector->in_channel_cb);
|
||||
}
|
||||
|
||||
int ssh_connector_set_out_channel(ssh_connector connector,
|
||||
ssh_channel channel,
|
||||
enum ssh_connector_flags_e flags)
|
||||
{
|
||||
connector->out_channel = channel;
|
||||
connector->out_fd = SSH_INVALID_SOCKET;
|
||||
connector->out_flags = flags;
|
||||
|
||||
/* Fallback to default value for invalid flags */
|
||||
if (!(flags & SSH_CONNECTOR_STDOUT) && !(flags & SSH_CONNECTOR_STDERR)) {
|
||||
connector->in_flags = SSH_CONNECTOR_STDOUT;
|
||||
}
|
||||
|
||||
return ssh_add_channel_callbacks(channel, &connector->out_channel_cb);
|
||||
}
|
||||
|
||||
void ssh_connector_set_in_fd(ssh_connector connector, socket_t fd)
|
||||
{
|
||||
connector->in_fd = fd;
|
||||
connector->in_channel = NULL;
|
||||
}
|
||||
|
||||
void ssh_connector_set_out_fd(ssh_connector connector, socket_t fd)
|
||||
{
|
||||
connector->out_fd = fd;
|
||||
connector->out_channel = NULL;
|
||||
}
|
||||
|
||||
/* TODO */
|
||||
static void ssh_connector_except(ssh_connector connector, socket_t fd)
|
||||
{
|
||||
(void) connector;
|
||||
(void) fd;
|
||||
}
|
||||
|
||||
/* TODO */
|
||||
static void ssh_connector_except_channel(ssh_connector connector,
|
||||
ssh_channel channel)
|
||||
{
|
||||
(void) connector;
|
||||
(void) channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Reset the poll events to be followed for each file descriptors.
|
||||
*/
|
||||
static void ssh_connector_reset_pollevents(ssh_connector connector)
|
||||
{
|
||||
if (connector->in_fd != SSH_INVALID_SOCKET) {
|
||||
if (connector->in_available) {
|
||||
ssh_poll_remove_events(connector->in_poll, POLLIN);
|
||||
} else {
|
||||
ssh_poll_add_events(connector->in_poll, POLLIN);
|
||||
}
|
||||
}
|
||||
|
||||
if (connector->out_fd != SSH_INVALID_SOCKET) {
|
||||
if (connector->out_wontblock) {
|
||||
ssh_poll_remove_events(connector->out_poll, POLLOUT);
|
||||
} else {
|
||||
ssh_poll_add_events(connector->out_poll, POLLOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Callback called when a poll event is received on an input fd.
|
||||
*/
|
||||
static void ssh_connector_fd_in_cb(ssh_connector connector)
|
||||
{
|
||||
unsigned char buffer[CHUNKSIZE];
|
||||
int r;
|
||||
int toread = CHUNKSIZE;
|
||||
int w;
|
||||
int total = 0;
|
||||
int rc;
|
||||
|
||||
SSH_LOG(SSH_LOG_TRACE, "connector POLLIN event for fd %d", connector->in_fd);
|
||||
|
||||
if (connector->out_wontblock) {
|
||||
if (connector->out_channel != NULL) {
|
||||
size_t size = ssh_channel_window_size(connector->out_channel);
|
||||
|
||||
/* Don't attempt reading more than the window */
|
||||
toread = MIN(size, CHUNKSIZE);
|
||||
}
|
||||
|
||||
r = read(connector->in_fd, buffer, toread);
|
||||
if (r < 0) {
|
||||
ssh_connector_except(connector, connector->in_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (connector->out_channel != NULL) {
|
||||
if (r == 0) {
|
||||
rc = ssh_channel_send_eof(connector->out_channel);
|
||||
(void)rc; /* TODO Handle rc? */
|
||||
} else if (r> 0) {
|
||||
/* loop around ssh_channel_write in case our window reduced due to a race */
|
||||
while (total != r){
|
||||
if (connector->out_flags & SSH_CONNECTOR_STDOUT) {
|
||||
w = ssh_channel_write(connector->out_channel,
|
||||
buffer + total,
|
||||
r - total);
|
||||
} else {
|
||||
w = ssh_channel_write_stderr(connector->out_channel,
|
||||
buffer + total,
|
||||
r - total);
|
||||
}
|
||||
if (w == SSH_ERROR) {
|
||||
return;
|
||||
}
|
||||
total += w;
|
||||
}
|
||||
}
|
||||
} else if (connector->out_fd != SSH_INVALID_SOCKET) {
|
||||
if (r == 0){
|
||||
close (connector->out_fd);
|
||||
connector->out_fd = SSH_INVALID_SOCKET;
|
||||
} else {
|
||||
/*
|
||||
* Loop around write in case the write blocks even for CHUNKSIZE
|
||||
* bytes
|
||||
*/
|
||||
while (total != r) {
|
||||
w = write(connector->out_fd, buffer + total, r - total);
|
||||
if (w < 0){
|
||||
ssh_connector_except(connector, connector->out_fd);
|
||||
return;
|
||||
}
|
||||
total += w;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ssh_set_error(connector->session, SSH_FATAL, "output socket or channel closed");
|
||||
return;
|
||||
}
|
||||
connector->out_wontblock = 0;
|
||||
connector->in_available = 0;
|
||||
} else {
|
||||
connector->in_available = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief Callback called when a poll event is received on an output fd
|
||||
*/
|
||||
static void ssh_connector_fd_out_cb(ssh_connector connector){
|
||||
unsigned char buffer[CHUNKSIZE];
|
||||
int r;
|
||||
int w;
|
||||
int total = 0;
|
||||
SSH_LOG(SSH_LOG_TRACE, "connector POLLOUT event for fd %d", connector->out_fd);
|
||||
|
||||
if(connector->in_available){
|
||||
if (connector->in_channel != NULL){
|
||||
r = ssh_channel_read_nonblocking(connector->in_channel, buffer, CHUNKSIZE, 0);
|
||||
if(r == SSH_ERROR){
|
||||
ssh_connector_except_channel(connector, connector->in_channel);
|
||||
return;
|
||||
} else if(r == 0 && ssh_channel_is_eof(connector->in_channel)){
|
||||
close(connector->out_fd);
|
||||
connector->out_fd = SSH_INVALID_SOCKET;
|
||||
return;
|
||||
} else if(r>0) {
|
||||
/* loop around write in case the write blocks even for CHUNKSIZE bytes */
|
||||
while (total != r){
|
||||
w = write(connector->out_fd, buffer + total, r - total);
|
||||
if (w < 0){
|
||||
ssh_connector_except(connector, connector->out_fd);
|
||||
return;
|
||||
}
|
||||
total += w;
|
||||
}
|
||||
}
|
||||
} else if (connector->in_fd != SSH_INVALID_SOCKET){
|
||||
/* fallback on the socket input callback */
|
||||
connector->out_wontblock = 1;
|
||||
ssh_connector_fd_in_cb(connector);
|
||||
} else {
|
||||
ssh_set_error(connector->session,
|
||||
SSH_FATAL,
|
||||
"Output socket or channel closed");
|
||||
return;
|
||||
}
|
||||
connector->in_available = 0;
|
||||
connector->out_wontblock = 0;
|
||||
} else {
|
||||
connector->out_wontblock = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Callback called when a poll event is received on a file descriptor.
|
||||
*
|
||||
* This is for (input or output.
|
||||
*
|
||||
* @param[in] fd file descriptor receiving the event
|
||||
*
|
||||
* @param[in] revents received Poll(2) events
|
||||
*
|
||||
* @param[in] userdata connector
|
||||
*
|
||||
* @returns 0
|
||||
*/
|
||||
static int ssh_connector_fd_cb(ssh_poll_handle p,
|
||||
socket_t fd,
|
||||
int revents,
|
||||
void *userdata)
|
||||
{
|
||||
ssh_connector connector = userdata;
|
||||
|
||||
(void)p;
|
||||
|
||||
if (revents & POLLERR) {
|
||||
ssh_connector_except(connector, fd);
|
||||
} else if((revents & (POLLIN|POLLHUP)) && fd == connector->in_fd) {
|
||||
ssh_connector_fd_in_cb(connector);
|
||||
} else if(((revents & POLLOUT) || (revents & POLLHUP)) &&
|
||||
fd == connector->out_fd) {
|
||||
ssh_connector_fd_out_cb(connector);
|
||||
}
|
||||
ssh_connector_reset_pollevents(connector);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Callback called when data is received on channel.
|
||||
*
|
||||
* @param[in] data Pointer to the data
|
||||
*
|
||||
* @param[in] len Length of data
|
||||
*
|
||||
* @param[in] is_stderr Set to 1 if the data are out of band
|
||||
*
|
||||
* @param[in] userdata The ssh connector
|
||||
*
|
||||
* @returns Amount of data bytes consumed
|
||||
*/
|
||||
static int ssh_connector_channel_data_cb(ssh_session session,
|
||||
ssh_channel channel,
|
||||
void *data,
|
||||
uint32_t len,
|
||||
int is_stderr,
|
||||
void *userdata)
|
||||
{
|
||||
ssh_connector connector = userdata;
|
||||
int w;
|
||||
size_t window;
|
||||
|
||||
(void) session;
|
||||
(void) channel;
|
||||
(void) is_stderr;
|
||||
|
||||
SSH_LOG(SSH_LOG_TRACE,"connector data on channel");
|
||||
|
||||
if (is_stderr && !(connector->in_flags & SSH_CONNECTOR_STDERR)) {
|
||||
/* ignore stderr */
|
||||
return 0;
|
||||
} else if (!is_stderr && !(connector->in_flags & SSH_CONNECTOR_STDOUT)) {
|
||||
/* ignore stdout */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (connector->out_wontblock) {
|
||||
if (connector->out_channel != NULL) {
|
||||
int window_len;
|
||||
|
||||
window = ssh_channel_window_size(connector->out_channel);
|
||||
window_len = MIN(window, len);
|
||||
|
||||
/* Route the data to the right exception channel */
|
||||
if (is_stderr && (connector->out_flags & SSH_CONNECTOR_STDERR)) {
|
||||
w = ssh_channel_write_stderr(connector->out_channel,
|
||||
data,
|
||||
window_len);
|
||||
} else if (!is_stderr &&
|
||||
(connector->out_flags & SSH_CONNECTOR_STDOUT)) {
|
||||
w = ssh_channel_write(connector->out_channel,
|
||||
data,
|
||||
window_len);
|
||||
} else if (connector->out_flags & SSH_CONNECTOR_STDOUT) {
|
||||
w = ssh_channel_write(connector->out_channel,
|
||||
data,
|
||||
window_len);
|
||||
} else {
|
||||
w = ssh_channel_write_stderr(connector->out_channel,
|
||||
data,
|
||||
window_len);
|
||||
}
|
||||
if (w == SSH_ERROR) {
|
||||
ssh_connector_except_channel(connector, connector->out_channel);
|
||||
}
|
||||
} else if (connector->out_fd != SSH_INVALID_SOCKET) {
|
||||
w = write(connector->out_fd, data, len);
|
||||
if (w < 0)
|
||||
ssh_connector_except(connector, connector->out_fd);
|
||||
} else {
|
||||
ssh_set_error(session, SSH_FATAL, "output socket or channel closed");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
connector->out_wontblock = 0;
|
||||
connector->in_available = 0;
|
||||
if ((unsigned int)w < len) {
|
||||
connector->in_available = 1;
|
||||
}
|
||||
ssh_connector_reset_pollevents(connector);
|
||||
|
||||
return w;
|
||||
} else {
|
||||
connector->in_available = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Callback called when the channel is free to write.
|
||||
*
|
||||
* @param[in] bytes Amount of bytes that can be written without blocking
|
||||
*
|
||||
* @param[in] userdata The ssh connector
|
||||
*
|
||||
* @returns Amount of data bytes consumed
|
||||
*/
|
||||
static int ssh_connector_channel_write_wontblock_cb(ssh_session session,
|
||||
ssh_channel channel,
|
||||
size_t bytes,
|
||||
void *userdata)
|
||||
{
|
||||
ssh_connector connector = userdata;
|
||||
uint8_t buffer[CHUNKSIZE];
|
||||
int r, w;
|
||||
|
||||
(void) channel;
|
||||
|
||||
SSH_LOG(SSH_LOG_TRACE, "Channel write won't block");
|
||||
if (connector->in_available) {
|
||||
if (connector->in_channel != NULL) {
|
||||
size_t len = MIN(CHUNKSIZE, bytes);
|
||||
|
||||
r = ssh_channel_read_nonblocking(connector->in_channel,
|
||||
buffer,
|
||||
len,
|
||||
0);
|
||||
if (r == SSH_ERROR) {
|
||||
ssh_connector_except_channel(connector, connector->in_channel);
|
||||
} else if(r == 0 && ssh_channel_is_eof(connector->in_channel)){
|
||||
ssh_channel_send_eof(connector->out_channel);
|
||||
} else if (r > 0) {
|
||||
w = ssh_channel_write(connector->out_channel, buffer, r);
|
||||
if (w == SSH_ERROR) {
|
||||
ssh_connector_except_channel(connector,
|
||||
connector->out_channel);
|
||||
}
|
||||
}
|
||||
} else if (connector->in_fd != SSH_INVALID_SOCKET) {
|
||||
/* fallback on on the socket input callback */
|
||||
connector->out_wontblock = 1;
|
||||
ssh_connector_fd_in_cb(connector);
|
||||
ssh_connector_reset_pollevents(connector);
|
||||
} else {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Output socket or channel closed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
connector->in_available = 0;
|
||||
connector->out_wontblock = 0;
|
||||
} else {
|
||||
connector->out_wontblock = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ssh_connector_set_event(ssh_connector connector, ssh_event event)
|
||||
{
|
||||
int rc = SSH_OK;
|
||||
|
||||
if ((connector->in_fd == SSH_INVALID_SOCKET &&
|
||||
connector->in_channel == NULL)
|
||||
|| (connector->out_fd == SSH_INVALID_SOCKET &&
|
||||
connector->out_channel == NULL)) {
|
||||
rc = SSH_ERROR;
|
||||
ssh_set_error(connector->session,SSH_FATAL,"Connector not complete");
|
||||
goto error;
|
||||
}
|
||||
|
||||
connector->event = event;
|
||||
if (connector->in_fd != SSH_INVALID_SOCKET) {
|
||||
if (connector->in_poll == NULL) {
|
||||
connector->in_poll = ssh_poll_new(connector->in_fd,
|
||||
POLLIN|POLLERR,
|
||||
ssh_connector_fd_cb,
|
||||
connector);
|
||||
}
|
||||
rc = ssh_event_add_poll(event, connector->in_poll);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (connector->out_fd != SSH_INVALID_SOCKET) {
|
||||
if (connector->out_poll == NULL) {
|
||||
connector->out_poll = ssh_poll_new(connector->out_fd,
|
||||
POLLOUT|POLLERR,
|
||||
ssh_connector_fd_cb,
|
||||
connector);
|
||||
}
|
||||
|
||||
rc = ssh_event_add_poll(event, connector->out_poll);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (connector->in_channel != NULL) {
|
||||
rc = ssh_event_add_session(event,
|
||||
ssh_channel_get_session(connector->in_channel));
|
||||
if (rc != SSH_OK)
|
||||
goto error;
|
||||
if (ssh_channel_poll_timeout(connector->in_channel, 0, 0) > 0){
|
||||
connector->in_available = 1;
|
||||
}
|
||||
}
|
||||
if(connector->out_channel != NULL) {
|
||||
ssh_session session = ssh_channel_get_session(connector->out_channel);
|
||||
|
||||
rc = ssh_event_add_session(event, session);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
if (ssh_channel_window_size(connector->out_channel) > 0) {
|
||||
connector->out_wontblock = 1;
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ssh_connector_remove_event(ssh_connector connector) {
|
||||
ssh_session session;
|
||||
|
||||
if (connector->in_poll != NULL) {
|
||||
ssh_event_remove_poll(connector->event, connector->in_poll);
|
||||
ssh_poll_free(connector->in_poll);
|
||||
connector->in_poll = NULL;
|
||||
}
|
||||
|
||||
if (connector->out_poll != NULL) {
|
||||
ssh_event_remove_poll(connector->event, connector->out_poll);
|
||||
ssh_poll_free(connector->out_poll);
|
||||
connector->out_poll = NULL;
|
||||
}
|
||||
|
||||
if (connector->in_channel != NULL) {
|
||||
session = ssh_channel_get_session(connector->in_channel);
|
||||
|
||||
ssh_event_remove_session(connector->event, session);
|
||||
connector->in_channel = NULL;
|
||||
}
|
||||
|
||||
if (connector->out_channel != NULL) {
|
||||
session = ssh_channel_get_session(connector->out_channel);
|
||||
|
||||
ssh_event_remove_session(connector->event, session);
|
||||
connector->out_channel = NULL;
|
||||
}
|
||||
connector->event = NULL;
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
95
src/crc32.c
95
src/crc32.c
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* crc32.c - simple CRC32 code
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2005 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/crc32.h"
|
||||
|
||||
static uint32_t crc_table[] = {
|
||||
0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
|
||||
0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
|
||||
0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
|
||||
0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
|
||||
0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
|
||||
0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
|
||||
0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
|
||||
0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
|
||||
0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
|
||||
0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
|
||||
0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
|
||||
0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
|
||||
0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
|
||||
0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
|
||||
0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
|
||||
0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
|
||||
0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
|
||||
0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
|
||||
0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
|
||||
0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
|
||||
0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
|
||||
0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
|
||||
0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
|
||||
0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
|
||||
0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
|
||||
0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
|
||||
0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
|
||||
0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
|
||||
0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
|
||||
0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
|
||||
0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
|
||||
0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
|
||||
0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
|
||||
0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
|
||||
0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
|
||||
0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
|
||||
0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
|
||||
0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
|
||||
0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
|
||||
0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
|
||||
0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
|
||||
0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
|
||||
0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
|
||||
0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
|
||||
0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
|
||||
0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
|
||||
0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
|
||||
0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
|
||||
0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
|
||||
0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
|
||||
0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
|
||||
0x2d02ef8dUL
|
||||
};
|
||||
|
||||
uint32_t ssh_crc32(const char *buf, uint32_t len) {
|
||||
uint32_t ret = 0;
|
||||
while(len > 0) {
|
||||
ret = crc_table[(ret ^ *buf) & 0xff] ^ (ret >> 8);
|
||||
--len;
|
||||
++buf;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* curve25519.c - Curve25519 ECDH functions for key exchange
|
||||
* curve25519-sha256@libssh.org
|
||||
* curve25519-sha256@libssh.org and curve25519-sha256
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
@@ -40,13 +40,14 @@
|
||||
#include "libssh/bignum.h"
|
||||
|
||||
/** @internal
|
||||
* @brief Starts curve25519-sha256@libssh.org key exchange
|
||||
* @brief Starts curve25519-sha256@libssh.org / curve25519-sha256 key exchange
|
||||
*/
|
||||
int ssh_client_curve25519_init(ssh_session session){
|
||||
int rc;
|
||||
int ok;
|
||||
|
||||
rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
|
||||
if (rc == 0){
|
||||
ok = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
|
||||
if (!ok) {
|
||||
ssh_set_error(session, SSH_FATAL, "PRNG error");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -64,18 +65,27 @@ int ssh_client_curve25519_init(ssh_session session){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = packet_send(session);
|
||||
rc = ssh_packet_send(session);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ssh_curve25519_build_k(ssh_session session) {
|
||||
ssh_curve25519_pubkey k;
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
session->next_crypto->k = bignum_new();
|
||||
|
||||
if (session->next_crypto->k == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
session->next_crypto->k = bignum_new();
|
||||
|
||||
if (session->next_crypto->k == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (session->server)
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
@@ -84,7 +94,13 @@ static int ssh_curve25519_build_k(ssh_session session) {
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_server_pubkey);
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->k);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Session server cookie",
|
||||
@@ -103,19 +119,26 @@ static int ssh_curve25519_build_k(ssh_session session) {
|
||||
*/
|
||||
int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){
|
||||
ssh_string q_s_string = NULL;
|
||||
ssh_string pubkey = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
ssh_string signature = NULL;
|
||||
int rc;
|
||||
pubkey = buffer_get_ssh_string(packet);
|
||||
if (pubkey == NULL){
|
||||
|
||||
pubkey_blob = ssh_buffer_get_ssh_string(packet);
|
||||
if (pubkey_blob == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No public key in packet");
|
||||
goto error;
|
||||
}
|
||||
/* this is the server host key */
|
||||
session->next_crypto->server_pubkey = pubkey;
|
||||
pubkey = NULL;
|
||||
|
||||
q_s_string = buffer_get_ssh_string(packet);
|
||||
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
|
||||
ssh_string_free(pubkey_blob);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Failed to import next public key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
q_s_string = ssh_buffer_get_ssh_string(packet);
|
||||
if (q_s_string == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No Q_S ECC point in packet");
|
||||
goto error;
|
||||
@@ -129,7 +152,7 @@ int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){
|
||||
memcpy(session->next_crypto->curve25519_server_pubkey, ssh_string_data(q_s_string), CURVE25519_PUBKEY_SIZE);
|
||||
ssh_string_free(q_s_string);
|
||||
|
||||
signature = buffer_get_ssh_string(packet);
|
||||
signature = ssh_buffer_get_ssh_string(packet);
|
||||
if (signature == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No signature in packet");
|
||||
goto error;
|
||||
@@ -143,11 +166,11 @@ int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc=packet_send(session);
|
||||
rc=ssh_packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
return rc;
|
||||
error:
|
||||
@@ -163,14 +186,16 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
|
||||
/* ECDH keys */
|
||||
ssh_string q_c_string;
|
||||
ssh_string q_s_string;
|
||||
ssh_string server_pubkey_blob = NULL;
|
||||
|
||||
/* SSH host keys (rsa,dsa,ecdsa) */
|
||||
ssh_key privkey;
|
||||
ssh_string sig_blob = NULL;
|
||||
int ok;
|
||||
int rc;
|
||||
|
||||
/* Extract the client pubkey from the init packet */
|
||||
q_c_string = buffer_get_ssh_string(packet);
|
||||
q_c_string = ssh_buffer_get_ssh_string(packet);
|
||||
if (q_c_string == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
|
||||
return SSH_ERROR;
|
||||
@@ -187,8 +212,8 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
|
||||
ssh_string_free(q_c_string);
|
||||
/* Build server's keypair */
|
||||
|
||||
rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
|
||||
if (rc == 0){
|
||||
ok = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
|
||||
if (!ok) {
|
||||
ssh_set_error(session, SSH_FATAL, "PRNG error");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -196,7 +221,7 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
|
||||
crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey,
|
||||
session->next_crypto->curve25519_privkey);
|
||||
|
||||
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_REPLY);
|
||||
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_REPLY);
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
@@ -215,15 +240,22 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = make_sessionid(session);
|
||||
rc = ssh_make_sessionid(session);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_dh_get_next_server_publickey_blob(session, &server_pubkey_blob);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not export server public key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* add host's public key */
|
||||
rc = buffer_add_ssh_string(session->out_buffer,
|
||||
session->next_crypto->server_pubkey);
|
||||
rc = ssh_buffer_add_ssh_string(session->out_buffer,
|
||||
server_pubkey_blob);
|
||||
ssh_string_free(server_pubkey_blob);
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
@@ -239,7 +271,7 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
|
||||
session->next_crypto->curve25519_server_pubkey,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
|
||||
rc = buffer_add_ssh_string(session->out_buffer, q_s_string);
|
||||
rc = ssh_buffer_add_ssh_string(session->out_buffer, q_s_string);
|
||||
ssh_string_free(q_s_string);
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
@@ -252,7 +284,7 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = buffer_add_ssh_string(session->out_buffer, sig_blob);
|
||||
rc = ssh_buffer_add_ssh_string(session->out_buffer, sig_blob);
|
||||
ssh_string_free(sig_blob);
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
@@ -260,19 +292,19 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_ECDH_REPLY sent");
|
||||
rc = packet_send(session);
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
|
||||
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
rc = packet_send(session);
|
||||
rc = ssh_packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
|
||||
return rc;
|
||||
|
||||
463
src/dh.c
463
src/dh.c
@@ -68,6 +68,7 @@
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include "libssh/libcrypto.h"
|
||||
#endif
|
||||
|
||||
static unsigned char p_group1_value[] = {
|
||||
@@ -115,128 +116,102 @@ static unsigned long g_int = 2 ; /* G is defined as 2 by the ssh2 standards */
|
||||
static bignum g;
|
||||
static bignum p_group1;
|
||||
static bignum p_group14;
|
||||
static int ssh_crypto_initialized;
|
||||
static int dh_crypto_initialized;
|
||||
|
||||
static bignum select_p(enum ssh_key_exchange_e type) {
|
||||
return type == SSH_KEX_DH_GROUP14_SHA1 ? p_group14 : p_group1;
|
||||
}
|
||||
|
||||
int ssh_get_random(void *where, int len, int strong){
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
/* variable not used in gcrypt */
|
||||
(void) strong;
|
||||
/* not using GCRY_VERY_STRONG_RANDOM which is a bit overkill */
|
||||
gcry_randomize(where,len,GCRY_STRONG_RANDOM);
|
||||
|
||||
return 1;
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
if (strong) {
|
||||
return RAND_bytes(where,len);
|
||||
} else {
|
||||
return RAND_pseudo_bytes(where,len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* never reached */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This inits the values g and p which are used for DH key agreement
|
||||
* FIXME: Make the function thread safe by adding a semaphore or mutex.
|
||||
/**
|
||||
* @internal
|
||||
* @brief Initialize global constants used in DH key agreement
|
||||
* @return SSH_OK on success, SSH_ERROR otherwise.
|
||||
*/
|
||||
int ssh_crypto_init(void) {
|
||||
if (ssh_crypto_initialized == 0) {
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_check_version(NULL);
|
||||
if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P,0)) {
|
||||
gcry_control(GCRYCTL_INIT_SECMEM, 4096);
|
||||
gcry_control(GCRYCTL_INITIALIZATION_FINISHED,0);
|
||||
int ssh_dh_init(void)
|
||||
{
|
||||
if (dh_crypto_initialized) {
|
||||
return SSH_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
g = bignum_new();
|
||||
if (g == NULL) {
|
||||
return -1;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
bignum_set_word(g,g_int);
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#if defined(HAVE_LIBGCRYPT)
|
||||
bignum_bin2bn(p_group1_value, P_GROUP1_LEN, &p_group1);
|
||||
if (p_group1 == NULL) {
|
||||
bignum_free(g);
|
||||
g = NULL;
|
||||
return -1;
|
||||
bignum_safe_free(g);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, &p_group14);
|
||||
if (p_group14 == NULL) {
|
||||
bignum_free(g);
|
||||
bignum_free(p_group1);
|
||||
g = NULL;
|
||||
p_group1 = NULL;
|
||||
return -1;
|
||||
}
|
||||
bignum_safe_free(g);
|
||||
bignum_safe_free(p_group1);
|
||||
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#elif defined(HAVE_LIBCRYPTO)
|
||||
p_group1 = bignum_new();
|
||||
if (p_group1 == NULL) {
|
||||
bignum_free(g);
|
||||
g = NULL;
|
||||
return -1;
|
||||
bignum_safe_free(g);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
bignum_bin2bn(p_group1_value, P_GROUP1_LEN, p_group1);
|
||||
|
||||
p_group14 = bignum_new();
|
||||
if (p_group14 == NULL) {
|
||||
bignum_free(g);
|
||||
bignum_free(p_group1);
|
||||
g = NULL;
|
||||
p_group1 = NULL;
|
||||
return -1;
|
||||
bignum_safe_free(g);
|
||||
bignum_safe_free(p_group1);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14);
|
||||
#elif defined(HAVE_LIBMBEDCRYPTO)
|
||||
p_group1 = bignum_new();
|
||||
bignum_bin2bn(p_group1_value, P_GROUP1_LEN, p_group1);
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
p_group14 = bignum_new();
|
||||
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14);
|
||||
#endif
|
||||
dh_crypto_initialized = 1;
|
||||
|
||||
ssh_crypto_initialized = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ssh_crypto_finalize(void) {
|
||||
if (ssh_crypto_initialized) {
|
||||
bignum_free(g);
|
||||
g = NULL;
|
||||
bignum_free(p_group1);
|
||||
p_group1 = NULL;
|
||||
bignum_free(p_group14);
|
||||
p_group14 = NULL;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_control(GCRYCTL_TERM_SECMEM);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
EVP_cleanup();
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
#endif
|
||||
ssh_crypto_initialized=0;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
* @brief Finalize and free global constants used in DH key agreement
|
||||
*/
|
||||
void ssh_dh_finalize(void)
|
||||
{
|
||||
if (!dh_crypto_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
bignum_safe_free(g);
|
||||
bignum_safe_free(p_group1);
|
||||
bignum_safe_free(p_group14);
|
||||
|
||||
dh_crypto_initialized = 0;
|
||||
}
|
||||
|
||||
int dh_generate_x(ssh_session session) {
|
||||
int ssh_dh_generate_x(ssh_session session) {
|
||||
int keysize;
|
||||
if (session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1) {
|
||||
keysize = 1023;
|
||||
} else {
|
||||
keysize = 2047;
|
||||
}
|
||||
session->next_crypto->x = bignum_new();
|
||||
if (session->next_crypto->x == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
bignum_rand(session->next_crypto->x, 128);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bignum_rand(session->next_crypto->x, 128, 0, -1);
|
||||
#endif
|
||||
bignum_rand(session->next_crypto->x, keysize);
|
||||
|
||||
/* not harder than this */
|
||||
#ifdef DEBUG_CRYPTO
|
||||
@@ -247,17 +222,19 @@ int dh_generate_x(ssh_session session) {
|
||||
}
|
||||
|
||||
/* used by server */
|
||||
int dh_generate_y(ssh_session session) {
|
||||
session->next_crypto->y = bignum_new();
|
||||
int ssh_dh_generate_y(ssh_session session) {
|
||||
int keysize;
|
||||
if (session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1) {
|
||||
keysize = 1023;
|
||||
} else {
|
||||
keysize = 2047;
|
||||
}
|
||||
session->next_crypto->y = bignum_new();
|
||||
if (session->next_crypto->y == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
bignum_rand(session->next_crypto->y, 128);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bignum_rand(session->next_crypto->y, 128, 0, -1);
|
||||
#endif
|
||||
bignum_rand(session->next_crypto->y, keysize);
|
||||
|
||||
/* not harder than this */
|
||||
#ifdef DEBUG_CRYPTO
|
||||
@@ -268,7 +245,7 @@ int dh_generate_y(ssh_session session) {
|
||||
}
|
||||
|
||||
/* used by server */
|
||||
int dh_generate_e(ssh_session session) {
|
||||
int ssh_dh_generate_e(ssh_session session) {
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
if (ctx == NULL) {
|
||||
@@ -290,6 +267,9 @@ int dh_generate_e(ssh_session session) {
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x,
|
||||
select_p(session->next_crypto->kex_type), ctx);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x,
|
||||
select_p(session->next_crypto->kex_type), NULL);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
@@ -303,7 +283,7 @@ int dh_generate_e(ssh_session session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dh_generate_f(ssh_session session) {
|
||||
int ssh_dh_generate_f(ssh_session session) {
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
if (ctx == NULL) {
|
||||
@@ -325,6 +305,9 @@ int dh_generate_f(ssh_session session) {
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y,
|
||||
select_p(session->next_crypto->kex_type), ctx);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y,
|
||||
select_p(session->next_crypto->kex_type), NULL);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
@@ -338,21 +321,30 @@ int dh_generate_f(ssh_session session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssh_string dh_get_e(ssh_session session) {
|
||||
return make_bignum_string(session->next_crypto->e);
|
||||
ssh_string ssh_dh_get_e(ssh_session session) {
|
||||
return ssh_make_bignum_string(session->next_crypto->e);
|
||||
}
|
||||
|
||||
/* used by server */
|
||||
ssh_string dh_get_f(ssh_session session) {
|
||||
return make_bignum_string(session->next_crypto->f);
|
||||
ssh_string ssh_dh_get_f(ssh_session session) {
|
||||
return ssh_make_bignum_string(session->next_crypto->f);
|
||||
}
|
||||
|
||||
void dh_import_pubkey(ssh_session session, ssh_string pubkey_string) {
|
||||
session->next_crypto->server_pubkey = pubkey_string;
|
||||
int ssh_dh_import_pubkey_blob(ssh_session session, ssh_string pubkey_blob)
|
||||
{
|
||||
return ssh_pki_import_pubkey_blob(pubkey_blob,
|
||||
&session->current_crypto->server_pubkey);
|
||||
}
|
||||
|
||||
int dh_import_f(ssh_session session, ssh_string f_string) {
|
||||
session->next_crypto->f = make_string_bn(f_string);
|
||||
int ssh_dh_import_next_pubkey_blob(ssh_session session, ssh_string pubkey_blob)
|
||||
{
|
||||
return ssh_pki_import_pubkey_blob(pubkey_blob,
|
||||
&session->next_crypto->server_pubkey);
|
||||
|
||||
}
|
||||
|
||||
int ssh_dh_import_f(ssh_session session, ssh_string f_string) {
|
||||
session->next_crypto->f = ssh_make_string_bn(f_string);
|
||||
if (session->next_crypto->f == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -365,8 +357,8 @@ int dh_import_f(ssh_session session, ssh_string f_string) {
|
||||
}
|
||||
|
||||
/* used by the server implementation */
|
||||
int dh_import_e(ssh_session session, ssh_string e_string) {
|
||||
session->next_crypto->e = make_string_bn(e_string);
|
||||
int ssh_dh_import_e(ssh_session session, ssh_string e_string) {
|
||||
session->next_crypto->e = ssh_make_string_bn(e_string);
|
||||
if (session->next_crypto->e == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -378,7 +370,7 @@ int dh_import_e(ssh_session session, ssh_string e_string) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dh_build_k(ssh_session session) {
|
||||
int ssh_dh_build_k(ssh_session session) {
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
if (ctx == NULL) {
|
||||
@@ -411,6 +403,14 @@ int dh_build_k(ssh_session session) {
|
||||
bignum_mod_exp(session->next_crypto->k, session->next_crypto->e,
|
||||
session->next_crypto->y, select_p(session->next_crypto->kex_type), ctx);
|
||||
}
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
if (session->client) {
|
||||
bignum_mod_exp(session->next_crypto->k, session->next_crypto->f,
|
||||
session->next_crypto->x, select_p(session->next_crypto->kex_type), NULL);
|
||||
} else {
|
||||
bignum_mod_exp(session->next_crypto->k, session->next_crypto->e,
|
||||
session->next_crypto->y, select_p(session->next_crypto->kex_type), NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
@@ -435,14 +435,14 @@ int ssh_client_dh_init(ssh_session session){
|
||||
ssh_string e = NULL;
|
||||
int rc;
|
||||
|
||||
if (dh_generate_x(session) < 0) {
|
||||
if (ssh_dh_generate_x(session) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (dh_generate_e(session) < 0) {
|
||||
if (ssh_dh_generate_e(session) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
e = dh_get_e(session);
|
||||
e = ssh_dh_get_e(session);
|
||||
if (e == NULL) {
|
||||
goto error;
|
||||
}
|
||||
@@ -456,7 +456,7 @@ int ssh_client_dh_init(ssh_session session){
|
||||
ssh_string_free(e);
|
||||
e=NULL;
|
||||
|
||||
rc = packet_send(session);
|
||||
rc = ssh_packet_send(session);
|
||||
return rc;
|
||||
error:
|
||||
if(e != NULL){
|
||||
@@ -469,22 +469,28 @@ int ssh_client_dh_init(ssh_session session){
|
||||
|
||||
int ssh_client_dh_reply(ssh_session session, ssh_buffer packet){
|
||||
ssh_string f;
|
||||
ssh_string pubkey = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
ssh_string signature = NULL;
|
||||
int rc;
|
||||
pubkey = buffer_get_ssh_string(packet);
|
||||
if (pubkey == NULL){
|
||||
|
||||
pubkey_blob = ssh_buffer_get_ssh_string(packet);
|
||||
if (pubkey_blob == NULL){
|
||||
ssh_set_error(session,SSH_FATAL, "No public key in packet");
|
||||
goto error;
|
||||
}
|
||||
dh_import_pubkey(session, pubkey);
|
||||
|
||||
f = buffer_get_ssh_string(packet);
|
||||
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
|
||||
ssh_string_free(pubkey_blob);
|
||||
if (rc != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
f = ssh_buffer_get_ssh_string(packet);
|
||||
if (f == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No F number in packet");
|
||||
goto error;
|
||||
}
|
||||
rc = dh_import_f(session, f);
|
||||
rc = ssh_dh_import_f(session, f);
|
||||
ssh_string_burn(f);
|
||||
ssh_string_free(f);
|
||||
if (rc < 0) {
|
||||
@@ -492,35 +498,36 @@ int ssh_client_dh_reply(ssh_session session, ssh_buffer packet){
|
||||
goto error;
|
||||
}
|
||||
|
||||
signature = buffer_get_ssh_string(packet);
|
||||
signature = ssh_buffer_get_ssh_string(packet);
|
||||
if (signature == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No signature in packet");
|
||||
goto error;
|
||||
}
|
||||
session->next_crypto->dh_server_signature = signature;
|
||||
signature=NULL; /* ownership changed */
|
||||
if (dh_build_k(session) < 0) {
|
||||
if (ssh_dh_build_k(session) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc=packet_send(session);
|
||||
rc=ssh_packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
return rc;
|
||||
error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
int make_sessionid(ssh_session session) {
|
||||
int ssh_make_sessionid(ssh_session session) {
|
||||
ssh_string num = NULL;
|
||||
ssh_buffer server_hash = NULL;
|
||||
ssh_buffer client_hash = NULL;
|
||||
ssh_buffer buf = NULL;
|
||||
ssh_string server_pubkey_blob = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
buf = ssh_buffer_new();
|
||||
@@ -550,37 +557,42 @@ int make_sessionid(ssh_session session) {
|
||||
* boolean first_kex_packet_follows
|
||||
* uint32 0 (reserved for future extension)
|
||||
*/
|
||||
rc = buffer_add_u8(server_hash, 0);
|
||||
rc = ssh_buffer_add_u8(server_hash, 0);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
rc = buffer_add_u32(server_hash, 0);
|
||||
rc = ssh_buffer_add_u32(server_hash, 0);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* These fields are handled for the server case in ssh_packet_kexinit. */
|
||||
if (session->client) {
|
||||
rc = buffer_add_u8(client_hash, 0);
|
||||
rc = ssh_buffer_add_u8(client_hash, 0);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
rc = buffer_add_u32(client_hash, 0);
|
||||
rc = ssh_buffer_add_u32(client_hash, 0);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ssh_dh_get_next_server_publickey_blob(session, &server_pubkey_blob);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(buf,
|
||||
"dPdPS",
|
||||
buffer_get_rest_len(client_hash),
|
||||
buffer_get_rest_len(client_hash),
|
||||
buffer_get_rest(client_hash),
|
||||
buffer_get_rest_len(server_hash),
|
||||
buffer_get_rest_len(server_hash),
|
||||
buffer_get_rest(server_hash),
|
||||
session->next_crypto->server_pubkey);
|
||||
|
||||
ssh_buffer_get_len(client_hash),
|
||||
ssh_buffer_get_len(client_hash),
|
||||
ssh_buffer_get(client_hash),
|
||||
ssh_buffer_get_len(server_hash),
|
||||
ssh_buffer_get_len(server_hash),
|
||||
ssh_buffer_get(server_hash),
|
||||
server_pubkey_blob);
|
||||
ssh_string_free(server_pubkey_blob);
|
||||
if(rc != SSH_OK){
|
||||
goto error;
|
||||
}
|
||||
@@ -596,7 +608,9 @@ int make_sessionid(ssh_session session) {
|
||||
}
|
||||
|
||||
#ifdef HAVE_ECDH
|
||||
} else if (session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
|
||||
} else if ((session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP256) ||
|
||||
(session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP384) ||
|
||||
(session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP521)) {
|
||||
if (session->next_crypto->ecdh_client_pubkey == NULL ||
|
||||
session->next_crypto->ecdh_server_pubkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "ECDH parameted missing");
|
||||
@@ -611,7 +625,8 @@ int make_sessionid(ssh_session session) {
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_CURVE25519
|
||||
} else if (session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG) {
|
||||
} else if ((session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256) ||
|
||||
(session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG)) {
|
||||
rc = ssh_buffer_pack(buf,
|
||||
"dPdP",
|
||||
CURVE25519_PUBKEY_SIZE,
|
||||
@@ -630,7 +645,7 @@ int make_sessionid(ssh_session session) {
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("hash buffer", ssh_buffer_get_begin(buf), ssh_buffer_get_len(buf));
|
||||
ssh_print_hexa("hash buffer", ssh_buffer_get(buf), ssh_buffer_get_len(buf));
|
||||
#endif
|
||||
|
||||
switch (session->next_crypto->kex_type) {
|
||||
@@ -643,10 +658,11 @@ int make_sessionid(ssh_session session) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
sha1(buffer_get_rest(buf), buffer_get_rest_len(buf),
|
||||
sha1(ssh_buffer_get(buf), ssh_buffer_get_len(buf),
|
||||
session->next_crypto->secret_hash);
|
||||
break;
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
case SSH_KEX_CURVE25519_SHA256:
|
||||
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
|
||||
session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
|
||||
session->next_crypto->mac_type = SSH_MAC_SHA256;
|
||||
@@ -655,7 +671,29 @@ int make_sessionid(ssh_session session) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
sha256(buffer_get_rest(buf), buffer_get_rest_len(buf),
|
||||
sha256(ssh_buffer_get(buf), ssh_buffer_get_len(buf),
|
||||
session->next_crypto->secret_hash);
|
||||
break;
|
||||
case SSH_KEX_ECDH_SHA2_NISTP384:
|
||||
session->next_crypto->digest_len = SHA384_DIGEST_LENGTH;
|
||||
session->next_crypto->mac_type = SSH_MAC_SHA384;
|
||||
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
|
||||
if (session->next_crypto->secret_hash == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
sha384(ssh_buffer_get(buf), ssh_buffer_get_len(buf),
|
||||
session->next_crypto->secret_hash);
|
||||
break;
|
||||
case SSH_KEX_ECDH_SHA2_NISTP521:
|
||||
session->next_crypto->digest_len = SHA512_DIGEST_LENGTH;
|
||||
session->next_crypto->mac_type = SSH_MAC_SHA512;
|
||||
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
|
||||
if (session->next_crypto->secret_hash == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
sha512(ssh_buffer_get(buf), ssh_buffer_get_len(buf),
|
||||
session->next_crypto->secret_hash);
|
||||
break;
|
||||
}
|
||||
@@ -692,13 +730,22 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int hashbufout_add_cookie(ssh_session session) {
|
||||
int ssh_hashbufout_add_cookie(ssh_session session) {
|
||||
int rc;
|
||||
|
||||
session->out_hashbuf = ssh_buffer_new();
|
||||
if (session->out_hashbuf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffer_add_u8(session->out_hashbuf, 20) < 0) {
|
||||
rc = ssh_buffer_allocate_size(session->out_hashbuf,
|
||||
sizeof(uint8_t) + 16);
|
||||
if (rc < 0) {
|
||||
ssh_buffer_reinit(session->out_hashbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ssh_buffer_add_u8(session->out_hashbuf, 20) < 0) {
|
||||
ssh_buffer_reinit(session->out_hashbuf);
|
||||
return -1;
|
||||
}
|
||||
@@ -720,13 +767,22 @@ int hashbufout_add_cookie(ssh_session session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hashbufin_add_cookie(ssh_session session, unsigned char *cookie) {
|
||||
int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie) {
|
||||
int rc;
|
||||
|
||||
session->in_hashbuf = ssh_buffer_new();
|
||||
if (session->in_hashbuf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffer_add_u8(session->in_hashbuf, 20) < 0) {
|
||||
rc = ssh_buffer_allocate_size(session->in_hashbuf,
|
||||
sizeof(uint8_t) + 20 + 16);
|
||||
if (rc < 0) {
|
||||
ssh_buffer_reinit(session->in_hashbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ssh_buffer_add_u8(session->in_hashbuf, 20) < 0) {
|
||||
ssh_buffer_reinit(session->in_hashbuf);
|
||||
return -1;
|
||||
}
|
||||
@@ -777,12 +833,12 @@ static int generate_one_key(ssh_string k,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int generate_session_keys(ssh_session session) {
|
||||
int ssh_generate_session_keys(ssh_session session) {
|
||||
ssh_string k_string = NULL;
|
||||
struct ssh_crypto_struct *crypto = session->next_crypto;
|
||||
int rc = -1;
|
||||
|
||||
k_string = make_bignum_string(crypto->k);
|
||||
k_string = ssh_make_bignum_string(crypto->k);
|
||||
if (k_string == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
@@ -887,39 +943,55 @@ error:
|
||||
* @deprecated Use ssh_get_publickey_hash()
|
||||
*/
|
||||
int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) {
|
||||
ssh_string pubkey;
|
||||
MD5CTX ctx;
|
||||
unsigned char *h;
|
||||
ssh_key pubkey = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
MD5CTX ctx;
|
||||
unsigned char *h;
|
||||
int rc;
|
||||
|
||||
if (session == NULL || hash == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
*hash = NULL;
|
||||
if (session->current_crypto == NULL ||
|
||||
session->current_crypto->server_pubkey == NULL){
|
||||
ssh_set_error(session,SSH_FATAL,"No current cryptographic context");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (session == NULL || hash == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
*hash = NULL;
|
||||
if (session->current_crypto == NULL ||
|
||||
session->current_crypto->server_pubkey == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL,"No current cryptographic context");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
h = malloc(sizeof(unsigned char) * MD5_DIGEST_LEN);
|
||||
if (h == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
h = calloc(MD5_DIGEST_LEN, sizeof(unsigned char));
|
||||
if (h == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
ctx = md5_init();
|
||||
if (ctx == NULL) {
|
||||
SAFE_FREE(h);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
ctx = md5_init();
|
||||
if (ctx == NULL) {
|
||||
SAFE_FREE(h);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
pubkey = session->current_crypto->server_pubkey;
|
||||
rc = ssh_get_server_publickey(session, &pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
md5_final(h, ctx);
|
||||
SAFE_FREE(h);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
md5_update(ctx, ssh_string_data(pubkey), ssh_string_len(pubkey));
|
||||
md5_final(h, ctx);
|
||||
rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_blob);
|
||||
ssh_key_free(pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
md5_final(h, ctx);
|
||||
SAFE_FREE(h);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
*hash = h;
|
||||
md5_update(ctx, ssh_string_data(pubkey_blob), ssh_string_len(pubkey_blob));
|
||||
ssh_string_free(pubkey_blob);
|
||||
md5_final(h, ctx);
|
||||
|
||||
return MD5_DIGEST_LEN;
|
||||
*hash = h;
|
||||
|
||||
return MD5_DIGEST_LEN;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -949,16 +1021,59 @@ void ssh_clean_pubkey_hash(unsigned char **hash) {
|
||||
*
|
||||
* @see ssh_key_free()
|
||||
*/
|
||||
int ssh_get_publickey(ssh_session session, ssh_key *key)
|
||||
int ssh_get_server_publickey(ssh_session session, ssh_key *key)
|
||||
{
|
||||
if (session==NULL ||
|
||||
session->current_crypto ==NULL ||
|
||||
ssh_key pubkey = NULL;
|
||||
|
||||
if (session == NULL ||
|
||||
session->current_crypto == NULL ||
|
||||
session->current_crypto->server_pubkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return ssh_pki_import_pubkey_blob(session->current_crypto->server_pubkey,
|
||||
key);
|
||||
pubkey = ssh_key_dup(session->current_crypto->server_pubkey);
|
||||
if (pubkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
*key = pubkey;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
ssh_key ssh_dh_get_current_server_publickey(ssh_session session)
|
||||
{
|
||||
return session->current_crypto->server_pubkey;
|
||||
}
|
||||
|
||||
/* Caller need to free the blob */
|
||||
int ssh_dh_get_current_server_publickey_blob(ssh_session session,
|
||||
ssh_string *pubkey_blob)
|
||||
{
|
||||
const ssh_key pubkey = ssh_dh_get_current_server_publickey(session);
|
||||
|
||||
return ssh_pki_export_pubkey_blob(pubkey, pubkey_blob);
|
||||
}
|
||||
|
||||
ssh_key ssh_dh_get_next_server_publickey(ssh_session session)
|
||||
{
|
||||
return session->next_crypto->server_pubkey;
|
||||
}
|
||||
|
||||
/* Caller need to free the blob */
|
||||
int ssh_dh_get_next_server_publickey_blob(ssh_session session,
|
||||
ssh_string *pubkey_blob)
|
||||
{
|
||||
const ssh_key pubkey = ssh_dh_get_next_server_publickey(session);
|
||||
|
||||
return ssh_pki_export_pubkey_blob(pubkey, pubkey_blob);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use ssh_get_server_publickey()
|
||||
*/
|
||||
int ssh_get_publickey(ssh_session session, ssh_key *key)
|
||||
{
|
||||
return ssh_get_server_publickey(session, key);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -984,7 +1099,7 @@ int ssh_get_publickey(ssh_session session, ssh_key *key)
|
||||
* you at making things secure.
|
||||
* OpenSSH uses SHA1 to print public key digests.
|
||||
*
|
||||
* @see ssh_is_server_known()
|
||||
* @see ssh_session_update_known_hosts()
|
||||
* @see ssh_get_hexa()
|
||||
* @see ssh_print_hexa()
|
||||
* @see ssh_clean_pubkey_hash()
|
||||
@@ -1114,11 +1229,9 @@ void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) {
|
||||
if (hexa == NULL) {
|
||||
return;
|
||||
}
|
||||
printf("%s: %s\n", descr, hexa);
|
||||
fprintf(stderr, "%s: %s\n", descr, hexa);
|
||||
|
||||
free(hexa);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
291
src/ecdh.c
291
src/ecdh.c
@@ -29,148 +29,6 @@
|
||||
#include "libssh/bignum.h"
|
||||
|
||||
#ifdef HAVE_ECDH
|
||||
#include <openssl/ecdh.h>
|
||||
|
||||
#define NISTP256 NID_X9_62_prime256v1
|
||||
#define NISTP384 NID_secp384r1
|
||||
#define NISTP521 NID_secp521r1
|
||||
|
||||
/** @internal
|
||||
* @brief Starts ecdh-sha2-nistp256 key exchange
|
||||
*/
|
||||
int ssh_client_ecdh_init(ssh_session session){
|
||||
EC_KEY *key;
|
||||
const EC_GROUP *group;
|
||||
const EC_POINT *pubkey;
|
||||
ssh_string client_pubkey;
|
||||
int len;
|
||||
int rc;
|
||||
bignum_CTX ctx = BN_CTX_new();
|
||||
|
||||
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
|
||||
if (rc < 0) {
|
||||
BN_CTX_free(ctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
key = EC_KEY_new_by_curve_name(NISTP256);
|
||||
if (key == NULL) {
|
||||
BN_CTX_free(ctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
group = EC_KEY_get0_group(key);
|
||||
|
||||
EC_KEY_generate_key(key);
|
||||
|
||||
pubkey=EC_KEY_get0_public_key(key);
|
||||
len = EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
|
||||
NULL,0,ctx);
|
||||
|
||||
client_pubkey = ssh_string_new(len);
|
||||
if (client_pubkey == NULL) {
|
||||
BN_CTX_free(ctx);
|
||||
EC_KEY_free(key);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
|
||||
ssh_string_data(client_pubkey),len,ctx);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
rc = buffer_add_ssh_string(session->out_buffer,client_pubkey);
|
||||
if (rc < 0) {
|
||||
EC_KEY_free(key);
|
||||
ssh_string_free(client_pubkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
session->next_crypto->ecdh_privkey = key;
|
||||
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
||||
|
||||
rc = packet_send(session);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void ecdh_import_pubkey(ssh_session session, ssh_string pubkey_string) {
|
||||
session->next_crypto->server_pubkey = pubkey_string;
|
||||
}
|
||||
|
||||
static int ecdh_build_k(ssh_session session) {
|
||||
const EC_GROUP *group = EC_KEY_get0_group(session->next_crypto->ecdh_privkey);
|
||||
EC_POINT *pubkey;
|
||||
void *buffer;
|
||||
int rc;
|
||||
int len = (EC_GROUP_get_degree(group) + 7) / 8;
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
session->next_crypto->k = bignum_new();
|
||||
if (session->next_crypto->k == NULL) {
|
||||
bignum_ctx_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pubkey = EC_POINT_new(group);
|
||||
if (pubkey == NULL) {
|
||||
bignum_ctx_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (session->server) {
|
||||
rc = EC_POINT_oct2point(group,
|
||||
pubkey,
|
||||
ssh_string_data(session->next_crypto->ecdh_client_pubkey),
|
||||
ssh_string_len(session->next_crypto->ecdh_client_pubkey),
|
||||
ctx);
|
||||
} else {
|
||||
rc = EC_POINT_oct2point(group,
|
||||
pubkey,
|
||||
ssh_string_data(session->next_crypto->ecdh_server_pubkey),
|
||||
ssh_string_len(session->next_crypto->ecdh_server_pubkey),
|
||||
ctx);
|
||||
}
|
||||
bignum_ctx_free(ctx);
|
||||
if (rc <= 0) {
|
||||
EC_POINT_clear_free(pubkey);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer = malloc(len);
|
||||
if (buffer == NULL) {
|
||||
EC_POINT_clear_free(pubkey);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = ECDH_compute_key(buffer,
|
||||
len,
|
||||
pubkey,
|
||||
session->next_crypto->ecdh_privkey,
|
||||
NULL);
|
||||
EC_POINT_clear_free(pubkey);
|
||||
if (rc <= 0) {
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bignum_bin2bn(buffer, len, session->next_crypto->k);
|
||||
free(buffer);
|
||||
|
||||
EC_KEY_free(session->next_crypto->ecdh_privkey);
|
||||
session->next_crypto->ecdh_privkey = NULL;
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Session server cookie",
|
||||
session->next_crypto->server_kex.cookie, 16);
|
||||
ssh_print_hexa("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie, 16);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->k);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
|
||||
@@ -178,23 +36,29 @@ static int ecdh_build_k(ssh_session session) {
|
||||
*/
|
||||
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet){
|
||||
ssh_string q_s_string = NULL;
|
||||
ssh_string pubkey = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
ssh_string signature = NULL;
|
||||
int rc;
|
||||
pubkey = buffer_get_ssh_string(packet);
|
||||
if (pubkey == NULL){
|
||||
|
||||
pubkey_blob = ssh_buffer_get_ssh_string(packet);
|
||||
if (pubkey_blob == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No public key in packet");
|
||||
goto error;
|
||||
}
|
||||
ecdh_import_pubkey(session, pubkey);
|
||||
|
||||
q_s_string = buffer_get_ssh_string(packet);
|
||||
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
|
||||
ssh_string_free(pubkey_blob);
|
||||
if (rc != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
q_s_string = ssh_buffer_get_ssh_string(packet);
|
||||
if (q_s_string == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No Q_S ECC point in packet");
|
||||
goto error;
|
||||
}
|
||||
session->next_crypto->ecdh_server_pubkey = q_s_string;
|
||||
signature = buffer_get_ssh_string(packet);
|
||||
signature = ssh_buffer_get_ssh_string(packet);
|
||||
if (signature == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No signature in packet");
|
||||
goto error;
|
||||
@@ -208,142 +72,15 @@ int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet){
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc=packet_send(session);
|
||||
rc=ssh_packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
return rc;
|
||||
error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
|
||||
* SSH_MSG_KEXDH_REPLY
|
||||
*/
|
||||
|
||||
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){
|
||||
/* ECDH keys */
|
||||
ssh_string q_c_string;
|
||||
ssh_string q_s_string;
|
||||
EC_KEY *ecdh_key;
|
||||
const EC_GROUP *group;
|
||||
const EC_POINT *ecdh_pubkey;
|
||||
bignum_CTX ctx;
|
||||
/* SSH host keys (rsa,dsa,ecdsa) */
|
||||
ssh_key privkey;
|
||||
ssh_string sig_blob = NULL;
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
/* Extract the client pubkey from the init packet */
|
||||
q_c_string = buffer_get_ssh_string(packet);
|
||||
if (q_c_string == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
session->next_crypto->ecdh_client_pubkey = q_c_string;
|
||||
|
||||
/* Build server's keypair */
|
||||
|
||||
ctx = BN_CTX_new();
|
||||
ecdh_key = EC_KEY_new_by_curve_name(NISTP256);
|
||||
if (ecdh_key == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
BN_CTX_free(ctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
group = EC_KEY_get0_group(ecdh_key);
|
||||
EC_KEY_generate_key(ecdh_key);
|
||||
|
||||
ecdh_pubkey = EC_KEY_get0_public_key(ecdh_key);
|
||||
len = EC_POINT_point2oct(group,
|
||||
ecdh_pubkey,
|
||||
POINT_CONVERSION_UNCOMPRESSED,
|
||||
NULL,
|
||||
0,
|
||||
ctx);
|
||||
|
||||
q_s_string = ssh_string_new(len);
|
||||
if (q_s_string == NULL) {
|
||||
EC_KEY_free(ecdh_key);
|
||||
BN_CTX_free(ctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
EC_POINT_point2oct(group,
|
||||
ecdh_pubkey,
|
||||
POINT_CONVERSION_UNCOMPRESSED,
|
||||
ssh_string_data(q_s_string),
|
||||
len,
|
||||
ctx);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
session->next_crypto->ecdh_privkey = ecdh_key;
|
||||
session->next_crypto->ecdh_server_pubkey = q_s_string;
|
||||
|
||||
/* build k and session_id */
|
||||
rc = ecdh_build_k(session);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* privkey is not allocated */
|
||||
rc = ssh_get_key_params(session, &privkey);
|
||||
if (rc == SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = make_sessionid(session);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
|
||||
if (sig_blob == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bSSS",
|
||||
SSH2_MSG_KEXDH_REPLY,
|
||||
session->next_crypto->server_pubkey, /* host's pubkey */
|
||||
q_s_string, /* ecdh public key */
|
||||
sig_blob); /* signature blob */
|
||||
|
||||
ssh_string_free(sig_blob);
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent");
|
||||
rc = packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
|
||||
if (rc < 0) {
|
||||
return SSH_ERROR;;
|
||||
}
|
||||
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
rc = packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#endif /* HAVE_ECDH */
|
||||
|
||||
336
src/ecdh_crypto.c
Normal file
336
src/ecdh_crypto.c
Normal file
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2011-2013 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/ecdh.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/bignum.h"
|
||||
|
||||
#ifdef HAVE_ECDH
|
||||
#include <openssl/ecdh.h>
|
||||
|
||||
#define NISTP256 NID_X9_62_prime256v1
|
||||
#define NISTP384 NID_secp384r1
|
||||
#define NISTP521 NID_secp521r1
|
||||
|
||||
/** @internal
|
||||
* @brief Map the given key exchange enum value to its curve name.
|
||||
*/
|
||||
static int ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
|
||||
if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
|
||||
return NISTP256;
|
||||
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP384) {
|
||||
return NISTP384;
|
||||
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) {
|
||||
return NISTP521;
|
||||
}
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief Starts ecdh-sha2-nistp256 key exchange
|
||||
*/
|
||||
int ssh_client_ecdh_init(ssh_session session){
|
||||
EC_KEY *key;
|
||||
const EC_GROUP *group;
|
||||
const EC_POINT *pubkey;
|
||||
ssh_string client_pubkey;
|
||||
int curve;
|
||||
int len;
|
||||
int rc;
|
||||
bignum_CTX ctx = BN_CTX_new();
|
||||
|
||||
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
|
||||
if (rc < 0) {
|
||||
BN_CTX_free(ctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
|
||||
if (curve == SSH_ERROR) {
|
||||
BN_CTX_free(ctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
key = EC_KEY_new_by_curve_name(curve);
|
||||
if (key == NULL) {
|
||||
BN_CTX_free(ctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
group = EC_KEY_get0_group(key);
|
||||
|
||||
EC_KEY_generate_key(key);
|
||||
|
||||
pubkey=EC_KEY_get0_public_key(key);
|
||||
len = EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
|
||||
NULL,0,ctx);
|
||||
|
||||
client_pubkey = ssh_string_new(len);
|
||||
if (client_pubkey == NULL) {
|
||||
BN_CTX_free(ctx);
|
||||
EC_KEY_free(key);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
|
||||
ssh_string_data(client_pubkey),len,ctx);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
rc = ssh_buffer_add_ssh_string(session->out_buffer,client_pubkey);
|
||||
if (rc < 0) {
|
||||
EC_KEY_free(key);
|
||||
ssh_string_free(client_pubkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
session->next_crypto->ecdh_privkey = key;
|
||||
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ecdh_build_k(ssh_session session) {
|
||||
const EC_GROUP *group = EC_KEY_get0_group(session->next_crypto->ecdh_privkey);
|
||||
EC_POINT *pubkey;
|
||||
void *buffer;
|
||||
int rc;
|
||||
int len = (EC_GROUP_get_degree(group) + 7) / 8;
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
session->next_crypto->k = bignum_new();
|
||||
if (session->next_crypto->k == NULL) {
|
||||
bignum_ctx_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pubkey = EC_POINT_new(group);
|
||||
if (pubkey == NULL) {
|
||||
bignum_ctx_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (session->server) {
|
||||
rc = EC_POINT_oct2point(group,
|
||||
pubkey,
|
||||
ssh_string_data(session->next_crypto->ecdh_client_pubkey),
|
||||
ssh_string_len(session->next_crypto->ecdh_client_pubkey),
|
||||
ctx);
|
||||
} else {
|
||||
rc = EC_POINT_oct2point(group,
|
||||
pubkey,
|
||||
ssh_string_data(session->next_crypto->ecdh_server_pubkey),
|
||||
ssh_string_len(session->next_crypto->ecdh_server_pubkey),
|
||||
ctx);
|
||||
}
|
||||
bignum_ctx_free(ctx);
|
||||
if (rc <= 0) {
|
||||
EC_POINT_clear_free(pubkey);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer = malloc(len);
|
||||
if (buffer == NULL) {
|
||||
EC_POINT_clear_free(pubkey);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = ECDH_compute_key(buffer,
|
||||
len,
|
||||
pubkey,
|
||||
session->next_crypto->ecdh_privkey,
|
||||
NULL);
|
||||
EC_POINT_clear_free(pubkey);
|
||||
if (rc <= 0) {
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bignum_bin2bn(buffer, len, session->next_crypto->k);
|
||||
free(buffer);
|
||||
|
||||
EC_KEY_free(session->next_crypto->ecdh_privkey);
|
||||
session->next_crypto->ecdh_privkey = NULL;
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Session server cookie",
|
||||
session->next_crypto->server_kex.cookie, 16);
|
||||
ssh_print_hexa("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie, 16);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->k);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
|
||||
* SSH_MSG_KEXDH_REPLY
|
||||
*/
|
||||
|
||||
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){
|
||||
/* ECDH keys */
|
||||
ssh_string q_c_string;
|
||||
ssh_string q_s_string;
|
||||
EC_KEY *ecdh_key;
|
||||
const EC_GROUP *group;
|
||||
const EC_POINT *ecdh_pubkey;
|
||||
bignum_CTX ctx;
|
||||
/* SSH host keys (rsa,dsa,ecdsa) */
|
||||
ssh_key privkey;
|
||||
ssh_string sig_blob = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
int curve;
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
/* Extract the client pubkey from the init packet */
|
||||
q_c_string = ssh_buffer_get_ssh_string(packet);
|
||||
if (q_c_string == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
session->next_crypto->ecdh_client_pubkey = q_c_string;
|
||||
|
||||
/* Build server's keypair */
|
||||
|
||||
ctx = BN_CTX_new();
|
||||
|
||||
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
|
||||
if (curve == SSH_ERROR) {
|
||||
BN_CTX_free(ctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
ecdh_key = EC_KEY_new_by_curve_name(curve);
|
||||
if (ecdh_key == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
BN_CTX_free(ctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
group = EC_KEY_get0_group(ecdh_key);
|
||||
EC_KEY_generate_key(ecdh_key);
|
||||
|
||||
ecdh_pubkey = EC_KEY_get0_public_key(ecdh_key);
|
||||
len = EC_POINT_point2oct(group,
|
||||
ecdh_pubkey,
|
||||
POINT_CONVERSION_UNCOMPRESSED,
|
||||
NULL,
|
||||
0,
|
||||
ctx);
|
||||
|
||||
q_s_string = ssh_string_new(len);
|
||||
if (q_s_string == NULL) {
|
||||
EC_KEY_free(ecdh_key);
|
||||
BN_CTX_free(ctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
EC_POINT_point2oct(group,
|
||||
ecdh_pubkey,
|
||||
POINT_CONVERSION_UNCOMPRESSED,
|
||||
ssh_string_data(q_s_string),
|
||||
len,
|
||||
ctx);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
session->next_crypto->ecdh_privkey = ecdh_key;
|
||||
session->next_crypto->ecdh_server_pubkey = q_s_string;
|
||||
|
||||
/* build k and session_id */
|
||||
rc = ecdh_build_k(session);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* privkey is not allocated */
|
||||
rc = ssh_get_key_params(session, &privkey);
|
||||
if (rc == SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_make_sessionid(session);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
|
||||
if (sig_blob == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not export server public key");
|
||||
ssh_string_free(sig_blob);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bSSS",
|
||||
SSH2_MSG_KEXDH_REPLY,
|
||||
pubkey_blob, /* host's pubkey */
|
||||
q_s_string, /* ecdh public key */
|
||||
sig_blob); /* signature blob */
|
||||
|
||||
ssh_string_free(sig_blob);
|
||||
ssh_string_free(pubkey_blob);
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent");
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
|
||||
if (rc < 0) {
|
||||
return SSH_ERROR;;
|
||||
}
|
||||
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
rc = ssh_packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#endif /* HAVE_ECDH */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user