Compare commits
1154 Commits
libssh-0.1
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76b14eaed7 | ||
|
|
8e8f091aba | ||
|
|
d75a54e206 | ||
|
|
efb7a7c4e0 | ||
|
|
7342e73d10 | ||
|
|
832f92e35f | ||
|
|
ea3464532e | ||
|
|
7e235f8748 | ||
|
|
052c8217b7 | ||
|
|
26b9ba5f8c | ||
|
|
1b3c061aae | ||
|
|
1525ea3dda | ||
|
|
a189c2ef4d | ||
|
|
b2abcf8534 | ||
|
|
809f9b7729 | ||
|
|
d297621c33 | ||
|
|
d936b7e81d | ||
|
|
971d44107e | ||
|
|
a1e49728ba | ||
|
|
6c5459e7fc | ||
|
|
f47d1c797a | ||
|
|
da27d23125 | ||
|
|
34db488e4d | ||
|
|
9780fa2f01 | ||
|
|
5a795ce47c | ||
|
|
b33a90d20b | ||
|
|
ef45b8ae8c | ||
|
|
3c2b254206 | ||
|
|
7dea005729 | ||
|
|
ad8d0c1e03 | ||
|
|
cb0f7d963e | ||
|
|
c90b239230 | ||
|
|
18ec01c980 | ||
|
|
a983142a07 | ||
|
|
89d51ced0d | ||
|
|
16771cc574 | ||
|
|
247ebb4d7f | ||
|
|
acd5dace66 | ||
|
|
5545b8808b | ||
|
|
be5a900ed0 | ||
|
|
40ba3c6c80 | ||
|
|
57225a7168 | ||
|
|
02ae2ace35 | ||
|
|
76c6ee9ccf | ||
|
|
9a3351934b | ||
|
|
1f1309c915 | ||
|
|
a8ca282033 | ||
|
|
b61bb3f8ac | ||
|
|
c9abf5ebbb | ||
|
|
48fdf4b80a | ||
|
|
f5eb3e532b | ||
|
|
3f0007895c | ||
|
|
06186279a8 | ||
|
|
c36bd2304a | ||
|
|
82db6a7ab3 | ||
|
|
deffea5ad2 | ||
|
|
320844669a | ||
|
|
d0d45c8915 | ||
|
|
65abae059e | ||
|
|
7c2574682c | ||
|
|
d2bb1ba889 | ||
|
|
9b4ee9c6d4 | ||
|
|
d3e80d9a19 | ||
|
|
4d3da7819c | ||
|
|
b79a681ebb | ||
|
|
f7cad4245a | ||
|
|
11c4b29e20 | ||
|
|
e04d753ace | ||
|
|
06eea93ded | ||
|
|
06edb2db5e | ||
|
|
ced98d41cf | ||
|
|
88c2ea6752 | ||
|
|
5fed1bc8be | ||
|
|
a30ba0091f | ||
|
|
ad23fe8c27 | ||
|
|
3710b31d24 | ||
|
|
2c5bb17211 | ||
|
|
83ae6b3f0a | ||
|
|
06cefe1d67 | ||
|
|
043b1fb133 | ||
|
|
f1490170f3 | ||
|
|
4ba0746135 | ||
|
|
e94fd6ccd1 | ||
|
|
83114b636f | ||
|
|
5a99cf9c7f | ||
|
|
213556ce01 | ||
|
|
5d06ee459b | ||
|
|
96807b9313 | ||
|
|
6d81ecddbe | ||
|
|
d0e5cf78d0 | ||
|
|
a0707afc3e | ||
|
|
06b61f75fa | ||
|
|
f9d7cadf4b | ||
|
|
c1aab9903f | ||
|
|
fd1c3e8878 | ||
|
|
d730b40b91 | ||
|
|
9044fcdb52 | ||
|
|
bc5211d055 | ||
|
|
701a2155a7 | ||
|
|
38f3d158f6 | ||
|
|
0d5a2652b4 | ||
|
|
5c496acef7 | ||
|
|
3e074a3fba | ||
|
|
98a844ceb2 | ||
|
|
ce45ba8c61 | ||
|
|
62c85a59a9 | ||
|
|
c4f1a70a89 | ||
|
|
f52be27114 | ||
|
|
228208af5e | ||
|
|
163373c9d9 | ||
|
|
e82677a923 | ||
|
|
79966eb924 | ||
|
|
4feb0dd79d | ||
|
|
f8d943afda | ||
|
|
4bad7cc08f | ||
|
|
3526e02dee | ||
|
|
ecea5b6052 | ||
|
|
1833ce86f9 | ||
|
|
3938e5e850 | ||
|
|
dd80a56029 | ||
|
|
9d6df9d0fa | ||
|
|
ee180c660e | ||
|
|
541cd39f14 | ||
|
|
64f72ed55f | ||
|
|
0ef79018b3 | ||
|
|
7911580304 | ||
|
|
e5108f2ffc | ||
|
|
5ce4b65abb | ||
|
|
b62675b435 | ||
|
|
f333d95013 | ||
|
|
92d0f8aba6 | ||
|
|
66460578b1 | ||
|
|
b93db6c3d1 | ||
|
|
1c3143ff00 | ||
|
|
47305a2f72 | ||
|
|
5bbaecfaa7 | ||
|
|
6e5d0a935f | ||
|
|
5d4d9f8208 | ||
|
|
c128cf8807 | ||
|
|
5937b5ba4e | ||
|
|
1241a3a8c9 | ||
|
|
21d338737a | ||
|
|
d91630308d | ||
|
|
37f0e91814 | ||
|
|
32a256e157 | ||
|
|
14bd26e71c | ||
|
|
97e71606e0 | ||
|
|
d4b0de702b | ||
|
|
acc080ac03 | ||
|
|
e56af9fa79 | ||
|
|
c4b2bd34a8 | ||
|
|
50ee6411f2 | ||
|
|
c1dd30b47b | ||
|
|
8ba9e931e8 | ||
|
|
eda5c6576b | ||
|
|
302d868875 | ||
|
|
7db75e8fd0 | ||
|
|
ebe632cf8f | ||
|
|
150d606db7 | ||
|
|
63fbf00efe | ||
|
|
ae33ced0dc | ||
|
|
ee6e2c69e1 | ||
|
|
cefc4f8c97 | ||
|
|
b64e7f67d3 | ||
|
|
491cd81a32 | ||
|
|
3444f4c449 | ||
|
|
80541ab828 | ||
|
|
b042477f83 | ||
|
|
950abbbd81 | ||
|
|
b9c6701c68 | ||
|
|
a94df4bb8f | ||
|
|
41b8b3326c | ||
|
|
a9c8f942a5 | ||
|
|
d307bfa239 | ||
|
|
66e8491f73 | ||
|
|
e93c1f6a61 | ||
|
|
358553e976 | ||
|
|
07d099f652 | ||
|
|
f3d70e54e9 | ||
|
|
74d1bf51b5 | ||
|
|
00f1d6fac2 | ||
|
|
029754efb3 | ||
|
|
a49e0c2a84 | ||
|
|
8966e577ab | ||
|
|
dc45b8f3f1 | ||
|
|
c932790b82 | ||
|
|
8a0aa17bca | ||
|
|
ecb11f1a18 | ||
|
|
6aea779918 | ||
|
|
a51384fe4e | ||
|
|
c55140272f | ||
|
|
607dad040b | ||
|
|
55bb909252 | ||
|
|
08cbbea461 | ||
|
|
8c4e337ab7 | ||
|
|
8541b6584f | ||
|
|
2f77727796 | ||
|
|
a3c5d3b256 | ||
|
|
59a502ede6 | ||
|
|
c94e2efcf1 | ||
|
|
3d3b12891f | ||
|
|
6ca59307d4 | ||
|
|
e8bbd194c7 | ||
|
|
df4e907dff | ||
|
|
c99261437f | ||
|
|
53ac23ded4 | ||
|
|
ffed80f8c0 | ||
|
|
9ada7aa0e4 | ||
|
|
d357a9f3e2 | ||
|
|
c9d95ab0c7 | ||
|
|
ccff22d378 | ||
|
|
4310a696f2 | ||
|
|
771e19a7a9 | ||
|
|
118a747acd | ||
|
|
5691e0f609 | ||
|
|
5a6e2fd02a | ||
|
|
e8099375fe | ||
|
|
d00f267bc6 | ||
|
|
35d337834b | ||
|
|
ba1e8303f8 | ||
|
|
ef50a3c0f0 | ||
|
|
e7cffe7e1b | ||
|
|
d1bf9068a9 | ||
|
|
737f9ecc3c | ||
|
|
cc667021e5 | ||
|
|
f9f8c939bc | ||
|
|
aab6ce364a | ||
|
|
0cec257077 | ||
|
|
957efe51a2 | ||
|
|
bb85492d4f | ||
|
|
22c1b6970c | ||
|
|
09155adb19 | ||
|
|
95f8cbc7f0 | ||
|
|
3423399f98 | ||
|
|
ccbec9c275 | ||
|
|
ed52c88a03 | ||
|
|
0f0ac314d2 | ||
|
|
95e4c39e8a | ||
|
|
8c89633a45 | ||
|
|
8069679033 | ||
|
|
c2e9d39dbe | ||
|
|
ab44f606b2 | ||
|
|
444982b38a | ||
|
|
3df61a4e86 | ||
|
|
961c79637c | ||
|
|
7eefbbd478 | ||
|
|
c4c28c6473 | ||
|
|
08a32ac381 | ||
|
|
62762bbbc9 | ||
|
|
ab3e08c2b5 | ||
|
|
809898b980 | ||
|
|
51bd08027e | ||
|
|
0b4b71cc11 | ||
|
|
5d3ef7261c | ||
|
|
9817392e26 | ||
|
|
168302b9d6 | ||
|
|
82c8bbc504 | ||
|
|
1ea1782036 | ||
|
|
c17112f070 | ||
|
|
28c0056bca | ||
|
|
7e4f08e22a | ||
|
|
aeb0b2ec6f | ||
|
|
67cf8e3702 | ||
|
|
309f36fa83 | ||
|
|
7a2a743a39 | ||
|
|
ccb8cf88c8 | ||
|
|
b43392c31d | ||
|
|
5fc65e7270 | ||
|
|
8310b8cc2b | ||
|
|
b0063b52d8 | ||
|
|
33a947dcb0 | ||
|
|
72c282434b | ||
|
|
ba9642882d | ||
|
|
a6b73219e2 | ||
|
|
e2afe196d8 | ||
|
|
32833b40bc | ||
|
|
bc4804aa9b | ||
|
|
acb158e827 | ||
|
|
faf9caafc6 | ||
|
|
8dc29f140b | ||
|
|
7501ca1e08 | ||
|
|
2eb2af4426 | ||
|
|
5d27f69494 | ||
|
|
6fc1bf6901 | ||
|
|
a85813e6e6 | ||
|
|
f039edd85d | ||
|
|
1229ad650b | ||
|
|
937552aed2 | ||
|
|
f6709b03e6 | ||
|
|
96595d1674 | ||
|
|
c799a18d89 | ||
|
|
babd891e82 | ||
|
|
320e5154b2 | ||
|
|
986e0c593f | ||
|
|
d38007c4be | ||
|
|
c22bfa792f | ||
|
|
926d45b6dd | ||
|
|
681a5aaa26 | ||
|
|
e322e8f50c | ||
|
|
a4118ddc06 | ||
|
|
db7f101d1c | ||
|
|
ae8881dfe5 | ||
|
|
00f09acbec | ||
|
|
74eb01f26d | ||
|
|
4f239f79c6 | ||
|
|
b8e587e498 | ||
|
|
b314fd3e04 | ||
|
|
d1ad796496 | ||
|
|
e2064b743d | ||
|
|
6d2a3e4eb6 | ||
|
|
7c34fa783d | ||
|
|
2a2c714dfa | ||
|
|
12baa5200a | ||
|
|
f2b64abcbd | ||
|
|
4135154b6d | ||
|
|
ca4c874a9e | ||
|
|
c7b6ffad0e | ||
|
|
c1fb0d872d | ||
|
|
3a167a89b5 | ||
|
|
dfa9421e01 | ||
|
|
efc5bc633f | ||
|
|
3a4ba8b763 | ||
|
|
47db54b7c1 | ||
|
|
d1c2d3db9d | ||
|
|
dcb65fe584 | ||
|
|
d758990d39 | ||
|
|
bfae56634c | ||
|
|
3d0226cadc | ||
|
|
0bcd7d12d8 | ||
|
|
bd10ec1162 | ||
|
|
69c169e4cb | ||
|
|
f0b9db586b | ||
|
|
c735b44f83 | ||
|
|
3b4b8033de | ||
|
|
0068fdd594 | ||
|
|
344235c954 | ||
|
|
d00f7b1bf9 | ||
|
|
b14018ecab | ||
|
|
5e47b1c1c2 | ||
|
|
9ce885b168 | ||
|
|
184dad101d | ||
|
|
04a58919f8 | ||
|
|
b106211d92 | ||
|
|
af10857aa3 | ||
|
|
f3b389d112 | ||
|
|
18e7423e70 | ||
|
|
8c8d3ceef7 | ||
|
|
0d0ed4b1f8 | ||
|
|
8dc234c909 | ||
|
|
2e686c5cea | ||
|
|
d3706d5940 | ||
|
|
d92a057090 | ||
|
|
1434f24911 | ||
|
|
cce600f980 | ||
|
|
95150b1137 | ||
|
|
65b2591b91 | ||
|
|
a5e9529ca7 | ||
|
|
49a355c272 | ||
|
|
84d02e7440 | ||
|
|
0b91ba779c | ||
|
|
d02163546d | ||
|
|
a93e84efb9 | ||
|
|
a59d587060 | ||
|
|
6c4e4a9e1c | ||
|
|
aa681c268e | ||
|
|
fe381d6aa4 | ||
|
|
1f76cc0c6a | ||
|
|
bf2b8954e8 | ||
|
|
7e3935e7d2 | ||
|
|
d38b471fd8 | ||
|
|
735a4368c2 | ||
|
|
a25f9d211d | ||
|
|
3a52bf1679 | ||
|
|
f7bdd779d6 | ||
|
|
8ef249a4a4 | ||
|
|
d9da8f212d | ||
|
|
9613e9508d | ||
|
|
6b9a6529bd | ||
|
|
b14cde6d2a | ||
|
|
e01c32f41e | ||
|
|
dd6a711354 | ||
|
|
c1a7de78d1 | ||
|
|
9735f074ba | ||
|
|
b2b56151c0 | ||
|
|
de7903a633 | ||
|
|
a089513e40 | ||
|
|
ec9d7d13fd | ||
|
|
f14568262a | ||
|
|
257e8eb2c1 | ||
|
|
99fcd56135 | ||
|
|
8922e43578 | ||
|
|
e36ca61e36 | ||
|
|
02c092d3d9 | ||
|
|
520f758902 | ||
|
|
12b8eed093 | ||
|
|
3372c2ad78 | ||
|
|
6b83aa9a40 | ||
|
|
7f045e2d91 | ||
|
|
2b916b3b88 | ||
|
|
a10553ae57 | ||
|
|
d1ce336ae3 | ||
|
|
79ac8b85d8 | ||
|
|
9a9cafeed5 | ||
|
|
a0a5292692 | ||
|
|
1a64c577f6 | ||
|
|
c03d0d4823 | ||
|
|
d5456931cc | ||
|
|
dc18b41357 | ||
|
|
0f5dec7fb7 | ||
|
|
0cda1c0e83 | ||
|
|
1ea9708409 | ||
|
|
39fcaac3ca | ||
|
|
dab51d8e20 | ||
|
|
4becc8eb82 | ||
|
|
3468cc0dc5 | ||
|
|
4bd8d8d362 | ||
|
|
083a4781d8 | ||
|
|
7e3263d995 | ||
|
|
fbf02d5936 | ||
|
|
16fd55b4b2 | ||
|
|
799557384d | ||
|
|
c6be50cc97 | ||
|
|
af90168624 | ||
|
|
9dbd1ec80b | ||
|
|
9b9a2ea97d | ||
|
|
e9b76ff1bd | ||
|
|
e9046fc069 | ||
|
|
0cd749a533 | ||
|
|
e795849299 | ||
|
|
d887e1320a | ||
|
|
9eaa7a6394 | ||
|
|
4af88c84d4 | ||
|
|
00fce9cb6c | ||
|
|
a547b7f115 | ||
|
|
8bf908a56f | ||
|
|
b7018c17c7 | ||
|
|
a15c977cdc | ||
|
|
91e228b08b | ||
|
|
cbcd6d6f46 | ||
|
|
49b0c859f9 | ||
|
|
79ba546cde | ||
|
|
0ea982d4ec | ||
|
|
c043122655 | ||
|
|
5da8963c1d | ||
|
|
f3d80833fe | ||
|
|
874b75429f | ||
|
|
f8a6b1e2b3 | ||
|
|
5b9b901e48 | ||
|
|
2966a4a33c | ||
|
|
867630750c | ||
|
|
9a40d51162 | ||
|
|
259721e523 | ||
|
|
4bc40a47a3 | ||
|
|
f0b55391a8 | ||
|
|
d2e5b69b02 | ||
|
|
2971e122d0 | ||
|
|
e2524538f6 | ||
|
|
d0ecb5388c | ||
|
|
72b6fad284 | ||
|
|
258c2eef3b | ||
|
|
a02268a254 | ||
|
|
f16b3539da | ||
|
|
0306581f1c | ||
|
|
d8f00aca20 | ||
|
|
e0aa182e7e | ||
|
|
0e756306f0 | ||
|
|
904c3e024c | ||
|
|
b58cb9f72b | ||
|
|
861590192f | ||
|
|
9ad2f6b3b1 | ||
|
|
ef8e90863b | ||
|
|
d29ed23010 | ||
|
|
46d7417620 | ||
|
|
c73a8a824e | ||
|
|
7712c7d0f9 | ||
|
|
d7a0cbcfbb | ||
|
|
cb0237e85b | ||
|
|
5b0f480acd | ||
|
|
629ba3fd34 | ||
|
|
48d474f78c | ||
|
|
e298600303 | ||
|
|
8295945011 | ||
|
|
8363929104 | ||
|
|
71e1baeb5f | ||
|
|
82b363f294 | ||
|
|
8fb2c5d2fd | ||
|
|
9ce53b6972 | ||
|
|
7b89ff760a | ||
|
|
362ab3a684 | ||
|
|
ea97d41bbb | ||
|
|
c85268c38b | ||
|
|
c9cfeb9b83 | ||
|
|
deedc0e108 | ||
|
|
57073d588a | ||
|
|
d416ef533f | ||
|
|
2743b510ac | ||
|
|
41d370864e | ||
|
|
7e4ea0d111 | ||
|
|
b0b2e8fefd | ||
|
|
b804aa9286 | ||
|
|
ab10f5c2f7 | ||
|
|
9634668258 | ||
|
|
894e07aede | ||
|
|
c4d77b9438 | ||
|
|
bd091239d3 | ||
|
|
716950fc9e | ||
|
|
f6e2d18da1 | ||
|
|
754fb9afc4 | ||
|
|
60ec21a5bf | ||
|
|
7d82bc377f | ||
|
|
325ea6dc40 | ||
|
|
9ddde3803e | ||
|
|
8ed9f5e69b | ||
|
|
af8de95805 | ||
|
|
17a8a8b3c3 | ||
|
|
a001e19882 | ||
|
|
eacab52789 | ||
|
|
97e9289271 | ||
|
|
3bfa6e8637 | ||
|
|
965a94b515 | ||
|
|
74d42ca38b | ||
|
|
6d1ed76c7a | ||
|
|
fe53cdfabd | ||
|
|
bed4438695 | ||
|
|
2fe9ed1764 | ||
|
|
11b792a076 | ||
|
|
5a2654c837 | ||
|
|
0ce88225c0 | ||
|
|
3e0c2275ef | ||
|
|
13935fca7e | ||
|
|
ec6363d6b5 | ||
|
|
2d3b7e07af | ||
|
|
c662bcc466 | ||
|
|
5f0e08912e | ||
|
|
7812e71b8f | ||
|
|
0f102fd1a2 | ||
|
|
40b2279407 | ||
|
|
145222eef6 | ||
|
|
d41a0aaa13 | ||
|
|
21627509f5 | ||
|
|
3809db771d | ||
|
|
5d60805fda | ||
|
|
d4adad584e | ||
|
|
b4ed60024b | ||
|
|
6c59d975ba | ||
|
|
c4e547f3f7 | ||
|
|
ac7c788ef0 | ||
|
|
5802017b7f | ||
|
|
b3e40e2bf7 | ||
|
|
b73608e7b7 | ||
|
|
e1a64c924d | ||
|
|
414a276d2b | ||
|
|
60aa354c19 | ||
|
|
cf1e02010c | ||
|
|
e33ef71dee | ||
|
|
e90df71955 | ||
|
|
c93a730bc1 | ||
|
|
70d0993312 | ||
|
|
0cbd35f1fd | ||
|
|
f3fe85f45e | ||
|
|
51a728dcdf | ||
|
|
e17161dc4f | ||
|
|
0796331c67 | ||
|
|
48d8733f6e | ||
|
|
c15ef71999 | ||
|
|
32d99ec5e5 | ||
|
|
fc5dd6f57c | ||
|
|
b815ca08b3 | ||
|
|
0882338142 | ||
|
|
a8883199d4 | ||
|
|
1db37cd9f4 | ||
|
|
a5f082db83 | ||
|
|
04d86aeeae | ||
|
|
d40a6448a4 | ||
|
|
fdf8dc2750 | ||
|
|
b2d3a4670a | ||
|
|
bc1acb5312 | ||
|
|
3ce68badca | ||
|
|
d7bfbebad6 | ||
|
|
765597e31f | ||
|
|
8aa808a600 | ||
|
|
649f381029 | ||
|
|
081a59371b | ||
|
|
8577f588c3 | ||
|
|
9170320298 | ||
|
|
7f442afd57 | ||
|
|
89c53e1962 | ||
|
|
dceb17d2ad | ||
|
|
2e4a9e3f7b | ||
|
|
cbabc72555 | ||
|
|
3577eea324 | ||
|
|
46a28cfc49 | ||
|
|
3227a4cae0 | ||
|
|
efc1176232 | ||
|
|
fc451a8f3d | ||
|
|
19e62a78a6 | ||
|
|
164ca9ae93 | ||
|
|
455d26a479 | ||
|
|
095ab5ad61 | ||
|
|
a9c998c080 | ||
|
|
b500c2f0cf | ||
|
|
4edd0669fd | ||
|
|
2daf3dc4a8 | ||
|
|
d34bfdab69 | ||
|
|
5dd42dfa22 | ||
|
|
a8b7e17aa0 | ||
|
|
1bdc78d69f | ||
|
|
74a8d271ad | ||
|
|
d2a8a464a7 | ||
|
|
4a83c50ce9 | ||
|
|
996037e77b | ||
|
|
78378291b1 | ||
|
|
60085debb1 | ||
|
|
07cb0be12f | ||
|
|
9d5c31205c | ||
|
|
49c61bb263 | ||
|
|
b6fd4912d7 | ||
|
|
45334b6736 | ||
|
|
2fc77d90cf | ||
|
|
c5a0d0fc09 | ||
|
|
46e6804c89 | ||
|
|
ed68fdaa61 | ||
|
|
9cee4fa054 | ||
|
|
a9d1cfa9e2 | ||
|
|
b9d4e11456 | ||
|
|
fcd63abb6a | ||
|
|
81f9b00005 | ||
|
|
64ef3fefb4 | ||
|
|
6a03f6cefe | ||
|
|
9ee8d8cd20 | ||
|
|
3b7095acbb | ||
|
|
b2fcef3fad | ||
|
|
a7d212cd7d | ||
|
|
6e5eb4ed2d | ||
|
|
cd6e84a6c3 | ||
|
|
b5daac6772 | ||
|
|
1291ceb17d | ||
|
|
6ad455a8ac | ||
|
|
486d2289fa | ||
|
|
ff111a4a8b | ||
|
|
fbfc9b3595 | ||
|
|
3e2bbbc96a | ||
|
|
4172752b4b | ||
|
|
172f6bfb47 | ||
|
|
2c918aad67 | ||
|
|
1176a71d61 | ||
|
|
c0354c4689 | ||
|
|
2be44b4c5a | ||
|
|
d97a5930c9 | ||
|
|
ebcd6eee3c | ||
|
|
d7f7c952f2 | ||
|
|
9857a5ef59 | ||
|
|
47d8bcf9a5 | ||
|
|
d73a0acef7 | ||
|
|
188a9cf68f | ||
|
|
91990f9dfa | ||
|
|
d2d5e717f3 | ||
|
|
4f24fbd3a0 | ||
|
|
5ea247df8e | ||
|
|
63ee84862b | ||
|
|
99e8f34142 | ||
|
|
9cf3d79abc | ||
|
|
3fa6c1639e | ||
|
|
22c41e6784 | ||
|
|
804e283c8b | ||
|
|
8fbb12eddf | ||
|
|
a5cc515f02 | ||
|
|
24dfc59264 | ||
|
|
283d75802d | ||
|
|
71c47b464a | ||
|
|
d53236d69f | ||
|
|
6f6e453d7b | ||
|
|
4f997aee7c | ||
|
|
b3de3a3335 | ||
|
|
59c00c66c4 | ||
|
|
5c407d2f16 | ||
|
|
10c200037a | ||
|
|
a16f34c57a | ||
|
|
a8b9d13687 | ||
|
|
bdcdf92096 | ||
|
|
3876976ced | ||
|
|
7ecc6a704b | ||
|
|
f353b39ff2 | ||
|
|
2c92e8ce93 | ||
|
|
92e35c291c | ||
|
|
7b697d711e | ||
|
|
95c6f880ef | ||
|
|
2cd971e10e | ||
|
|
0ff85b034a | ||
|
|
b83368b2ed | ||
|
|
1dfde16f49 | ||
|
|
57ec9a35c6 | ||
|
|
75a177f8d6 | ||
|
|
417a0f01f8 | ||
|
|
3fa28aaf49 | ||
|
|
30d5ab4313 | ||
|
|
baa773d1cd | ||
|
|
63be7f7651 | ||
|
|
04acf9a8ab | ||
|
|
0cfd4d8ec7 | ||
|
|
ad458c4633 | ||
|
|
d22194f0b1 | ||
|
|
c925907917 | ||
|
|
f41f0492e4 | ||
|
|
0ff6adeb80 | ||
|
|
1fcaac9a35 | ||
|
|
bac71d1e9c | ||
|
|
1a5ff139e2 | ||
|
|
e179675f2c | ||
|
|
baa4eb1232 | ||
|
|
14c7b6a3fb | ||
|
|
aae1bc1058 | ||
|
|
c1630fa097 | ||
|
|
7d4f210234 | ||
|
|
4f903812e6 | ||
|
|
d604d7f872 | ||
|
|
a8c844c9c2 | ||
|
|
de8f36c93c | ||
|
|
44de06e8db | ||
|
|
16ebd4597e | ||
|
|
dd11d469dc | ||
|
|
2c026e4314 | ||
|
|
ae4040a7eb | ||
|
|
12b1fcdfcf | ||
|
|
19439fcfd8 | ||
|
|
54ac7c95e8 | ||
|
|
46ab527bbe | ||
|
|
677d1e1d10 | ||
|
|
c0a76cf9b1 | ||
|
|
d0c76b5baa | ||
|
|
d1960cb9a2 | ||
|
|
12f28a519b | ||
|
|
f4fe781f65 | ||
|
|
710ce11cf0 | ||
|
|
be0c558bcc | ||
|
|
08a8bd936c | ||
|
|
4e239484fe | ||
|
|
d8790d06c4 | ||
|
|
4768d2970a | ||
|
|
c1606da450 | ||
|
|
7455b6ae64 | ||
|
|
c3e03ab465 | ||
|
|
a8fe05cc40 | ||
|
|
6e834b8df2 | ||
|
|
9f2b42382c | ||
|
|
edb04af5be | ||
|
|
0e938ebcf4 | ||
|
|
19ced21adb | ||
|
|
2df2324638 | ||
|
|
66144f6f60 | ||
|
|
5d792a3b5a | ||
|
|
6cf5f0e340 | ||
|
|
4e56c5c956 | ||
|
|
f86bec735b | ||
|
|
7645892ca2 | ||
|
|
8ed50ea6ed | ||
|
|
adfb2bcc75 | ||
|
|
6a64f5a11a | ||
|
|
60db508054 | ||
|
|
3e748512c7 | ||
|
|
d68108f3a4 | ||
|
|
f09bb04025 | ||
|
|
504faca67a | ||
|
|
06fbf5c159 | ||
|
|
85d7cc5cf2 | ||
|
|
e4c13817cc | ||
|
|
9c8486aafb | ||
|
|
33cdc4e3e4 | ||
|
|
3417161b81 | ||
|
|
812576c122 | ||
|
|
a71e2f8f37 | ||
|
|
00bafe0a82 | ||
|
|
d0ffe917fb | ||
|
|
582905affa | ||
|
|
254149dbe8 | ||
|
|
db32a8e683 | ||
|
|
15dbf3ace7 | ||
|
|
83ce7bfa59 | ||
|
|
321e468eca | ||
|
|
393a9bf82c | ||
|
|
5726af1956 | ||
|
|
fe80f47b0a | ||
|
|
ccc7302fc8 | ||
|
|
cba1dfac6c | ||
|
|
6e016c1c54 | ||
|
|
96faaeea03 | ||
|
|
19404bf509 | ||
|
|
a7f85944c8 | ||
|
|
55cabab847 | ||
|
|
f8a7571a91 | ||
|
|
9c19ba7f33 | ||
|
|
ebea7d9023 | ||
|
|
62f013ae96 | ||
|
|
20dcb8b830 | ||
|
|
9709a466d7 | ||
|
|
ddfc2e08b9 | ||
|
|
9847f3f638 | ||
|
|
1bd690d75f | ||
|
|
5b2957f0a7 | ||
|
|
812ba3b717 | ||
|
|
4b8db203b0 | ||
|
|
a45b9938fe | ||
|
|
e6d2b6c713 | ||
|
|
df0a445c87 | ||
|
|
79425f8b92 | ||
|
|
7009df7b04 | ||
|
|
6bebac10b7 | ||
|
|
af771cc35f | ||
|
|
213d1c7fd8 | ||
|
|
c024280669 | ||
|
|
baa18d3712 | ||
|
|
e5a6dc6757 | ||
|
|
cd54390188 | ||
|
|
f09b475c4b | ||
|
|
3fc30681f4 | ||
|
|
2a0d6d854a | ||
|
|
423bb3c8f0 | ||
|
|
492317efe9 | ||
|
|
1fe98800d2 | ||
|
|
7427090a9f | ||
|
|
ff897165ca | ||
|
|
d0bfab2549 | ||
|
|
94cbd58128 | ||
|
|
691105e93b | ||
|
|
5ea54c8159 | ||
|
|
af60e23081 | ||
|
|
f1f766f14f | ||
|
|
13b2727023 | ||
|
|
5854937328 | ||
|
|
0affa5d705 | ||
|
|
2f45688066 | ||
|
|
cb4bdf893d | ||
|
|
8e1d6e4567 | ||
|
|
254ec093ff | ||
|
|
97e038c6e9 | ||
|
|
8104c19013 | ||
|
|
0a5161a7d1 | ||
|
|
329d53a109 | ||
|
|
69ad6985de | ||
|
|
48d14ee9a9 | ||
|
|
f8bfb5a7a1 | ||
|
|
4d98390678 | ||
|
|
6a965e0981 | ||
|
|
c01377081f | ||
|
|
5eb8685932 | ||
|
|
1c0b8f624e | ||
|
|
c4a00ee430 | ||
|
|
3951bbabd5 | ||
|
|
5c7bfaa5f6 | ||
|
|
2bf49e3e65 | ||
|
|
6424971a98 | ||
|
|
f7a9c07de3 | ||
|
|
b3f6194122 | ||
|
|
009bbc0546 | ||
|
|
96d7616166 | ||
|
|
241c1ed91a | ||
|
|
da815b641b | ||
|
|
cbd85a48db | ||
|
|
31abaec00b | ||
|
|
8f463a851c | ||
|
|
ce7cc49465 | ||
|
|
e4bf3b97b4 | ||
|
|
4278499e26 | ||
|
|
28dc1ef45b | ||
|
|
f80faa89ce | ||
|
|
fcb6ee4031 | ||
|
|
4022ef69f3 | ||
|
|
20f52432fc | ||
|
|
9b263cf5e1 | ||
|
|
4f64aa3a5a | ||
|
|
655cda2b0e | ||
|
|
fa94777ed9 | ||
|
|
ae59d21e93 | ||
|
|
7ea71ead61 | ||
|
|
543f3cba7d | ||
|
|
4e1b0e269f | ||
|
|
0e3bb8cbf9 | ||
|
|
9f8d46a45a | ||
|
|
4b5ccd4995 | ||
|
|
0bda152ad2 | ||
|
|
4e8db9d44b | ||
|
|
8bb17c46a8 | ||
|
|
08386d4787 | ||
|
|
8dbe055328 | ||
|
|
cd0aa0bd91 | ||
|
|
f455ffe8b8 | ||
|
|
1c85acb6e6 | ||
|
|
4fb6bccf22 | ||
|
|
fa902a37ae | ||
|
|
df350d3aa4 | ||
|
|
3981aeede2 | ||
|
|
070f679767 | ||
|
|
82850b6ed1 | ||
|
|
a29d28d1f6 | ||
|
|
2fdb5a121f | ||
|
|
c00a3369c2 | ||
|
|
1d6f2e4d9b | ||
|
|
e6cc8dfef5 | ||
|
|
d6bc4905ad | ||
|
|
e1be63d78d | ||
|
|
b0ce6935fc | ||
|
|
1f3143b18c | ||
|
|
8cdf602330 | ||
|
|
0a9b5bcd45 | ||
|
|
bb4e6ad1ee | ||
|
|
19ec009b7d | ||
|
|
ccc87f5593 | ||
|
|
23ff6f9388 | ||
|
|
5928d7962e | ||
|
|
3334070f63 | ||
|
|
f691dbbaab | ||
|
|
bdabf25a5b | ||
|
|
2b5bef9c03 | ||
|
|
14f3910d12 | ||
|
|
bfa7a94b83 | ||
|
|
08a6996103 | ||
|
|
9741054422 | ||
|
|
d109b5bd5f | ||
|
|
9cd23fecac | ||
|
|
bfa988a7c7 | ||
|
|
ef901829c1 | ||
|
|
b067d7a123 | ||
|
|
73c3d8965d | ||
|
|
88335c8e07 | ||
|
|
804814b895 | ||
|
|
a12a8a0153 | ||
|
|
2122fc3dcb | ||
|
|
c3aa0cb182 | ||
|
|
fffdcfb373 | ||
|
|
3058549bf7 | ||
|
|
2c876464ab | ||
|
|
7f40974802 | ||
|
|
f6f1bfaa4e | ||
|
|
91279e0aac | ||
|
|
2ba5a5e976 | ||
|
|
e0011a1970 | ||
|
|
6f029598c7 | ||
|
|
49490ac06d | ||
|
|
f9147a3cf4 | ||
|
|
cb19677d2e | ||
|
|
0c6995b149 | ||
|
|
7b12876f04 | ||
|
|
45a8d1dbb1 | ||
|
|
8c3c21537d | ||
|
|
3513c4bfc0 | ||
|
|
46df3890e8 | ||
|
|
0b826c986c | ||
|
|
6d3e7e1c44 | ||
|
|
2ed0525f40 | ||
|
|
30b5a2e33b | ||
|
|
e15f493d4a | ||
|
|
19c4de7350 | ||
|
|
832b94a660 | ||
|
|
5506aadf05 | ||
|
|
258560da16 | ||
|
|
e364b1e793 | ||
|
|
49b34987d6 | ||
|
|
4a7a7e3186 | ||
|
|
e2b89dec9d | ||
|
|
e7b8de1363 | ||
|
|
f8d7fee588 | ||
|
|
2539d72b7c | ||
|
|
7291f2173c | ||
|
|
96aee531ff | ||
|
|
cc4a11b2ba | ||
|
|
a3a13eb3a8 | ||
|
|
486df37a84 | ||
|
|
c9291ce878 | ||
|
|
9931f158e0 | ||
|
|
b7c1f792cc | ||
|
|
4fb5af1da5 | ||
|
|
bc2e99dc3f | ||
|
|
6d34718f89 | ||
|
|
31073780d1 | ||
|
|
1eb3df5254 | ||
|
|
02fda2ef80 | ||
|
|
2187c3feae | ||
|
|
b231562858 | ||
|
|
b2cd025fcb | ||
|
|
bb9c3245c4 | ||
|
|
dcfc8a2c5d | ||
|
|
cc1b021153 | ||
|
|
aeb60fcf28 | ||
|
|
e97cd2d02e | ||
|
|
10296dbc76 | ||
|
|
492f5d82b8 | ||
|
|
dac62e7439 | ||
|
|
ab24110ae0 | ||
|
|
96ee1c62dd | ||
|
|
c52f40bcb2 | ||
|
|
98b81ebcad | ||
|
|
342b69246c | ||
|
|
c784bf345c | ||
|
|
6b4c2a21bc | ||
|
|
834603c96b | ||
|
|
a54d2377d6 | ||
|
|
8f237bde15 | ||
|
|
d54d45871a | ||
|
|
a5631280a9 | ||
|
|
8c1b159a3a | ||
|
|
96ad1b380d | ||
|
|
edcce095e0 | ||
|
|
f297dc6ab8 | ||
|
|
54c1703cb2 | ||
|
|
9a3e218b6f | ||
|
|
df48ddd895 | ||
|
|
c0c063f94c | ||
|
|
1bd499febb | ||
|
|
87d694d5ad | ||
|
|
1ff893c914 | ||
|
|
435f1549f1 | ||
|
|
4cd58350a8 | ||
|
|
7f742680c2 | ||
|
|
c8373e652c | ||
|
|
da357b1cb4 | ||
|
|
9941e89f30 | ||
|
|
0fa215e2ac | ||
|
|
44f60d878a | ||
|
|
4f6aa53b16 | ||
|
|
b610757e63 | ||
|
|
aa206cbfe5 | ||
|
|
a2aefeb1ab | ||
|
|
9514547c2a | ||
|
|
abe222e1e8 | ||
|
|
80c986bf89 | ||
|
|
01e9341d10 | ||
|
|
039d1b2775 | ||
|
|
53fa00abeb | ||
|
|
61218df5d5 | ||
|
|
23cebfadea | ||
|
|
9d429eda93 | ||
|
|
34baecf49a | ||
|
|
d1947b55ec | ||
|
|
5e81eec4ec | ||
|
|
06a0a957c9 | ||
|
|
8f7c179bed | ||
|
|
0c64a62fb7 | ||
|
|
178d7934f9 | ||
|
|
66d3afd0ab | ||
|
|
358ce46551 | ||
|
|
28d27c3ae4 | ||
|
|
67762bd68b | ||
|
|
9717b99136 | ||
|
|
bafa59825e | ||
|
|
eb40fb60ae | ||
|
|
2074fb1948 | ||
|
|
3c272d00fb | ||
|
|
50713d8ab1 | ||
|
|
46b1f1091b | ||
|
|
367be19990 | ||
|
|
769cb46ac8 | ||
|
|
97c9ac2f58 | ||
|
|
22f0f0dd60 | ||
|
|
78978dc6ce | ||
|
|
e29ffd78b3 | ||
|
|
7757ebf7a5 | ||
|
|
e4d4ca78b4 | ||
|
|
787735098f | ||
|
|
b53d0608b6 | ||
|
|
346e6db318 | ||
|
|
20d9642c4c | ||
|
|
5f4347d5e1 | ||
|
|
657d9143d1 | ||
|
|
7ea75cda45 | ||
|
|
bd1d06f51d | ||
|
|
22954af49a | ||
|
|
37deed27d6 | ||
|
|
76d375064b | ||
|
|
38765d82fc | ||
|
|
80e77802ab | ||
|
|
4070784029 | ||
|
|
3d740c09da | ||
|
|
27e223ba22 | ||
|
|
954f9c86ce | ||
|
|
99bad9006e | ||
|
|
c17b8f1fb2 | ||
|
|
d57a383d43 | ||
|
|
5ef99fcaa5 | ||
|
|
85f73a9bf6 | ||
|
|
6d67d3ca5d | ||
|
|
d3f0aabe7f | ||
|
|
f8ba12f0a6 | ||
|
|
425353d986 | ||
|
|
26895498fb | ||
|
|
bccb8513fa | ||
|
|
bcc541f467 | ||
|
|
915df08058 | ||
|
|
9abb541a0f | ||
|
|
accbc91a86 | ||
|
|
3e4c2205c5 | ||
|
|
2d79c7a9d5 | ||
|
|
b3b3fbfa1d | ||
|
|
d69026d7a4 | ||
|
|
7787dad9bd | ||
|
|
23546e354c | ||
|
|
e5af9524e3 | ||
|
|
f86727e06a | ||
|
|
a69424d4c5 | ||
|
|
8aade7ce6f | ||
|
|
41f2ee92c6 | ||
|
|
8cf9c8162f | ||
|
|
bd2db30174 | ||
|
|
d642b20d9c | ||
|
|
2546b62242 | ||
|
|
6268417ac6 | ||
|
|
8c0be750db | ||
|
|
f306aafdc6 | ||
|
|
648baf0f3c | ||
|
|
20406e51c9 | ||
|
|
8164e1ff9c | ||
|
|
af85ee8e59 | ||
|
|
25a678190c | ||
|
|
0799775185 | ||
|
|
17aec429f5 | ||
|
|
6e2648af6b | ||
|
|
a81e78aff4 | ||
|
|
0800618f32 | ||
|
|
f721ee847b | ||
|
|
382ff38caa | ||
|
|
bc0c027ac0 | ||
|
|
ac6d2fad4a | ||
|
|
1286a70e13 | ||
|
|
aa1e136ea3 | ||
|
|
a07ec441fd | ||
|
|
5dd8c03b3a | ||
|
|
33bcd8e81c | ||
|
|
4d96c667bc | ||
|
|
2e8e666b1d | ||
|
|
66be590657 | ||
|
|
f193e6840d | ||
|
|
0982715bb5 | ||
|
|
ebeee7631d | ||
|
|
aca482a5a5 | ||
|
|
355e29d881 | ||
|
|
163951d869 | ||
|
|
84df28ee31 | ||
|
|
224298a4d0 | ||
|
|
8f6b283582 | ||
|
|
c09b02c573 | ||
|
|
0da54f2908 | ||
|
|
b42e9a19a3 | ||
|
|
e27ee9d0a4 | ||
|
|
4a7791b784 | ||
|
|
9a4c5203af | ||
|
|
8343a43edc | ||
|
|
964df4dc29 | ||
|
|
bb5f7e2707 | ||
|
|
e53a2711d3 | ||
|
|
a0c0efaf2e | ||
|
|
21ef488121 | ||
|
|
0128ed0d2c | ||
|
|
6a25f07777 | ||
|
|
cc0939df73 | ||
|
|
eccedf8f79 |
29
.clang-format
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
IndentWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BraceWrapping:
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: true
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeElse: false
|
||||||
|
BeforeWhile: false
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentCaseBlocks: false
|
||||||
|
ColumnLimit: 80
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
BreakAfterReturnType: ExceptShortType
|
||||||
|
AlwaysBreakAfterReturnType: AllDefinitions
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
ForEachMacros: ['ssh_callbacks_iterate']
|
||||||
|
AlignConsecutiveMacros: 'Consecutive'
|
||||||
1
.clang-format-ignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
src/external/*
|
||||||
6
.cmake-format.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
line_width: 80
|
||||||
|
tab_size: 4
|
||||||
|
use_tabchars: false
|
||||||
|
separate_ctrl_name_with_space: true
|
||||||
|
separate_fn_name_with_space: false
|
||||||
@@ -12,7 +12,12 @@ indent_style = space
|
|||||||
indent_size = 4
|
indent_size = 4
|
||||||
tab_width = 4
|
tab_width = 4
|
||||||
|
|
||||||
[{CMakeLists.txt,*.cmake}]
|
[CMakeLists.txt]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
tab_width = 4
|
tab_width = 4
|
||||||
|
|
||||||
|
[*.cmake]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
tab_width = 4
|
||||||
|
|||||||
3
.gitignore
vendored
@@ -1,6 +1,5 @@
|
|||||||
*.a
|
*.a
|
||||||
*.o
|
*.o
|
||||||
.*
|
|
||||||
*.swp
|
*.swp
|
||||||
*~$
|
*~$
|
||||||
cscope.*
|
cscope.*
|
||||||
@@ -10,3 +9,5 @@ compile_commands.json
|
|||||||
tags
|
tags
|
||||||
/build
|
/build
|
||||||
/obj*
|
/obj*
|
||||||
|
doc/tags.xml
|
||||||
|
.DS_Store
|
||||||
|
|||||||
622
.gitlab-ci.yml
@@ -1,26 +1,43 @@
|
|||||||
---
|
---
|
||||||
variables:
|
variables:
|
||||||
BUILD_IMAGES_PROJECT: libssh/build-images
|
BUILD_IMAGES_PROJECT: libssh/build-images
|
||||||
CENTOS7_BUILD: buildenv-centos7
|
CENTOS8_BUILD: buildenv-c8s
|
||||||
COVERITY_BUILD: buildenv-coverity
|
CENTOS9_BUILD: buildenv-c9s
|
||||||
|
CENTOS10_BUILD: buildenv-c10s
|
||||||
FEDORA_BUILD: buildenv-fedora
|
FEDORA_BUILD: buildenv-fedora
|
||||||
MINGW_BUILD: buildenv-mingw
|
MINGW_BUILD: buildenv-mingw
|
||||||
TUMBLEWEED_BUILD: buildenv-tumbleweed
|
TUMBLEWEED_BUILD: buildenv-tumbleweed
|
||||||
UBUNTU_BUILD: buildenv-ubuntu
|
UBUNTU_BUILD: buildenv-ubuntu
|
||||||
RAWHIDE_BUILD: buildenv-rawhide
|
ALPINE_BUILD: buildenv-alpine
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
|
- review
|
||||||
- build
|
- build
|
||||||
- test
|
- test
|
||||||
- analysis
|
- analysis
|
||||||
|
|
||||||
.build:
|
# This is some black magic to select between branch pipelines and
|
||||||
stage: build
|
# merge request pipelines to avoid running same pipelines twice
|
||||||
|
workflow:
|
||||||
|
rules:
|
||||||
|
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"'
|
||||||
|
when: never
|
||||||
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
||||||
|
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
|
||||||
|
when: never
|
||||||
|
- if: '$CI_COMMIT_BRANCH'
|
||||||
|
|
||||||
|
.build_options:
|
||||||
variables:
|
variables:
|
||||||
CMAKE_DEFAULT_OPTIONS: "-DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON"
|
CMAKE_DEFAULT_OPTIONS: "-DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON"
|
||||||
CMAKE_BUILD_OPTIONS: "-DWITH_BLOWFISH_CIPHER=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON -DWITH_DSA=ON"
|
CMAKE_DEFAULT_DEBUG_OPTIONS: "-DCMAKE_C_FLAGS='-O0 -g -ggdb' -DPICKY_DEVELOPER=ON"
|
||||||
CMAKE_TEST_OPTIONS: "-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DWITH_BENCHMARKS=ON"
|
CMAKE_BUILD_OPTIONS: "-DWITH_BLOWFISH_CIPHER=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON -DWITH_FIDO2=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON"
|
||||||
|
CMAKE_TEST_OPTIONS: "-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DGSSAPI_TESTING=ON -DWITH_BENCHMARKS=ON -DFUZZ_TESTING=ON"
|
||||||
CMAKE_OPTIONS: $CMAKE_DEFAULT_OPTIONS $CMAKE_BUILD_OPTIONS $CMAKE_TEST_OPTIONS
|
CMAKE_OPTIONS: $CMAKE_DEFAULT_OPTIONS $CMAKE_BUILD_OPTIONS $CMAKE_TEST_OPTIONS
|
||||||
|
|
||||||
|
.build:
|
||||||
|
extends: .build_options
|
||||||
|
stage: build
|
||||||
before_script: &build
|
before_script: &build
|
||||||
- uname -a
|
- uname -a
|
||||||
- cat /etc/os-release
|
- cat /etc/os-release
|
||||||
@@ -35,7 +52,11 @@ stages:
|
|||||||
make -j$(nproc) install
|
make -j$(nproc) install
|
||||||
# Do not use after_script as it does not make the targets fail
|
# Do not use after_script as it does not make the targets fail
|
||||||
tags:
|
tags:
|
||||||
- shared
|
- saas-linux-small-amd64
|
||||||
|
only:
|
||||||
|
- merge_requests
|
||||||
|
- branches
|
||||||
|
|
||||||
except:
|
except:
|
||||||
- tags
|
- tags
|
||||||
artifacts:
|
artifacts:
|
||||||
@@ -58,34 +79,154 @@ stages:
|
|||||||
.fedora:
|
.fedora:
|
||||||
extends: .tests
|
extends: .tests
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||||
variables:
|
|
||||||
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON
|
|
||||||
|
|
||||||
.fedora_rawhide:
|
|
||||||
extends: .fedora
|
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$RAWHIDE_BUILD
|
|
||||||
before_script:
|
|
||||||
- *build
|
|
||||||
# Legacy cp is needed for SHA1 tests to pass
|
|
||||||
- update-crypto-policies --set LEGACY
|
|
||||||
|
|
||||||
.tumbleweed:
|
.tumbleweed:
|
||||||
extends: .tests
|
extends: .tests
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
||||||
|
script:
|
||||||
|
# torture_gssapi_key_exchange_null is excluded because of a bug
|
||||||
|
# https://bugzilla.opensuse.org/show_bug.cgi?id=1254680
|
||||||
|
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
||||||
|
make -j$(nproc) &&
|
||||||
|
ctest --output-on-failure -E "^torture_gssapi_key_exchange_null$"
|
||||||
|
|
||||||
|
.centos:
|
||||||
|
extends: .tests
|
||||||
|
variables:
|
||||||
|
OPENSSL_ENABLE_SHA1_SIGNATURES: 1
|
||||||
|
|
||||||
|
.centos10:
|
||||||
|
extends: .centos
|
||||||
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS10_BUILD
|
||||||
|
|
||||||
|
.centos9:
|
||||||
|
extends: .centos
|
||||||
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
|
||||||
|
|
||||||
|
# Unit testing only, no client and pkd testing, because cwrap is not available
|
||||||
|
# for MinGW
|
||||||
|
.mingw:
|
||||||
|
extends: .tests
|
||||||
|
variables:
|
||||||
|
WINEDEBUG: -all
|
||||||
|
script:
|
||||||
|
- $WINEBIN $CMAKE_DEFAULT_OPTIONS
|
||||||
|
-DWITH_SFTP=ON
|
||||||
|
-DWITH_SERVER=ON
|
||||||
|
-DWITH_ZLIB=ON
|
||||||
|
-DWITH_PCAP=ON
|
||||||
|
-DWITH_FIDO2=ON
|
||||||
|
-DUNIT_TESTING=ON .. &&
|
||||||
|
make -j$(nproc) &&
|
||||||
|
ctest --output-on-failure -E torture_rand
|
||||||
|
|
||||||
|
.fips:
|
||||||
|
extends: .tests
|
||||||
|
variables:
|
||||||
|
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON
|
||||||
|
before_script:
|
||||||
|
- *build
|
||||||
|
- echo "# userspace fips" > /etc/system-fips
|
||||||
|
# We do not need the kernel part, but in case we ever do:
|
||||||
|
# mkdir -p /var/tmp/userspace-fips
|
||||||
|
# echo 1 > /var/tmp/userspace-fips/fips_enabled
|
||||||
|
# mount --bind /var/tmp/userspace-fips/fips_enabled \
|
||||||
|
# /proc/sys/crypto/fips_enabled
|
||||||
|
- update-crypto-policies --show
|
||||||
|
- update-crypto-policies --set FIPS
|
||||||
|
- update-crypto-policies --show
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Review #
|
||||||
|
###############################################################################
|
||||||
|
review:
|
||||||
|
variables:
|
||||||
|
GIT_DEPTH: 100
|
||||||
|
stage: review
|
||||||
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||||
|
script:
|
||||||
|
- ERROR=0
|
||||||
|
codespell --ignore-words-list=keypair,sorce,ned,nd,ue,pendin || ERROR=1;
|
||||||
|
./.gitlab-ci/clang-format-check.sh || ERROR=1;
|
||||||
|
./.gitlab-ci/git-check-signoff-trailer.sh ${CI_MERGE_REQUEST_DIFF_BASE_SHA} || ERROR=1;
|
||||||
|
./.gitlab-ci/shellcheck.sh || ERROR=1;
|
||||||
|
exit $ERROR
|
||||||
|
# the format is not always matching our intentions
|
||||||
|
allow_failure: true
|
||||||
|
tags:
|
||||||
|
- saas-linux-small-amd64
|
||||||
|
only:
|
||||||
|
- merge_requests
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# CentOS builds #
|
# CentOS builds #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# pkd tests fail on CentOS7 docker images, so we don't use -DSERVER_TESTING=ON
|
centos10s/openssl_3.5.x/x86_64:
|
||||||
centos7/openssl_1.0.x/x86_64:
|
extends: .centos10
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS7_BUILD
|
variables:
|
||||||
extends: .tests
|
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
|
||||||
script:
|
script:
|
||||||
- cmake3 $CMAKE_OPTIONS .. &&
|
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
||||||
make -j$(nproc) &&
|
make -j$(nproc) &&
|
||||||
ctest --output-on-failure
|
ctest --output-on-failure
|
||||||
|
|
||||||
|
centos10s/openssl_3.5.x/x86_64/fips:
|
||||||
|
extends: .fips
|
||||||
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS10_BUILD
|
||||||
|
variables:
|
||||||
|
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
|
||||||
|
OPENSSL_ENABLE_SHA1_SIGNATURES: 1
|
||||||
|
script:
|
||||||
|
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
||||||
|
make -j$(nproc) &&
|
||||||
|
OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure
|
||||||
|
|
||||||
|
centos9s/openssl_3.5.x/x86_64:
|
||||||
|
extends: .centos9
|
||||||
|
variables:
|
||||||
|
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
|
||||||
|
script:
|
||||||
|
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
||||||
|
make -j$(nproc) &&
|
||||||
|
ctest --output-on-failure
|
||||||
|
|
||||||
|
centos9s/mbedtls_2.x/x86_64:
|
||||||
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
|
||||||
|
extends: .tests
|
||||||
|
variables:
|
||||||
|
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF"
|
||||||
|
|
||||||
|
centos9s/openssl_3.5.x/x86_64/fips:
|
||||||
|
extends: .fips
|
||||||
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
|
||||||
|
variables:
|
||||||
|
OPENSSL_ENABLE_SHA1_SIGNATURES: 1
|
||||||
|
script:
|
||||||
|
# torture_gssapi_key_exchange_* tests are excluded because gssapi-keyex is disabled
|
||||||
|
# by OpenSSH in FIPS mode in RHEL 9
|
||||||
|
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
||||||
|
make -j$(nproc) &&
|
||||||
|
OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure -E "^torture_gssapi_key_exchange.*"
|
||||||
|
|
||||||
|
centos8s/openssl_1.1.1/x86_64:
|
||||||
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS8_BUILD
|
||||||
|
extends: .tests
|
||||||
|
variables:
|
||||||
|
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON
|
||||||
|
script:
|
||||||
|
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
||||||
|
make -j$(nproc) &&
|
||||||
|
ctest --output-on-failure
|
||||||
|
|
||||||
|
centos8s/openssl_1.1.1/x86_64/fips:
|
||||||
|
extends: .fips
|
||||||
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS8_BUILD
|
||||||
|
script:
|
||||||
|
# torture_gssapi_key_exchange_* and torture_gssapi_server_key_exchange_* tests are excluded
|
||||||
|
# because gssapi-keyex is not allowed in FIPS mode in RHEL 8
|
||||||
|
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
||||||
|
make -j$(nproc) &&
|
||||||
|
OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure -E "^torture_gssapi.*key_exchange.*"
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Fedora builds #
|
# Fedora builds #
|
||||||
@@ -98,99 +239,115 @@ fedora/docs:
|
|||||||
extends: .build
|
extends: .build
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||||
script:
|
script:
|
||||||
- cmake .. && make docs
|
- cmake -DWITH_INTERNAL_DOC=ON .. && make docs_coverage && make docs
|
||||||
|
coverage: '/^Documentation coverage is \d+.\d+%/'
|
||||||
|
|
||||||
fedora/ninja:
|
fedora/ninja:
|
||||||
extends: .fedora
|
extends: .fedora
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||||
|
variables:
|
||||||
|
CTEST_OUTPUT_ON_FAILURE: 1
|
||||||
script:
|
script:
|
||||||
- cmake -G Ninja $CMAKE_OPTIONS ../ && ninja && ninja test
|
- cmake -G Ninja $CMAKE_OPTIONS ../ && ninja && ninja test
|
||||||
|
|
||||||
fedora/openssl_1.1.x/x86_64:
|
fedora/coverage:
|
||||||
extends: .fedora
|
extends: .fedora
|
||||||
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||||
fedora/openssl_1.1.x/x86_64/fips:
|
variables:
|
||||||
extends: .fedora
|
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_BUILD_TYPE=Debug -DWITH_COVERAGE=ON"
|
||||||
before_script:
|
|
||||||
- echo "# userspace fips" > /etc/system-fips
|
|
||||||
# We do not need the kernel part, but in case we ever do:
|
|
||||||
# mkdir -p /var/tmp/userspace-fips
|
|
||||||
# echo 1 > /var/tmp/userspace-fips/fips_enabled
|
|
||||||
# mount --bind /var/tmp/userspace-fips/fips_enabled \
|
|
||||||
# /proc/sys/crypto/fips_enabled
|
|
||||||
- update-crypto-policies --show
|
|
||||||
- update-crypto-policies --set FIPS
|
|
||||||
- update-crypto-policies --show
|
|
||||||
- mkdir -p obj && cd obj && cmake
|
|
||||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
|
||||||
-DPICKY_DEVELOPER=ON
|
|
||||||
-DWITH_BLOWFISH_CIPHER=ON
|
|
||||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
|
||||||
-DWITH_DEBUG_CRYPTO=ON -DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON
|
|
||||||
-DWITH_DSA=ON
|
|
||||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON ..
|
|
||||||
script:
|
script:
|
||||||
- cmake $CMAKE_OPTIONS .. &&
|
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
||||||
make -j$(nproc) &&
|
make -j$(nproc) &&
|
||||||
OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure
|
make coverage_xml
|
||||||
|
coverage: /^\s*lines:\s*\d+.\d+\%/
|
||||||
|
artifacts:
|
||||||
|
name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
|
||||||
|
expire_in: 1 week
|
||||||
|
reports:
|
||||||
|
coverage_report:
|
||||||
|
coverage_format: cobertura
|
||||||
|
path: obj/coverage_xml.xml
|
||||||
|
|
||||||
fedora/openssl_1.1.x/x86_64/minimal:
|
fedora/openssl_3.x/x86_64:
|
||||||
|
extends: .fedora
|
||||||
|
|
||||||
|
fedora/openssl_3.x/x86_64/pkcs11-provider:
|
||||||
|
variables:
|
||||||
|
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
|
||||||
|
extends: .fedora
|
||||||
|
|
||||||
|
fedora/openssl_3.x/x86_64/minimal:
|
||||||
extends: .fedora
|
extends: .fedora
|
||||||
variables:
|
variables:
|
||||||
script:
|
script:
|
||||||
- cmake $CMAKE_DEFAULT_OPTIONS
|
- cmake $CMAKE_DEFAULT_OPTIONS
|
||||||
|
-DWITH_EXEC=OFF
|
||||||
-DWITH_SFTP=OFF
|
-DWITH_SFTP=OFF
|
||||||
-DWITH_SERVER=OFF
|
-DWITH_SERVER=OFF
|
||||||
-DWITH_ZLIB=OFF
|
-DWITH_ZLIB=OFF
|
||||||
-DWITH_PCAP=OFF
|
-DWITH_PCAP=OFF
|
||||||
-DWITH_DSA=OFF
|
-DWITH_GSSAPI=OFF
|
||||||
|
-DWITH_GEX=OFF
|
||||||
-DUNIT_TESTING=ON
|
-DUNIT_TESTING=ON
|
||||||
-DCLIENT_TESTING=ON
|
-DCLIENT_TESTING=ON .. &&
|
||||||
-DWITH_GEX=OFF .. &&
|
|
||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
|
|
||||||
fedora/openssl_3.0/x86_64:
|
.valgrind:
|
||||||
extends: .fedora_rawhide
|
extends: .fedora
|
||||||
|
stage: analysis
|
||||||
fedora/openssl_3.0/x86_64/fips:
|
|
||||||
extends: .fedora_rawhide
|
|
||||||
before_script:
|
|
||||||
- echo "# userspace fips" > /etc/system-fips
|
|
||||||
# We do not need the kernel part, but in case we ever do:
|
|
||||||
# mkdir -p /var/tmp/userspace-fips
|
|
||||||
# echo 1 > /var/tmp/userspace-fips/fips_enabled
|
|
||||||
# mount --bind /var/tmp/userspace-fips/fips_enabled \
|
|
||||||
# /proc/sys/crypto/fips_enabled
|
|
||||||
- update-crypto-policies --show
|
|
||||||
- update-crypto-policies --set FIPS
|
|
||||||
- update-crypto-policies --show
|
|
||||||
- mkdir -p obj && cd obj && cmake
|
|
||||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
|
||||||
-DPICKY_DEVELOPER=ON
|
|
||||||
-DWITH_BLOWFISH_CIPHER=ON
|
|
||||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
|
||||||
-DWITH_DEBUG_CRYPTO=ON -DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON
|
|
||||||
-DWITH_DSA=ON
|
|
||||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON ..
|
|
||||||
script:
|
script:
|
||||||
- cmake $CMAKE_OPTIONS .. &&
|
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
||||||
make -j$(nproc) &&
|
make -j$(nproc) &&
|
||||||
OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure
|
make test_memcheck
|
||||||
|
- cat Testing/Temporary/MemoryChecker.*.log | wc -l | grep "^0$"
|
||||||
|
|
||||||
fedora/openssl_3.0/x86_64/minimal:
|
fedora/libressl/x86_64:
|
||||||
extends: .fedora_rawhide
|
extends: .fedora
|
||||||
|
stage: test
|
||||||
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||||
variables:
|
variables:
|
||||||
|
LIBRESSL_VERSION: "4.2.1"
|
||||||
|
CMAKE_ADDITIONAL_OPTIONS: >
|
||||||
|
-DCMAKE_C_FLAGS="-I/opt/libressl/include"
|
||||||
|
-DOPENSSL_ROOT_DIR=/opt/libressl
|
||||||
|
-DOPENSSL_INCLUDE_DIR=/opt/libressl/include
|
||||||
|
-DOPENSSL_CRYPTO_LIBRARY=/opt/libressl/lib/libcrypto.so
|
||||||
|
-DOPENSSL_SSL_LIBRARY=/opt/libressl/lib/libssl.so
|
||||||
|
-DWITH_GSSAPI=OFF
|
||||||
|
-DWITH_FIDO2=OFF
|
||||||
|
before_script:
|
||||||
|
- *build
|
||||||
|
- dnf install -y perl-core autoconf automake libtool pkgconf-pkg-config
|
||||||
|
- curl -LO https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${LIBRESSL_VERSION}.tar.gz
|
||||||
|
- tar xf libressl-${LIBRESSL_VERSION}.tar.gz
|
||||||
|
- cd libressl-${LIBRESSL_VERSION}
|
||||||
|
- ./configure --prefix=/opt/libressl
|
||||||
|
- make -j$(nproc)
|
||||||
|
- make install
|
||||||
|
- cd ..
|
||||||
script:
|
script:
|
||||||
- cmake $CMAKE_DEFAULT_OPTIONS
|
- export PKG_CONFIG_PATH=/opt/libressl/lib/pkgconfig
|
||||||
-DWITH_SFTP=OFF
|
- export LD_LIBRARY_PATH=/opt/libressl/lib
|
||||||
-DWITH_SERVER=OFF
|
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
||||||
-DWITH_ZLIB=OFF
|
make -j$(nproc) &&
|
||||||
-DWITH_PCAP=OFF
|
ctest --output-on-failure
|
||||||
-DWITH_DSA=OFF
|
|
||||||
-DUNIT_TESTING=ON
|
# The PKCS#11 support is turned off as it brings dozens of memory issues from
|
||||||
-DCLIENT_TESTING=ON
|
# engine_pkcs11 or openssl itself
|
||||||
-DWITH_GEX=OFF .. &&
|
fedora/valgrind/openssl:
|
||||||
make -j$(nproc)
|
variables:
|
||||||
|
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=OFF
|
||||||
|
extends: .valgrind
|
||||||
|
|
||||||
|
fedora/valgrind/mbedtls:
|
||||||
|
variables:
|
||||||
|
CMAKE_ADDITIONAL_OPTIONS: -DWITH_MBEDTLS=ON
|
||||||
|
extends: .valgrind
|
||||||
|
|
||||||
|
fedora/valgrind/libgcrypt:
|
||||||
|
variables:
|
||||||
|
CMAKE_ADDITIONAL_OPTIONS: -DWITH_GCRYPT=ON
|
||||||
|
extends: .valgrind
|
||||||
|
|
||||||
# Address sanitizer doesn't mix well with LD_PRELOAD used in the testsuite
|
# Address sanitizer doesn't mix well with LD_PRELOAD used in the testsuite
|
||||||
# so, this is only enabled for unit tests right now.
|
# so, this is only enabled for unit tests right now.
|
||||||
@@ -245,47 +402,26 @@ fedora/undefined-sanitizer:
|
|||||||
fedora/libgcrypt/x86_64:
|
fedora/libgcrypt/x86_64:
|
||||||
extends: .fedora
|
extends: .fedora
|
||||||
variables:
|
variables:
|
||||||
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_GCRYPT=ON -DWITH_DEBUG_CRYPTO=ON"
|
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_GCRYPT=ON"
|
||||||
|
|
||||||
fedora/mbedtls/x86_64:
|
fedora/mbedtls_3.x/x86_64:
|
||||||
extends: .fedora
|
extends: .fedora
|
||||||
variables:
|
variables:
|
||||||
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_DSA=OFF"
|
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_MBEDTLS=ON"
|
||||||
|
|
||||||
# Unit testing only, no client and pkd testing, because cwrap is not available
|
|
||||||
# for MinGW
|
|
||||||
fedora/mingw64:
|
fedora/mingw64:
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
|
||||||
extends: .tests
|
extends: .mingw
|
||||||
script:
|
variables:
|
||||||
- export WINEPATH=/usr/x86_64-w64-mingw32/sys-root/mingw/bin
|
WINEPATH: /usr/x86_64-w64-mingw32/sys-root/mingw/bin
|
||||||
- export WINEDEBUG=-all
|
WINEBIN: mingw64-cmake
|
||||||
- mingw64-cmake $CMAKE_DEFAULT_OPTIONS
|
|
||||||
-DWITH_SFTP=ON
|
|
||||||
-DWITH_SERVER=ON
|
|
||||||
-DWITH_ZLIB=ON
|
|
||||||
-DWITH_PCAP=ON
|
|
||||||
-DUNIT_TESTING=ON .. &&
|
|
||||||
make -j$(nproc) &&
|
|
||||||
ctest --output-on-failure
|
|
||||||
|
|
||||||
# Unit testing only, no client and pkd testing, because cwrap is not available
|
|
||||||
# for MinGW
|
|
||||||
fedora/mingw32:
|
fedora/mingw32:
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
|
||||||
extends: .tests
|
extends: .mingw
|
||||||
script:
|
variables:
|
||||||
- export WINEPATH=/usr/i686-w64-mingw32/sys-root/mingw/bin
|
WINEPATH: /usr/i686-w64-mingw32/sys-root/mingw/bin
|
||||||
- export WINEDEBUG=-all
|
WINEBIN: mingw32-cmake
|
||||||
- mingw32-cmake $CMAKE_DEFAULT_OPTIONS
|
|
||||||
-DWITH_SFTP=ON
|
|
||||||
-DWITH_SERVER=ON
|
|
||||||
-DWITH_ZLIB=ON
|
|
||||||
-DWITH_PCAP=ON
|
|
||||||
-DUNIT_TESTING=ON .. &&
|
|
||||||
make -j$(nproc) &&
|
|
||||||
ctest --output-on-failure
|
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Fedora csbuild #
|
# Fedora csbuild #
|
||||||
@@ -294,9 +430,16 @@ fedora/mingw32:
|
|||||||
stage: analysis
|
stage: analysis
|
||||||
variables:
|
variables:
|
||||||
GIT_DEPTH: "100"
|
GIT_DEPTH: "100"
|
||||||
|
CSCPPC_ADD_OPTS: "--library=./.gitlab-ci/cmocka.cfg"
|
||||||
|
CMAKE_OPTIONS: "-DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON"
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||||
before_script:
|
before_script:
|
||||||
- |
|
- |
|
||||||
|
# for merge requests
|
||||||
|
if [[ -n "$CI_MERGE_REQUEST_DIFF_BASE_SHA" ]]; then
|
||||||
|
export CI_COMMIT_BEFORE_SHA="$CI_MERGE_REQUEST_DIFF_BASE_SHA"
|
||||||
|
fi
|
||||||
|
# for branches run
|
||||||
if [[ -z "$CI_COMMIT_BEFORE_SHA" ]]; then
|
if [[ -z "$CI_COMMIT_BEFORE_SHA" ]]; then
|
||||||
export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
|
export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
|
||||||
fi
|
fi
|
||||||
@@ -306,75 +449,134 @@ fedora/mingw32:
|
|||||||
git branch --contains $CI_COMMIT_BEFORE_SHA 2>/dev/null || export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
|
git branch --contains $CI_COMMIT_BEFORE_SHA 2>/dev/null || export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
|
||||||
|
|
||||||
export CI_COMMIT_RANGE="$CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA"
|
export CI_COMMIT_RANGE="$CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA"
|
||||||
|
script:
|
||||||
|
- csbuild
|
||||||
|
--build-dir=obj-csbuild
|
||||||
|
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS @SRCDIR@ && make clean && make -j$(nproc)"
|
||||||
|
--git-commit-range $CI_COMMIT_RANGE
|
||||||
|
--color
|
||||||
|
--print-current --print-fixed
|
||||||
|
|
||||||
tags:
|
tags:
|
||||||
- shared
|
- saas-linux-small-amd64
|
||||||
except:
|
except:
|
||||||
- tags
|
- tags
|
||||||
|
only:
|
||||||
|
- merge_requests
|
||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 1 week
|
expire_in: 1 week
|
||||||
when: on_failure
|
when: on_failure
|
||||||
paths:
|
paths:
|
||||||
- obj-csbuild/
|
- obj-csbuild/
|
||||||
|
|
||||||
fedora/csbuild/openssl_1.1.x:
|
fedora/csbuild/openssl_3.x:
|
||||||
extends: .csbuild
|
extends: .csbuild
|
||||||
script:
|
|
||||||
- csbuild
|
|
||||||
--build-dir=obj-csbuild
|
|
||||||
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON -DWITH_DSA=ON @SRCDIR@ && make clean && make -j$(nproc)"
|
|
||||||
--git-commit-range $CI_COMMIT_RANGE
|
|
||||||
--color
|
|
||||||
--print-current --print-fixed
|
|
||||||
|
|
||||||
fedora/csbuild/openssl_3.0.x:
|
|
||||||
extends: .csbuild
|
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$RAWHIDE_BUILD
|
|
||||||
script:
|
|
||||||
- csbuild
|
|
||||||
--build-dir=obj-csbuild
|
|
||||||
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON -DWITH_DSA=ON @SRCDIR@ && make clean && make -j$(nproc)"
|
|
||||||
--git-commit-range $CI_COMMIT_RANGE
|
|
||||||
--color
|
|
||||||
--print-current --print-fixed
|
|
||||||
|
|
||||||
fedora/csbuild/libgcrypt:
|
fedora/csbuild/libgcrypt:
|
||||||
extends: .csbuild
|
extends: .csbuild
|
||||||
script:
|
variables:
|
||||||
- csbuild
|
CMAKE_ADDITIONAL_OPTIONS: -DWITH_GCRYPT=ON
|
||||||
--build-dir=obj-csbuild
|
|
||||||
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON -DWITH_GCRYPT=ON -DWITH_DSA=ON @SRCDIR@ && make clean && make -j$(nproc)"
|
|
||||||
--git-commit-range $CI_COMMIT_RANGE
|
|
||||||
--color
|
|
||||||
--print-current --print-fixed
|
|
||||||
|
|
||||||
fedora/csbuild/mbedtls:
|
fedora/csbuild/mbedtls:
|
||||||
extends: .csbuild
|
extends: .csbuild
|
||||||
script:
|
variables:
|
||||||
- csbuild
|
CMAKE_ADDITIONAL_OPTIONS: -DWITH_MBEDTLS=ON
|
||||||
--build-dir=obj-csbuild
|
|
||||||
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON -DWITH_MBEDTLS=ON @SRCDIR@ && make clean && make -j$(nproc)"
|
|
||||||
--git-commit-range $CI_COMMIT_RANGE
|
|
||||||
--color
|
|
||||||
--print-current --print-fixed
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Fedora abidiff #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
fedora/abidiff:
|
||||||
|
stage: analysis
|
||||||
|
variables:
|
||||||
|
GIT_DEPTH: "100"
|
||||||
|
CMAKE_OPTIONS: $CMAKE_DEFAULT_DEBUG_OPTIONS $CMAKE_BUILD_OPTIONS
|
||||||
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||||
|
before_script:
|
||||||
|
- uname -a
|
||||||
|
- cat /etc/os-release
|
||||||
|
- mount
|
||||||
|
- df -h
|
||||||
|
- cat /proc/swaps
|
||||||
|
- free -h
|
||||||
|
- |
|
||||||
|
# for merge requests
|
||||||
|
if [[ -n "$CI_MERGE_REQUEST_DIFF_BASE_SHA" ]]; then
|
||||||
|
export CI_COMMIT_BEFORE_SHA="$CI_MERGE_REQUEST_DIFF_BASE_SHA"
|
||||||
|
fi
|
||||||
|
# for branches run
|
||||||
|
if [[ -z "$CI_COMMIT_BEFORE_SHA" ]]; then
|
||||||
|
export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if the commit exists in this branch
|
||||||
|
# This is not the case for a force push
|
||||||
|
git branch --contains $CI_COMMIT_BEFORE_SHA 2>/dev/null || export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
|
||||||
|
|
||||||
|
- mkdir -p obj-${CI_COMMIT_BEFORE_SHA}
|
||||||
|
- mkdir -p obj-${CI_COMMIT_SHA}
|
||||||
|
|
||||||
|
- export INSTALL_DIR1=$(pwd)/install/${CI_COMMIT_BEFORE_SHA}
|
||||||
|
- export INSTALL_DIR2=$(pwd)/install/${CI_COMMIT_SHA}
|
||||||
|
script:
|
||||||
|
- git checkout ${CI_COMMIT_BEFORE_SHA}
|
||||||
|
- pushd obj-${CI_COMMIT_BEFORE_SHA}
|
||||||
|
- cmake ${CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR1} .. &&
|
||||||
|
make -j$(nproc) && make -j$(nproc) install
|
||||||
|
- popd
|
||||||
|
- ls -l ${INSTALL_DIR1}/lib*/
|
||||||
|
- git checkout ${CI_COMMIT_SHA}
|
||||||
|
- pushd obj-${CI_COMMIT_SHA}
|
||||||
|
- cmake ${CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR2} .. &&
|
||||||
|
make -j$(nproc) && make -j$(nproc) install
|
||||||
|
- popd
|
||||||
|
- ls -l ${INSTALL_DIR2}/lib*/
|
||||||
|
- ./.gitlab-ci/checkabi.sh ${INSTALL_DIR1} ${INSTALL_DIR2}
|
||||||
|
tags:
|
||||||
|
- saas-linux-small-amd64
|
||||||
|
except:
|
||||||
|
- tags
|
||||||
|
only:
|
||||||
|
- merge_requests
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Ubuntu builds #
|
# Ubuntu builds #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
ubuntu/openssl_1.1.x/x86_64:
|
ubuntu/openssl_3.0.x/x86_64:
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$UBUNTU_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$UBUNTU_BUILD
|
||||||
extends: .tests
|
extends: .tests
|
||||||
|
script:
|
||||||
|
# torture_gssapi_key_exchange_null is excluded because of a bug
|
||||||
|
# https://bugs.launchpad.net/ubuntu/+source/openssh/+bug/2134527
|
||||||
|
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
||||||
|
make -j$(nproc) &&
|
||||||
|
ctest --output-on-failure -E "^torture_gssapi_key_exchange_null$"
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Alpine builds #
|
||||||
|
###############################################################################
|
||||||
|
alpine/openssl_3.x/musl:
|
||||||
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$ALPINE_BUILD
|
||||||
|
extends: .tests
|
||||||
|
script:
|
||||||
|
- cmake $CMAKE_DEFAULT_OPTIONS
|
||||||
|
-DWITH_SFTP=ON
|
||||||
|
-DWITH_SERVER=ON
|
||||||
|
-DWITH_ZLIB=ON
|
||||||
|
-DWITH_PCAP=ON
|
||||||
|
-DUNIT_TESTING=ON .. &&
|
||||||
|
make -j$(nproc) &&
|
||||||
|
ctest --output-on-failure
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Tumbleweed builds #
|
# Tumbleweed builds #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
tumbleweed/openssl_1.1.x/x86_64/gcc:
|
tumbleweed/openssl_3.x/x86_64/gcc:
|
||||||
extends: .tumbleweed
|
extends: .tumbleweed
|
||||||
variables:
|
|
||||||
CMAKE_ADDITIONAL_OPTIONS: "-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config"
|
|
||||||
|
|
||||||
tumbleweed/openssl_1.1.x/x86/gcc:
|
tumbleweed/openssl_3.x/x86/gcc:
|
||||||
extends: .tumbleweed
|
extends: .tumbleweed
|
||||||
script:
|
script:
|
||||||
- cmake
|
- cmake
|
||||||
@@ -384,15 +586,15 @@ tumbleweed/openssl_1.1.x/x86/gcc:
|
|||||||
-DWITH_SERVER=ON
|
-DWITH_SERVER=ON
|
||||||
-DWITH_ZLIB=ON
|
-DWITH_ZLIB=ON
|
||||||
-DWITH_PCAP=ON
|
-DWITH_PCAP=ON
|
||||||
-DWITH_DSA=ON
|
-DUNIT_TESTING=ON .. &&
|
||||||
-DUNIT_TESTING=ON ..
|
make -j$(nproc)
|
||||||
|
|
||||||
tumbleweed/openssl_1.1.x/x86_64/gcc7:
|
tumbleweed/openssl_3.x/x86_64/gcc7:
|
||||||
extends: .tumbleweed
|
extends: .tumbleweed
|
||||||
variables:
|
variables:
|
||||||
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7 -DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config"
|
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7"
|
||||||
|
|
||||||
tumbleweed/openssl_1.1.x/x86/gcc7:
|
tumbleweed/openssl_3.x/x86/gcc7:
|
||||||
extends: .tumbleweed
|
extends: .tumbleweed
|
||||||
script:
|
script:
|
||||||
- cmake
|
- cmake
|
||||||
@@ -400,23 +602,33 @@ tumbleweed/openssl_1.1.x/x86/gcc7:
|
|||||||
-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7
|
-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7
|
||||||
$CMAKE_DEFAULT_OPTIONS
|
$CMAKE_DEFAULT_OPTIONS
|
||||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||||
-DWITH_DSA=ON
|
|
||||||
-DUNIT_TESTING=ON .. &&
|
-DUNIT_TESTING=ON .. &&
|
||||||
make -j$(nproc) &&
|
make -j$(nproc) &&
|
||||||
ctest --output-on-failure
|
ctest --output-on-failure
|
||||||
|
|
||||||
tumbleweed/openssl_1.1.x/x86_64/clang:
|
tumbleweed/openssl_3.x/x86_64/clang:
|
||||||
extends: .tumbleweed
|
extends: .tumbleweed
|
||||||
variables:
|
variables:
|
||||||
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config"
|
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
|
||||||
|
|
||||||
|
tumbleweed/mbedtls-3.6.x/x86_64/gcc:
|
||||||
|
extends: .tumbleweed
|
||||||
|
variables:
|
||||||
|
CMAKE_ADDITIONAL_OPTIONS: "-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config -DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF "
|
||||||
|
|
||||||
|
tumbleweed/mbedtls-3.6.x/x86_64/clang:
|
||||||
|
extends: .tumbleweed
|
||||||
|
variables:
|
||||||
|
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config -DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF "
|
||||||
|
|
||||||
tumbleweed/static-analysis:
|
tumbleweed/static-analysis:
|
||||||
extends: .tests
|
extends: .tests
|
||||||
stage: analysis
|
stage: analysis
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
||||||
|
variables:
|
||||||
|
CCC_CC: clang
|
||||||
|
CCC_CXX: clang++
|
||||||
script:
|
script:
|
||||||
- export CCC_CC=clang
|
|
||||||
- export CCC_CXX=clang++
|
|
||||||
- scan-build cmake
|
- scan-build cmake
|
||||||
-DCMAKE_BUILD_TYPE=Debug
|
-DCMAKE_BUILD_TYPE=Debug
|
||||||
-DCMAKE_C_COMPILER=clang
|
-DCMAKE_C_COMPILER=clang
|
||||||
@@ -437,22 +649,15 @@ tumbleweed/static-analysis:
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# That is a specific runner that we cannot enable universally.
|
# That is a specific runner that we cannot enable universally.
|
||||||
# We restrict it to builds under the $BUILD_IMAGES_PROJECT project.
|
# We restrict it to builds under the $BUILD_IMAGES_PROJECT project.
|
||||||
freebsd/x86_64:
|
freebsd/openssl_1.1.1/x86_64:
|
||||||
image:
|
image:
|
||||||
extends: .tests
|
extends: .tests
|
||||||
|
variables:
|
||||||
|
CMAKE_OPTIONS: $CMAKE_DEFAULT_OPTIONS -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON -DUNIT_TESTING=ON
|
||||||
before_script:
|
before_script:
|
||||||
- mkdir -p obj && cd obj && cmake
|
- mkdir -p obj && cd obj && cmake $CMAKE_OPTIONS ..
|
||||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
|
||||||
-DPICKY_DEVELOPER=ON
|
|
||||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
|
||||||
-DUNIT_TESTING=ON ..
|
|
||||||
script:
|
script:
|
||||||
- cmake $CMAKE_DEFAULT_OPTIONS
|
- cmake $CMAKE_OPTIONS .. &&
|
||||||
-DWITH_SFTP=ON
|
|
||||||
-DWITH_SERVER=ON
|
|
||||||
-DWITH_ZLIB=ON
|
|
||||||
-DWITH_PCAP=ON
|
|
||||||
-DUNIT_TESTING=ON .. &&
|
|
||||||
make &&
|
make &&
|
||||||
ctest --output-on-failure
|
ctest --output-on-failure
|
||||||
tags:
|
tags:
|
||||||
@@ -462,12 +667,13 @@ freebsd/x86_64:
|
|||||||
- branches@libssh/libssh-mirror
|
- branches@libssh/libssh-mirror
|
||||||
- branches@cryptomilk/libssh-mirror
|
- branches@cryptomilk/libssh-mirror
|
||||||
- branches@jjelen/libssh-mirror
|
- branches@jjelen/libssh-mirror
|
||||||
- branches@marco.fortina/libssh-mirror
|
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Visual Studio builds #
|
# Visual Studio builds #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
# 2024-05-13: These jobs run out of the stages as they take extremely long and
|
||||||
|
# usually timeout with the update to Gitlab 17.0
|
||||||
.vs:
|
.vs:
|
||||||
stage: test
|
stage: test
|
||||||
cache:
|
cache:
|
||||||
@@ -480,8 +686,10 @@ freebsd/x86_64:
|
|||||||
- cmake --build .
|
- cmake --build .
|
||||||
- ctest --output-on-failure
|
- ctest --output-on-failure
|
||||||
tags:
|
tags:
|
||||||
- windows
|
- saas-windows-medium-amd64
|
||||||
- shared-windows
|
only:
|
||||||
|
- merge_requests
|
||||||
|
- branches
|
||||||
except:
|
except:
|
||||||
- tags
|
- tags
|
||||||
artifacts:
|
artifacts:
|
||||||
@@ -490,8 +698,6 @@ freebsd/x86_64:
|
|||||||
paths:
|
paths:
|
||||||
- obj/
|
- obj/
|
||||||
before_script:
|
before_script:
|
||||||
- choco install --no-progress -y cmake
|
|
||||||
- $env:Path += ';C:\Program Files\CMake\bin'
|
|
||||||
- If (!(test-path .vcpkg\archives)) { mkdir -p .vcpkg\archives }
|
- If (!(test-path .vcpkg\archives)) { mkdir -p .vcpkg\archives }
|
||||||
- $env:VCPKG_DEFAULT_BINARY_CACHE="$PWD\.vcpkg\archives"
|
- $env:VCPKG_DEFAULT_BINARY_CACHE="$PWD\.vcpkg\archives"
|
||||||
- echo $env:VCPKG_DEFAULT_BINARY_CACHE
|
- echo $env:VCPKG_DEFAULT_BINARY_CACHE
|
||||||
@@ -499,13 +705,14 @@ freebsd/x86_64:
|
|||||||
- vcpkg install cmocka
|
- vcpkg install cmocka
|
||||||
- vcpkg install openssl
|
- vcpkg install openssl
|
||||||
- vcpkg install zlib
|
- vcpkg install zlib
|
||||||
|
- vcpkg install libfido2
|
||||||
- vcpkg integrate install
|
- vcpkg integrate install
|
||||||
- mkdir -p obj; if ($?) {cd obj}; if (! $?) {exit 1}
|
- mkdir -p obj; if ($?) {cd obj}; if (! $?) {exit 1}
|
||||||
- cmake
|
- cmake
|
||||||
-A $PLATFORM
|
-A $PLATFORM
|
||||||
-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
|
-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
|
||||||
-DPICKY_DEVELOPER=ON
|
-DPICKY_DEVELOPER=ON
|
||||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON -DWITH_FIDO2=ON
|
||||||
-DUNIT_TESTING=ON ..
|
-DUNIT_TESTING=ON ..
|
||||||
|
|
||||||
visualstudio/x86_64:
|
visualstudio/x86_64:
|
||||||
@@ -531,7 +738,7 @@ visualstudio/x86:
|
|||||||
|
|
||||||
coverity:
|
coverity:
|
||||||
stage: analysis
|
stage: analysis
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$COVERITY_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
|
||||||
script:
|
script:
|
||||||
- mkdir obj && cd obj
|
- mkdir obj && cd obj
|
||||||
- wget https://scan.coverity.com/download/linux64 --post-data "token=$COVERITY_SCAN_TOKEN&project=$COVERITY_SCAN_PROJECT_NAME" -O /tmp/coverity_tool.tgz
|
- wget https://scan.coverity.com/download/linux64 --post-data "token=$COVERITY_SCAN_TOKEN&project=$COVERITY_SCAN_PROJECT_NAME" -O /tmp/coverity_tool.tgz
|
||||||
@@ -547,7 +754,7 @@ coverity:
|
|||||||
--form description="CI build"
|
--form description="CI build"
|
||||||
https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
|
https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
|
||||||
tags:
|
tags:
|
||||||
- shared
|
- saas-linux-small-amd64
|
||||||
only:
|
only:
|
||||||
refs:
|
refs:
|
||||||
- master
|
- master
|
||||||
@@ -561,3 +768,38 @@ coverity:
|
|||||||
when: on_failure
|
when: on_failure
|
||||||
paths:
|
paths:
|
||||||
- obj/cov-int/*.txt
|
- obj/cov-int/*.txt
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# MacOS #
|
||||||
|
###############################################################################
|
||||||
|
.macos:
|
||||||
|
extends: .build_options
|
||||||
|
tags:
|
||||||
|
- saas-macos-medium-m1
|
||||||
|
image: macos-14-xcode-15
|
||||||
|
before_script:
|
||||||
|
- echo "MacOS runner started"
|
||||||
|
- brew update
|
||||||
|
- brew install cmake openssl cmocka doxygen
|
||||||
|
- mkdir obj && cd obj
|
||||||
|
only:
|
||||||
|
- branches@libssh/libssh-mirror
|
||||||
|
- branches@cryptomilk/libssh-mirror
|
||||||
|
- branches@jjelen/libssh-mirror
|
||||||
|
|
||||||
|
# TODO add -DFUZZ_TESTING=ON clang cant find _LLVMFuzzerInitialize on arm64
|
||||||
|
macos-m1:
|
||||||
|
extends: .macos
|
||||||
|
variables:
|
||||||
|
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||||
|
CMAKE_TEST_OPTIONS: "-DUNIT_TESTING=ON"
|
||||||
|
stage: test
|
||||||
|
script:
|
||||||
|
- cmake $CMAKE_OPTIONS .. &&
|
||||||
|
make -j$(sysctl -n hw.logicalcpu) &&
|
||||||
|
ctest --output-on-failure
|
||||||
|
artifacts:
|
||||||
|
expire_in: 1 week
|
||||||
|
when: on_failure
|
||||||
|
paths:
|
||||||
|
- obj/
|
||||||
|
|||||||
42
.gitlab-ci/checkabi.sh
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
INSTALL_DIR1=${1}
|
||||||
|
INSTALL_DIR2=${2}
|
||||||
|
|
||||||
|
abidiff \
|
||||||
|
--headers-dir1 "${INSTALL_DIR1}/include/libssh/" \
|
||||||
|
--headers-dir2 "${INSTALL_DIR2}/include/libssh/" \
|
||||||
|
"${INSTALL_DIR1}/lib64/libssh.so" \
|
||||||
|
"${INSTALL_DIR2}/lib64/libssh.so" \
|
||||||
|
--fail-no-debug-info
|
||||||
|
abiret=$?
|
||||||
|
|
||||||
|
ABIDIFF_ERROR=$(((abiret & 0x01) != 0))
|
||||||
|
ABIDIFF_USAGE_ERROR=$(((abiret & 0x02) != 0))
|
||||||
|
ABIDIFF_ABI_CHANGE=$(((abiret & 0x04) != 0))
|
||||||
|
ABIDIFF_ABI_INCOMPATIBLE_CHANGE=$(((abiret & 0x08) != 0))
|
||||||
|
ABIDIFF_UNKNOWN_BIT_SET=$(((abiret & 0xf0) != 0))
|
||||||
|
|
||||||
|
if [ $ABIDIFF_ERROR -ne 0 ]; then
|
||||||
|
echo "abidiff reported ABIDIFF_ERROR."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ $ABIDIFF_USAGE_ERROR -ne 0 ]; then
|
||||||
|
echo "abidiff reported ABIDIFF_USAGE_ERROR."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ $ABIDIFF_UNKNOWN_BIT_SET -ne 0 ]; then
|
||||||
|
echo "abidiff reported ABIDIFF_UNKNOWN_BIT_SET."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $ABIDIFF_ABI_INCOMPATIBLE_CHANGE -ne 0 ]; then
|
||||||
|
echo "abidiff result ABIDIFF_ABI_INCOMPATIBLE_CHANGE, this breaks the API!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $ABIDIFF_ABI_CHANGE -ne 0 ]; then
|
||||||
|
echo "Ignoring abidiff result ABI_CHANGE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
12
.gitlab-ci/clang-format-check.sh
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Based on Github Action
|
||||||
|
# https://github.com/yshui/git-clang-format-lint
|
||||||
|
|
||||||
|
diff=$(git-clang-format --diff --commit "$CI_MERGE_REQUEST_DIFF_BASE_SHA")
|
||||||
|
[ "$diff" = "no modified files to format" ] && exit 0
|
||||||
|
[ "$diff" = "clang-format did not modify any files" ] && exit 0
|
||||||
|
|
||||||
|
printf "You have introduced coding style breakages, suggested changes:\n\n"
|
||||||
|
|
||||||
|
echo "${diff}" | colordiff
|
||||||
|
exit 1
|
||||||
475
.gitlab-ci/cmocka.cfg
Normal file
@@ -0,0 +1,475 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!--
|
||||||
|
cppcheck library configuration for cmocka
|
||||||
|
|
||||||
|
This file provides cppcheck with information about cmocka's assertion functions
|
||||||
|
and their behavior, particularly that assertion failures do not return.
|
||||||
|
|
||||||
|
This helps cppcheck understand that after assert_non_null(ptr), the pointer
|
||||||
|
is guaranteed to be non-NULL, eliminating false positives like:
|
||||||
|
- nullPointerArithmeticOutOfMemory
|
||||||
|
- nullPointer
|
||||||
|
- etc.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
cppcheck --library=cmocka.cfg [other options] <source files>
|
||||||
|
|
||||||
|
For more information on cppcheck library format, see:
|
||||||
|
https://cppcheck.sourceforge.io/manual.html#library-configuration
|
||||||
|
-->
|
||||||
|
<def format="2">
|
||||||
|
<!-- Core functions -->
|
||||||
|
<function name="_fail">
|
||||||
|
<noreturn>true</noreturn>
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<!-- Boolean assertions -->
|
||||||
|
<function name="_assert_true">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<valid>arg1 != 0</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="4" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_false">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<valid>arg1 == 0</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="4" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<!-- Pointer assertions -->
|
||||||
|
<function name="_assert_ptr_equal_msg">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<valid>arg1 == arg2</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="4" direction="in"/>
|
||||||
|
<arg nr="5" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_ptr_not_equal_msg">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<valid>arg1 != arg2</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="4" direction="in"/>
|
||||||
|
<arg nr="5" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<!-- Integer assertions -->
|
||||||
|
<function name="_assert_int_equal">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<valid>arg1 == arg2</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="4" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_int_not_equal">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<valid>arg1 != arg2</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="4" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_uint_equal">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<valid>arg1 == arg2</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="4" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_uint_not_equal">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<valid>arg1 != arg2</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="4" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<!-- Float/double assertions -->
|
||||||
|
<function name="_assert_float_equal">
|
||||||
|
<arg nr="1" direction="in"/>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_float_not_equal">
|
||||||
|
<arg nr="1" direction="in"/>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_double_equal">
|
||||||
|
<arg nr="1" direction="in"/>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_double_not_equal">
|
||||||
|
<arg nr="1" direction="in"/>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<!-- String assertions -->
|
||||||
|
<function name="_assert_string_equal">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="4" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_string_not_equal">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="4" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<!-- Memory assertions -->
|
||||||
|
<function name="_assert_memory_equal">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_memory_not_equal">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<!-- Range assertions -->
|
||||||
|
<function name="_assert_int_in_range">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<valid>arg2 <= arg1 && arg1 <= arg3</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_int_not_in_range">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<valid>arg1 < arg2 || arg3 < arg1</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_uint_in_range">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<valid>arg2 <= arg1 && arg1 <= arg3</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_uint_not_in_range">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<valid>arg1 < arg2 || arg3 < arg1</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_float_in_range">
|
||||||
|
<arg nr="1" direction="in"/>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in"/>
|
||||||
|
<arg nr="5" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="6" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_float_not_in_range">
|
||||||
|
<arg nr="1" direction="in"/>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in"/>
|
||||||
|
<arg nr="5" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="6" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<!-- Set assertions -->
|
||||||
|
<function name="_assert_int_in_set">
|
||||||
|
<arg nr="1" direction="in"/>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="6" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_int_not_in_set">
|
||||||
|
<arg nr="1" direction="in"/>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="6" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_uint_in_set">
|
||||||
|
<arg nr="1" direction="in"/>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="6" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_uint_not_in_set">
|
||||||
|
<arg nr="1" direction="in"/>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="6" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_not_in_set">
|
||||||
|
<arg nr="1" direction="in"/>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="6" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_float_in_set">
|
||||||
|
<arg nr="1" direction="in"/>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in"/>
|
||||||
|
<arg nr="5" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="6" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="7" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function name="_assert_float_not_in_set">
|
||||||
|
<arg nr="1" direction="in"/>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="in"/>
|
||||||
|
<arg nr="4" direction="in"/>
|
||||||
|
<arg nr="5" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="6" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="7" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<!-- Return code assertion -->
|
||||||
|
<function name="_assert_return_code">
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<valid>0 <= arg1</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in"/>
|
||||||
|
<arg nr="3" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="4" direction="in">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="5" direction="in"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<!-- Macro definitions -->
|
||||||
|
<!-- Boolean macros -->
|
||||||
|
<define name="assert_true(c)" value="_assert_true(cast_to_uintmax_type(c), #c, __FILE__, __LINE__)"/>
|
||||||
|
<define name="assert_false(c)" value="_assert_false(cast_to_uintmax_type(c), #c, __FILE__, __LINE__)"/>
|
||||||
|
|
||||||
|
<!-- Pointer macros -->
|
||||||
|
<define name="assert_non_null(c)" value="assert_ptr_not_equal((c), NULL)"/>
|
||||||
|
<define name="assert_non_null_msg(c, msg)" value="assert_ptr_not_equal_msg((c), NULL, (msg))"/>
|
||||||
|
<define name="assert_null(c)" value="assert_ptr_equal((c), NULL)"/>
|
||||||
|
<define name="assert_null_msg(c, msg)" value="assert_ptr_equal_msg((c), NULL, (msg))"/>
|
||||||
|
<define name="assert_ptr_equal(a, b)" value="assert_ptr_equal_msg((a), (b), NULL)"/>
|
||||||
|
<define name="assert_ptr_equal_msg(a, b, msg)" value="_assert_ptr_equal_msg((const void*)(a), (const void*)(b), __FILE__, __LINE__, (msg))"/>
|
||||||
|
<define name="assert_ptr_not_equal(a, b)" value="_assert_ptr_not_equal_msg((const void*)(a), (const void*)(b), __FILE__, __LINE__, NULL)"/>
|
||||||
|
<define name="assert_ptr_not_equal_msg(a, b, msg)" value="_assert_ptr_not_equal_msg((const void*)(a), (const void*)(b), __FILE__, __LINE__, (msg))"/>
|
||||||
|
|
||||||
|
<!-- Integer macros -->
|
||||||
|
<define name="assert_int_equal(a, b)" value="_assert_int_equal(cast_to_intmax_type(a), cast_to_intmax_type(b), __FILE__, __LINE__)"/>
|
||||||
|
<define name="assert_int_not_equal(a, b)" value="_assert_int_not_equal(cast_to_intmax_type(a), cast_to_intmax_type(b), __FILE__, __LINE__)"/>
|
||||||
|
<define name="assert_uint_equal(a, b)" value="_assert_uint_equal(cast_to_uintmax_type(a), cast_to_uintmax_type(b), __FILE__, __LINE__)"/>
|
||||||
|
<define name="assert_uint_not_equal(a, b)" value="_assert_uint_not_equal(cast_to_uintmax_type(a), cast_to_uintmax_type(b), __FILE__, __LINE__)"/>
|
||||||
|
|
||||||
|
<!-- Float/double macros -->
|
||||||
|
<define name="assert_float_equal(a, b, epsilon)" value="_assert_float_equal((float)(a), (float)(b), (float)(epsilon), __FILE__, __LINE__)"/>
|
||||||
|
<define name="assert_float_not_equal(a, b, epsilon)" value="_assert_float_not_equal((float)(a), (float)(b), (float)(epsilon), __FILE__, __LINE__)"/>
|
||||||
|
<define name="assert_double_equal(a, b, epsilon)" value="_assert_double_equal((double)(a), (double)(b), (double)(epsilon), __FILE__, __LINE__)"/>
|
||||||
|
<define name="assert_double_not_equal(a, b, epsilon)" value="_assert_double_not_equal((double)(a), (double)(b), (double)(epsilon), __FILE__, __LINE__)"/>
|
||||||
|
|
||||||
|
<!-- String macros -->
|
||||||
|
<define name="assert_string_equal(a, b)" value="_assert_string_equal((const char*)(a), (const char*)(b), __FILE__, __LINE__)"/>
|
||||||
|
<define name="assert_string_not_equal(a, b)" value="_assert_string_not_equal((const char*)(a), (const char*)(b), __FILE__, __LINE__)"/>
|
||||||
|
|
||||||
|
<!-- Memory macros -->
|
||||||
|
<define name="assert_memory_equal(a, b, size)" value="_assert_memory_equal((const void*)(a), (const void*)(b), size, __FILE__, __LINE__)"/>
|
||||||
|
<define name="assert_memory_not_equal(a, b, size)" value="_assert_memory_not_equal((const void*)(a), (const void*)(b), size, __FILE__, __LINE__)"/>
|
||||||
|
|
||||||
|
<!-- Range macros -->
|
||||||
|
<define name="assert_int_in_range(value, minimum, maximum)" value="_assert_int_in_range(cast_to_intmax_type(value), cast_to_intmax_type(minimum), cast_to_intmax_type(maximum), __FILE__, __LINE__)"/>
|
||||||
|
<define name="assert_int_not_in_range(value, minimum, maximum)" value="_assert_int_not_in_range(cast_to_intmax_type(value), cast_to_intmax_type(minimum), cast_to_intmax_type(maximum), __FILE__, __LINE__)"/>
|
||||||
|
<define name="assert_uint_in_range(value, minimum, maximum)" value="_assert_uint_in_range(cast_to_uintmax_type(value), cast_to_uintmax_type(minimum), cast_to_uintmax_type(maximum), __FILE__, __LINE__)"/>
|
||||||
|
<define name="assert_uint_not_in_range(value, minimum, maximum)" value="_assert_uint_not_in_range(cast_to_uintmax_type(value), cast_to_uintmax_type(minimum), cast_to_uintmax_type(maximum), __FILE__, __LINE__)"/>
|
||||||
|
<define name="assert_in_range(value, minimum, maximum)" value="assert_uint_in_range(value, minimum, maximum)"/>
|
||||||
|
<define name="assert_not_in_range(value, minimum, maximum)" value="assert_uint_not_in_range(value, minimum, maximum)"/>
|
||||||
|
<define name="assert_float_in_range(value, minimum, maximum, epsilon)" value="_assert_float_in_range((double)(value), (double)(minimum), (double)(maximum), (double)(epsilon), __FILE__, __LINE__)"/>
|
||||||
|
<define name="assert_float_not_in_range(value, minimum, maximum, epsilon)" value="_assert_float_not_in_range((double)(value), (double)(minimum), (double)(maximum), (double)(epsilon), __FILE__, __LINE__)"/>
|
||||||
|
|
||||||
|
<!-- Set macros -->
|
||||||
|
<define name="assert_in_set(value, values, number_of_values)" value="_assert_not_in_set(cast_to_uintmax_type(value), (uintmax_t*)(values), number_of_values, __FILE__, __LINE__, 0)"/>
|
||||||
|
<define name="assert_not_in_set(value, values, number_of_values)" value="_assert_not_in_set(cast_to_uintmax_type(value), (uintmax_t*)(values), number_of_values, __FILE__, __LINE__, 1)"/>
|
||||||
|
<define name="assert_int_in_set(value, values, number_of_values)" value="_assert_int_in_set(cast_to_intmax_type(value), (intmax_t*)(values), number_of_values, __FILE__, __LINE__, 0)"/>
|
||||||
|
<define name="assert_int_not_in_set(value, values, number_of_values)" value="_assert_int_not_in_set(cast_to_intmax_type(value), (intmax_t*)(values), number_of_values, __FILE__, __LINE__, 1)"/>
|
||||||
|
<define name="assert_uint_in_set(value, values, number_of_values)" value="_assert_uint_in_set(cast_to_uintmax_type(value), (uintmax_t*)(values), number_of_values, __FILE__, __LINE__, 0)"/>
|
||||||
|
<define name="assert_uint_not_in_set(value, values, number_of_values)" value="_assert_uint_not_in_set(cast_to_uintmax_type(value), (uintmax_t*)(values), number_of_values, __FILE__, __LINE__, 1)"/>
|
||||||
|
<define name="assert_float_in_set(value, values, number_of_values, epsilon)" value="_assert_float_in_set((double)(value), (double*)(values), number_of_values, (double)(epsilon), __FILE__, __LINE__, 0)"/>
|
||||||
|
<define name="assert_float_not_in_set(value, values, number_of_values, epsilon)" value="_assert_float_not_in_set((double)(value), (double*)(values), number_of_values, (double)(epsilon), __FILE__, __LINE__, 1)"/>
|
||||||
|
|
||||||
|
<!-- Return code macro -->
|
||||||
|
<define name="assert_return_code(rc, error)" value="_assert_return_code(cast_to_intmax_type(rc), (int32_t)(error), #rc, __FILE__, __LINE__)"/>
|
||||||
|
</def>
|
||||||
36
.gitlab-ci/git-check-signoff-trailer.sh
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ $# != 1 ]; then
|
||||||
|
echo "Usage: $0 UPSTREAM_COMMIT_SHA"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
failed=0
|
||||||
|
|
||||||
|
if [ -z "$CI_COMMIT_SHA" ]; then
|
||||||
|
echo "CI_COMMIT_SHA is not set"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
CI_COMMIT_RANGE="$1..$CI_COMMIT_SHA"
|
||||||
|
|
||||||
|
red='\033[0;31m'
|
||||||
|
blue='\033[0;34m'
|
||||||
|
|
||||||
|
echo -e "${blue}Checking commit range: $CI_COMMIT_RANGE"
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
|
||||||
|
for commit in $(git rev-list "$CI_COMMIT_RANGE"); do
|
||||||
|
git show -s --format=%B "$commit" | grep "^Signed-off-by: " >/dev/null 2>&1
|
||||||
|
ret=$?
|
||||||
|
if [ $ret -eq 1 ]; then
|
||||||
|
echo -e "${red} >>> Missing Signed-off-by trailer in commit $commit"
|
||||||
|
failed=$(("$failed" + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
|
||||||
|
exit $failed
|
||||||
116
.gitlab-ci/local-ci.sh
Executable file
@@ -0,0 +1,116 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
RED="\033[1;31m"
|
||||||
|
GREEN="\033[1;32m"
|
||||||
|
YELLOW="\033[1;33m"
|
||||||
|
BLUE="\033[1;34m"
|
||||||
|
RESET="\033[0m"
|
||||||
|
|
||||||
|
export GCL_IGNORE_PREDEFINED_VARS=CI_REGISTRY
|
||||||
|
|
||||||
|
BASE_SHA=$(git merge-base HEAD origin/master 2>/dev/null || git rev-parse HEAD~1)
|
||||||
|
|
||||||
|
COMMON_ARGS=(
|
||||||
|
--variable "CI_MERGE_REQUEST_DIFF_BASE_SHA=$BASE_SHA"
|
||||||
|
--variable "CI_REGISTRY=registry.gitlab.com"
|
||||||
|
--json-schema-validation=false
|
||||||
|
)
|
||||||
|
|
||||||
|
check_requirements() {
|
||||||
|
for cmd in docker git gitlab-ci-local; do
|
||||||
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
echo -e "${RED}Missing dependency: $cmd${RESET}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo -e "${GREEN}Found: $cmd${RESET}"
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! docker info >/dev/null 2>&1; then
|
||||||
|
echo -e "${RED}Docker daemon is not running or permission denied${RESET}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
list_jobs() {
|
||||||
|
gitlab-ci-local --list --json-schema-validation=false | awk 'NR>1 {print $1}'
|
||||||
|
}
|
||||||
|
|
||||||
|
run_job() {
|
||||||
|
JOB="$1"
|
||||||
|
echo -e "${YELLOW}Running CI job: $JOB${RESET}"
|
||||||
|
gitlab-ci-local "$JOB" "${COMMON_ARGS[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_images() {
|
||||||
|
echo -e "${BLUE}Removing libssh CI images only...${RESET}"
|
||||||
|
docker images --format "{{.Repository}}:{{.Tag}} {{.ID}}" \
|
||||||
|
| grep "$CI_REGISTRY/$BUILD_IMAGES_PROJECT" \
|
||||||
|
| awk '{print $2}' \
|
||||||
|
| xargs -r docker rmi -f
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo
|
||||||
|
echo -e "${BLUE}Usage:${RESET}"
|
||||||
|
echo " $0 --list"
|
||||||
|
echo " $0 --run <job-name>"
|
||||||
|
echo " $0 --all"
|
||||||
|
echo " $0 --run <job-name> --clean"
|
||||||
|
echo " $0 --all --clean"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
check_requirements
|
||||||
|
|
||||||
|
CLEAN=0
|
||||||
|
MODE=""
|
||||||
|
JOB=""
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--list)
|
||||||
|
MODE="list"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--run)
|
||||||
|
MODE="run"
|
||||||
|
JOB="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--all)
|
||||||
|
MODE="all"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--clean)
|
||||||
|
CLEAN=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
case "$MODE" in
|
||||||
|
list)
|
||||||
|
list_jobs
|
||||||
|
;;
|
||||||
|
run)
|
||||||
|
[[ -z "$JOB" ]] && usage
|
||||||
|
run_job "$JOB"
|
||||||
|
[[ "$CLEAN" -eq 1 ]] && cleanup_images
|
||||||
|
;;
|
||||||
|
all)
|
||||||
|
for job in $(list_jobs); do
|
||||||
|
run_job "$job"
|
||||||
|
[[ "$CLEAN" -eq 1 ]] && cleanup_images
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo -e "${GREEN}Done.${RESET}"
|
||||||
56
.gitlab-ci/shellcheck.sh
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Simplified and de-github-ed version of
|
||||||
|
# https://github.com/ludeeus/action-shellcheck/blob/master/action.yaml
|
||||||
|
|
||||||
|
statuscode=0
|
||||||
|
|
||||||
|
declare -a filepaths
|
||||||
|
shebangregex="^#! */[^ ]*/(env *)?[abk]*sh"
|
||||||
|
set -f # temporarily disable globbing so that globs in inputs aren't expanded
|
||||||
|
|
||||||
|
while IFS= read -r -d '' file; do
|
||||||
|
filepaths+=("$file")
|
||||||
|
done < <(find . \
|
||||||
|
-type f \
|
||||||
|
'(' \
|
||||||
|
-name '*.bash' \
|
||||||
|
-o -name '.bashrc' \
|
||||||
|
-o -name 'bashrc' \
|
||||||
|
-o -name '.bash_aliases' \
|
||||||
|
-o -name '.bash_completion' \
|
||||||
|
-o -name '.bash_login' \
|
||||||
|
-o -name '.bash_logout' \
|
||||||
|
-o -name '.bash_profile' \
|
||||||
|
-o -name 'bash_profile' \
|
||||||
|
-o -name '*.ksh' \
|
||||||
|
-o -name 'suid_profile' \
|
||||||
|
-o -name '*.zsh' \
|
||||||
|
-o -name '.zlogin' \
|
||||||
|
-o -name 'zlogin' \
|
||||||
|
-o -name '.zlogout' \
|
||||||
|
-o -name 'zlogout' \
|
||||||
|
-o -name '.zprofile' \
|
||||||
|
-o -name 'zprofile' \
|
||||||
|
-o -name '.zsenv' \
|
||||||
|
-o -name 'zsenv' \
|
||||||
|
-o -name '.zshrc' \
|
||||||
|
-o -name 'zshrc' \
|
||||||
|
-o -name '*.sh' \
|
||||||
|
-o -path '*/.profile' \
|
||||||
|
-o -path '*/profile' \
|
||||||
|
-o -name '*.shlib' \
|
||||||
|
')' \
|
||||||
|
-print0)
|
||||||
|
|
||||||
|
while IFS= read -r -d '' file; do
|
||||||
|
head -n1 "$file" | grep -Eqs "$shebangregex" || continue
|
||||||
|
filepaths+=("$file")
|
||||||
|
done < <(find . \
|
||||||
|
-type f ! -name '*.*' -perm /111 \
|
||||||
|
-print0)
|
||||||
|
|
||||||
|
shellcheck "${filepaths[@]}" || statuscode=$?
|
||||||
|
|
||||||
|
set +f # re-enable globbing
|
||||||
|
|
||||||
|
exit "$statuscode"
|
||||||
16
.gitlab/merge_request_templates/default.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
Add a description of the new feature/bug fix. Reference any relevant bugs.
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
* [ ] Commits have `Signed-off-by:` with name/author being identical to the commit author
|
||||||
|
* [ ] Code modified for feature
|
||||||
|
* [ ] Test suite updated with functionality tests
|
||||||
|
* [ ] Test suite updated with negative tests
|
||||||
|
* [ ] Documentation updated
|
||||||
|
* [ ] The project pipelines timeout is [extended](https://docs.gitlab.com/ee/ci/pipelines/settings.html#set-a-limit-for-how-long-jobs-can-run) at least to 2 hours.
|
||||||
|
|
||||||
|
## Reviewer's checklist:
|
||||||
|
* [ ] Any issues marked for closing are addressed
|
||||||
|
* [ ] There is a test suite reasonably covering new functionality or modifications
|
||||||
|
* [ ] Function naming, parameters, return values, types, etc., are consistent and according to [CONTRIBUTING.md](https://gitlab.com/libssh/libssh-mirror/-/blob/master/CONTRIBUTING.md)
|
||||||
|
* [ ] This feature/change has adequate documentation added
|
||||||
|
* [ ] No obvious mistakes in the code
|
||||||
10
.gitleaks.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#
|
||||||
|
# GitLeaks Repo Specific Configuration
|
||||||
|
#
|
||||||
|
# This allowlist is used to help Red Hat ignore false positives during its code
|
||||||
|
# scans.
|
||||||
|
|
||||||
|
[allowlist]
|
||||||
|
paths = [
|
||||||
|
'''tests/*''',
|
||||||
|
]
|
||||||
147
CHANGELOG
@@ -1,7 +1,128 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
version 0.10.0 (released 2022-07-xx)
|
version 0.11.0 (released 2024-07-31)
|
||||||
|
* Deprecations and Removals:
|
||||||
|
* Dropped support for DSA
|
||||||
|
* Deprecated Blowfish cipher (will be removed in next release)
|
||||||
|
* Deprecated SSH_BIND_OPTIONS_{RSA,ECDSA}KEY in favor of generic HOSTKEY
|
||||||
|
* Removed the usage of deprecated OpenSSL APIs (Note: Minimum supported
|
||||||
|
OpenSSL version is 1.1.1)
|
||||||
|
* Disabled preauth compression (zlib) by default
|
||||||
|
* Support for pkcs#11 engines are deprecated, pkcs11-provider is used instead
|
||||||
|
* Deprecation of old async SFTP API
|
||||||
|
* libgcrypt cryptographic backend is deprecated
|
||||||
|
* Deprecation of knownhosts hashing
|
||||||
|
* SFTP Improvements:
|
||||||
|
* Added support for async SFTP IO
|
||||||
|
* Added support for sftp_limits() and applied capping to SFTP read/write
|
||||||
|
operations accordingly
|
||||||
|
* Added sftp_home_directory() API support for sftp extension "home-directory"
|
||||||
|
* Added sftp_lsetstat() API for lsetstat extensions
|
||||||
|
* Added sftp_expand_path() to canonicalize path using expand-path@openssh.com
|
||||||
|
extension
|
||||||
|
* Implemented stat and realpath in sftpserver
|
||||||
|
* Added sftp_readlink() API to support hardlink@openssh.com
|
||||||
|
* New extensible callback based SFTP server
|
||||||
|
* Introduced the posix-rename@openssh.com extension
|
||||||
|
* New functions and features:
|
||||||
|
* Added support for PKCS #11 provider for OpenSSL 3.0
|
||||||
|
* Added testing for GSSAPI Authentication
|
||||||
|
* Implemented proxy jump using libssh
|
||||||
|
* Recategorized loglevels to show fatal errors and alignment with OpenSSH
|
||||||
|
log levels
|
||||||
|
* Added ssh_channel_request_pty_size_modes() API to set terminal modes for
|
||||||
|
PTYs
|
||||||
|
* Added function to check username syntax
|
||||||
|
* Added support to check all keys in authorized_keys instead of one in
|
||||||
|
example server implementation
|
||||||
|
* Handled hostkey similar to OpenSSH
|
||||||
|
* Added ssh_session_socket_close() API in order to not close socket passed
|
||||||
|
through options on error conditions
|
||||||
|
* Added option SSH_BIND_OPTIONS_IMPORT_KEY_STR to read user-supplied key
|
||||||
|
string in ssh_bind_options_set()
|
||||||
|
* Improved log handling around ssh_set_callbacks
|
||||||
|
* Added ssh_set_error_invalid in ssh_options_set()
|
||||||
|
* Prevented signature blob to start with 1 bit in libgcrypt
|
||||||
|
* Added support to unbreak key comparison of Ed25519 keys imported from PEM
|
||||||
|
or OpenSSH container
|
||||||
|
* Added support to calculate missing CRT parameters when building RSA key
|
||||||
|
* Added ssh_pki_export_privkey_base64_format() and
|
||||||
|
ssh_pki_export_privkey_file_format() to support exporting keys in different
|
||||||
|
formats (PEM, OpenSSH)
|
||||||
|
* Added support to compare certificates and handle automatic certificate
|
||||||
|
authentication
|
||||||
|
* Added support to make compile-commands generation conditional
|
||||||
|
* Built fuzzers for normal testing
|
||||||
|
* Avoided passing other events to callbacks when called recursively
|
||||||
|
* Added control master and path options
|
||||||
|
* Refactored channel_rcv_data, check for errors and report more useful errors
|
||||||
|
* Added support to connect to other host addresses than just the first one
|
||||||
|
* Terminated the server properly when the MaxAuthTries is reached
|
||||||
|
* Added support for no-more-sessions@openssh.com request in both client and
|
||||||
|
server
|
||||||
|
* Added callback to support forwarded-tcpip requests
|
||||||
|
* Bumped minimal CMake version to 3.12
|
||||||
|
* Added support for MBedTLS 3.6.x
|
||||||
|
* Added support for +,-,^ modifiers in front of algorithm lists in options
|
||||||
|
* Added callbacks for channel open response, and channel request response
|
||||||
|
* Replaced chroot() from chroot_wrapper internal library with chroot()
|
||||||
|
from priv_wrapper package
|
||||||
|
* Added a placeholder for non-expanded identities
|
||||||
|
* Improved handling of channel transfer window sizes
|
||||||
|
|
||||||
|
version 0.10.6 (released 2023-12-18)
|
||||||
|
* Fix CVE-2023-6004: Command injection using proxycommand
|
||||||
|
* Fix CVE-2023-48795: Potential downgrade attack using strict kex
|
||||||
|
* Fix CVE-2023-6918: Missing checks for return values of MD functions
|
||||||
|
* Fix ssh_send_issue_banner() for CMD(PowerShell)
|
||||||
|
* Avoid passing other events to callbacks when poll is called recursively (#202)
|
||||||
|
* Allow @ in usernames when parsing from URI composes
|
||||||
|
|
||||||
|
version 0.10.5 (released 2023-05-04)
|
||||||
|
* Fix CVE-2023-1667: a NULL dereference during rekeying with algorithm guessing
|
||||||
|
* Fix CVE-2023-2283: a possible authorization bypass in
|
||||||
|
pki_verify_data_signature under low-memory conditions.
|
||||||
|
* Fix several memory leaks in GSSAPI handling code
|
||||||
|
* Escape braces in ProxyCommand created from ProxyJump options for zsh
|
||||||
|
compatibility.
|
||||||
|
* Fix pkg-config path relocation for MinGW
|
||||||
|
* Improve doxygen documentation
|
||||||
|
* Fix build with cygwin due to the glob support
|
||||||
|
* Do not enqueue outgoing packets after sending SSH2_MSG_NEWKEYS
|
||||||
|
* Add support for SSH_SUPPRESS_DEPRECATED
|
||||||
|
* Avoid functions declarations without prototype to build with clang 15
|
||||||
|
* Fix spelling issues
|
||||||
|
* Avoid expanding KnownHosts, ProxyCommands and IdentityFiles repetitively
|
||||||
|
* Add support sk-* keys through configuration
|
||||||
|
* Improve checking for Argp library
|
||||||
|
* Log information about received extensions
|
||||||
|
* Correctly handle rekey with delayed compression
|
||||||
|
* Move the EC keys handling to OpenSSL 3.0 API
|
||||||
|
* Record peer disconnect message
|
||||||
|
* Avoid deadlock when write buffering occurs and we call poll recursively to
|
||||||
|
flush the output buffer
|
||||||
|
* Disable preauthentication compression by default
|
||||||
|
* Add CentOS 8 Stream / OpenSSL 1.1.1 to CI
|
||||||
|
* Add accidentally removed default compile flags
|
||||||
|
* Solve incorrect parsing of ProxyCommand option
|
||||||
|
|
||||||
|
version 0.10.4 (released 2022-09-07)
|
||||||
|
* Fixed issues with KDF on big endian
|
||||||
|
|
||||||
|
version 0.10.3 (released 2022-09-05)
|
||||||
|
* Fixed possible infinite loop in known hosts checking
|
||||||
|
|
||||||
|
version 0.10.2 (released 2022-09-02)
|
||||||
|
* Fixed tilde expansion when handling include directives
|
||||||
|
* Fixed building the shared torture library
|
||||||
|
* Made rekey test more robust (fixes running on i586 build systems e.g koji)
|
||||||
|
|
||||||
|
version 0.10.1 (released 2022-08-30)
|
||||||
|
* Fixed proxycommand support
|
||||||
|
* Fixed musl libc support
|
||||||
|
|
||||||
|
version 0.10.0 (released 2022-08-26)
|
||||||
* Added support for OpenSSL 3.0
|
* Added support for OpenSSL 3.0
|
||||||
* Added support for mbedTLS 3
|
* Added support for mbedTLS 3
|
||||||
* Added support for Smart Cards (through openssl pkcs11 engine)
|
* Added support for Smart Cards (through openssl pkcs11 engine)
|
||||||
@@ -57,7 +178,7 @@ version 0.9.4 (released 2020-04-09)
|
|||||||
* Fixed CVE-2020-1730 - Possible DoS in client and server when handling
|
* Fixed CVE-2020-1730 - Possible DoS in client and server when handling
|
||||||
AES-CTR keys with OpenSSL
|
AES-CTR keys with OpenSSL
|
||||||
* Added diffie-hellman-group14-sha256
|
* Added diffie-hellman-group14-sha256
|
||||||
* Fixed serveral possible memory leaks
|
* Fixed several possible memory leaks
|
||||||
|
|
||||||
version 0.9.3 (released 2019-12-10)
|
version 0.9.3 (released 2019-12-10)
|
||||||
* Fixed CVE-2019-14889 - SCP: Unsanitized location leads to command execution
|
* Fixed CVE-2019-14889 - SCP: Unsanitized location leads to command execution
|
||||||
@@ -208,7 +329,7 @@ version 0.6.1 (released 2014-02-08)
|
|||||||
* Fixed DSA signature extraction.
|
* Fixed DSA signature extraction.
|
||||||
* Fixed some memory leaks.
|
* Fixed some memory leaks.
|
||||||
* Fixed read of non-connected socket.
|
* Fixed read of non-connected socket.
|
||||||
* Fixed thread dectection.
|
* Fixed thread detection.
|
||||||
|
|
||||||
version 0.6.0 (released 2014-01-08)
|
version 0.6.0 (released 2014-01-08)
|
||||||
* Added new publicy key API.
|
* Added new publicy key API.
|
||||||
@@ -233,7 +354,7 @@ version 0.6.0 (released 2014-01-08)
|
|||||||
version 0.5.5 (released 2013-07-26)
|
version 0.5.5 (released 2013-07-26)
|
||||||
* BUG 103: Fix ProxyCommand parsing.
|
* BUG 103: Fix ProxyCommand parsing.
|
||||||
* Fix setting -D_FORTIFY_SOURCE=2.
|
* Fix setting -D_FORTIFY_SOURCE=2.
|
||||||
* Fix pollset error return if emtpy.
|
* Fix pollset error return if empty.
|
||||||
* Fix NULL pointer checks in channel functions.
|
* Fix NULL pointer checks in channel functions.
|
||||||
* Several bugfixes.
|
* Several bugfixes.
|
||||||
|
|
||||||
@@ -249,7 +370,7 @@ version 0.5.3 (released 2012-11-20)
|
|||||||
* BUG #84 - Fix bug in sftp_mkdir not returning on error.
|
* BUG #84 - Fix bug in sftp_mkdir not returning on error.
|
||||||
* BUG #85 - Fixed a possible channel infinite loop if the connection dropped.
|
* BUG #85 - Fixed a possible channel infinite loop if the connection dropped.
|
||||||
* BUG #88 - Added missing channel request_state and set it to accepted.
|
* BUG #88 - Added missing channel request_state and set it to accepted.
|
||||||
* BUG #89 - Reset error state to no error on successful SSHv1 authentiction.
|
* BUG #89 - Reset error state to no error on successful SSHv1 authentication.
|
||||||
* Fixed a possible use after free in ssh_free().
|
* Fixed a possible use after free in ssh_free().
|
||||||
* Fixed multiple possible NULL pointer dereferences.
|
* Fixed multiple possible NULL pointer dereferences.
|
||||||
* Fixed multiple memory leaks in error paths.
|
* Fixed multiple memory leaks in error paths.
|
||||||
@@ -310,7 +431,7 @@ version 0.4.7 (released 2010-12-28)
|
|||||||
* Fixed a possible memory leak in ssh_get_user_home().
|
* Fixed a possible memory leak in ssh_get_user_home().
|
||||||
* Fixed a memory leak in sftp_xstat.
|
* Fixed a memory leak in sftp_xstat.
|
||||||
* Fixed uninitialized fd->revents member.
|
* Fixed uninitialized fd->revents member.
|
||||||
* Fixed timout value in ssh_channel_accept().
|
* Fixed timeout value in ssh_channel_accept().
|
||||||
* Fixed length checks in ssh_analyze_banner().
|
* Fixed length checks in ssh_analyze_banner().
|
||||||
* Fixed a possible data overread and crash bug.
|
* Fixed a possible data overread and crash bug.
|
||||||
* Fixed setting max_fd which breaks ssh_select().
|
* Fixed setting max_fd which breaks ssh_select().
|
||||||
@@ -333,7 +454,7 @@ version 0.4.5 (released 2010-07-13)
|
|||||||
* Added option to bind a client to an ip address.
|
* Added option to bind a client to an ip address.
|
||||||
* Fixed the ssh socket polling function.
|
* Fixed the ssh socket polling function.
|
||||||
* Fixed Windows related bugs in bsd_poll().
|
* Fixed Windows related bugs in bsd_poll().
|
||||||
* Fixed serveral build warnings.
|
* Fixed several build warnings.
|
||||||
|
|
||||||
version 0.4.4 (released 2010-06-01)
|
version 0.4.4 (released 2010-06-01)
|
||||||
* Fixed a bug in the expand function for escape sequences.
|
* Fixed a bug in the expand function for escape sequences.
|
||||||
@@ -352,17 +473,17 @@ version 0.4.3 (released 2010-05-18)
|
|||||||
* Fixed sftp_chown.
|
* Fixed sftp_chown.
|
||||||
* Fixed sftp_rename on protocol version 3.
|
* Fixed sftp_rename on protocol version 3.
|
||||||
* Fixed a blocking bug in channel_poll.
|
* Fixed a blocking bug in channel_poll.
|
||||||
* Fixed config parsing wich has overwritten user specified values.
|
* Fixed config parsing which has overwritten user specified values.
|
||||||
* Fixed hashed [host]:port format in knownhosts
|
* Fixed hashed [host]:port format in knownhosts
|
||||||
* Fixed Windows build.
|
* Fixed Windows build.
|
||||||
* Fixed doublefree happening after a negociation error.
|
* Fixed doublefree happening after a negotiation error.
|
||||||
* Fixed aes*-ctr with <= OpenSSL 0.9.7b.
|
* Fixed aes*-ctr with <= OpenSSL 0.9.7b.
|
||||||
* Fixed some documentation.
|
* Fixed some documentation.
|
||||||
* Fixed exec example which has broken read usage.
|
* Fixed exec example which has broken read usage.
|
||||||
* Fixed broken algorithm choice for server.
|
* Fixed broken algorithm choice for server.
|
||||||
* Fixed a typo that we don't export all symbols.
|
* Fixed a typo that we don't export all symbols.
|
||||||
* Removed the unneeded dependency to doxygen.
|
* Removed the unneeded dependency to doxygen.
|
||||||
* Build examples only on the Linux plattform.
|
* Build examples only on the Linux platform.
|
||||||
|
|
||||||
version 0.4.2 (released 2010-03-15)
|
version 0.4.2 (released 2010-03-15)
|
||||||
* Added owner and group information in sftp attributes.
|
* Added owner and group information in sftp attributes.
|
||||||
@@ -384,7 +505,7 @@ version 0.4.1 (released 2010-02-13)
|
|||||||
* Added an example for exec.
|
* Added an example for exec.
|
||||||
* Added private key type detection feature in privatekey_from_file().
|
* Added private key type detection feature in privatekey_from_file().
|
||||||
* Fixed zlib compression fallback.
|
* Fixed zlib compression fallback.
|
||||||
* Fixed kex bug that client preference should be prioritary
|
* Fixed kex bug that client preference should be priority
|
||||||
* Fixed known_hosts file set by the user.
|
* Fixed known_hosts file set by the user.
|
||||||
* Fixed a memleak in channel_accept().
|
* Fixed a memleak in channel_accept().
|
||||||
* Fixed underflow when leave_function() are unbalanced
|
* Fixed underflow when leave_function() are unbalanced
|
||||||
@@ -522,7 +643,7 @@ version 0.11-dev
|
|||||||
* Keyboard-interactive authentication working.
|
* Keyboard-interactive authentication working.
|
||||||
|
|
||||||
version 0.1 (released 2004-03-05)
|
version 0.1 (released 2004-03-05)
|
||||||
* Begining of sftp subsystem implementation.
|
* Beginning of sftp subsystem implementation.
|
||||||
* Some cleanup into channels implementation
|
* Some cleanup into channels implementation
|
||||||
* Now every channel functions is called by its CHANNEL handler.
|
* Now every channel functions is called by its CHANNEL handler.
|
||||||
* Added channel_poll() and channel_read().
|
* Added channel_poll() and channel_read().
|
||||||
@@ -543,7 +664,7 @@ version 0.0.4 (released 2003-10-10)
|
|||||||
* Added a wrapper.c file. The goal is to provide a similar API to every
|
* Added a wrapper.c file. The goal is to provide a similar API to every
|
||||||
cryptographic functions. bignums and sha/md5 are wrapped now.
|
cryptographic functions. bignums and sha/md5 are wrapped now.
|
||||||
* More work than it first looks.
|
* More work than it first looks.
|
||||||
* Support for other crypto libs planed (lighter libs)
|
* Support for other crypto libs planned (lighter libs)
|
||||||
* Fixed stupid select() bug.
|
* Fixed stupid select() bug.
|
||||||
* Libssh now compiles and links with openssl 0.9.6
|
* Libssh now compiles and links with openssl 0.9.6
|
||||||
* RSA pubkey authentication code now works !
|
* RSA pubkey authentication code now works !
|
||||||
|
|||||||
116
CMakeLists.txt
@@ -1,5 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.3.0)
|
cmake_minimum_required(VERSION 3.14.0)
|
||||||
cmake_policy(SET CMP0048 NEW)
|
|
||||||
|
|
||||||
# Specify search path for CMake modules to be loaded by include()
|
# Specify search path for CMake modules to be loaded by include()
|
||||||
# and find_package()
|
# and find_package()
|
||||||
@@ -10,7 +9,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
|
|||||||
include(DefineCMakeDefaults)
|
include(DefineCMakeDefaults)
|
||||||
include(DefineCompilerFlags)
|
include(DefineCompilerFlags)
|
||||||
|
|
||||||
project(libssh VERSION 0.10.0 LANGUAGES C)
|
project(libssh VERSION 0.11.00 LANGUAGES C)
|
||||||
|
|
||||||
# global needed variable
|
# global needed variable
|
||||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||||
@@ -22,7 +21,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
|
|||||||
# Increment AGE. Set REVISION to 0
|
# Increment AGE. Set REVISION to 0
|
||||||
# If the source code was changed, but there were no interface changes:
|
# If the source code was changed, but there were no interface changes:
|
||||||
# Increment REVISION.
|
# Increment REVISION.
|
||||||
set(LIBRARY_VERSION "4.9.0")
|
set(LIBRARY_VERSION "4.10.0")
|
||||||
set(LIBRARY_SOVERSION "4")
|
set(LIBRARY_SOVERSION "4")
|
||||||
|
|
||||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||||
@@ -42,6 +41,8 @@ macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source buil
|
|||||||
# Copy library files to a lib sub-directory
|
# Copy library files to a lib sub-directory
|
||||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
||||||
|
|
||||||
|
set(LIBSSSH_PC_REQUIRES_PRIVATE "")
|
||||||
|
|
||||||
# search for libraries
|
# search for libraries
|
||||||
if (WITH_ZLIB)
|
if (WITH_ZLIB)
|
||||||
find_package(ZLIB REQUIRED)
|
find_package(ZLIB REQUIRED)
|
||||||
@@ -49,32 +50,12 @@ endif (WITH_ZLIB)
|
|||||||
|
|
||||||
if (WITH_GCRYPT)
|
if (WITH_GCRYPT)
|
||||||
find_package(GCrypt 1.5.0 REQUIRED)
|
find_package(GCrypt 1.5.0 REQUIRED)
|
||||||
if (NOT GCRYPT_FOUND)
|
message(WARNING "libgcrypt cryptographic backend is deprecated and will be removed in future releases.")
|
||||||
message(FATAL_ERROR "Could not find GCrypt")
|
|
||||||
endif (NOT GCRYPT_FOUND)
|
|
||||||
elseif(WITH_MBEDTLS)
|
elseif(WITH_MBEDTLS)
|
||||||
find_package(MbedTLS REQUIRED)
|
find_package(MbedTLS REQUIRED)
|
||||||
if (NOT MBEDTLS_FOUND)
|
else()
|
||||||
message(FATAL_ERROR "Could not find mbedTLS")
|
find_package(OpenSSL 1.1.1 REQUIRED)
|
||||||
endif (NOT MBEDTLS_FOUND)
|
endif()
|
||||||
else (WITH_GCRYPT)
|
|
||||||
find_package(OpenSSL 1.0.1)
|
|
||||||
if (OPENSSL_FOUND)
|
|
||||||
# On CMake < 3.16, OPENSSL_CRYPTO_LIBRARIES is usually a synonym for OPENSSL_CRYPTO_LIBRARY, but is not defined
|
|
||||||
# when building on Windows outside of Cygwin. We provide the synonym here, if FindOpenSSL didn't define it already.
|
|
||||||
if (NOT DEFINED OPENSSL_CRYPTO_LIBRARIES)
|
|
||||||
set(OPENSSL_CRYPTO_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
|
||||||
endif (NOT DEFINED OPENSSL_CRYPTO_LIBRARIES)
|
|
||||||
else (OPENSSL_FOUND)
|
|
||||||
find_package(GCrypt)
|
|
||||||
if (NOT GCRYPT_FOUND)
|
|
||||||
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 (OPENSSL_FOUND)
|
|
||||||
endif(WITH_GCRYPT)
|
|
||||||
|
|
||||||
if (UNIT_TESTING)
|
if (UNIT_TESTING)
|
||||||
find_package(CMocka REQUIRED)
|
find_package(CMocka REQUIRED)
|
||||||
@@ -87,15 +68,9 @@ find_package(Threads)
|
|||||||
|
|
||||||
if (WITH_GSSAPI)
|
if (WITH_GSSAPI)
|
||||||
find_package(GSSAPI)
|
find_package(GSSAPI)
|
||||||
|
list(APPEND LIBSSH_PC_REQUIRES_PRIVATE ${GSSAPI_PC_REQUIRES})
|
||||||
endif (WITH_GSSAPI)
|
endif (WITH_GSSAPI)
|
||||||
|
|
||||||
if (WITH_PKCS11_URI)
|
|
||||||
find_package(softhsm)
|
|
||||||
if (NOT SOFTHSM_FOUND)
|
|
||||||
message(SEND_ERROR "Could not find softhsm module!")
|
|
||||||
endif (NOT SOFTHSM_FOUND)
|
|
||||||
endif (WITH_PKCS11_URI)
|
|
||||||
|
|
||||||
if (WITH_NACL)
|
if (WITH_NACL)
|
||||||
find_package(NaCl)
|
find_package(NaCl)
|
||||||
if (NOT NACL_FOUND)
|
if (NOT NACL_FOUND)
|
||||||
@@ -103,13 +78,19 @@ if (WITH_NACL)
|
|||||||
endif (NOT NACL_FOUND)
|
endif (NOT NACL_FOUND)
|
||||||
endif (WITH_NACL)
|
endif (WITH_NACL)
|
||||||
|
|
||||||
if (BSD OR SOLARIS OR OSX OR CYGWIN)
|
if (WITH_FIDO2)
|
||||||
find_package(Argp)
|
find_package(libfido2)
|
||||||
endif (BSD OR SOLARIS OR OSX OR CYGWIN)
|
if (LIBFIDO2_FOUND)
|
||||||
|
set(HAVE_LIBFIDO2 ON)
|
||||||
|
else (LIBFIDO2_FOUND)
|
||||||
|
set(HAVE_LIBFIDO2 OFF)
|
||||||
|
message(WARNING "libfido2 was not found. Internal support for interacting with FIDO2/U2F devices using the USB HID protocol will not be available.")
|
||||||
|
endif (LIBFIDO2_FOUND)
|
||||||
|
endif (WITH_FIDO2)
|
||||||
|
|
||||||
# Disable symbol versioning in non UNIX platforms
|
# Disable symbol versioning in non UNIX platforms
|
||||||
if (UNIX)
|
if (UNIX)
|
||||||
find_package(ABIMap 0.3.1)
|
find_package(ABIMap 0.4.0)
|
||||||
else (UNIX)
|
else (UNIX)
|
||||||
set(WITH_SYMBOL_VERSIONING OFF)
|
set(WITH_SYMBOL_VERSIONING OFF)
|
||||||
endif (UNIX)
|
endif (UNIX)
|
||||||
@@ -118,6 +99,10 @@ endif (UNIX)
|
|||||||
include(ConfigureChecks.cmake)
|
include(ConfigureChecks.cmake)
|
||||||
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||||
|
|
||||||
|
if (NOT HAVE_ARGP_PARSE)
|
||||||
|
find_package(Argp)
|
||||||
|
endif (NOT HAVE_ARGP_PARSE)
|
||||||
|
|
||||||
# check subdirectories
|
# check subdirectories
|
||||||
add_subdirectory(doc)
|
add_subdirectory(doc)
|
||||||
add_subdirectory(include)
|
add_subdirectory(include)
|
||||||
@@ -125,7 +110,7 @@ add_subdirectory(src)
|
|||||||
|
|
||||||
# pkg-config file
|
# pkg-config file
|
||||||
if (UNIX OR MINGW)
|
if (UNIX OR MINGW)
|
||||||
configure_file(libssh.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh.pc)
|
configure_file(libssh.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh.pc @ONLY)
|
||||||
install(
|
install(
|
||||||
FILES
|
FILES
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
|
${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
|
||||||
@@ -196,6 +181,10 @@ if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
|||||||
set(ALLOW_ABI_BREAK "BREAK_ABI")
|
set(ALLOW_ABI_BREAK "BREAK_ABI")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (WITH_FINAL)
|
||||||
|
set(FINAL "FINAL")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Target we can depend on in 'make dist'
|
# Target we can depend on in 'make dist'
|
||||||
set(_SYMBOL_TARGET "${PROJECT_NAME}.map")
|
set(_SYMBOL_TARGET "${PROJECT_NAME}.map")
|
||||||
|
|
||||||
@@ -208,7 +197,7 @@ if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
|||||||
RELEASE_NAME_VERSION ${PROJECT_NAME}_${LIBRARY_VERSION}
|
RELEASE_NAME_VERSION ${PROJECT_NAME}_${LIBRARY_VERSION}
|
||||||
CURRENT_MAP ${MAP_PATH}
|
CURRENT_MAP ${MAP_PATH}
|
||||||
COPY_TO ${MAP_PATH}
|
COPY_TO ${MAP_PATH}
|
||||||
FINAL
|
${FINAL}
|
||||||
${ALLOW_ABI_BREAK})
|
${ALLOW_ABI_BREAK})
|
||||||
|
|
||||||
# Write the current version to the source
|
# Write the current version to the source
|
||||||
@@ -216,16 +205,36 @@ if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
|||||||
endif(UPDATE_ABI)
|
endif(UPDATE_ABI)
|
||||||
endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
||||||
|
|
||||||
|
# Coverage
|
||||||
|
if (WITH_COVERAGE)
|
||||||
|
ENABLE_LANGUAGE(CXX)
|
||||||
|
include(CodeCoverage)
|
||||||
|
setup_target_for_coverage_lcov(
|
||||||
|
NAME "coverage"
|
||||||
|
EXECUTABLE make test
|
||||||
|
DEPENDENCIES ssh tests)
|
||||||
|
set(GCOVR_ADDITIONAL_ARGS --xml-pretty --exclude-unreachable-branches --print-summary --gcov-ignore-parse-errors)
|
||||||
|
setup_target_for_coverage_gcovr_xml(
|
||||||
|
NAME "coverage_xml"
|
||||||
|
EXECUTABLE make test
|
||||||
|
DEPENDENCIES ssh tests)
|
||||||
|
endif (WITH_COVERAGE)
|
||||||
|
|
||||||
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source DEPENDS ${_SYMBOL_TARGET} VERBATIM)
|
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source DEPENDS ${_SYMBOL_TARGET} VERBATIM)
|
||||||
|
|
||||||
# Link compile database for clangd
|
get_directory_property(hasParent PARENT_DIRECTORY)
|
||||||
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink
|
if(NOT(hasParent))
|
||||||
"${CMAKE_BINARY_DIR}/compile_commands.json"
|
# Link compile database for clangd if we are the master project
|
||||||
"${CMAKE_SOURCE_DIR}/compile_commands.json")
|
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink
|
||||||
|
"${CMAKE_BINARY_DIR}/compile_commands.json"
|
||||||
|
"${CMAKE_SOURCE_DIR}/compile_commands.json")
|
||||||
|
endif()
|
||||||
|
|
||||||
message(STATUS "********************************************")
|
message(STATUS "********************************************")
|
||||||
message(STATUS "********** ${PROJECT_NAME} build options : **********")
|
message(STATUS "********** ${PROJECT_NAME} build options : **********")
|
||||||
|
|
||||||
|
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||||
|
message(STATUS "Coverage: ${WITH_COVERAGE}")
|
||||||
message(STATUS "zlib support: ${WITH_ZLIB}")
|
message(STATUS "zlib support: ${WITH_ZLIB}")
|
||||||
message(STATUS "libgcrypt support: ${WITH_GCRYPT}")
|
message(STATUS "libgcrypt support: ${WITH_GCRYPT}")
|
||||||
message(STATUS "libmbedTLS support: ${WITH_MBEDTLS}")
|
message(STATUS "libmbedTLS support: ${WITH_MBEDTLS}")
|
||||||
@@ -235,13 +244,18 @@ message(STATUS "Server support : ${WITH_SERVER}")
|
|||||||
message(STATUS "GSSAPI support : ${WITH_GSSAPI}")
|
message(STATUS "GSSAPI support : ${WITH_GSSAPI}")
|
||||||
message(STATUS "GEX support : ${WITH_GEX}")
|
message(STATUS "GEX support : ${WITH_GEX}")
|
||||||
message(STATUS "Support insecure none cipher and MAC : ${WITH_INSECURE_NONE}")
|
message(STATUS "Support insecure none cipher and MAC : ${WITH_INSECURE_NONE}")
|
||||||
|
message(STATUS "Support exec : ${WITH_EXEC}")
|
||||||
message(STATUS "Pcap debugging support : ${WITH_PCAP}")
|
message(STATUS "Pcap debugging support : ${WITH_PCAP}")
|
||||||
message(STATUS "Build shared library: ${BUILD_SHARED_LIBS}")
|
message(STATUS "Build shared library: ${BUILD_SHARED_LIBS}")
|
||||||
message(STATUS "Unit testing: ${UNIT_TESTING}")
|
message(STATUS "Unit testing: ${UNIT_TESTING}")
|
||||||
message(STATUS "Client code testing: ${CLIENT_TESTING}")
|
message(STATUS "Client code testing: ${CLIENT_TESTING}")
|
||||||
message(STATUS "Blowfish cipher support: ${WITH_BLOWFISH_CIPHER}")
|
message(STATUS "Blowfish cipher support: ${HAVE_BLOWFISH}")
|
||||||
message(STATUS "PKCS #11 URI support: ${WITH_PKCS11_URI}")
|
message(STATUS "PKCS #11 URI support: ${WITH_PKCS11_URI}")
|
||||||
message(STATUS "DSA support: ${WITH_DSA}")
|
message(STATUS "With PKCS #11 provider support: ${WITH_PKCS11_PROVIDER}")
|
||||||
|
message(STATUS "With FIDO2/U2F support: ${WITH_FIDO2}")
|
||||||
|
if (WITH_FIDO2)
|
||||||
|
message(STATUS "With libfido2 (internal usb-hid support): ${HAVE_LIBFIDO2}")
|
||||||
|
endif (WITH_FIDO2)
|
||||||
set(_SERVER_TESTING OFF)
|
set(_SERVER_TESTING OFF)
|
||||||
if (WITH_SERVER)
|
if (WITH_SERVER)
|
||||||
set(_SERVER_TESTING ${SERVER_TESTING})
|
set(_SERVER_TESTING ${SERVER_TESTING})
|
||||||
@@ -256,9 +270,15 @@ message(STATUS "Benchmarks: ${WITH_BENCHMARKS}")
|
|||||||
message(STATUS "Symbol versioning: ${WITH_SYMBOL_VERSIONING}")
|
message(STATUS "Symbol versioning: ${WITH_SYMBOL_VERSIONING}")
|
||||||
message(STATUS "Allow ABI break: ${WITH_ABI_BREAK}")
|
message(STATUS "Allow ABI break: ${WITH_ABI_BREAK}")
|
||||||
message(STATUS "Release is final: ${WITH_FINAL}")
|
message(STATUS "Release is final: ${WITH_FINAL}")
|
||||||
|
if (WITH_HERMETIC_USR)
|
||||||
|
message(STATUS "User global client config: ${USR_GLOBAL_CLIENT_CONFIG}")
|
||||||
|
endif ()
|
||||||
message(STATUS "Global client config: ${GLOBAL_CLIENT_CONFIG}")
|
message(STATUS "Global client config: ${GLOBAL_CLIENT_CONFIG}")
|
||||||
if (WITH_SERVER)
|
if (WITH_SERVER)
|
||||||
message(STATUS "Global bind config: ${GLOBAL_BIND_CONFIG}")
|
if (WITH_HERMETIC_USR)
|
||||||
|
message(STATUS "User global bind config: ${USR_GLOBAL_BIND_CONFIG}")
|
||||||
|
endif ()
|
||||||
|
message(STATUS "Global bind config: ${GLOBAL_BIND_CONFIG}")
|
||||||
endif()
|
endif()
|
||||||
message(STATUS "********************************************")
|
message(STATUS "********************************************")
|
||||||
|
|
||||||
|
|||||||
118
CONTRIBUTING.md
@@ -117,6 +117,52 @@ 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
|
patch. Just the sign-off message is all that is required once we've
|
||||||
received the initial email.
|
received the initial email.
|
||||||
|
|
||||||
|
## Continuous Integration
|
||||||
|
|
||||||
|
Contributing patches through Merge Request workflow on Gitlab allows us to run
|
||||||
|
various checks on various configuration as part of Gitlab CI. Unfortunately,
|
||||||
|
some pipelines are slower (as they involve building dependencies) so the default
|
||||||
|
timeout of 1 hour needs to be extended at least to 2 hours. This can be done in
|
||||||
|
project settings of your libssh fork:
|
||||||
|
|
||||||
|
https://docs.gitlab.com/ee/ci/pipelines/settings.html#set-a-limit-for-how-long-jobs-can-run
|
||||||
|
|
||||||
|
Otherwise you will encounter errors like these, usually on visualstudio builds:
|
||||||
|
|
||||||
|
```
|
||||||
|
ERROR: Job failed: execution took longer than 1h0m0s seconds
|
||||||
|
The script exceeded the maximum execution time set for the job
|
||||||
|
```
|
||||||
|
|
||||||
|
Note, that the built dependencies are cached so after successful build in your
|
||||||
|
namespace, the rebuilds should be much faster.
|
||||||
|
|
||||||
|
## Running GitLab CI locally (optional helper)
|
||||||
|
|
||||||
|
For contributors working on CI, build system changes, or adding new CI jobs, it can be useful to run GitLab CI pipelines locally before pushing.
|
||||||
|
|
||||||
|
libssh provides a small helper script based on `gitlab-ci-local` that can:
|
||||||
|
|
||||||
|
- List all jobs defined in `.gitlab-ci.yml`
|
||||||
|
- Run a specific job or the full pipeline locally
|
||||||
|
- Automatically pick up new jobs when they are added to the CI configuration
|
||||||
|
- Optionally clean up CI Docker images after execution
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- Docker (daemon running)
|
||||||
|
- git
|
||||||
|
- gitlab-ci-local
|
||||||
|
https://github.com/firecow/gitlab-ci-local
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./.gitlab-ci/local-ci.sh --list
|
||||||
|
./.gitlab-ci/local-ci.sh --run fedora/libressl/x86_64
|
||||||
|
./.gitlab-ci/local-ci.sh --all
|
||||||
|
./.gitlab-ci/local-ci.sh --run fedora/libressl/x86_64 --clean
|
||||||
|
```
|
||||||
|
|
||||||
# Coding conventions in the libssh tree
|
# Coding conventions in the libssh tree
|
||||||
|
|
||||||
@@ -274,7 +320,7 @@ This is bad:
|
|||||||
* This is a multi line comment,
|
* This is a multi line comment,
|
||||||
* with some more words...*/
|
* with some more words...*/
|
||||||
|
|
||||||
### Indention & Whitespace & 80 columns
|
### Indentation & Whitespace & 80 columns
|
||||||
|
|
||||||
To avoid confusion, indentations have to be 4 spaces. Do not use tabs!. When
|
To avoid confusion, indentations have to be 4 spaces. Do not use tabs!. When
|
||||||
wrapping parameters for function calls, align the parameter list with the first
|
wrapping parameters for function calls, align the parameter list with the first
|
||||||
@@ -478,6 +524,76 @@ Macros like `STATUS_NOT_OK_RETURN` that change control flow (return/goto/etc)
|
|||||||
from within the macro are considered bad, because they look like function calls
|
from within the macro are considered bad, because they look like function calls
|
||||||
that never change control flow. Please do not introduce them.
|
that never change control flow. Please do not introduce them.
|
||||||
|
|
||||||
|
### Switch/case indentation
|
||||||
|
|
||||||
|
The `case` should not be indented to avoid wasting too much horizontal space.
|
||||||
|
When the case block contains local variables that need to be wrapped in braces,
|
||||||
|
they should not be indented again either.
|
||||||
|
|
||||||
|
Good example:
|
||||||
|
|
||||||
|
switch (x) {
|
||||||
|
case 0:
|
||||||
|
do_stuff();
|
||||||
|
break;
|
||||||
|
case 1: {
|
||||||
|
int y;
|
||||||
|
do_stuff();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
do_other_stuff();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bad example:
|
||||||
|
|
||||||
|
switch (x) {
|
||||||
|
case 0:
|
||||||
|
do_stuff();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int y;
|
||||||
|
do_stuff();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
do_other_stuff();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
## ABI Versioning and Symbol Management
|
||||||
|
|
||||||
|
To maintain [ABI](https://en.wikipedia.org/wiki/Application_binary_interface) stability
|
||||||
|
and ensure backward compatibility, libssh uses **symbol versioning** to track and manage
|
||||||
|
exported functions and variables. This allows libssh to introduce new symbols or modify
|
||||||
|
existing functions in an ABI-compatible way.
|
||||||
|
|
||||||
|
When introducing a new symbol:
|
||||||
|
|
||||||
|
1. Use the `LIBSSH_API` macro to mark the symbol as part of the public API.
|
||||||
|
2. If you have [abimap](https://github.com/ansasaki/abimap) installed, the new symbols are
|
||||||
|
automatically generated in the `src/libssh_dev.map` file in the **build** directory and used automatically for building the updated library. But, depending on the version of `abimap` under use, you may face linker errors like: `unable to find version dependency LIBSSH_4_9_0`. In this case, you need to manually replace the existing `src/libssh.map` file with the generated `libssh_dev.map` file to update the symbol versioning.
|
||||||
|
3. If you do not have abimap installed, the modified/added symbols must manually be added to the
|
||||||
|
`src/libssh.map` file. The symbols must be added in the following format (assuming that 4_10_0 is the latest released version):
|
||||||
|
|
||||||
|
```
|
||||||
|
LIBSSH_AFTER_4_10_0
|
||||||
|
{
|
||||||
|
global:
|
||||||
|
new_function;
|
||||||
|
new_variable;
|
||||||
|
} LIBSSH_4_10_0;
|
||||||
|
```
|
||||||
|
4. After following either of the above steps, the library can be successfully built and
|
||||||
|
tested without any linker errors.
|
||||||
|
|
||||||
|
5. When submitting the patch, make sure that any new symbols have been added to `libssh.map` as described in step 3, so that the new additions may not be excluded from the next release due to human error.
|
||||||
|
|
||||||
|
Also, to maintain ABI compatibility, existing symbols must not be removed. Instead, they can
|
||||||
|
be marked as deprecated using the `LIBSSH_DEPRECATED` macro. This allows the symbol to be
|
||||||
|
removed in a future release without breaking the ABI.
|
||||||
|
|
||||||
Have fun and happy libssh hacking!
|
Have fun and happy libssh hacking!
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
|
|||||||
|
|
||||||
# SOURCE GENERATOR
|
# SOURCE GENERATOR
|
||||||
set(CPACK_SOURCE_GENERATOR "TXZ")
|
set(CPACK_SOURCE_GENERATOR "TXZ")
|
||||||
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]git/;/[.]clangd/;/[.]cache/;.gitignore;/build*;/obj*;tags;cscope.*;compile_commands.json;.*\.patch")
|
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]bare/;/[.]git/;/[.]git;/[.]clangd/;/[.]cache/;.gitignore;/build*;/obj*;tags;cscope.*;compile_commands.json;.*\.patch")
|
||||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
||||||
|
|
||||||
### NSIS INSTALLER
|
### NSIS INSTALLER
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ if (UNIX)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_c_compiler_flag("-std=gnu99" SUPPORTED_COMPILER_FLAGS)
|
|
||||||
add_c_compiler_flag("-Wpedantic" SUPPORTED_COMPILER_FLAGS)
|
add_c_compiler_flag("-Wpedantic" SUPPORTED_COMPILER_FLAGS)
|
||||||
add_c_compiler_flag("-Wall" SUPPORTED_COMPILER_FLAGS)
|
add_c_compiler_flag("-Wall" SUPPORTED_COMPILER_FLAGS)
|
||||||
add_c_compiler_flag("-Wshadow" SUPPORTED_COMPILER_FLAGS)
|
add_c_compiler_flag("-Wshadow" SUPPORTED_COMPILER_FLAGS)
|
||||||
@@ -43,6 +42,13 @@ if (UNIX)
|
|||||||
add_c_compiler_flag("-Wno-format-zero-length" SUPPORTED_COMPILER_FLAGS)
|
add_c_compiler_flag("-Wno-format-zero-length" SUPPORTED_COMPILER_FLAGS)
|
||||||
add_c_compiler_flag("-Wmissing-field-initializers" SUPPORTED_COMPILER_FLAGS)
|
add_c_compiler_flag("-Wmissing-field-initializers" SUPPORTED_COMPILER_FLAGS)
|
||||||
add_c_compiler_flag("-Wsign-compare" SUPPORTED_COMPILER_FLAGS)
|
add_c_compiler_flag("-Wsign-compare" SUPPORTED_COMPILER_FLAGS)
|
||||||
|
add_c_compiler_flag("-Wold-style-definition" SUPPORTED_COMPILER_FLAGS)
|
||||||
|
add_c_compiler_flag("-Werror=old-style-definition" SUPPORTED_COMPILER_FLAGS)
|
||||||
|
add_c_compiler_flag("-Wimplicit-int" SUPPORTED_COMPILER_FLAGS)
|
||||||
|
add_c_compiler_flag("-Werror=implicit-int" SUPPORTED_COMPILER_FLAGS)
|
||||||
|
add_c_compiler_flag("-Wint-conversion" SUPPORTED_COMPILER_FLAGS)
|
||||||
|
add_c_compiler_flag("-Werror=int-conversion" SUPPORTED_COMPILER_FLAGS)
|
||||||
|
add_c_compiler_flag("-Werror=unused-variable" SUPPORTED_COMPILER_FLAGS)
|
||||||
|
|
||||||
check_c_compiler_flag("-Wformat" REQUIRED_FLAGS_WFORMAT)
|
check_c_compiler_flag("-Wformat" REQUIRED_FLAGS_WFORMAT)
|
||||||
if (REQUIRED_FLAGS_WFORMAT)
|
if (REQUIRED_FLAGS_WFORMAT)
|
||||||
@@ -70,7 +76,7 @@ if (UNIX)
|
|||||||
check_c_compiler_flag_ssp("-fstack-protector-strong" WITH_STACK_PROTECTOR_STRONG)
|
check_c_compiler_flag_ssp("-fstack-protector-strong" WITH_STACK_PROTECTOR_STRONG)
|
||||||
if (WITH_STACK_PROTECTOR_STRONG)
|
if (WITH_STACK_PROTECTOR_STRONG)
|
||||||
list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-protector-strong")
|
list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-protector-strong")
|
||||||
# This is needed as Solaris has a seperate libssp
|
# This is needed as Solaris has a separate libssp
|
||||||
if (SOLARIS)
|
if (SOLARIS)
|
||||||
list(APPEND SUPPORTED_LINKER_FLAGS "-fstack-protector-strong")
|
list(APPEND SUPPORTED_LINKER_FLAGS "-fstack-protector-strong")
|
||||||
endif()
|
endif()
|
||||||
@@ -78,7 +84,7 @@ if (UNIX)
|
|||||||
check_c_compiler_flag_ssp("-fstack-protector" WITH_STACK_PROTECTOR)
|
check_c_compiler_flag_ssp("-fstack-protector" WITH_STACK_PROTECTOR)
|
||||||
if (WITH_STACK_PROTECTOR)
|
if (WITH_STACK_PROTECTOR)
|
||||||
list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-protector")
|
list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-protector")
|
||||||
# This is needed as Solaris has a seperate libssp
|
# This is needed as Solaris has a separate libssp
|
||||||
if (SOLARIS)
|
if (SOLARIS)
|
||||||
list(APPEND SUPPORTED_LINKER_FLAGS "-fstack-protector")
|
list(APPEND SUPPORTED_LINKER_FLAGS "-fstack-protector")
|
||||||
endif()
|
endif()
|
||||||
@@ -86,9 +92,12 @@ if (UNIX)
|
|||||||
endif (WITH_STACK_PROTECTOR_STRONG)
|
endif (WITH_STACK_PROTECTOR_STRONG)
|
||||||
|
|
||||||
if (NOT WINDOWS AND NOT CYGWIN)
|
if (NOT WINDOWS AND NOT CYGWIN)
|
||||||
check_c_compiler_flag_ssp("-fstack-clash-protection" WITH_STACK_CLASH_PROTECTION)
|
# apple m* chips do not support this option
|
||||||
if (WITH_STACK_CLASH_PROTECTION)
|
if (NOT ${CMAKE_SYSTEM_PROCESSOR} STREQUAL arm64)
|
||||||
list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-clash-protection")
|
check_c_compiler_flag_ssp("-fstack-clash-protection" WITH_STACK_CLASH_PROTECTION)
|
||||||
|
if (WITH_STACK_CLASH_PROTECTION)
|
||||||
|
list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-clash-protection")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ int main(void){ return 0; }
|
|||||||
endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2)
|
endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2)
|
||||||
|
|
||||||
# HEADER FILES
|
# HEADER FILES
|
||||||
|
check_function_exists(argp_parse HAVE_ARGP_PARSE)
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${ARGP_INCLUDE_DIR})
|
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${ARGP_INCLUDE_DIR})
|
||||||
check_include_file(argp.h HAVE_ARGP_H)
|
check_include_file(argp.h HAVE_ARGP_H)
|
||||||
unset(CMAKE_REQUIRED_INCLUDES)
|
unset(CMAKE_REQUIRED_INCLUDES)
|
||||||
@@ -62,6 +64,7 @@ check_include_file(arpa/inet.h HAVE_ARPA_INET_H)
|
|||||||
check_include_file(byteswap.h HAVE_BYTESWAP_H)
|
check_include_file(byteswap.h HAVE_BYTESWAP_H)
|
||||||
check_include_file(glob.h HAVE_GLOB_H)
|
check_include_file(glob.h HAVE_GLOB_H)
|
||||||
check_include_file(valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H)
|
check_include_file(valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H)
|
||||||
|
check_include_file(ifaddrs.h HAVE_IFADDRS_H)
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
check_include_file(io.h HAVE_IO_H)
|
check_include_file(io.h HAVE_IO_H)
|
||||||
@@ -75,73 +78,37 @@ endif (WIN32)
|
|||||||
|
|
||||||
if (OPENSSL_FOUND)
|
if (OPENSSL_FOUND)
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES OpenSSL::Crypto)
|
||||||
|
|
||||||
check_include_file(openssl/des.h HAVE_OPENSSL_DES_H)
|
check_include_file(openssl/des.h HAVE_OPENSSL_DES_H)
|
||||||
if (NOT HAVE_OPENSSL_DES_H)
|
if (NOT HAVE_OPENSSL_DES_H)
|
||||||
message(FATAL_ERROR "Could not detect openssl/des.h")
|
message(FATAL_ERROR "Could not detect openssl/des.h")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
|
||||||
check_include_file(openssl/aes.h HAVE_OPENSSL_AES_H)
|
check_include_file(openssl/aes.h HAVE_OPENSSL_AES_H)
|
||||||
if (NOT HAVE_OPENSSL_AES_H)
|
if (NOT HAVE_OPENSSL_AES_H)
|
||||||
message(FATAL_ERROR "Could not detect openssl/aes.h")
|
message(FATAL_ERROR "Could not detect openssl/aes.h")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WITH_BLOWFISH_CIPHER)
|
if (WITH_BLOWFISH_CIPHER)
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
check_include_file(openssl/blowfish.h HAVE_BLOWFISH)
|
||||||
check_include_file(openssl/blowfish.h HAVE_OPENSSL_BLOWFISH_H)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
|
||||||
check_include_file(openssl/ecdh.h HAVE_OPENSSL_ECDH_H)
|
check_include_file(openssl/ecdh.h HAVE_OPENSSL_ECDH_H)
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
|
||||||
check_include_file(openssl/ec.h HAVE_OPENSSL_EC_H)
|
check_include_file(openssl/ec.h HAVE_OPENSSL_EC_H)
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
|
||||||
check_include_file(openssl/ecdsa.h HAVE_OPENSSL_ECDSA_H)
|
check_include_file(openssl/ecdsa.h HAVE_OPENSSL_ECDSA_H)
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
|
||||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
|
||||||
check_function_exists(EVP_KDF_CTX_new_id HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID)
|
check_function_exists(EVP_KDF_CTX_new_id HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID)
|
||||||
|
check_function_exists(EVP_KDF_CTX_new HAVE_OPENSSL_EVP_KDF_CTX_NEW)
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
|
||||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
|
||||||
check_function_exists(FIPS_mode HAVE_OPENSSL_FIPS_MODE)
|
check_function_exists(FIPS_mode HAVE_OPENSSL_FIPS_MODE)
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
|
||||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
|
||||||
check_function_exists(RAND_priv_bytes HAVE_OPENSSL_RAND_PRIV_BYTES)
|
check_function_exists(RAND_priv_bytes HAVE_OPENSSL_RAND_PRIV_BYTES)
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
|
||||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
|
||||||
check_function_exists(EVP_DigestSign HAVE_OPENSSL_EVP_DIGESTSIGN)
|
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
|
||||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
|
||||||
check_function_exists(EVP_DigestVerify HAVE_OPENSSL_EVP_DIGESTVERIFY)
|
|
||||||
|
|
||||||
check_function_exists(OPENSSL_ia32cap_loc HAVE_OPENSSL_IA32CAP_LOC)
|
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
|
||||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
|
||||||
check_symbol_exists(EVP_PKEY_ED25519 "openssl/evp.h" FOUND_OPENSSL_ED25519)
|
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
|
||||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
|
||||||
check_function_exists(EVP_chacha20 HAVE_OPENSSL_EVP_CHACHA20)
|
check_function_exists(EVP_chacha20 HAVE_OPENSSL_EVP_CHACHA20)
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
# Check for ML-KEM availability (OpenSSL 3.5+)
|
||||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
if (OPENSSL_VERSION VERSION_GREATER_EQUAL "3.5.0")
|
||||||
check_symbol_exists(EVP_PKEY_POLY1305 "openssl/evp.h" HAVE_OPENSSL_EVP_POLY1305)
|
set(HAVE_OPENSSL_MLKEM 1)
|
||||||
|
set(HAVE_MLKEM1024 1)
|
||||||
if (HAVE_OPENSSL_EVP_DIGESTSIGN AND HAVE_OPENSSL_EVP_DIGESTVERIFY AND
|
endif ()
|
||||||
FOUND_OPENSSL_ED25519)
|
|
||||||
set(HAVE_OPENSSL_ED25519 1)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
|
||||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
|
|
||||||
check_symbol_exists(EVP_PKEY_X25519 "openssl/evp.h" HAVE_OPENSSL_X25519)
|
|
||||||
|
|
||||||
unset(CMAKE_REQUIRED_INCLUDES)
|
unset(CMAKE_REQUIRED_INCLUDES)
|
||||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||||
@@ -159,13 +126,12 @@ if (NOT WITH_GCRYPT AND NOT WITH_MBEDTLS)
|
|||||||
if (HAVE_OPENSSL_ECC)
|
if (HAVE_OPENSSL_ECC)
|
||||||
set(HAVE_ECC 1)
|
set(HAVE_ECC 1)
|
||||||
endif (HAVE_OPENSSL_ECC)
|
endif (HAVE_OPENSSL_ECC)
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (WITH_DSA)
|
if (HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID OR HAVE_OPENSSL_EVP_KDF_CTX_NEW)
|
||||||
if (NOT WITH_MBEDTLS)
|
set(HAVE_OPENSSL_EVP_KDF_CTX 1)
|
||||||
set(HAVE_DSA 1)
|
endif (HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID OR HAVE_OPENSSL_EVP_KDF_CTX_NEW)
|
||||||
endif (NOT WITH_MBEDTLS)
|
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
# FUNCTIONS
|
# FUNCTIONS
|
||||||
|
|
||||||
@@ -174,6 +140,7 @@ check_function_exists(strncpy HAVE_STRNCPY)
|
|||||||
check_function_exists(strndup HAVE_STRNDUP)
|
check_function_exists(strndup HAVE_STRNDUP)
|
||||||
check_function_exists(strtoull HAVE_STRTOULL)
|
check_function_exists(strtoull HAVE_STRTOULL)
|
||||||
check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO)
|
check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO)
|
||||||
|
check_function_exists(memset_explicit HAVE_MEMSET_EXPLICIT)
|
||||||
check_function_exists(memset_s HAVE_MEMSET_S)
|
check_function_exists(memset_s HAVE_MEMSET_S)
|
||||||
|
|
||||||
if (HAVE_GLOB_H)
|
if (HAVE_GLOB_H)
|
||||||
@@ -266,7 +233,12 @@ if (GCRYPT_FOUND)
|
|||||||
endif (GCRYPT_VERSION VERSION_GREATER "1.4.6")
|
endif (GCRYPT_VERSION VERSION_GREATER "1.4.6")
|
||||||
if (NOT GCRYPT_VERSION VERSION_LESS "1.7.0")
|
if (NOT GCRYPT_VERSION VERSION_LESS "1.7.0")
|
||||||
set(HAVE_GCRYPT_CHACHA_POLY 1)
|
set(HAVE_GCRYPT_CHACHA_POLY 1)
|
||||||
|
set(HAVE_GCRYPT_CURVE25519 1)
|
||||||
endif (NOT GCRYPT_VERSION VERSION_LESS "1.7.0")
|
endif (NOT GCRYPT_VERSION VERSION_LESS "1.7.0")
|
||||||
|
if (GCRYPT_VERSION VERSION_GREATER_EQUAL "1.10.1")
|
||||||
|
set(HAVE_GCRYPT_MLKEM 1)
|
||||||
|
set(HAVE_MLKEM1024 1)
|
||||||
|
endif ()
|
||||||
endif (GCRYPT_FOUND)
|
endif (GCRYPT_FOUND)
|
||||||
|
|
||||||
if (MBEDTLS_FOUND)
|
if (MBEDTLS_FOUND)
|
||||||
@@ -276,6 +248,17 @@ if (MBEDTLS_FOUND)
|
|||||||
set(CMAKE_REQUIRED_INCLUDES "${MBEDTLS_INCLUDE_DIR}/mbedtls")
|
set(CMAKE_REQUIRED_INCLUDES "${MBEDTLS_INCLUDE_DIR}/mbedtls")
|
||||||
check_include_file(chacha20.h HAVE_MBEDTLS_CHACHA20_H)
|
check_include_file(chacha20.h HAVE_MBEDTLS_CHACHA20_H)
|
||||||
check_include_file(poly1305.h HAVE_MBEDTLS_POLY1305_H)
|
check_include_file(poly1305.h HAVE_MBEDTLS_POLY1305_H)
|
||||||
|
if (MBEDTLS_VERSION VERSION_LESS "3.0.0")
|
||||||
|
check_symbol_exists(MBEDTLS_ECP_DP_CURVE25519_ENABLED "config.h" HAVE_MBEDTLS_CURVE25519)
|
||||||
|
else()
|
||||||
|
check_symbol_exists(MBEDTLS_ECP_DP_CURVE25519_ENABLED "mbedtls_config.h" HAVE_MBEDTLS_CURVE25519)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
if (WITH_BLOWFISH_CIPHER)
|
||||||
|
check_include_file(blowfish.h HAVE_BLOWFISH)
|
||||||
|
endif()
|
||||||
|
|
||||||
unset(CMAKE_REQUIRED_INCLUDES)
|
unset(CMAKE_REQUIRED_INCLUDES)
|
||||||
|
|
||||||
endif (MBEDTLS_FOUND)
|
endif (MBEDTLS_FOUND)
|
||||||
@@ -311,7 +294,7 @@ int main(void) {
|
|||||||
# For detecting attributes we need to treat warnings as
|
# For detecting attributes we need to treat warnings as
|
||||||
# errors
|
# errors
|
||||||
if (UNIX OR MINGW)
|
if (UNIX OR MINGW)
|
||||||
# Get warnings for attributs
|
# Get warnings for attributes
|
||||||
check_c_compiler_flag("-Wattributes" REQUIRED_FLAGS_WERROR)
|
check_c_compiler_flag("-Wattributes" REQUIRED_FLAGS_WERROR)
|
||||||
if (REQUIRED_FLAGS_WERROR)
|
if (REQUIRED_FLAGS_WERROR)
|
||||||
string(APPEND CMAKE_REQUIRED_FLAGS "-Wattributes ")
|
string(APPEND CMAKE_REQUIRED_FLAGS "-Wattributes ")
|
||||||
@@ -366,6 +349,23 @@ int main(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}" HAVE_FALLTHROUGH_ATTRIBUTE)
|
}" HAVE_FALLTHROUGH_ATTRIBUTE)
|
||||||
|
|
||||||
|
check_c_source_compiles("
|
||||||
|
#define WEAK __attribute__((weak))
|
||||||
|
|
||||||
|
WEAK int sum(int a, int b)
|
||||||
|
{
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int i = sum(2, 2);
|
||||||
|
|
||||||
|
(void)i;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}" HAVE_WEAK_ATTRIBUTE)
|
||||||
|
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
check_c_source_compiles("
|
check_c_source_compiles("
|
||||||
#define __unused __attribute__((unused))
|
#define __unused __attribute__((unused))
|
||||||
@@ -463,18 +463,22 @@ if (WITH_PKCS11_URI)
|
|||||||
if (WITH_GCRYPT)
|
if (WITH_GCRYPT)
|
||||||
message(FATAL_ERROR "PKCS #11 is not supported for gcrypt.")
|
message(FATAL_ERROR "PKCS #11 is not supported for gcrypt.")
|
||||||
set(WITH_PKCS11_URI 0)
|
set(WITH_PKCS11_URI 0)
|
||||||
endif()
|
elseif (WITH_MBEDTLS)
|
||||||
if (WITH_MBEDTLS)
|
|
||||||
message(FATAL_ERROR "PKCS #11 is not supported for mbedcrypto")
|
message(FATAL_ERROR "PKCS #11 is not supported for mbedcrypto")
|
||||||
set(WITH_PKCS11_URI 0)
|
set(WITH_PKCS11_URI 0)
|
||||||
endif()
|
elseif (OPENSSL_FOUND AND OPENSSL_VERSION VERSION_GREATER_EQUAL "3.0.0")
|
||||||
endif()
|
find_library(PKCS11_PROVIDER
|
||||||
|
NAMES
|
||||||
if (WITH_MBEDTLS)
|
pkcs11.so
|
||||||
if (WITH_DSA)
|
PATH_SUFFIXES
|
||||||
message(FATAL_ERROR "DSA is not supported with mbedTLS crypto")
|
ossl-modules
|
||||||
set(HAVE_DSA 0)
|
)
|
||||||
endif()
|
if (NOT PKCS11_PROVIDER)
|
||||||
|
set(WITH_PKCS11_PROVIDER 0)
|
||||||
|
message(WARNING "Could not find pkcs11 provider! Falling back to engines")
|
||||||
|
message(WARNING "The support for engines is deprecated in OpenSSL and will be removed from libssh in the future releases.")
|
||||||
|
endif (NOT PKCS11_PROVIDER)
|
||||||
|
endif ()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# ENDIAN
|
# ENDIAN
|
||||||
|
|||||||
@@ -2,29 +2,33 @@ option(WITH_GSSAPI "Build with GSSAPI support" ON)
|
|||||||
option(WITH_ZLIB "Build with ZLIB support" ON)
|
option(WITH_ZLIB "Build with ZLIB support" ON)
|
||||||
option(WITH_SFTP "Build with SFTP support" ON)
|
option(WITH_SFTP "Build with SFTP support" ON)
|
||||||
option(WITH_SERVER "Build with SSH server support" ON)
|
option(WITH_SERVER "Build with SSH server support" ON)
|
||||||
option(WITH_DEBUG_CRYPTO "Build with cryto debug output" OFF)
|
option(WITH_DEBUG_CRYPTO "Build with crypto debug output" OFF)
|
||||||
option(WITH_DEBUG_PACKET "Build with packet 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_DEBUG_CALLTRACE "Build with calltrace debug output" ON)
|
||||||
option(WITH_DSA "Build with DSA" OFF)
|
option(WITH_GCRYPT "Compile against libgcrypt (deprecated)" OFF)
|
||||||
option(WITH_GCRYPT "Compile against libgcrypt" OFF)
|
|
||||||
option(WITH_MBEDTLS "Compile against libmbedtls" OFF)
|
option(WITH_MBEDTLS "Compile against libmbedtls" OFF)
|
||||||
option(WITH_BLOWFISH_CIPHER "Compile with blowfish support" OFF)
|
option(WITH_BLOWFISH_CIPHER "Compile with blowfish support" OFF)
|
||||||
option(WITH_PCAP "Compile with Pcap generation support" ON)
|
option(WITH_PCAP "Compile with Pcap generation support" ON)
|
||||||
option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
|
option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
|
||||||
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||||
option(WITH_PKCS11_URI "Build with PKCS#11 URI support" OFF)
|
option(WITH_PKCS11_URI "Build with PKCS#11 URI support" OFF)
|
||||||
|
option(WITH_PKCS11_PROVIDER "Use the PKCS#11 provider for accessing pkcs11 objects" OFF)
|
||||||
|
option(WITH_FIDO2 "Build with FIDO2/U2F support" OFF)
|
||||||
option(UNIT_TESTING "Build with unit tests" OFF)
|
option(UNIT_TESTING "Build with unit tests" OFF)
|
||||||
option(CLIENT_TESTING "Build with client tests; requires openssh" OFF)
|
option(CLIENT_TESTING "Build with client tests; requires openssh" OFF)
|
||||||
option(SERVER_TESTING "Build with server tests; requires openssh and dropbear" OFF)
|
option(SERVER_TESTING "Build with server tests; requires openssh and dropbear" OFF)
|
||||||
option(WITH_BENCHMARKS "Build benchmarks tools" OFF)
|
option(GSSAPI_TESTING "Build with GSSAPI tests; requires krb5-server,krb5-libs and krb5-workstation" OFF)
|
||||||
|
option(WITH_BENCHMARKS "Build benchmarks tools; enables unit testing and client tests" OFF)
|
||||||
option(WITH_EXAMPLES "Build examples" ON)
|
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_SYMBOL_VERSIONING "Build with symbol versioning" ON)
|
||||||
option(WITH_ABI_BREAK "Allow ABI break" OFF)
|
option(WITH_ABI_BREAK "Allow ABI break" OFF)
|
||||||
option(WITH_GEX "Enable DH Group exchange mechanisms" ON)
|
option(WITH_GEX "Enable DH Group exchange mechanisms" ON)
|
||||||
option(WITH_INSECURE_NONE "Enable insecure none cipher and MAC algorithms (not suitable for production!)" OFF)
|
option(WITH_INSECURE_NONE "Enable insecure none cipher and MAC algorithms (not suitable for production!)" OFF)
|
||||||
|
option(WITH_EXEC "Enable libssh to execute arbitrary commands from configuration files or options (match exec, proxy commands and OpenSSH-based proxy-jumps)." ON)
|
||||||
option(FUZZ_TESTING "Build with fuzzer for the server and client (automatically enables none cipher!)" OFF)
|
option(FUZZ_TESTING "Build with fuzzer for the server and client (automatically enables none cipher!)" OFF)
|
||||||
option(PICKY_DEVELOPER "Build with picky developer flags" OFF)
|
option(PICKY_DEVELOPER "Build with picky developer flags" OFF)
|
||||||
|
option(WITH_HERMETIC_USR "Build with support for hermetic /usr/" OFF)
|
||||||
|
|
||||||
if (WITH_ZLIB)
|
if (WITH_ZLIB)
|
||||||
set(WITH_LIBZ ON)
|
set(WITH_LIBZ ON)
|
||||||
@@ -37,7 +41,7 @@ if (WITH_BENCHMARKS)
|
|||||||
set(CLIENT_TESTING ON)
|
set(CLIENT_TESTING ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNIT_TESTING OR CLIENT_TESTING OR SERVER_TESTING)
|
if (UNIT_TESTING OR CLIENT_TESTING OR SERVER_TESTING OR GSSAPI_TESTING)
|
||||||
set(BUILD_STATIC_LIB ON)
|
set(BUILD_STATIC_LIB ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -57,6 +61,15 @@ if (NOT GLOBAL_CLIENT_CONFIG)
|
|||||||
set(GLOBAL_CLIENT_CONFIG "/etc/ssh/ssh_config")
|
set(GLOBAL_CLIENT_CONFIG "/etc/ssh/ssh_config")
|
||||||
endif (NOT GLOBAL_CLIENT_CONFIG)
|
endif (NOT GLOBAL_CLIENT_CONFIG)
|
||||||
|
|
||||||
|
if (WITH_HERMETIC_USR)
|
||||||
|
set(USR_GLOBAL_BIND_CONFIG "/usr${GLOBAL_BIND_CONFIG}")
|
||||||
|
set(USR_GLOBAL_CLIENT_CONFIG "/usr${GLOBAL_CLIENT_CONFIG}")
|
||||||
|
endif (WITH_HERMETIC_USR)
|
||||||
|
|
||||||
if (FUZZ_TESTING)
|
if (FUZZ_TESTING)
|
||||||
set(WITH_INSECURE_NONE ON)
|
set(WITH_INSECURE_NONE ON)
|
||||||
endif (FUZZ_TESTING)
|
endif (FUZZ_TESTING)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
set(WITH_EXEC 0)
|
||||||
|
endif(WIN32)
|
||||||
|
|||||||
19
INSTALL
@@ -7,11 +7,13 @@
|
|||||||
In order to build libssh, you need to install several components:
|
In order to build libssh, you need to install several components:
|
||||||
|
|
||||||
- A C compiler
|
- A C compiler
|
||||||
- [CMake](https://www.cmake.org) >= 3.3.0
|
- [CMake](https://www.cmake.org) >= 3.12.0
|
||||||
- [openssl](https://www.openssl.org) >= 1.0.1
|
|
||||||
or
|
|
||||||
- [gcrypt](https://www.gnu.org/directory/Security/libgcrypt.html) >= 1.4
|
|
||||||
- [libz](https://www.zlib.net) >= 1.2
|
- [libz](https://www.zlib.net) >= 1.2
|
||||||
|
- [openssl](https://www.openssl.org) >= 1.1.1
|
||||||
|
or
|
||||||
|
- [gcrypt](https://www.gnu.org/directory/Security/libgcrypt.html) >= 1.5
|
||||||
|
or
|
||||||
|
- [Mbed TLS](https://www.trustedfirmware.org/projects/mbed-tls/)
|
||||||
|
|
||||||
optional:
|
optional:
|
||||||
- [cmocka](https://cmocka.org/) >= 1.1.0
|
- [cmocka](https://cmocka.org/) >= 1.1.0
|
||||||
@@ -19,6 +21,7 @@ optional:
|
|||||||
- [nss_wrapper](https://cwrap.org/) >= 1.1.2
|
- [nss_wrapper](https://cwrap.org/) >= 1.1.2
|
||||||
- [uid_wrapper](https://cwrap.org/) >= 1.2.0
|
- [uid_wrapper](https://cwrap.org/) >= 1.2.0
|
||||||
- [pam_wrapper](https://cwrap.org/) >= 1.0.1
|
- [pam_wrapper](https://cwrap.org/) >= 1.0.1
|
||||||
|
- [priv_wrapper](https://cwrap.org/) >= 1.0.0
|
||||||
|
|
||||||
Note that these version numbers are version we know works correctly. If you
|
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.
|
build and run libssh successfully with an older version, please let us know.
|
||||||
@@ -35,14 +38,16 @@ First, you need to configure the compilation, using CMake. Go inside the
|
|||||||
`build` dir. Create it if it doesn't exist.
|
`build` dir. Create it if it doesn't exist.
|
||||||
|
|
||||||
GNU/Linux, MacOS X, MSYS/MinGW:
|
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
|
make
|
||||||
|
|
||||||
On Windows you should choose a makefile gernerator with -G or use
|
On Windows you should choose a makefile generator with -G or use
|
||||||
|
|
||||||
cmake-gui.exe ..
|
cmake-gui.exe ..
|
||||||
|
|
||||||
|
To enable building tests use -DUNIT_TESTING=ON. For this, the
|
||||||
|
[cmocka](https://cmocka.org) dependency is required.
|
||||||
|
|
||||||
To enable additional client tests against a local OpenSSH server, add the
|
To enable additional client tests against a local OpenSSH server, add the
|
||||||
compile option -DCLIENT_TESTING=ON. These tests require an OpenSSH
|
compile option -DCLIENT_TESTING=ON. These tests require an OpenSSH
|
||||||
server package and some wrapper libraries (see optional requirements) to
|
server package and some wrapper libraries (see optional requirements) to
|
||||||
|
|||||||
@@ -116,5 +116,10 @@ function(ADD_CMOCKA_TEST _TARGET_NAME)
|
|||||||
add_test(${_TARGET_NAME}
|
add_test(${_TARGET_NAME}
|
||||||
${TARGET_SYSTEM_EMULATOR} ${_TARGET_NAME}
|
${TARGET_SYSTEM_EMULATOR} ${_TARGET_NAME}
|
||||||
)
|
)
|
||||||
|
if (WITH_COVERAGE)
|
||||||
|
ENABLE_LANGUAGE(CXX)
|
||||||
|
include(CodeCoverage)
|
||||||
|
append_coverage_compiler_flags_to_target(${_TARGET_NAME})
|
||||||
|
endif (WITH_COVERAGE)
|
||||||
|
|
||||||
endfunction (ADD_CMOCKA_TEST)
|
endfunction (ADD_CMOCKA_TEST)
|
||||||
|
|||||||
750
cmake/Modules/CodeCoverage.cmake
Normal file
@@ -0,0 +1,750 @@
|
|||||||
|
# Copyright (c) 2012 - 2017, Lars Bilke
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
# are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
# list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
# may be used to endorse or promote products derived from this software without
|
||||||
|
# specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
# CHANGES:
|
||||||
|
#
|
||||||
|
# 2012-01-31, Lars Bilke
|
||||||
|
# - Enable Code Coverage
|
||||||
|
#
|
||||||
|
# 2013-09-17, Joakim Söderberg
|
||||||
|
# - Added support for Clang.
|
||||||
|
# - Some additional usage instructions.
|
||||||
|
#
|
||||||
|
# 2016-02-03, Lars Bilke
|
||||||
|
# - Refactored functions to use named parameters
|
||||||
|
#
|
||||||
|
# 2017-06-02, Lars Bilke
|
||||||
|
# - Merged with modified version from github.com/ufz/ogs
|
||||||
|
#
|
||||||
|
# 2019-05-06, Anatolii Kurotych
|
||||||
|
# - Remove unnecessary --coverage flag
|
||||||
|
#
|
||||||
|
# 2019-12-13, FeRD (Frank Dana)
|
||||||
|
# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor
|
||||||
|
# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments.
|
||||||
|
# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY
|
||||||
|
# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list
|
||||||
|
# - Set lcov basedir with -b argument
|
||||||
|
# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be
|
||||||
|
# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().)
|
||||||
|
# - Delete output dir, .info file on 'make clean'
|
||||||
|
# - Remove Python detection, since version mismatches will break gcovr
|
||||||
|
# - Minor cleanup (lowercase function names, update examples...)
|
||||||
|
#
|
||||||
|
# 2019-12-19, FeRD (Frank Dana)
|
||||||
|
# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets
|
||||||
|
#
|
||||||
|
# 2020-01-19, Bob Apthorpe
|
||||||
|
# - Added gfortran support
|
||||||
|
#
|
||||||
|
# 2020-02-17, FeRD (Frank Dana)
|
||||||
|
# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters
|
||||||
|
# in EXCLUDEs, and remove manual escaping from gcovr targets
|
||||||
|
#
|
||||||
|
# 2021-01-19, Robin Mueller
|
||||||
|
# - Add CODE_COVERAGE_VERBOSE option which will allow to print out commands which are run
|
||||||
|
# - Added the option for users to set the GCOVR_ADDITIONAL_ARGS variable to supply additional
|
||||||
|
# flags to the gcovr command
|
||||||
|
#
|
||||||
|
# 2020-05-04, Mihchael Davis
|
||||||
|
# - Add -fprofile-abs-path to make gcno files contain absolute paths
|
||||||
|
# - Fix BASE_DIRECTORY not working when defined
|
||||||
|
# - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines
|
||||||
|
#
|
||||||
|
# 2021-05-10, Martin Stump
|
||||||
|
# - Check if the generator is multi-config before warning about non-Debug builds
|
||||||
|
#
|
||||||
|
# 2022-02-22, Marko Wehle
|
||||||
|
# - Change gcovr output from -o <filename> for --xml <filename> and --html <filename> output respectively.
|
||||||
|
# This will allow for Multiple Output Formats at the same time by making use of GCOVR_ADDITIONAL_ARGS, e.g. GCOVR_ADDITIONAL_ARGS "--txt".
|
||||||
|
#
|
||||||
|
# 2022-09-28, Sebastian Mueller
|
||||||
|
# - fix append_coverage_compiler_flags_to_target to correctly add flags
|
||||||
|
# - replace "-fprofile-arcs -ftest-coverage" with "--coverage" (equivalent)
|
||||||
|
#
|
||||||
|
# USAGE:
|
||||||
|
#
|
||||||
|
# 1. Copy this file into your cmake modules path.
|
||||||
|
#
|
||||||
|
# 2. Add the following line to your CMakeLists.txt (best inside an if-condition
|
||||||
|
# using a CMake option() to enable it just optionally):
|
||||||
|
# include(CodeCoverage)
|
||||||
|
#
|
||||||
|
# 3. Append necessary compiler flags for all supported source files:
|
||||||
|
# append_coverage_compiler_flags()
|
||||||
|
# Or for specific target:
|
||||||
|
# append_coverage_compiler_flags_to_target(YOUR_TARGET_NAME)
|
||||||
|
#
|
||||||
|
# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og
|
||||||
|
#
|
||||||
|
# 4. If you need to exclude additional directories from the report, specify them
|
||||||
|
# using full paths in the COVERAGE_EXCLUDES variable before calling
|
||||||
|
# setup_target_for_coverage_*().
|
||||||
|
# Example:
|
||||||
|
# set(COVERAGE_EXCLUDES
|
||||||
|
# '${PROJECT_SOURCE_DIR}/src/dir1/*'
|
||||||
|
# '/path/to/my/src/dir2/*')
|
||||||
|
# Or, use the EXCLUDE argument to setup_target_for_coverage_*().
|
||||||
|
# Example:
|
||||||
|
# setup_target_for_coverage_lcov(
|
||||||
|
# NAME coverage
|
||||||
|
# EXECUTABLE testrunner
|
||||||
|
# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*")
|
||||||
|
#
|
||||||
|
# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set
|
||||||
|
# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR)
|
||||||
|
# Example:
|
||||||
|
# set(COVERAGE_EXCLUDES "dir1/*")
|
||||||
|
# setup_target_for_coverage_gcovr_html(
|
||||||
|
# NAME coverage
|
||||||
|
# EXECUTABLE testrunner
|
||||||
|
# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src"
|
||||||
|
# EXCLUDE "dir2/*")
|
||||||
|
#
|
||||||
|
# 5. Use the functions described below to create a custom make target which
|
||||||
|
# runs your test executable and produces a code coverage report.
|
||||||
|
#
|
||||||
|
# 6. Build a Debug build:
|
||||||
|
# cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||||
|
# make
|
||||||
|
# make my_coverage_target
|
||||||
|
#
|
||||||
|
|
||||||
|
include(CMakeParseArguments)
|
||||||
|
|
||||||
|
option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE)
|
||||||
|
|
||||||
|
# Check prereqs
|
||||||
|
find_program( GCOV_PATH gcov )
|
||||||
|
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
|
||||||
|
find_program( FASTCOV_PATH NAMES fastcov fastcov.py )
|
||||||
|
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
|
||||||
|
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
|
||||||
|
find_program( CPPFILT_PATH NAMES c++filt )
|
||||||
|
|
||||||
|
if(NOT GCOV_PATH)
|
||||||
|
message(FATAL_ERROR "gcov not found! Aborting...")
|
||||||
|
endif() # NOT GCOV_PATH
|
||||||
|
|
||||||
|
# Check supported compiler (Clang, GNU and Flang)
|
||||||
|
get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||||
|
foreach(LANG ${LANGUAGES})
|
||||||
|
if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
|
||||||
|
if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3)
|
||||||
|
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
|
||||||
|
endif()
|
||||||
|
elseif(NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "GNU"
|
||||||
|
AND NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(LLVM)?[Ff]lang")
|
||||||
|
message(FATAL_ERROR "Compiler is not GNU or Flang! Aborting...")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(COVERAGE_COMPILER_FLAGS "-g --coverage -fprofile-update=atomic"
|
||||||
|
CACHE INTERNAL "")
|
||||||
|
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
check_cxx_compiler_flag(-fprofile-abs-path HAVE_cxx_fprofile_abs_path)
|
||||||
|
if(HAVE_cxx_fprofile_abs_path)
|
||||||
|
set(COVERAGE_CXX_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if(CMAKE_C_COMPILER_ID MATCHES "(GNU|Clang)")
|
||||||
|
include(CheckCCompilerFlag)
|
||||||
|
check_c_compiler_flag(-fprofile-abs-path HAVE_c_fprofile_abs_path)
|
||||||
|
if(HAVE_c_fprofile_abs_path)
|
||||||
|
set(COVERAGE_C_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_FLAGS_COVERAGE
|
||||||
|
${COVERAGE_COMPILER_FLAGS}
|
||||||
|
CACHE STRING "Flags used by the Fortran compiler during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
set(CMAKE_CXX_FLAGS_COVERAGE
|
||||||
|
${COVERAGE_COMPILER_FLAGS}
|
||||||
|
CACHE STRING "Flags used by the C++ compiler during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
set(CMAKE_C_FLAGS_COVERAGE
|
||||||
|
${COVERAGE_COMPILER_FLAGS}
|
||||||
|
CACHE STRING "Flags used by the C compiler during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||||
|
""
|
||||||
|
CACHE STRING "Flags used for linking binaries during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
|
||||||
|
""
|
||||||
|
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
mark_as_advanced(
|
||||||
|
CMAKE_Fortran_FLAGS_COVERAGE
|
||||||
|
CMAKE_CXX_FLAGS_COVERAGE
|
||||||
|
CMAKE_C_FLAGS_COVERAGE
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
|
||||||
|
|
||||||
|
get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||||
|
if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG))
|
||||||
|
message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
|
||||||
|
endif() # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG)
|
||||||
|
|
||||||
|
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
|
||||||
|
link_libraries(gcov)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Defines a target for running and collection code coverage information
|
||||||
|
# Builds dependencies, runs the given executable and outputs reports.
|
||||||
|
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||||
|
# the coverage generation will not complete.
|
||||||
|
#
|
||||||
|
# setup_target_for_coverage_lcov(
|
||||||
|
# NAME testrunner_coverage # New target name
|
||||||
|
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||||
|
# DEPENDENCIES testrunner # Dependencies to build first
|
||||||
|
# BASE_DIRECTORY "../" # Base directory for report
|
||||||
|
# # (defaults to PROJECT_SOURCE_DIR)
|
||||||
|
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
||||||
|
# # to BASE_DIRECTORY, with CMake 3.4+)
|
||||||
|
# NO_DEMANGLE # Don't demangle C++ symbols
|
||||||
|
# # even if c++filt is found
|
||||||
|
# )
|
||||||
|
function(setup_target_for_coverage_lcov)
|
||||||
|
|
||||||
|
set(options NO_DEMANGLE SONARQUBE)
|
||||||
|
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||||
|
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
|
||||||
|
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT LCOV_PATH)
|
||||||
|
message(FATAL_ERROR "lcov not found! Aborting...")
|
||||||
|
endif() # NOT LCOV_PATH
|
||||||
|
|
||||||
|
if(NOT GENHTML_PATH)
|
||||||
|
message(FATAL_ERROR "genhtml not found! Aborting...")
|
||||||
|
endif() # NOT GENHTML_PATH
|
||||||
|
|
||||||
|
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||||
|
if(DEFINED Coverage_BASE_DIRECTORY)
|
||||||
|
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||||
|
else()
|
||||||
|
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect excludes (CMake 3.4+: Also compute absolute paths)
|
||||||
|
set(LCOV_EXCLUDES "")
|
||||||
|
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES})
|
||||||
|
if(CMAKE_VERSION VERSION_GREATER 3.4)
|
||||||
|
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
|
||||||
|
endif()
|
||||||
|
list(APPEND LCOV_EXCLUDES "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
list(REMOVE_DUPLICATES LCOV_EXCLUDES)
|
||||||
|
|
||||||
|
# Conditional arguments
|
||||||
|
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
|
||||||
|
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Setting up commands which will be run to generate coverage data.
|
||||||
|
# Cleanup lcov
|
||||||
|
set(LCOV_CLEAN_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory .
|
||||||
|
-b ${BASEDIR} --zerocounters
|
||||||
|
)
|
||||||
|
# Create baseline to make sure untouched files show up in the report
|
||||||
|
set(LCOV_BASELINE_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b
|
||||||
|
${BASEDIR} -o ${Coverage_NAME}.base
|
||||||
|
)
|
||||||
|
# Run tests
|
||||||
|
set(LCOV_EXEC_TESTS_CMD
|
||||||
|
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||||
|
)
|
||||||
|
# Capturing lcov counters and generating report
|
||||||
|
set(LCOV_CAPTURE_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b
|
||||||
|
${BASEDIR} --capture --output-file ${Coverage_NAME}.capture
|
||||||
|
)
|
||||||
|
# add baseline counters
|
||||||
|
set(LCOV_BASELINE_COUNT_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base
|
||||||
|
-a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total
|
||||||
|
)
|
||||||
|
# filter collected data to final coverage report
|
||||||
|
set(LCOV_FILTER_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove
|
||||||
|
${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info
|
||||||
|
)
|
||||||
|
# Generate HTML output
|
||||||
|
set(LCOV_GEN_HTML_CMD
|
||||||
|
${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o
|
||||||
|
${Coverage_NAME} ${Coverage_NAME}.info
|
||||||
|
)
|
||||||
|
if(${Coverage_SONARQUBE})
|
||||||
|
# Generate SonarQube output
|
||||||
|
set(GCOVR_XML_CMD
|
||||||
|
${GCOVR_PATH} --sonarqube ${Coverage_NAME}_sonarqube.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
|
||||||
|
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
set(GCOVR_XML_CMD_COMMAND
|
||||||
|
COMMAND ${GCOVR_XML_CMD}
|
||||||
|
)
|
||||||
|
set(GCOVR_XML_CMD_BYPRODUCTS ${Coverage_NAME}_sonarqube.xml)
|
||||||
|
set(GCOVR_XML_CMD_COMMENT COMMENT "SonarQube code coverage info report saved in ${Coverage_NAME}_sonarqube.xml.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
if(CODE_COVERAGE_VERBOSE)
|
||||||
|
message(STATUS "Executed command report")
|
||||||
|
message(STATUS "Command to clean up lcov: ")
|
||||||
|
string(REPLACE ";" " " LCOV_CLEAN_CMD_SPACED "${LCOV_CLEAN_CMD}")
|
||||||
|
message(STATUS "${LCOV_CLEAN_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to create baseline: ")
|
||||||
|
string(REPLACE ";" " " LCOV_BASELINE_CMD_SPACED "${LCOV_BASELINE_CMD}")
|
||||||
|
message(STATUS "${LCOV_BASELINE_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to run the tests: ")
|
||||||
|
string(REPLACE ";" " " LCOV_EXEC_TESTS_CMD_SPACED "${LCOV_EXEC_TESTS_CMD}")
|
||||||
|
message(STATUS "${LCOV_EXEC_TESTS_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to capture counters and generate report: ")
|
||||||
|
string(REPLACE ";" " " LCOV_CAPTURE_CMD_SPACED "${LCOV_CAPTURE_CMD}")
|
||||||
|
message(STATUS "${LCOV_CAPTURE_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to add baseline counters: ")
|
||||||
|
string(REPLACE ";" " " LCOV_BASELINE_COUNT_CMD_SPACED "${LCOV_BASELINE_COUNT_CMD}")
|
||||||
|
message(STATUS "${LCOV_BASELINE_COUNT_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to filter collected data: ")
|
||||||
|
string(REPLACE ";" " " LCOV_FILTER_CMD_SPACED "${LCOV_FILTER_CMD}")
|
||||||
|
message(STATUS "${LCOV_FILTER_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to generate lcov HTML output: ")
|
||||||
|
string(REPLACE ";" " " LCOV_GEN_HTML_CMD_SPACED "${LCOV_GEN_HTML_CMD}")
|
||||||
|
message(STATUS "${LCOV_GEN_HTML_CMD_SPACED}")
|
||||||
|
|
||||||
|
if(${Coverage_SONARQUBE})
|
||||||
|
message(STATUS "Command to generate SonarQube XML output: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}")
|
||||||
|
message(STATUS "${GCOVR_XML_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Setup target
|
||||||
|
add_custom_target(${Coverage_NAME}
|
||||||
|
COMMAND ${LCOV_CLEAN_CMD}
|
||||||
|
COMMAND ${LCOV_BASELINE_CMD}
|
||||||
|
COMMAND ${LCOV_EXEC_TESTS_CMD}
|
||||||
|
COMMAND ${LCOV_CAPTURE_CMD}
|
||||||
|
COMMAND ${LCOV_BASELINE_COUNT_CMD}
|
||||||
|
COMMAND ${LCOV_FILTER_CMD}
|
||||||
|
COMMAND ${LCOV_GEN_HTML_CMD}
|
||||||
|
${GCOVR_XML_CMD_COMMAND}
|
||||||
|
|
||||||
|
# Set output files as GENERATED (will be removed on 'make clean')
|
||||||
|
BYPRODUCTS
|
||||||
|
${Coverage_NAME}.base
|
||||||
|
${Coverage_NAME}.capture
|
||||||
|
${Coverage_NAME}.total
|
||||||
|
${Coverage_NAME}.info
|
||||||
|
${GCOVR_XML_CMD_BYPRODUCTS}
|
||||||
|
${Coverage_NAME}/index.html
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||||
|
DEPENDS ${Coverage_DEPENDENCIES}
|
||||||
|
VERBATIM # Protect arguments to commands
|
||||||
|
COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show where to find the lcov info report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ;
|
||||||
|
COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
|
||||||
|
${GCOVR_XML_CMD_COMMENT}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show info where to find the report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ;
|
||||||
|
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
|
||||||
|
)
|
||||||
|
|
||||||
|
endfunction() # setup_target_for_coverage_lcov
|
||||||
|
|
||||||
|
# Defines a target for running and collection code coverage information
|
||||||
|
# Builds dependencies, runs the given executable and outputs reports.
|
||||||
|
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||||
|
# the coverage generation will not complete.
|
||||||
|
#
|
||||||
|
# setup_target_for_coverage_gcovr_xml(
|
||||||
|
# NAME ctest_coverage # New target name
|
||||||
|
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||||
|
# DEPENDENCIES executable_target # Dependencies to build first
|
||||||
|
# BASE_DIRECTORY "../" # Base directory for report
|
||||||
|
# # (defaults to PROJECT_SOURCE_DIR)
|
||||||
|
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
||||||
|
# # to BASE_DIRECTORY, with CMake 3.4+)
|
||||||
|
# )
|
||||||
|
# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the
|
||||||
|
# GCVOR command.
|
||||||
|
function(setup_target_for_coverage_gcovr_xml)
|
||||||
|
|
||||||
|
set(options NONE)
|
||||||
|
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||||
|
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
||||||
|
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT GCOVR_PATH)
|
||||||
|
message(FATAL_ERROR "gcovr not found! Aborting...")
|
||||||
|
endif() # NOT GCOVR_PATH
|
||||||
|
|
||||||
|
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||||
|
if(DEFINED Coverage_BASE_DIRECTORY)
|
||||||
|
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||||
|
else()
|
||||||
|
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect excludes (CMake 3.4+: Also compute absolute paths)
|
||||||
|
set(GCOVR_EXCLUDES "")
|
||||||
|
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
|
||||||
|
if(CMAKE_VERSION VERSION_GREATER 3.4)
|
||||||
|
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
|
||||||
|
endif()
|
||||||
|
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
|
||||||
|
|
||||||
|
# Combine excludes to several -e arguments
|
||||||
|
set(GCOVR_EXCLUDE_ARGS "")
|
||||||
|
foreach(EXCLUDE ${GCOVR_EXCLUDES})
|
||||||
|
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
|
||||||
|
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Set up commands which will be run to generate coverage data
|
||||||
|
# Run tests
|
||||||
|
set(GCOVR_XML_EXEC_TESTS_CMD
|
||||||
|
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||||
|
)
|
||||||
|
# Running gcovr
|
||||||
|
set(GCOVR_XML_CMD
|
||||||
|
${GCOVR_PATH} --xml ${Coverage_NAME}.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
|
||||||
|
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CODE_COVERAGE_VERBOSE)
|
||||||
|
message(STATUS "Executed command report")
|
||||||
|
|
||||||
|
message(STATUS "Command to run tests: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_XML_EXEC_TESTS_CMD_SPACED "${GCOVR_XML_EXEC_TESTS_CMD}")
|
||||||
|
message(STATUS "${GCOVR_XML_EXEC_TESTS_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to generate gcovr XML coverage data: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}")
|
||||||
|
message(STATUS "${GCOVR_XML_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_target(${Coverage_NAME}
|
||||||
|
COMMAND ${GCOVR_XML_EXEC_TESTS_CMD}
|
||||||
|
COMMAND ${GCOVR_XML_CMD}
|
||||||
|
|
||||||
|
BYPRODUCTS ${Coverage_NAME}.xml
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||||
|
DEPENDS ${Coverage_DEPENDENCIES}
|
||||||
|
VERBATIM # Protect arguments to commands
|
||||||
|
COMMENT "Running gcovr to produce Cobertura code coverage report."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show info where to find the report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ;
|
||||||
|
COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
|
||||||
|
)
|
||||||
|
endfunction() # setup_target_for_coverage_gcovr_xml
|
||||||
|
|
||||||
|
# Defines a target for running and collection code coverage information
|
||||||
|
# Builds dependencies, runs the given executable and outputs reports.
|
||||||
|
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||||
|
# the coverage generation will not complete.
|
||||||
|
#
|
||||||
|
# setup_target_for_coverage_gcovr_html(
|
||||||
|
# NAME ctest_coverage # New target name
|
||||||
|
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||||
|
# DEPENDENCIES executable_target # Dependencies to build first
|
||||||
|
# BASE_DIRECTORY "../" # Base directory for report
|
||||||
|
# # (defaults to PROJECT_SOURCE_DIR)
|
||||||
|
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
||||||
|
# # to BASE_DIRECTORY, with CMake 3.4+)
|
||||||
|
# )
|
||||||
|
# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the
|
||||||
|
# GCVOR command.
|
||||||
|
function(setup_target_for_coverage_gcovr_html)
|
||||||
|
|
||||||
|
set(options NONE)
|
||||||
|
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||||
|
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
||||||
|
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT GCOVR_PATH)
|
||||||
|
message(FATAL_ERROR "gcovr not found! Aborting...")
|
||||||
|
endif() # NOT GCOVR_PATH
|
||||||
|
|
||||||
|
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||||
|
if(DEFINED Coverage_BASE_DIRECTORY)
|
||||||
|
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||||
|
else()
|
||||||
|
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect excludes (CMake 3.4+: Also compute absolute paths)
|
||||||
|
set(GCOVR_EXCLUDES "")
|
||||||
|
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
|
||||||
|
if(CMAKE_VERSION VERSION_GREATER 3.4)
|
||||||
|
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
|
||||||
|
endif()
|
||||||
|
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
|
||||||
|
|
||||||
|
# Combine excludes to several -e arguments
|
||||||
|
set(GCOVR_EXCLUDE_ARGS "")
|
||||||
|
foreach(EXCLUDE ${GCOVR_EXCLUDES})
|
||||||
|
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
|
||||||
|
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Set up commands which will be run to generate coverage data
|
||||||
|
# Run tests
|
||||||
|
set(GCOVR_HTML_EXEC_TESTS_CMD
|
||||||
|
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||||
|
)
|
||||||
|
# Create folder
|
||||||
|
set(GCOVR_HTML_FOLDER_CMD
|
||||||
|
${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
|
||||||
|
)
|
||||||
|
# Running gcovr
|
||||||
|
set(GCOVR_HTML_CMD
|
||||||
|
${GCOVR_PATH} --html ${Coverage_NAME}/index.html --html-details -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
|
||||||
|
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CODE_COVERAGE_VERBOSE)
|
||||||
|
message(STATUS "Executed command report")
|
||||||
|
|
||||||
|
message(STATUS "Command to run tests: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_HTML_EXEC_TESTS_CMD_SPACED "${GCOVR_HTML_EXEC_TESTS_CMD}")
|
||||||
|
message(STATUS "${GCOVR_HTML_EXEC_TESTS_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to create a folder: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_HTML_FOLDER_CMD_SPACED "${GCOVR_HTML_FOLDER_CMD}")
|
||||||
|
message(STATUS "${GCOVR_HTML_FOLDER_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to generate gcovr HTML coverage data: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_HTML_CMD_SPACED "${GCOVR_HTML_CMD}")
|
||||||
|
message(STATUS "${GCOVR_HTML_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_target(${Coverage_NAME}
|
||||||
|
COMMAND ${GCOVR_HTML_EXEC_TESTS_CMD}
|
||||||
|
COMMAND ${GCOVR_HTML_FOLDER_CMD}
|
||||||
|
COMMAND ${GCOVR_HTML_CMD}
|
||||||
|
|
||||||
|
BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||||
|
DEPENDS ${Coverage_DEPENDENCIES}
|
||||||
|
VERBATIM # Protect arguments to commands
|
||||||
|
COMMENT "Running gcovr to produce HTML code coverage report."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show info where to find the report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ;
|
||||||
|
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
|
||||||
|
)
|
||||||
|
|
||||||
|
endfunction() # setup_target_for_coverage_gcovr_html
|
||||||
|
|
||||||
|
# Defines a target for running and collection code coverage information
|
||||||
|
# Builds dependencies, runs the given executable and outputs reports.
|
||||||
|
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||||
|
# the coverage generation will not complete.
|
||||||
|
#
|
||||||
|
# setup_target_for_coverage_fastcov(
|
||||||
|
# NAME testrunner_coverage # New target name
|
||||||
|
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||||
|
# DEPENDENCIES testrunner # Dependencies to build first
|
||||||
|
# BASE_DIRECTORY "../" # Base directory for report
|
||||||
|
# # (defaults to PROJECT_SOURCE_DIR)
|
||||||
|
# EXCLUDE "src/dir1/" "src/dir2/" # Patterns to exclude.
|
||||||
|
# NO_DEMANGLE # Don't demangle C++ symbols
|
||||||
|
# # even if c++filt is found
|
||||||
|
# SKIP_HTML # Don't create html report
|
||||||
|
# POST_CMD perl -i -pe s!${PROJECT_SOURCE_DIR}/!!g ctest_coverage.json # E.g. for stripping source dir from file paths
|
||||||
|
# )
|
||||||
|
function(setup_target_for_coverage_fastcov)
|
||||||
|
|
||||||
|
set(options NO_DEMANGLE SKIP_HTML)
|
||||||
|
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||||
|
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES FASTCOV_ARGS GENHTML_ARGS POST_CMD)
|
||||||
|
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT FASTCOV_PATH)
|
||||||
|
message(FATAL_ERROR "fastcov not found! Aborting...")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT Coverage_SKIP_HTML AND NOT GENHTML_PATH)
|
||||||
|
message(FATAL_ERROR "genhtml not found! Aborting...")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||||
|
if(Coverage_BASE_DIRECTORY)
|
||||||
|
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||||
|
else()
|
||||||
|
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect excludes (Patterns, not paths, for fastcov)
|
||||||
|
set(FASTCOV_EXCLUDES "")
|
||||||
|
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_FASTCOV_EXCLUDES})
|
||||||
|
list(APPEND FASTCOV_EXCLUDES "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
list(REMOVE_DUPLICATES FASTCOV_EXCLUDES)
|
||||||
|
|
||||||
|
# Conditional arguments
|
||||||
|
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
|
||||||
|
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Set up commands which will be run to generate coverage data
|
||||||
|
set(FASTCOV_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS})
|
||||||
|
|
||||||
|
set(FASTCOV_CAPTURE_CMD ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH}
|
||||||
|
--search-directory ${BASEDIR}
|
||||||
|
--process-gcno
|
||||||
|
--output ${Coverage_NAME}.json
|
||||||
|
--exclude ${FASTCOV_EXCLUDES}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(FASTCOV_CONVERT_CMD ${FASTCOV_PATH}
|
||||||
|
-C ${Coverage_NAME}.json --lcov --output ${Coverage_NAME}.info
|
||||||
|
)
|
||||||
|
|
||||||
|
if(Coverage_SKIP_HTML)
|
||||||
|
set(FASTCOV_HTML_CMD ";")
|
||||||
|
else()
|
||||||
|
set(FASTCOV_HTML_CMD ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS}
|
||||||
|
-o ${Coverage_NAME} ${Coverage_NAME}.info
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(FASTCOV_POST_CMD ";")
|
||||||
|
if(Coverage_POST_CMD)
|
||||||
|
set(FASTCOV_POST_CMD ${Coverage_POST_CMD})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CODE_COVERAGE_VERBOSE)
|
||||||
|
message(STATUS "Code coverage commands for target ${Coverage_NAME} (fastcov):")
|
||||||
|
|
||||||
|
message(" Running tests:")
|
||||||
|
string(REPLACE ";" " " FASTCOV_EXEC_TESTS_CMD_SPACED "${FASTCOV_EXEC_TESTS_CMD}")
|
||||||
|
message(" ${FASTCOV_EXEC_TESTS_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(" Capturing fastcov counters and generating report:")
|
||||||
|
string(REPLACE ";" " " FASTCOV_CAPTURE_CMD_SPACED "${FASTCOV_CAPTURE_CMD}")
|
||||||
|
message(" ${FASTCOV_CAPTURE_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(" Converting fastcov .json to lcov .info:")
|
||||||
|
string(REPLACE ";" " " FASTCOV_CONVERT_CMD_SPACED "${FASTCOV_CONVERT_CMD}")
|
||||||
|
message(" ${FASTCOV_CONVERT_CMD_SPACED}")
|
||||||
|
|
||||||
|
if(NOT Coverage_SKIP_HTML)
|
||||||
|
message(" Generating HTML report: ")
|
||||||
|
string(REPLACE ";" " " FASTCOV_HTML_CMD_SPACED "${FASTCOV_HTML_CMD}")
|
||||||
|
message(" ${FASTCOV_HTML_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
if(Coverage_POST_CMD)
|
||||||
|
message(" Running post command: ")
|
||||||
|
string(REPLACE ";" " " FASTCOV_POST_CMD_SPACED "${FASTCOV_POST_CMD}")
|
||||||
|
message(" ${FASTCOV_POST_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Setup target
|
||||||
|
add_custom_target(${Coverage_NAME}
|
||||||
|
|
||||||
|
# Cleanup fastcov
|
||||||
|
COMMAND ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH}
|
||||||
|
--search-directory ${BASEDIR}
|
||||||
|
--zerocounters
|
||||||
|
|
||||||
|
COMMAND ${FASTCOV_EXEC_TESTS_CMD}
|
||||||
|
COMMAND ${FASTCOV_CAPTURE_CMD}
|
||||||
|
COMMAND ${FASTCOV_CONVERT_CMD}
|
||||||
|
COMMAND ${FASTCOV_HTML_CMD}
|
||||||
|
COMMAND ${FASTCOV_POST_CMD}
|
||||||
|
|
||||||
|
# Set output files as GENERATED (will be removed on 'make clean')
|
||||||
|
BYPRODUCTS
|
||||||
|
${Coverage_NAME}.info
|
||||||
|
${Coverage_NAME}.json
|
||||||
|
${Coverage_NAME}/index.html # report directory
|
||||||
|
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||||
|
DEPENDS ${Coverage_DEPENDENCIES}
|
||||||
|
VERBATIM # Protect arguments to commands
|
||||||
|
COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report."
|
||||||
|
)
|
||||||
|
|
||||||
|
set(INFO_MSG "fastcov code coverage info report saved in ${Coverage_NAME}.info and ${Coverage_NAME}.json.")
|
||||||
|
if(NOT Coverage_SKIP_HTML)
|
||||||
|
string(APPEND INFO_MSG " Open ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html in your browser to view the coverage report.")
|
||||||
|
endif()
|
||||||
|
# Show where to find the fastcov info report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E echo ${INFO_MSG}
|
||||||
|
)
|
||||||
|
|
||||||
|
endfunction() # setup_target_for_coverage_fastcov
|
||||||
|
|
||||||
|
function(append_coverage_compiler_flags)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||||
|
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||||
|
message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
|
||||||
|
endfunction() # append_coverage_compiler_flags
|
||||||
|
|
||||||
|
# Setup coverage for specific library
|
||||||
|
function(append_coverage_compiler_flags_to_target name)
|
||||||
|
separate_arguments(_flag_list NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}")
|
||||||
|
target_compile_options(${name} PRIVATE ${_flag_list})
|
||||||
|
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
|
||||||
|
target_link_libraries(${name} PRIVATE gcov)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
@@ -6,7 +6,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
|||||||
|
|
||||||
# Put the include dirs which are in the source or build tree
|
# Put the include dirs which are in the source or build tree
|
||||||
# before all other include dirs, so the headers in the sources
|
# before all other include dirs, so the headers in the sources
|
||||||
# are prefered over the already installed ones
|
# are preferred over the already installed ones
|
||||||
# since cmake 2.4.1
|
# since cmake 2.4.1
|
||||||
set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON)
|
set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON)
|
||||||
|
|
||||||
|
|||||||
@@ -50,15 +50,28 @@ file(READ ${HEADERS_LIST_FILE} HEADERS_LIST)
|
|||||||
|
|
||||||
set(symbols)
|
set(symbols)
|
||||||
foreach(header ${HEADERS_LIST})
|
foreach(header ${HEADERS_LIST})
|
||||||
|
file(READ ${header} header_content)
|
||||||
|
|
||||||
# Filter only lines containing the FILTER_PATTERN
|
# Filter only lines containing the FILTER_PATTERN
|
||||||
file(STRINGS ${header} contain_filter
|
# separated from the function name with one optional newline
|
||||||
REGEX "^.*${FILTER_PATTERN}.*[(]"
|
string(REGEX MATCHALL
|
||||||
|
"${FILTER_PATTERN}[^(\n]*\n?[^(\n]*[(]"
|
||||||
|
contain_filter
|
||||||
|
"${header_content}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Remove the optional newline now
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"(.+)\n?(.*)"
|
||||||
|
"\\1\\2"
|
||||||
|
oneline
|
||||||
|
"${contain_filter}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Remove function-like macros
|
# Remove function-like macros
|
||||||
foreach(line ${contain_filter})
|
# and anything with two underscores that sounds suspicious
|
||||||
if (NOT ${line} MATCHES ".*#[ ]*define")
|
foreach(line ${oneline})
|
||||||
|
if (NOT ${line} MATCHES ".*(#[ ]*define|__)")
|
||||||
list(APPEND not_macro ${line})
|
list(APPEND not_macro ${line})
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|||||||
@@ -220,13 +220,12 @@
|
|||||||
|
|
||||||
# Search for python which is required
|
# Search for python which is required
|
||||||
if (ABIMap_FIND_REQURIED)
|
if (ABIMap_FIND_REQURIED)
|
||||||
find_package(PythonInterp REQUIRED)
|
find_package(Python REQUIRED)
|
||||||
else()
|
else()
|
||||||
find_package(PythonInterp)
|
find_package(Python)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (TARGET Python::Interpreter)
|
||||||
if (PYTHONINTERP_FOUND)
|
|
||||||
# Search for abimap tool used to generate the map files
|
# Search for abimap tool used to generate the map files
|
||||||
find_program(ABIMAP_EXECUTABLE NAMES abimap DOC "path to the abimap executable")
|
find_program(ABIMAP_EXECUTABLE NAMES abimap DOC "path to the abimap executable")
|
||||||
mark_as_advanced(ABIMAP_EXECUTABLE)
|
mark_as_advanced(ABIMAP_EXECUTABLE)
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
# - Try to find ARGP
|
# - Try to find ARGP
|
||||||
|
#
|
||||||
|
# The argp can be either shipped as part of libc (ex. glibc) or as a separate
|
||||||
|
# library that requires additional linking (ex. Windows, Mac, musl libc, ...)
|
||||||
|
#
|
||||||
# Once done this will define
|
# Once done this will define
|
||||||
#
|
#
|
||||||
# ARGP_ROOT_DIR - Set this variable to the root installation of ARGP
|
# ARGP_ROOT_DIR - Set this variable to the root installation of ARGP
|
||||||
@@ -60,7 +64,7 @@ if (ARGP_LIBRARY)
|
|||||||
endif (ARGP_LIBRARY)
|
endif (ARGP_LIBRARY)
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
include(FindPackageHandleStandardArgs)
|
||||||
find_package_handle_standard_args(ARGP DEFAULT_MSG ARGP_LIBRARIES ARGP_INCLUDE_DIR)
|
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
|
# show the ARGP_INCLUDE_DIR and ARGP_LIBRARIES variables only in the advanced view
|
||||||
mark_as_advanced(ARGP_INCLUDE_DIR ARGP_LIBRARIES)
|
mark_as_advanced(ARGP_INCLUDE_DIR ARGP_LIBRARIES)
|
||||||
|
|||||||
@@ -39,6 +39,15 @@ find_path(GCRYPT_INCLUDE_DIR
|
|||||||
include
|
include
|
||||||
)
|
)
|
||||||
|
|
||||||
|
find_path(GCRYPT_ERROR_INCLUDE_DIR
|
||||||
|
NAMES
|
||||||
|
gpg-error.h
|
||||||
|
HINTS
|
||||||
|
${_GCRYPT_ROOT_HINTS_AND_PATHS}
|
||||||
|
PATH_SUFFIXES
|
||||||
|
include
|
||||||
|
)
|
||||||
|
|
||||||
find_library(GCRYPT_LIBRARY
|
find_library(GCRYPT_LIBRARY
|
||||||
NAMES
|
NAMES
|
||||||
gcrypt
|
gcrypt
|
||||||
@@ -56,8 +65,10 @@ find_library(GCRYPT_ERROR_LIBRARY
|
|||||||
libgpg-error6-0
|
libgpg-error6-0
|
||||||
HINTS
|
HINTS
|
||||||
${_GCRYPT_ROOT_HINTS_AND_PATHS}
|
${_GCRYPT_ROOT_HINTS_AND_PATHS}
|
||||||
|
PATH_SUFFIXES
|
||||||
|
lib
|
||||||
)
|
)
|
||||||
set(GCRYPT_LIBRARIES ${GCRYPT_LIBRARY} ${GCRYPT_ERROR_LIBRARY})
|
set(GCRYPT_LIBRARIES ${GCRYPT_ERROR_LIBRARY} ${GCRYPT_LIBRARY})
|
||||||
|
|
||||||
if (GCRYPT_INCLUDE_DIR)
|
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]")
|
||||||
@@ -83,5 +94,25 @@ else (GCRYPT_VERSION)
|
|||||||
GCRYPT_LIBRARIES)
|
GCRYPT_LIBRARIES)
|
||||||
endif (GCRYPT_VERSION)
|
endif (GCRYPT_VERSION)
|
||||||
|
|
||||||
# show the GCRYPT_INCLUDE_DIRS and GCRYPT_LIBRARIES variables only in the advanced view
|
# show the GCRYPT_INCLUDE_DIRS, GCRYPT_LIBRARIES and GCRYPT_ERROR_INCLUDE_DIR variables only in the advanced view
|
||||||
mark_as_advanced(GCRYPT_INCLUDE_DIR GCRYPT_LIBRARIES)
|
mark_as_advanced(GCRYPT_INCLUDE_DIR GCRYPT_ERROR_INCLUDE_DIR GCRYPT_LIBRARIES)
|
||||||
|
|
||||||
|
if(GCRYPT_FOUND)
|
||||||
|
if(NOT TARGET libgcrypt::libgcrypt)
|
||||||
|
add_library(libgcrypt::libgcrypt UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(libgcrypt::libgcrypt PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${GCRYPT_INCLUDE_DIR}"
|
||||||
|
INTERFACE_LINK_LIBRARIES libgcrypt::libgcrypt
|
||||||
|
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||||
|
IMPORTED_LOCATION "${GCRYPT_LIBRARY}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT TARGET libgpg-error::libgpg-error)
|
||||||
|
add_library(libgpg-error::libgpg-error UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(libgpg-error::libgpg-error PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${GCRYPT_ERROR_INCLUDE_DIR}"
|
||||||
|
INTERFACE_LINK_LIBRARIES libgpg-error::libgpg-error
|
||||||
|
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||||
|
IMPORTED_LOCATION "${GCRYPT_ERROR_LIBRARY}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -5,12 +5,14 @@
|
|||||||
# GSSAPI_ROOT_DIR - Set this variable to the root installation of GSSAPI
|
# GSSAPI_ROOT_DIR - Set this variable to the root installation of GSSAPI
|
||||||
#
|
#
|
||||||
# Read-Only variables:
|
# Read-Only variables:
|
||||||
# GSSAPI_FLAVOR_MIT - set to TURE if MIT Kerberos has been found
|
# GSSAPI_FLAVOR_MIT - set to TRUE if MIT Kerberos has been found
|
||||||
# GSSAPI_FLAVOR_HEIMDAL - set to TRUE if Heimdal Keberos has been found
|
# GSSAPI_FLAVOR_HEIMDAL - set to TRUE if Heimdal Keberos has been found
|
||||||
# GSSAPI_FOUND - system has GSSAPI
|
# GSSAPI_FOUND - system has GSSAPI
|
||||||
# GSSAPI_INCLUDE_DIR - the GSSAPI include directory
|
# GSSAPI_INCLUDE_DIR - the GSSAPI include directory
|
||||||
# GSSAPI_LIBRARIES - Link these to use GSSAPI
|
# GSSAPI_LIBRARIES - Link these to use GSSAPI
|
||||||
# GSSAPI_DEFINITIONS - Compiler switches required for using GSSAPI
|
# GSSAPI_DEFINITIONS - Compiler switches required for using GSSAPI
|
||||||
|
# GSSAPI_PC_REQUIRES - pkg-config module name if found, needed for
|
||||||
|
# Requires.private for static linking
|
||||||
#
|
#
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
# Copyright (c) 2013 Andreas Schneider <asn@cryptomilk.org>
|
# Copyright (c) 2013 Andreas Schneider <asn@cryptomilk.org>
|
||||||
@@ -24,12 +26,23 @@
|
|||||||
#=============================================================================
|
#=============================================================================
|
||||||
#
|
#
|
||||||
|
|
||||||
|
set(_mit_modname "mit-krb5-gssapi")
|
||||||
|
set(_heimdal_modname "heimdal-gssapi")
|
||||||
|
|
||||||
|
if(NOT _GSSAPI_ROOT_HINTS AND NOT _GSSAPI_ROOT_PATHS)
|
||||||
|
find_package(PkgConfig QUIET)
|
||||||
|
if (PKG_CONFIG_FOUND)
|
||||||
|
pkg_search_module(_GSSAPI ${_mit_modname} ${_heimdal_modname})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
find_path(GSSAPI_ROOT_DIR
|
find_path(GSSAPI_ROOT_DIR
|
||||||
NAMES
|
NAMES
|
||||||
include/gssapi.h
|
include/gssapi.h
|
||||||
include/gssapi/gssapi.h
|
include/gssapi/gssapi.h
|
||||||
HINTS
|
HINTS
|
||||||
${_GSSAPI_ROOT_HINTS}
|
${_GSSAPI_ROOT_HINTS}
|
||||||
|
"${_GSSAPI_INCLUDEDIR}"
|
||||||
PATHS
|
PATHS
|
||||||
${_GSSAPI_ROOT_PATHS}
|
${_GSSAPI_ROOT_PATHS}
|
||||||
)
|
)
|
||||||
@@ -317,9 +330,15 @@ endif (GSSAPI_FLAVOR_HEIMDAL)
|
|||||||
include(FindPackageHandleStandardArgs)
|
include(FindPackageHandleStandardArgs)
|
||||||
find_package_handle_standard_args(GSSAPI DEFAULT_MSG GSSAPI_LIBRARIES GSSAPI_INCLUDE_DIR)
|
find_package_handle_standard_args(GSSAPI DEFAULT_MSG GSSAPI_LIBRARIES GSSAPI_INCLUDE_DIR)
|
||||||
|
|
||||||
if (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES)
|
if(GSSAPI_FOUND)
|
||||||
set(GSSAPI_FOUND TRUE)
|
if(_GSSAPI_FOUND) # via pkg-config
|
||||||
endif (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES)
|
if (GSSAPI_FLAVOR_MIT)
|
||||||
|
set(GSSAPI_PC_REQUIRES ${_mit_modname})
|
||||||
|
elseif (GSSAPI_FLAVOR_HEIMDAL)
|
||||||
|
set(GSSAPI_PC_REQUIRES ${_heimdal_modname})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
# show the GSSAPI_INCLUDE_DIRS and GSSAPI_LIBRARIES variables only in the advanced view
|
# show the GSSAPI_INCLUDE_DIR and GSSAPI_LIBRARIES variables only in the advanced view
|
||||||
mark_as_advanced(GSSAPI_INCLUDE_DIRS GSSAPI_LIBRARIES)
|
mark_as_advanced(GSSAPI_INCLUDE_DIR GSSAPI_LIBRARIES)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ set(_MBEDTLS_ROOT_HINTS_AND_PATHS
|
|||||||
|
|
||||||
find_path(MBEDTLS_INCLUDE_DIR
|
find_path(MBEDTLS_INCLUDE_DIR
|
||||||
NAMES
|
NAMES
|
||||||
mbedtls/config.h
|
mbedtls/ssl.h
|
||||||
HINTS
|
HINTS
|
||||||
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
|
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
|
||||||
PATH_SUFFIXES
|
PATH_SUFFIXES
|
||||||
@@ -72,13 +72,23 @@ find_library(MBEDTLS_X509_LIBRARY
|
|||||||
set(MBEDTLS_LIBRARIES ${MBEDTLS_SSL_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY}
|
set(MBEDTLS_LIBRARIES ${MBEDTLS_SSL_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY}
|
||||||
${MBEDTLS_X509_LIBRARY})
|
${MBEDTLS_X509_LIBRARY})
|
||||||
|
|
||||||
|
# mbedtls 2.8
|
||||||
if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
|
if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
|
||||||
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX
|
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]+\"")
|
"^#[\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]+).*"
|
string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+\\.[0-9]+\\.[0-9]+).*$"
|
||||||
"\\1" MBEDTLS_VERSION "${_mbedtls_version_str}")
|
"\\1" MBEDTLS_VERSION "${_mbedtls_version_str}")
|
||||||
endif ()
|
endif()
|
||||||
|
|
||||||
|
# mbedtls 3.6
|
||||||
|
if (NOT MBEDTLS_VERSION AND MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h")
|
||||||
|
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.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)
|
include(FindPackageHandleStandardArgs)
|
||||||
if (MBEDTLS_VERSION)
|
if (MBEDTLS_VERSION)
|
||||||
@@ -93,8 +103,8 @@ if (MBEDTLS_VERSION)
|
|||||||
in the system variable MBEDTLS_ROOT_DIR"
|
in the system variable MBEDTLS_ROOT_DIR"
|
||||||
)
|
)
|
||||||
else (MBEDTLS_VERSION)
|
else (MBEDTLS_VERSION)
|
||||||
find_package_handle_standard_args(MBedTLS
|
find_package_handle_standard_args(MbedTLS
|
||||||
"Could NOT find mbedTLS, try to set the path to mbedLS root folder in
|
"Could NOT find mbedTLS, try to set the path to mbedTLS root folder in
|
||||||
the system variable MBEDTLS_ROOT_DIR"
|
the system variable MBEDTLS_ROOT_DIR"
|
||||||
MBEDTLS_INCLUDE_DIR
|
MBEDTLS_INCLUDE_DIR
|
||||||
MBEDTLS_LIBRARIES)
|
MBEDTLS_LIBRARIES)
|
||||||
@@ -102,3 +112,32 @@ endif (MBEDTLS_VERSION)
|
|||||||
|
|
||||||
# show the MBEDTLS_INCLUDE_DIRS and MBEDTLS_LIBRARIES variables only in the advanced view
|
# show the MBEDTLS_INCLUDE_DIRS and MBEDTLS_LIBRARIES variables only in the advanced view
|
||||||
mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARIES)
|
mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARIES)
|
||||||
|
|
||||||
|
if(MBEDTLS_FOUND)
|
||||||
|
if(NOT TARGET MbedTLS::mbedcrypto)
|
||||||
|
add_library(MbedTLS::mbedcrypto UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(MbedTLS::mbedcrypto PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${MBEDTLS_INCLUDE_DIR}"
|
||||||
|
INTERFACE_LINK_LIBRARIES MbedTLS::mbedcrypto
|
||||||
|
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||||
|
IMPORTED_LOCATION "${MBEDTLS_CRYPTO_LIBRARY}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT TARGET MbedTLS::mbedx509)
|
||||||
|
add_library(MbedTLS::mbedx509 UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(MbedTLS::mbedx509 PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${MBEDTLS_INCLUDE_DIR}"
|
||||||
|
INTERFACE_LINK_LIBRARIES MbedTLS::mbedx509
|
||||||
|
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||||
|
IMPORTED_LOCATION "${MBEDTLS_X509_LIBRARY}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT TARGET MbedTLS::mbedtls)
|
||||||
|
add_library(MbedTLS::mbedtls UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(MbedTLS::mbedtls PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${MBEDTLS_INCLUDE_DIR}"
|
||||||
|
INTERFACE_LINK_LIBRARIES MbedTLS::mbedtls
|
||||||
|
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||||
|
IMPORTED_LOCATION "${MBEDTLS_LIBRARY}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|||||||
63
cmake/Modules/Findlibfido2.cmake
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# - Try to find libfido2
|
||||||
|
# Once done this will define
|
||||||
|
#
|
||||||
|
# LIBFIDO2_ROOT_DIR - Set this variable to the root installation of libfido2
|
||||||
|
#
|
||||||
|
# Read-Only variables:
|
||||||
|
# LIBFIDO2_FOUND - system has libfido2
|
||||||
|
# LIBFIDO2_INCLUDE_DIR - the libfido2 include directory
|
||||||
|
# LIBFIDO2_LIBRARIES - Link these to use libfido2
|
||||||
|
#
|
||||||
|
# The libfido2 library provides support for communicating
|
||||||
|
# with FIDO2/U2F devices over USB/NFC.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2025 Praneeth Sarode <praneethsarode@gmail.com>
|
||||||
|
#
|
||||||
|
# Redistribution and use is allowed according to the terms of the New
|
||||||
|
# BSD license.
|
||||||
|
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
set(_LIBFIDO2_ROOT_HINTS
|
||||||
|
$ENV{LIBFIDO2_ROOT_DIR}
|
||||||
|
${LIBFIDO2_ROOT_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(_LIBFIDO2_ROOT_PATHS
|
||||||
|
"$ENV{PROGRAMFILES}/libfido2"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(_LIBFIDO2_ROOT_HINTS_AND_PATHS
|
||||||
|
HINTS ${_LIBFIDO2_ROOT_HINTS}
|
||||||
|
PATHS ${_LIBFIDO2_ROOT_PATHS}
|
||||||
|
)
|
||||||
|
|
||||||
|
find_path(LIBFIDO2_INCLUDE_DIR
|
||||||
|
NAMES
|
||||||
|
fido.h
|
||||||
|
HINTS
|
||||||
|
${_LIBFIDO2_ROOT_HINTS_AND_PATHS}
|
||||||
|
PATH_SUFFIXES
|
||||||
|
include
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(LIBFIDO2_LIBRARY
|
||||||
|
NAMES
|
||||||
|
fido2
|
||||||
|
HINTS
|
||||||
|
${_LIBFIDO2_ROOT_HINTS_AND_PATHS}
|
||||||
|
PATH_SUFFIXES
|
||||||
|
lib
|
||||||
|
lib64
|
||||||
|
)
|
||||||
|
|
||||||
|
set(LIBFIDO2_LIBRARIES
|
||||||
|
${LIBFIDO2_LIBRARY}
|
||||||
|
)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(libfido2 DEFAULT_MSG LIBFIDO2_LIBRARIES LIBFIDO2_INCLUDE_DIR)
|
||||||
|
|
||||||
|
# show the LIBFIDO2_INCLUDE_DIR and LIBFIDO2_LIBRARIES variables only in the advanced view
|
||||||
|
mark_as_advanced(LIBFIDO2_INCLUDE_DIR LIBFIDO2_LIBRARIES)
|
||||||
@@ -9,9 +9,11 @@
|
|||||||
#cmakedefine SOURCEDIR "${SOURCEDIR}"
|
#cmakedefine SOURCEDIR "${SOURCEDIR}"
|
||||||
|
|
||||||
/* Global bind configuration file path */
|
/* Global bind configuration file path */
|
||||||
|
#cmakedefine USR_GLOBAL_BIND_CONFIG "${USR_GLOBAL_BIND_CONFIG}"
|
||||||
#cmakedefine GLOBAL_BIND_CONFIG "${GLOBAL_BIND_CONFIG}"
|
#cmakedefine GLOBAL_BIND_CONFIG "${GLOBAL_BIND_CONFIG}"
|
||||||
|
|
||||||
/* Global client configuration file path */
|
/* Global client configuration file path */
|
||||||
|
#cmakedefine USR_GLOBAL_CLIENT_CONFIG "${USR_GLOBAL_CLIENT_CONFIG}"
|
||||||
#cmakedefine GLOBAL_CLIENT_CONFIG "${GLOBAL_CLIENT_CONFIG}"
|
#cmakedefine GLOBAL_CLIENT_CONFIG "${GLOBAL_CLIENT_CONFIG}"
|
||||||
|
|
||||||
/************************** HEADER FILES *************************/
|
/************************** HEADER FILES *************************/
|
||||||
@@ -58,15 +60,15 @@
|
|||||||
/* Define to 1 if you have the <stdint.h> header file. */
|
/* Define to 1 if you have the <stdint.h> header file. */
|
||||||
#cmakedefine HAVE_STDINT_H 1
|
#cmakedefine HAVE_STDINT_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <ifaddrs.h> header file. */
|
||||||
|
#cmakedefine HAVE_IFADDRS_H 1
|
||||||
|
|
||||||
/* Define to 1 if you have the <openssl/aes.h> header file. */
|
/* Define to 1 if you have the <openssl/aes.h> header file. */
|
||||||
#cmakedefine HAVE_OPENSSL_AES_H 1
|
#cmakedefine HAVE_OPENSSL_AES_H 1
|
||||||
|
|
||||||
/* Define to 1 if you have the <wspiapi.h> header file. */
|
/* Define to 1 if you have the <wspiapi.h> header file. */
|
||||||
#cmakedefine HAVE_WSPIAPI_H 1
|
#cmakedefine HAVE_WSPIAPI_H 1
|
||||||
|
|
||||||
/* Define to 1 if you have the <openssl/blowfish.h> header file. */
|
|
||||||
#cmakedefine HAVE_OPENSSL_BLOWFISH_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <openssl/des.h> header file. */
|
/* Define to 1 if you have the <openssl/des.h> header file. */
|
||||||
#cmakedefine HAVE_OPENSSL_DES_H 1
|
#cmakedefine HAVE_OPENSSL_DES_H 1
|
||||||
|
|
||||||
@@ -82,53 +84,38 @@
|
|||||||
/* Define to 1 if you have the <pthread.h> header file. */
|
/* Define to 1 if you have the <pthread.h> header file. */
|
||||||
#cmakedefine HAVE_PTHREAD_H 1
|
#cmakedefine HAVE_PTHREAD_H 1
|
||||||
|
|
||||||
/* Define to 1 if you have eliptic curve cryptography in openssl */
|
/* Define to 1 if you have elliptic curve cryptography in openssl */
|
||||||
#cmakedefine HAVE_OPENSSL_ECC 1
|
#cmakedefine HAVE_OPENSSL_ECC 1
|
||||||
|
|
||||||
/* Define to 1 if you have eliptic curve cryptography in gcrypt */
|
/* Define to 1 if mbedTLS supports curve25519 */
|
||||||
|
#cmakedefine HAVE_MBEDTLS_CURVE25519 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have elliptic curve cryptography in gcrypt */
|
||||||
#cmakedefine HAVE_GCRYPT_ECC 1
|
#cmakedefine HAVE_GCRYPT_ECC 1
|
||||||
|
|
||||||
/* Define to 1 if you have eliptic curve cryptography */
|
/* Define to 1 if you have elliptic curve cryptography */
|
||||||
#cmakedefine HAVE_ECC 1
|
#cmakedefine HAVE_ECC 1
|
||||||
|
|
||||||
/* Define to 1 if you have DSA */
|
/* Define to 1 if you have gl_flags as a glob_t struct member */
|
||||||
#cmakedefine HAVE_DSA 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have gl_flags as a glob_t sturct member */
|
|
||||||
#cmakedefine HAVE_GLOB_GL_FLAGS_MEMBER 1
|
#cmakedefine HAVE_GLOB_GL_FLAGS_MEMBER 1
|
||||||
|
|
||||||
/* Define to 1 if you have OpenSSL with Ed25519 support */
|
|
||||||
#cmakedefine HAVE_OPENSSL_ED25519 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have OpenSSL with X25519 support */
|
|
||||||
#cmakedefine HAVE_OPENSSL_X25519 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have OpenSSL with Poly1305 support */
|
|
||||||
#cmakedefine HAVE_OPENSSL_EVP_POLY1305 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have gcrypt with ChaCha20/Poly1305 support */
|
/* Define to 1 if you have gcrypt with ChaCha20/Poly1305 support */
|
||||||
#cmakedefine HAVE_GCRYPT_CHACHA_POLY 1
|
#cmakedefine HAVE_GCRYPT_CHACHA_POLY 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have gcrypt with curve25519 support */
|
||||||
|
#cmakedefine HAVE_GCRYPT_CURVE25519
|
||||||
|
|
||||||
/*************************** FUNCTIONS ***************************/
|
/*************************** FUNCTIONS ***************************/
|
||||||
|
|
||||||
/* Define to 1 if you have the `EVP_chacha20' function. */
|
/* Define to 1 if you have the `EVP_chacha20' function. */
|
||||||
#cmakedefine HAVE_OPENSSL_EVP_CHACHA20 1
|
#cmakedefine HAVE_OPENSSL_EVP_CHACHA20 1
|
||||||
|
|
||||||
/* Define to 1 if you have the `EVP_KDF_CTX_new_id' function. */
|
/* Define to 1 if you have the `EVP_KDF_CTX_new_id' or `EVP_KDF_CTX_new` function. */
|
||||||
#cmakedefine HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID 1
|
#cmakedefine HAVE_OPENSSL_EVP_KDF_CTX 1
|
||||||
|
|
||||||
/* Define to 1 if you have the `FIPS_mode' function. */
|
/* Define to 1 if you have the `FIPS_mode' function. */
|
||||||
#cmakedefine HAVE_OPENSSL_FIPS_MODE 1
|
#cmakedefine HAVE_OPENSSL_FIPS_MODE 1
|
||||||
|
|
||||||
/* Define to 1 if you have the `EVP_DigestSign' function. */
|
|
||||||
#cmakedefine HAVE_OPENSSL_EVP_DIGESTSIGN 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `EVP_DigestVerify' function. */
|
|
||||||
#cmakedefine HAVE_OPENSSL_EVP_DIGESTVERIFY 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `OPENSSL_ia32cap_loc' function. */
|
|
||||||
#cmakedefine HAVE_OPENSSL_IA32CAP_LOC 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `snprintf' function. */
|
/* Define to 1 if you have the `snprintf' function. */
|
||||||
#cmakedefine HAVE_SNPRINTF 1
|
#cmakedefine HAVE_SNPRINTF 1
|
||||||
|
|
||||||
@@ -192,6 +179,9 @@
|
|||||||
/* Define to 1 if you have the `explicit_bzero' function. */
|
/* Define to 1 if you have the `explicit_bzero' function. */
|
||||||
#cmakedefine HAVE_EXPLICIT_BZERO 1
|
#cmakedefine HAVE_EXPLICIT_BZERO 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `memset_explicit' function. */
|
||||||
|
#cmakedefine HAVE_MEMSET_EXPLICIT 1
|
||||||
|
|
||||||
/* Define to 1 if you have the `memset_s' function. */
|
/* Define to 1 if you have the `memset_s' function. */
|
||||||
#cmakedefine HAVE_MEMSET_S 1
|
#cmakedefine HAVE_MEMSET_S 1
|
||||||
|
|
||||||
@@ -201,6 +191,18 @@
|
|||||||
/* Define to 1 if you have the `cmocka_set_test_filter' function. */
|
/* Define to 1 if you have the `cmocka_set_test_filter' function. */
|
||||||
#cmakedefine HAVE_CMOCKA_SET_TEST_FILTER 1
|
#cmakedefine HAVE_CMOCKA_SET_TEST_FILTER 1
|
||||||
|
|
||||||
|
/* Define to 1 if we have support for blowfish */
|
||||||
|
#cmakedefine HAVE_BLOWFISH 1
|
||||||
|
|
||||||
|
/* Define to 1 if we have support for ML-KEM in libgcrypt */
|
||||||
|
#cmakedefine HAVE_GCRYPT_MLKEM 1
|
||||||
|
|
||||||
|
/* Define to 1 if we have support for ML-KEM in OpenSSL */
|
||||||
|
#cmakedefine HAVE_OPENSSL_MLKEM 1
|
||||||
|
|
||||||
|
/* Define to 1 if we have support for ML-KEM1024 in either backend */
|
||||||
|
#cmakedefine HAVE_MLKEM1024 1
|
||||||
|
|
||||||
/*************************** LIBRARIES ***************************/
|
/*************************** LIBRARIES ***************************/
|
||||||
|
|
||||||
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
||||||
@@ -218,6 +220,10 @@
|
|||||||
/* Define to 1 if you have the `cmocka' library (-lcmocka). */
|
/* Define to 1 if you have the `cmocka' library (-lcmocka). */
|
||||||
#cmakedefine HAVE_CMOCKA 1
|
#cmakedefine HAVE_CMOCKA 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `libfido2' library (-lfido2).
|
||||||
|
* This is required for interacting with FIDO2/U2F devices over USB-HID. */
|
||||||
|
#cmakedefine HAVE_LIBFIDO2 1
|
||||||
|
|
||||||
/**************************** OPTIONS ****************************/
|
/**************************** OPTIONS ****************************/
|
||||||
|
|
||||||
#cmakedefine HAVE_GCC_THREAD_LOCAL_STORAGE 1
|
#cmakedefine HAVE_GCC_THREAD_LOCAL_STORAGE 1
|
||||||
@@ -225,6 +231,7 @@
|
|||||||
|
|
||||||
#cmakedefine HAVE_FALLTHROUGH_ATTRIBUTE 1
|
#cmakedefine HAVE_FALLTHROUGH_ATTRIBUTE 1
|
||||||
#cmakedefine HAVE_UNUSED_ATTRIBUTE 1
|
#cmakedefine HAVE_UNUSED_ATTRIBUTE 1
|
||||||
|
#cmakedefine HAVE_WEAK_ATTRIBUTE 1
|
||||||
|
|
||||||
#cmakedefine HAVE_CONSTRUCTOR_ATTRIBUTE 1
|
#cmakedefine HAVE_CONSTRUCTOR_ATTRIBUTE 1
|
||||||
#cmakedefine HAVE_DESTRUCTOR_ATTRIBUTE 1
|
#cmakedefine HAVE_DESTRUCTOR_ATTRIBUTE 1
|
||||||
@@ -251,9 +258,14 @@
|
|||||||
/* Define to 1 if you want to enable DH group exchange algorithms */
|
/* Define to 1 if you want to enable DH group exchange algorithms */
|
||||||
#cmakedefine WITH_GEX 1
|
#cmakedefine WITH_GEX 1
|
||||||
|
|
||||||
/* Define to 1 if you want to enable none cipher and MAC */
|
/* Define to 1 if you want to enable insecure none cipher and MAC */
|
||||||
#cmakedefine WITH_INSECURE_NONE 1
|
#cmakedefine WITH_INSECURE_NONE 1
|
||||||
|
|
||||||
|
/* Define to 1 if you want to allow libssh to execute arbitrary commands from
|
||||||
|
* configuration files or options (match exec, proxy commands and OpenSSH-based
|
||||||
|
* proxy-jumps). */
|
||||||
|
#cmakedefine WITH_EXEC 1
|
||||||
|
|
||||||
/* Define to 1 if you want to enable blowfish cipher support */
|
/* Define to 1 if you want to enable blowfish cipher support */
|
||||||
#cmakedefine WITH_BLOWFISH_CIPHER 1
|
#cmakedefine WITH_BLOWFISH_CIPHER 1
|
||||||
|
|
||||||
@@ -275,6 +287,12 @@
|
|||||||
/* Define to 1 if you want to enable PKCS #11 URI support */
|
/* Define to 1 if you want to enable PKCS #11 URI support */
|
||||||
#cmakedefine WITH_PKCS11_URI 1
|
#cmakedefine WITH_PKCS11_URI 1
|
||||||
|
|
||||||
|
/* Define to 1 if we want to build a support for PKCS #11 provider. */
|
||||||
|
#cmakedefine WITH_PKCS11_PROVIDER 1
|
||||||
|
|
||||||
|
/* Define to 1 if you want to enable FIDO2/U2F support */
|
||||||
|
#cmakedefine WITH_FIDO2 1
|
||||||
|
|
||||||
/*************************** ENDIAN *****************************/
|
/*************************** ENDIAN *****************************/
|
||||||
|
|
||||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||||
|
|||||||
@@ -1,49 +1,247 @@
|
|||||||
#
|
#
|
||||||
# Build the documentation
|
# Build the documentation
|
||||||
#
|
#
|
||||||
if (${CMAKE_VERSION} VERSION_GREATER "3.8.99")
|
# To build the documentation with a local doxygen-awesome-css directory:
|
||||||
|
#
|
||||||
|
# cmake -S . -B obj \
|
||||||
|
# -DDOXYGEN_AWESOME_CSS_DIR=/path/to/doxygen-awesome-css
|
||||||
|
# cmake --build obj --target docs
|
||||||
|
#
|
||||||
|
# The tarball can be downloaded from:
|
||||||
|
# https://github.com/jothepro/doxygen-awesome-css/archive/refs/tags/v2.4.1.tar.gz
|
||||||
|
#
|
||||||
find_package(Doxygen)
|
find_package(Doxygen)
|
||||||
|
|
||||||
if (DOXYGEN_FOUND)
|
if (DOXYGEN_FOUND)
|
||||||
|
set(DOXYGEN_AWESOME_CSS_PROJECT
|
||||||
|
"https://github.com/jothepro/doxygen-awesome-css")
|
||||||
|
set(DOXYGEN_AWESOME_CSS_VERSION "2.4.1")
|
||||||
|
set(DOXYGEN_AWESOME_CSS_URL
|
||||||
|
"${DOXYGEN_AWESOME_CSS_PROJECT}/archive/refs/tags/v${DOXYGEN_AWESOME_CSS_VERSION}.tar.gz"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Allow specifying a local doxygen-awesome-css directory (useful for
|
||||||
|
# packaging)
|
||||||
|
if (NOT DEFINED DOXYGEN_AWESOME_CSS_DIR)
|
||||||
|
# Custom target to download doxygen-awesome-css at build time
|
||||||
|
add_custom_target(
|
||||||
|
doxygen-awesome-css
|
||||||
|
COMMAND
|
||||||
|
${CMAKE_COMMAND} -DURL=${DOXYGEN_AWESOME_CSS_URL}
|
||||||
|
-DDEST_DIR=${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
-DVERSION=${DOXYGEN_AWESOME_CSS_VERSION} -P
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/fetch_doxygen_awesome.cmake
|
||||||
|
COMMENT "Fetching doxygen-awesome-css theme")
|
||||||
|
|
||||||
|
set(AWESOME_CSS_DIR
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/doxygen-awesome-css-${DOXYGEN_AWESOME_CSS_VERSION}"
|
||||||
|
)
|
||||||
|
else ()
|
||||||
|
message(
|
||||||
|
STATUS
|
||||||
|
"Using doxygen-awesome-css from ${DOXYGEN_AWESOME_CSS_DIR}")
|
||||||
|
set(AWESOME_CSS_DIR "${DOXYGEN_AWESOME_CSS_DIR}")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
# Project title shown in documentation
|
||||||
set(DOXYGEN_PROJECT_NAME ${PROJECT_NAME})
|
set(DOXYGEN_PROJECT_NAME ${PROJECT_NAME})
|
||||||
|
# Project version number shown in documentation
|
||||||
set(DOXYGEN_PROJECT_NUMBER ${PROJECT_VERSION})
|
set(DOXYGEN_PROJECT_NUMBER ${PROJECT_VERSION})
|
||||||
|
# Brief description shown below project name
|
||||||
set(DOXYGEN_PROJECT_BRIEF "The SSH library")
|
set(DOXYGEN_PROJECT_BRIEF "The SSH library")
|
||||||
|
# Project favicon (browser tab icon)
|
||||||
|
set(DOXYGEN_PROJECT_ICON ${CMAKE_CURRENT_SOURCE_DIR}/favicon.png)
|
||||||
|
|
||||||
|
# Number of spaces used for indentation in code blocks
|
||||||
set(DOXYGEN_TAB_SIZE 4)
|
set(DOXYGEN_TAB_SIZE 4)
|
||||||
|
# Generate output optimized for C (vs C++)
|
||||||
set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C YES)
|
set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C YES)
|
||||||
|
# Enable parsing of markdown in comments
|
||||||
set(DOXYGEN_MARKDOWN_SUPPORT YES)
|
set(DOXYGEN_MARKDOWN_SUPPORT YES)
|
||||||
set(DOXYGEN_FULL_PATH_NAMES NO)
|
# Warn about undocumented members to improve documentation quality
|
||||||
|
set(DOXYGEN_WARN_IF_UNDOCUMENTED YES)
|
||||||
|
# Do not extract private class members
|
||||||
|
set(DOXYGEN_EXTRACT_PRIVATE NO)
|
||||||
|
if (WITH_INTERNAL_DOC)
|
||||||
|
# Include internal documentation
|
||||||
|
set(DOXYGEN_INTERNAL_DOCS YES)
|
||||||
|
else ()
|
||||||
|
# Do not include internal documentation
|
||||||
|
set(DOXYGEN_INTERNAL_DOCS NO)
|
||||||
|
endif( WITH_INTERNAL_DOC)
|
||||||
|
# Disable built-in clipboard (using doxygen-awesome extension instead)
|
||||||
|
set(DOXYGEN_HTML_COPY_CLIPBOARD NO)
|
||||||
|
# Disable page outline panel (using interactive TOC extension instead)
|
||||||
|
set(DOXYGEN_PAGE_OUTLINE_PANEL NO)
|
||||||
|
|
||||||
set(DOXYGEN_PREDEFINED DOXYGEN
|
# Required configuration for doxygen-awesome-css theme Generate treeview
|
||||||
WITH_SERVER
|
# sidebar for navigation
|
||||||
WITH_SFTP
|
set(DOXYGEN_GENERATE_TREEVIEW YES)
|
||||||
PRINTF_ATTRIBUTE(x,y))
|
# Enable default index pages
|
||||||
|
set(DOXYGEN_DISABLE_INDEX NO)
|
||||||
|
# Use top navigation bar instead of full sidebar (required for theme
|
||||||
|
# compatibility)
|
||||||
|
set(DOXYGEN_FULL_SIDEBAR NO)
|
||||||
|
# Use light color style (required for Doxygen >= 1.9.5)
|
||||||
|
set(DOXYGEN_HTML_COLORSTYLE LIGHT)
|
||||||
|
|
||||||
set(DOXYGEN_EXCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/that_style)
|
# Disable diagram generation (not relevant for C projects)
|
||||||
set(DOXYGEN_HTML_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/that_style/header.html)
|
set(DOXYGEN_HAVE_DOT NO)
|
||||||
set(DOXYGEN_HTML_EXTRA_STYLESHEET ${CMAKE_CURRENT_SOURCE_DIR}/that_style/that_style.css)
|
set(DOXYGEN_CLASS_DIAGRAMS NO)
|
||||||
set(DOXYGEN_HTML_EXTRA_FILES ${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/nav_edge_left.svg
|
set(DOXYGEN_CALL_GRAPH NO)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/nav_edge_right.svg
|
set(DOXYGEN_CALLER_GRAPH NO)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/nav_edge_inter.svg
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/sync_off.png
|
# Preprocessor defines to use when parsing code
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/sync_on.png
|
set(DOXYGEN_PREDEFINED DOXYGEN WITH_SERVER WITH_SFTP
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/splitbar_handle.svg
|
PRINTF_ATTRIBUTE\(x,y\))
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/doc.svg
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/mag_glass.svg
|
# Exclude patterns for files we don't want to document
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/folderclosed.svg
|
set(DOXYGEN_EXCLUDE_PATTERNS */src/external/* fe25519.h ge25519.h sc25519.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/that_style/img/folderopen.svg
|
blf.h)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/that_style/js/striped_bg.js)
|
# Exclude internal structures from documentation
|
||||||
|
set(DOXYGEN_EXCLUDE_SYMBOLS_STRUCTS
|
||||||
|
chacha20_poly1305_keysched,
|
||||||
|
dh_ctx,
|
||||||
|
dh_ctx,
|
||||||
|
dh_keypair,
|
||||||
|
error_struct,
|
||||||
|
packet_struct,
|
||||||
|
pem_get_password_struct,
|
||||||
|
ssh_tokens_st,
|
||||||
|
sftp_attributes_struct,
|
||||||
|
sftp_client_message_struct,
|
||||||
|
sftp_dir_struct,
|
||||||
|
sftp_ext_struct,
|
||||||
|
sftp_file_struct,
|
||||||
|
sftp_message_struct,
|
||||||
|
sftp_packet_struct,
|
||||||
|
sftp_request_queue_struct,
|
||||||
|
sftp_session_struct,
|
||||||
|
sftp_status_message_struct,
|
||||||
|
ssh_agent_state_struct,
|
||||||
|
ssh_agent_struct,
|
||||||
|
ssh_auth_auto_state_struct,
|
||||||
|
ssh_auth_request,
|
||||||
|
ssh_bind_config_keyword_table_s,
|
||||||
|
ssh_bind_config_match_keyword_table_s,
|
||||||
|
ssh_bind_struct,
|
||||||
|
ssh_buffer_struct,
|
||||||
|
ssh_channel_callbacks_struct,
|
||||||
|
ssh_channel_read_termination_struct,
|
||||||
|
ssh_channel_request,
|
||||||
|
ssh_channel_request_open,
|
||||||
|
ssh_channel_struct,
|
||||||
|
ssh_cipher_struct,
|
||||||
|
ssh_common_struct,
|
||||||
|
ssh_config_keyword_table_s,
|
||||||
|
ssh_config_match_keyword_table_s,
|
||||||
|
ssh_connector_struct,
|
||||||
|
ssh_counter_struct,
|
||||||
|
ssh_crypto_struct,
|
||||||
|
ssh_event_fd_wrapper,
|
||||||
|
ssh_event_struct,
|
||||||
|
ssh_global_request,
|
||||||
|
ssh_gssapi_struct,
|
||||||
|
ssh_hmac_struct,
|
||||||
|
ssh_iterator,
|
||||||
|
ssh_kbdint_struct,
|
||||||
|
ssh_kex_struct,
|
||||||
|
ssh_key_struct,
|
||||||
|
ssh_knownhosts_entry,
|
||||||
|
ssh_list,
|
||||||
|
ssh_mac_ctx_struct,
|
||||||
|
ssh_message_struct,
|
||||||
|
ssh_packet_callbacks_struct,
|
||||||
|
ssh_packet_header,
|
||||||
|
ssh_poll_ctx_struct,
|
||||||
|
ssh_poll_handle_struct,
|
||||||
|
ssh_pollfd_struct,
|
||||||
|
ssh_private_key_struct,
|
||||||
|
ssh_public_key_struct,
|
||||||
|
ssh_scp_struct,
|
||||||
|
ssh_service_request,
|
||||||
|
ssh_session_struct,
|
||||||
|
ssh_signature_struct,
|
||||||
|
ssh_socket_struct,
|
||||||
|
ssh_string_struct,
|
||||||
|
ssh_threads_callbacks_struct,
|
||||||
|
ssh_timestamp)
|
||||||
|
set(DOXYGEN_EXCLUDE_SYMBOLS_MACRO
|
||||||
|
SSH_FXP*,
|
||||||
|
SSH_SOCKET*,
|
||||||
|
SERVERBANNER,
|
||||||
|
SOCKOPT_TYPE_ARG4,
|
||||||
|
SSH_FILEXFER*,
|
||||||
|
SSH_FXF*,
|
||||||
|
SSH_S_*,
|
||||||
|
SFTP_*,
|
||||||
|
NSS_BUFLEN_PASSWD,
|
||||||
|
CLOCK,
|
||||||
|
MAX_LINE_SIZE,
|
||||||
|
PKCS11_URI,
|
||||||
|
KNOWNHOSTS_MAXTYPES)
|
||||||
|
set(DOXYGEN_EXCLUDE_SYMBOLS_TYPEDEFS
|
||||||
|
sftp_attributes,
|
||||||
|
sftp_client_message,
|
||||||
|
sftp_dir,
|
||||||
|
sftp_ext,
|
||||||
|
sftp_file,
|
||||||
|
sftp_message,
|
||||||
|
sftp_packet,
|
||||||
|
sftp_request_queue,
|
||||||
|
sftp_status_message,
|
||||||
|
sftp_statvfs_t,
|
||||||
|
poll_fn,
|
||||||
|
ssh_callback_int,
|
||||||
|
ssh_callback_data,
|
||||||
|
ssh_callback_int_int,
|
||||||
|
ssh_message_callback,
|
||||||
|
ssh_channel_callback_int,
|
||||||
|
ssh_channel_callback_data,
|
||||||
|
ssh_callbacks,
|
||||||
|
ssh_gssapi_select_oid_callback,
|
||||||
|
ssh_gssapi_accept_sec_ctx_callback,
|
||||||
|
ssh_gssapi_verify_mic_callback,
|
||||||
|
ssh_server_callbacks,
|
||||||
|
ssh_socket_callbacks,
|
||||||
|
ssh_packet_callbacks,
|
||||||
|
ssh_channel_callbacks,
|
||||||
|
ssh_bind,
|
||||||
|
ssh_bind_callbacks)
|
||||||
|
set(DOXYGEN_EXCLUDE_SYMBOLS
|
||||||
|
${DOXYGEN_EXCLUDE_SYMBOLS_STRUCTS} ${DOXYGEN_EXCLUDE_SYMBOLS_MACRO}
|
||||||
|
${DOXYGEN_EXCLUDE_SYMBOLS_TYPEDEFS})
|
||||||
|
|
||||||
|
# Custom layout file to rename "Topics" to "API Reference" and simplify
|
||||||
|
# navigation
|
||||||
|
set(DOXYGEN_LAYOUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/DoxygenLayout.xml)
|
||||||
|
# Custom HTML header with doxygen-awesome extension initialization
|
||||||
|
set(DOXYGEN_HTML_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/header.html)
|
||||||
|
# Modern CSS theme for documentation with custom libssh.org color scheme
|
||||||
|
set(DOXYGEN_HTML_EXTRA_STYLESHEET
|
||||||
|
${AWESOME_CSS_DIR}/doxygen-awesome.css
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/doxygen-custom.css)
|
||||||
|
# JavaScript extensions: dark mode toggle, copy button, paragraph links,
|
||||||
|
# interactive TOC
|
||||||
|
set(DOXYGEN_HTML_EXTRA_FILES
|
||||||
|
${AWESOME_CSS_DIR}/doxygen-awesome-darkmode-toggle.js
|
||||||
|
${AWESOME_CSS_DIR}/doxygen-awesome-fragment-copy-button.js
|
||||||
|
${AWESOME_CSS_DIR}/doxygen-awesome-paragraph-link.js
|
||||||
|
${AWESOME_CSS_DIR}/doxygen-awesome-interactive-toc.js)
|
||||||
|
|
||||||
# This updates the Doxyfile if we do changes here
|
|
||||||
set(_doxyfile_template "${CMAKE_BINARY_DIR}/CMakeDoxyfile.in")
|
set(_doxyfile_template "${CMAKE_BINARY_DIR}/CMakeDoxyfile.in")
|
||||||
set(_target_doxyfile "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.docs")
|
set(_target_doxyfile "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.docs")
|
||||||
configure_file("${_doxyfile_template}" "${_target_doxyfile}")
|
configure_file("${_doxyfile_template}" "${_target_doxyfile}")
|
||||||
|
|
||||||
doxygen_add_docs(docs
|
doxygen_add_docs(docs ${CMAKE_SOURCE_DIR}/include/libssh
|
||||||
${CMAKE_SOURCE_DIR}/include/libssh
|
${CMAKE_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
${CMAKE_SOURCE_DIR}/src
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR})
|
|
||||||
endif() # DOXYGEN_FOUND
|
|
||||||
|
|
||||||
endif() # CMAKE_VERSION
|
# Make docs depend on doxygen-awesome-css download (if not using local dir)
|
||||||
|
if (TARGET doxygen-awesome-css)
|
||||||
|
add_dependencies(docs doxygen-awesome-css)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
add_custom_target(
|
||||||
|
docs_coverage COMMAND ${CMAKE_SOURCE_DIR}/doc/doc_coverage.sh
|
||||||
|
${CMAKE_BINARY_DIR})
|
||||||
|
endif (DOXYGEN_FOUND)
|
||||||
|
|||||||
242
doc/DoxygenLayout.xml
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<doxygenlayout version="2.0">
|
||||||
|
<!-- Generated by doxygen 1.14.0 -->
|
||||||
|
<!-- Navigation index tabs for HTML output -->
|
||||||
|
<navindex>
|
||||||
|
<tab type="mainpage" visible="yes" title=""/>
|
||||||
|
<tab type="topics" visible="yes" title="API Reference" intro=""/>
|
||||||
|
<tab type="pages" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="files" visible="yes" title="">
|
||||||
|
<tab type="filelist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="globals" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="structs" visible="yes" title="">
|
||||||
|
<tab type="structlist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="structindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||||
|
</tab>
|
||||||
|
</navindex>
|
||||||
|
|
||||||
|
<!-- Layout definition for a class page -->
|
||||||
|
<class>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<includes visible="$SHOW_HEADERFILE"/>
|
||||||
|
<inheritancegraph visible="yes"/>
|
||||||
|
<collaborationgraph visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<nestedclasses visible="yes" title=""/>
|
||||||
|
<publictypes visible="yes" title=""/>
|
||||||
|
<services visible="yes" title=""/>
|
||||||
|
<interfaces visible="yes" title=""/>
|
||||||
|
<publicslots visible="yes" title=""/>
|
||||||
|
<signals visible="yes" title=""/>
|
||||||
|
<publicmethods visible="yes" title=""/>
|
||||||
|
<publicstaticmethods visible="yes" title=""/>
|
||||||
|
<publicattributes visible="yes" title=""/>
|
||||||
|
<publicstaticattributes visible="yes" title=""/>
|
||||||
|
<protectedtypes visible="yes" title=""/>
|
||||||
|
<protectedslots visible="yes" title=""/>
|
||||||
|
<protectedmethods visible="yes" title=""/>
|
||||||
|
<protectedstaticmethods visible="yes" title=""/>
|
||||||
|
<protectedattributes visible="yes" title=""/>
|
||||||
|
<protectedstaticattributes visible="yes" title=""/>
|
||||||
|
<packagetypes visible="yes" title=""/>
|
||||||
|
<packagemethods visible="yes" title=""/>
|
||||||
|
<packagestaticmethods visible="yes" title=""/>
|
||||||
|
<packageattributes visible="yes" title=""/>
|
||||||
|
<packagestaticattributes visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
<events visible="yes" title=""/>
|
||||||
|
<privatetypes visible="yes" title=""/>
|
||||||
|
<privateslots visible="yes" title=""/>
|
||||||
|
<privatemethods visible="yes" title=""/>
|
||||||
|
<privatestaticmethods visible="yes" title=""/>
|
||||||
|
<privateattributes visible="yes" title=""/>
|
||||||
|
<privatestaticattributes visible="yes" title=""/>
|
||||||
|
<friends visible="yes" title=""/>
|
||||||
|
<related visible="yes" title="" subtitle=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription visible="yes" title=""/>
|
||||||
|
<memberdef>
|
||||||
|
<inlineclasses visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<services visible="yes" title=""/>
|
||||||
|
<interfaces visible="yes" title=""/>
|
||||||
|
<constructors visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<related visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
<events visible="yes" title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<allmemberslink visible="yes"/>
|
||||||
|
<usedfiles visible="$SHOW_USED_FILES"/>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<!-- Layout definition for a namespace page -->
|
||||||
|
<namespace>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<nestednamespaces visible="yes" title=""/>
|
||||||
|
<constantgroups visible="yes" title=""/>
|
||||||
|
<interfaces visible="yes" title=""/>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<concepts visible="yes" title=""/>
|
||||||
|
<structs visible="yes" title=""/>
|
||||||
|
<exceptions visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<sequences visible="yes" title=""/>
|
||||||
|
<dictionaries visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription visible="yes" title=""/>
|
||||||
|
<memberdef>
|
||||||
|
<inlineclasses visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<sequences visible="yes" title=""/>
|
||||||
|
<dictionaries visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</namespace>
|
||||||
|
|
||||||
|
<!-- Layout definition for a concept page -->
|
||||||
|
<concept>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<includes visible="$SHOW_HEADERFILE"/>
|
||||||
|
<definition visible="yes" title=""/>
|
||||||
|
<detaileddescription visible="yes" title=""/>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</concept>
|
||||||
|
|
||||||
|
<!-- Layout definition for a file page -->
|
||||||
|
<file>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||||
|
<includegraph visible="yes"/>
|
||||||
|
<includedbygraph visible="yes"/>
|
||||||
|
<sourcelink visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<interfaces visible="yes" title=""/>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<structs visible="yes" title=""/>
|
||||||
|
<exceptions visible="yes" title=""/>
|
||||||
|
<namespaces visible="yes" title=""/>
|
||||||
|
<concepts visible="yes" title=""/>
|
||||||
|
<constantgroups visible="yes" title=""/>
|
||||||
|
<defines visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<sequences visible="yes" title=""/>
|
||||||
|
<dictionaries visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription visible="yes" title=""/>
|
||||||
|
<memberdef>
|
||||||
|
<inlineclasses visible="yes" title=""/>
|
||||||
|
<defines visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<sequences visible="yes" title=""/>
|
||||||
|
<dictionaries visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<authorsection/>
|
||||||
|
</file>
|
||||||
|
|
||||||
|
<!-- Layout definition for a group page -->
|
||||||
|
<group>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<groupgraph visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<nestedgroups visible="yes" title=""/>
|
||||||
|
<modules visible="yes" title=""/>
|
||||||
|
<dirs visible="yes" title=""/>
|
||||||
|
<files visible="yes" title=""/>
|
||||||
|
<namespaces visible="yes" title=""/>
|
||||||
|
<concepts visible="yes" title=""/>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<defines visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<sequences visible="yes" title=""/>
|
||||||
|
<dictionaries visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<enumvalues visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<signals visible="yes" title=""/>
|
||||||
|
<publicslots visible="yes" title=""/>
|
||||||
|
<protectedslots visible="yes" title=""/>
|
||||||
|
<privateslots visible="yes" title=""/>
|
||||||
|
<events visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
<friends visible="yes" title=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription visible="yes" title=""/>
|
||||||
|
<memberdef>
|
||||||
|
<pagedocs/>
|
||||||
|
<inlineclasses visible="yes" title=""/>
|
||||||
|
<defines visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<sequences visible="yes" title=""/>
|
||||||
|
<dictionaries visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<enumvalues visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<signals visible="yes" title=""/>
|
||||||
|
<publicslots visible="yes" title=""/>
|
||||||
|
<protectedslots visible="yes" title=""/>
|
||||||
|
<privateslots visible="yes" title=""/>
|
||||||
|
<events visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
<friends visible="yes" title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<!-- Layout definition for a C++20 module page -->
|
||||||
|
<module>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<exportedmodules visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<concepts visible="yes" title=""/>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<membergroups visible="yes" title=""/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription visible="yes" title=""/>
|
||||||
|
<memberdecl>
|
||||||
|
<files visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<!-- Layout definition for a directory page -->
|
||||||
|
<directory>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<directorygraph visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<dirs visible="yes"/>
|
||||||
|
<files visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription visible="yes" title=""/>
|
||||||
|
</directory>
|
||||||
|
</doxygenlayout>
|
||||||
@@ -105,7 +105,7 @@ Here is a small example of password authentication:
|
|||||||
@code
|
@code
|
||||||
int authenticate_password(ssh_session session)
|
int authenticate_password(ssh_session session)
|
||||||
{
|
{
|
||||||
char *password;
|
char *password = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
password = getpass("Enter your password: ");
|
password = getpass("Enter your password: ");
|
||||||
@@ -218,7 +218,7 @@ int authenticate_kbdint(ssh_session session)
|
|||||||
rc = ssh_userauth_kbdint(session, NULL, NULL);
|
rc = ssh_userauth_kbdint(session, NULL, NULL);
|
||||||
while (rc == SSH_AUTH_INFO)
|
while (rc == SSH_AUTH_INFO)
|
||||||
{
|
{
|
||||||
const char *name, *instruction;
|
const char *name = NULL, *instruction = NULL;
|
||||||
int nprompts, iprompt;
|
int nprompts, iprompt;
|
||||||
|
|
||||||
name = ssh_userauth_kbdint_getname(session);
|
name = ssh_userauth_kbdint_getname(session);
|
||||||
@@ -231,7 +231,7 @@ int authenticate_kbdint(ssh_session session)
|
|||||||
printf("%s\n", instruction);
|
printf("%s\n", instruction);
|
||||||
for (iprompt = 0; iprompt < nprompts; iprompt++)
|
for (iprompt = 0; iprompt < nprompts; iprompt++)
|
||||||
{
|
{
|
||||||
const char *prompt;
|
const char *prompt = NULL;
|
||||||
char echo;
|
char echo;
|
||||||
|
|
||||||
prompt = ssh_userauth_kbdint_getprompt(session, iprompt, &echo);
|
prompt = ssh_userauth_kbdint_getprompt(session, iprompt, &echo);
|
||||||
@@ -251,7 +251,7 @@ int authenticate_kbdint(ssh_session session)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *ptr;
|
char *ptr = NULL;
|
||||||
|
|
||||||
ptr = getpass(prompt);
|
ptr = getpass(prompt);
|
||||||
if (ssh_userauth_kbdint_setanswer(session, iprompt, ptr) < 0)
|
if (ssh_userauth_kbdint_setanswer(session, iprompt, ptr) < 0)
|
||||||
@@ -354,7 +354,7 @@ The following example shows how to retrieve and dispose the issue banner:
|
|||||||
int display_banner(ssh_session session)
|
int display_banner(ssh_session session)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
char *banner;
|
char *banner = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*** Does not work without calling ssh_userauth_none() first ***
|
*** Does not work without calling ssh_userauth_none() first ***
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ a SSH session that uses this channel:
|
|||||||
@code
|
@code
|
||||||
int show_remote_files(ssh_session session)
|
int show_remote_files(ssh_session session)
|
||||||
{
|
{
|
||||||
ssh_channel channel;
|
ssh_channel channel = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
channel = ssh_channel_new(session);
|
channel = ssh_channel_new(session);
|
||||||
@@ -91,4 +91,10 @@ that it used:
|
|||||||
}
|
}
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
|
Warning: In a single channel, only ONE command can be executed!
|
||||||
|
If you want to executed multiple commands, allocate separate channels for
|
||||||
|
them or consider opening interactive shell.
|
||||||
|
Attempting to run multiple consecutive commands in one channel will fail.
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ curve25519-sha256@libssh.org.txt Aris Adamantiadis <aris@badcode.be>
|
|||||||
|
|
||||||
1. Introduction
|
1. Introduction
|
||||||
|
|
||||||
This document describes the key exchange methode curve25519-sha256@libssh.org
|
This document describes the key exchange method curve25519-sha256@libssh.org
|
||||||
for SSH version 2 protocol. It is provided as an alternative to the existing
|
for SSH version 2 protocol. It is provided as an alternative to the existing
|
||||||
key exchange mechanisms based on either Diffie-Hellman or Elliptic Curve Diffie-
|
key exchange mechanisms based on either Diffie-Hellman or Elliptic Curve Diffie-
|
||||||
Hellman [RFC5656].
|
Hellman [RFC5656].
|
||||||
The reason is the following : During summer of 2013, revelations from ex-
|
The reason is the following : During summer of 2013, revelations from ex-
|
||||||
consultant at NSA Edward Snowden gave proof that NSA willingly inserts backdoors
|
consultant at NSA Edward Snowden gave proof that NSA willingly inserts backdoors
|
||||||
into softwares, hardware components and published standards. While it is still
|
into software, hardware components and published standards. While it is still
|
||||||
believed that the mathematics behind ECC cryptography are still sound and solid,
|
believed that the mathematics behind ECC cryptography are still sound and solid,
|
||||||
some people (including Bruce Schneier [SCHNEIER]), showed their lack of confidence
|
some people (including Bruce Schneier [SCHNEIER]), showed their lack of confidence
|
||||||
in NIST-published curves such as nistp256, nistp384, nistp521, for which constant
|
in NIST-published curves such as nistp256, nistp384, nistp521, for which constant
|
||||||
@@ -42,8 +42,8 @@ The following is an overview of the key exchange process:
|
|||||||
Client Server
|
Client Server
|
||||||
------ ------
|
------ ------
|
||||||
Generate ephemeral key pair.
|
Generate ephemeral key pair.
|
||||||
SSH_MSG_KEX_ECDH_INIT -------->
|
SSH_MSG_KEX_ECDH_INIT -------->
|
||||||
Verify that client public key
|
Verify that client public key
|
||||||
length is 32 bytes.
|
length is 32 bytes.
|
||||||
Generate ephemeral key pair.
|
Generate ephemeral key pair.
|
||||||
Compute shared secret.
|
Compute shared secret.
|
||||||
@@ -55,7 +55,7 @@ Compute shared secret.
|
|||||||
Generate exchange hash.
|
Generate exchange hash.
|
||||||
Verify server's signature.
|
Verify server's signature.
|
||||||
|
|
||||||
* Optional but strongly recommanded as this protects against MITM attacks.
|
* Optional but strongly recommended as this protects against MITM attacks.
|
||||||
|
|
||||||
This is implemented using the same messages as described in RFC5656 chapter 4
|
This is implemented using the same messages as described in RFC5656 chapter 4
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ This number is calculated using the following procedure:
|
|||||||
side's public key and the local private key scalar.
|
side's public key and the local private key scalar.
|
||||||
|
|
||||||
The whole 32 bytes of the number X are then converted into a big integer k.
|
The whole 32 bytes of the number X are then converted into a big integer k.
|
||||||
This conversion follows the network byte order. This step differs from
|
This conversion follows the network byte order. This step differs from
|
||||||
RFC5656.
|
RFC5656.
|
||||||
|
|
||||||
[RFC5656] https://tools.ietf.org/html/rfc5656
|
[RFC5656] https://tools.ietf.org/html/rfc5656
|
||||||
|
|||||||
52
doc/doc_coverage.sh
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
################################################################################
|
||||||
|
# .doc_coverage.sh #
|
||||||
|
# Script to detect overall documentation coverage of libssh. The script uses #
|
||||||
|
# doxygen to generate the documentation then parses it's output. #
|
||||||
|
# #
|
||||||
|
# maintainer: Norbert Pocs <npocs@redhat.com> #
|
||||||
|
################################################################################
|
||||||
|
BUILD_DIR="$1"
|
||||||
|
DOXYFILE_PATH="$BUILD_DIR/doc/Doxyfile.docs"
|
||||||
|
INDEX_XML_PATH="$BUILD_DIR/doc/xml/index.xml"
|
||||||
|
# filters
|
||||||
|
F_EXCLUDE_FILES=' wrapper.h legacy.h crypto.h priv.h chacha.h curve25519.h '
|
||||||
|
F_UNDOC_FUNC='(function).*is not documented'
|
||||||
|
F_FUNC='kind="function"'
|
||||||
|
F_HEADERS='libssh_8h_|group__libssh__'
|
||||||
|
F_CUT_BEFORE='.*<name>'
|
||||||
|
F_CUT_AFTER='<\/name><\/member>'
|
||||||
|
# Doxygen options
|
||||||
|
O_QUIET='QUIET=YES'
|
||||||
|
O_GEN_XML='GENERATE_XML=YES'
|
||||||
|
|
||||||
|
# check if build dir given
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
echo "Please provide the build directory e.g.: ./build"
|
||||||
|
exit 255
|
||||||
|
fi
|
||||||
|
|
||||||
|
# modify doxyfile to our needs:
|
||||||
|
# QUIET - less output
|
||||||
|
# GENERATE_XML - xml needed to inspect all the functions
|
||||||
|
# (note: the options are needed to be on separate lines)
|
||||||
|
# We want to exclude irrelevant files
|
||||||
|
MOD_DOXYFILE=$(cat "$DOXYFILE_PATH"; echo "$O_QUIET"; echo "$O_GEN_XML")
|
||||||
|
MOD_DOXYFILE=${MOD_DOXYFILE//EXCLUDE_PATTERNS.*=/EXCLUDE_PATTERNS=$F_EXCLUDE_FILES/g}
|
||||||
|
|
||||||
|
# call doxygen to get the warning messages
|
||||||
|
# and also generate the xml for inspection
|
||||||
|
DOXY_WARNINGS=$(echo "$MOD_DOXYFILE" | doxygen - 2>&1)
|
||||||
|
|
||||||
|
# get the number of undocumented functions
|
||||||
|
UNDOC_FUNC=$(echo "$DOXY_WARNINGS" | grep -cE "$F_UNDOC_FUNC")
|
||||||
|
|
||||||
|
# filter out the lines consisting of functions of our interest
|
||||||
|
FUNC_LINES=$(grep "$F_FUNC" "$INDEX_XML_PATH" | grep -E "$F_HEADERS")
|
||||||
|
# cut the irrelevant information and leave just the function names
|
||||||
|
ALL_FUNC=$(echo "$FUNC_LINES" | sed -e "s/$F_CUT_BEFORE//g" -e "s/$F_CUT_AFTER//")
|
||||||
|
# remove duplicates and get the number of functions
|
||||||
|
ALL_FUNC=$(echo "$ALL_FUNC" | sort - | uniq | wc -l)
|
||||||
|
|
||||||
|
# percentage of the documented functions
|
||||||
|
awk "BEGIN {printf \"Documentation coverage is %.2f%\n\", 100 - (${UNDOC_FUNC}/${ALL_FUNC}*100)}"
|
||||||
127
doc/doxygen-custom.css
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/**
|
||||||
|
* Custom color scheme for libssh documentation
|
||||||
|
* Based on libssh.org color palette
|
||||||
|
*/
|
||||||
|
|
||||||
|
html {
|
||||||
|
/* Primary colors - using libssh.org orange accent */
|
||||||
|
--primary-color: #F78C40;
|
||||||
|
--primary-dark-color: #f57900;
|
||||||
|
--primary-light-color: #fab889;
|
||||||
|
|
||||||
|
/* Accent color - neutral gray */
|
||||||
|
--primary-lighter-color: #5A5A5A;
|
||||||
|
|
||||||
|
/* Page colors - clean white background */
|
||||||
|
--page-background-color: #ffffff;
|
||||||
|
--page-foreground-color: #333333;
|
||||||
|
--page-secondary-foreground-color: #666666;
|
||||||
|
|
||||||
|
/* Links - use the warm orange color */
|
||||||
|
--link-color: #F78C40;
|
||||||
|
--link-hover-color: #f0690a;
|
||||||
|
|
||||||
|
/* Code blocks and fragments - very light background */
|
||||||
|
--code-background: #f9f9f9;
|
||||||
|
--fragment-background: #f9f9f9;
|
||||||
|
|
||||||
|
/* Borders - subtle light grey */
|
||||||
|
--separator-color: #e0e0e0;
|
||||||
|
--border-light-color: #f0f0f0;
|
||||||
|
|
||||||
|
/* Side navigation - pure white */
|
||||||
|
--side-nav-background: #ffffff;
|
||||||
|
|
||||||
|
/* Menu colors - warm orange accent */
|
||||||
|
--menu-selected-background: #F78C40;
|
||||||
|
|
||||||
|
/* Tables and boxes - lighter */
|
||||||
|
--tablehead-background: #fbc7a2;
|
||||||
|
--tablehead-foreground: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header styling with libssh brand colors */
|
||||||
|
#titlearea {
|
||||||
|
background-color: #5A5A5A;
|
||||||
|
background-image: linear-gradient(to right, #5A5A5A, #6a6a6a);
|
||||||
|
border-bottom: 3px solid #F78C40;
|
||||||
|
}
|
||||||
|
|
||||||
|
#projectname {
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#projectbrief {
|
||||||
|
color: #fab889 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Top navigation tabs */
|
||||||
|
#top {
|
||||||
|
background: linear-gradient(to bottom, #5A5A5A 0%, #6a6a6a 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs, .tabs2, .tabs3 {
|
||||||
|
background-image: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tablist li {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tablist li:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tablist li.current {
|
||||||
|
background: #F78C40;
|
||||||
|
border-bottom: 3px solid #f57900;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tab text colors - comprehensive selectors */
|
||||||
|
#nav-path ul li a,
|
||||||
|
.tabs a,
|
||||||
|
.tabs2 a,
|
||||||
|
.tabs3 a,
|
||||||
|
.tablist a,
|
||||||
|
.tablist a:link,
|
||||||
|
.tablist a:visited,
|
||||||
|
.tablist li a,
|
||||||
|
#main-nav a,
|
||||||
|
.sm > li > a,
|
||||||
|
.sm > li > a .sub-arrow {
|
||||||
|
color: #ffffff !important;
|
||||||
|
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Active/current tab text */
|
||||||
|
#nav-path ul li.current a,
|
||||||
|
.tabs .current a,
|
||||||
|
.tabs2 .current a,
|
||||||
|
.tabs3 .current a,
|
||||||
|
.tablist .current a,
|
||||||
|
.tablist .current a:link,
|
||||||
|
.tablist .current a:visited,
|
||||||
|
.tablist li.current a,
|
||||||
|
#main-nav .current a,
|
||||||
|
.sm .current a {
|
||||||
|
color: #333333 !important;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dropdown arrow - white color for top menu */
|
||||||
|
.sm-dox a span.sub-arrow {
|
||||||
|
border-right-color: #ffffff !important;
|
||||||
|
border-bottom-color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dropdown menu text - must be dark on white background */
|
||||||
|
/* Make this as specific as possible to override white color */
|
||||||
|
.sm-dox > li > ul > li > a,
|
||||||
|
.sm-dox li ul li a,
|
||||||
|
.sm-dox ul li a,
|
||||||
|
#main-menu ul li a {
|
||||||
|
color: #333333 !important;
|
||||||
|
text-shadow: none !important;
|
||||||
|
}
|
||||||
BIN
doc/favicon.png
Normal file
|
After Width: | Height: | Size: 858 B |
41
doc/fetch_doxygen_awesome.cmake
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Script to download doxygen-awesome-css at build time
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# cmake -P fetch_doxygen_awesome.cmake \
|
||||||
|
# -DURL=<download_url> \
|
||||||
|
# -DDEST_DIR=<destination_directory> \
|
||||||
|
# -DVERSION=<version>
|
||||||
|
|
||||||
|
if(NOT DEFINED URL)
|
||||||
|
message(FATAL_ERROR "URL not specified")
|
||||||
|
endif()
|
||||||
|
if(NOT DEFINED DEST_DIR)
|
||||||
|
message(FATAL_ERROR "DEST_DIR not specified")
|
||||||
|
endif()
|
||||||
|
if(NOT DEFINED VERSION)
|
||||||
|
message(FATAL_ERROR "VERSION not specified")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(EXTRACT_DIR "${DEST_DIR}/doxygen-awesome-css-${VERSION}")
|
||||||
|
|
||||||
|
if(NOT EXISTS "${EXTRACT_DIR}/doxygen-awesome.css")
|
||||||
|
message(STATUS "Downloading doxygen-awesome-css ${VERSION}...")
|
||||||
|
set(TARBALL "${DEST_DIR}/doxygen-awesome-css.tar.gz")
|
||||||
|
file(DOWNLOAD
|
||||||
|
"${URL}"
|
||||||
|
"${TARBALL}"
|
||||||
|
STATUS download_status
|
||||||
|
SHOW_PROGRESS
|
||||||
|
)
|
||||||
|
list(GET download_status 0 status_code)
|
||||||
|
if(NOT status_code EQUAL 0)
|
||||||
|
list(GET download_status 1 error_msg)
|
||||||
|
message(FATAL_ERROR "Download failed: ${error_msg}")
|
||||||
|
endif()
|
||||||
|
message(STATUS "Extracting doxygen-awesome-css...")
|
||||||
|
file(ARCHIVE_EXTRACT
|
||||||
|
INPUT "${TARBALL}"
|
||||||
|
DESTINATION "${DEST_DIR}"
|
||||||
|
)
|
||||||
|
file(REMOVE "${TARBALL}")
|
||||||
|
endif()
|
||||||
601
doc/fido2.dox
Normal file
@@ -0,0 +1,601 @@
|
|||||||
|
/**
|
||||||
|
|
||||||
|
@page libssh_tutor_fido2 Chapter 11: FIDO2/U2F Keys Support
|
||||||
|
|
||||||
|
@section fido2_intro Introduction
|
||||||
|
|
||||||
|
The traditional SSH public key model stores the private key on disk
|
||||||
|
and anyone who obtains that file (and possibly its passphrase) can impersonate
|
||||||
|
the user. FIDO2 authenticators, such as USB security keys, are hardware tokens
|
||||||
|
that generate or securely store private key material within a secure element
|
||||||
|
and may require explicit user interaction such as a touch, PIN, or biometric
|
||||||
|
verification for use. Hence, security keys are far safer from theft or
|
||||||
|
exfiltration than traditional file-based SSH keys. libssh provides support
|
||||||
|
for FIDO2/U2F security keys as hardware-backed SSH authentication credentials.
|
||||||
|
|
||||||
|
This chapter explains the concepts, build prerequisites, the API, and
|
||||||
|
usage patterns for enrolling (creating) and using security key-backed SSH
|
||||||
|
keys, including resident (discoverable) credentials.
|
||||||
|
|
||||||
|
@subsection fido2_resident_keys Resident Keys
|
||||||
|
|
||||||
|
Two credential storage modes exist for security keys:
|
||||||
|
|
||||||
|
- Non-resident (default): A credential ID (key handle) and metadata are
|
||||||
|
stored on the client-side in a key file. This key handle must be
|
||||||
|
presented to the FIDO2/U2F device while signing. This is somewhat
|
||||||
|
similar to traditional SSH keys, except that the key handle is not the
|
||||||
|
private key itself, but used in combination with the device's master key
|
||||||
|
to derive the actual private key.
|
||||||
|
|
||||||
|
- Resident (discoverable): The credential (and metadata like user id) is
|
||||||
|
stored on the device. No local file is needed; the device can enumerate or
|
||||||
|
locate the credential internally when queried.
|
||||||
|
|
||||||
|
Advantages of resident keys include portability (using the same device
|
||||||
|
across hosts) and resilience (no loss if the local machine is destroyed).
|
||||||
|
Although, they may be limited by the storage of the authenticator.
|
||||||
|
|
||||||
|
@subsection fido2_presence_verification User Presence vs. User Verification
|
||||||
|
|
||||||
|
FIDO2 distinguishes between:
|
||||||
|
|
||||||
|
- User Presence (UP): A simple physical interaction (touch) to confirm a
|
||||||
|
human is present.
|
||||||
|
|
||||||
|
- User Verification (UV): Verification of the user’s identity through
|
||||||
|
biometric authentication or a PIN.
|
||||||
|
|
||||||
|
Requiring UV provides additional protection if the device is stolen
|
||||||
|
and used without the PIN/biometric.
|
||||||
|
|
||||||
|
libssh exposes flags controlling these requirements (see below).
|
||||||
|
|
||||||
|
@subsection fido2_callbacks The Callback Abstraction
|
||||||
|
|
||||||
|
Different environments may need to access security keys through different
|
||||||
|
transport layers (e.g., USB-HID, NFC, Bluetooth, etc.). To accommodate
|
||||||
|
this variability, libssh does not hard-code a single implementation.
|
||||||
|
|
||||||
|
Instead, it defines a small callback interface (`ssh_sk_callbacks`) used for all
|
||||||
|
security key operations. Any implementation of this callback interface can be used
|
||||||
|
by higher-level PKI functions to perform enroll/sign/load_resident_keys
|
||||||
|
operations without needing to know the transport specifics. Hence, users can
|
||||||
|
define their own implementations for these callbacks to support different
|
||||||
|
transport protocols or custom hardware. Refer @ref fido2_custom_callbacks
|
||||||
|
for additional details.
|
||||||
|
|
||||||
|
The callback interface is defined in `libssh/callbacks.h` and the behaviour
|
||||||
|
and return values are specified by `libssh/sk_api.h`, which is the same
|
||||||
|
interface defined by OpenSSH for its security key support. This means that
|
||||||
|
any callback implementations (also called "middleware" in OpenSSH terminology)
|
||||||
|
developed for OpenSSH can be adapted to libssh with minimal changes.
|
||||||
|
|
||||||
|
The following operations are abstracted by the callback interface:
|
||||||
|
|
||||||
|
- api_version(): Report the version of the SK API that the callback implementation
|
||||||
|
is based on, so that libssh can check whether this implementation would be
|
||||||
|
compatible with the SK API version that it supports.
|
||||||
|
Refer @ref fido2_custom_callbacks_version for additional details.
|
||||||
|
- enroll(): Create (enroll) a new credential, returning public key, key
|
||||||
|
handle, attestation data.
|
||||||
|
- sign(): Produce a signature for supplied inputs using an existing key
|
||||||
|
handle.
|
||||||
|
- load_resident_keys(): Enumerate resident (discoverable) credentials stored
|
||||||
|
on the authenticator.
|
||||||
|
|
||||||
|
libssh provides a default implementation of the `ssh_sk_callbacks` using
|
||||||
|
the libfido2 library for the USB-HID transport protocol. Hence, by default,
|
||||||
|
libssh can interact with any FIDO2/U2F device that supports USB-HID and is
|
||||||
|
compatible with libfido2, without requiring any additional modifications.
|
||||||
|
|
||||||
|
@subsection fido2_build Building with FIDO2 Support
|
||||||
|
|
||||||
|
To enable FIDO2/U2F support, libssh must be built with the WITH_FIDO2
|
||||||
|
build option as follows:
|
||||||
|
|
||||||
|
@verbatim
|
||||||
|
cmake -DWITH_FIDO2=ON <other options> ..
|
||||||
|
@endverbatim
|
||||||
|
|
||||||
|
libssh will also build the default USB-HID `ssh_sk_callbacks`, if the
|
||||||
|
libfido2 library and headers are installed on your system.
|
||||||
|
|
||||||
|
@warning If built without libfido2, support for interacting with FIDO2/U2F
|
||||||
|
devices over USB-HID will not be available.
|
||||||
|
|
||||||
|
@subsection fido2_api_overview API Overview
|
||||||
|
|
||||||
|
Security key operations are configured through the `ssh_pki_ctx`
|
||||||
|
which allows to specify both general PKI options and FIDO2-specific
|
||||||
|
options such as the sk_callbacks, challenge data, application string, flags, etc.
|
||||||
|
|
||||||
|
The following sections describe the options that can be configured and how
|
||||||
|
the `ssh_pki_ctx` is used in conjunction with `ssh_key` to perform
|
||||||
|
enrollment, signing, and resident key loading operations.
|
||||||
|
|
||||||
|
@subsection fido2_key_objects Security Key Objects & Metadata
|
||||||
|
|
||||||
|
Security keys are surfaced as `ssh_key` objects of type
|
||||||
|
`SSH_KEYTYPE_SK_ECDSA` and `SSH_KEYTYPE_SK_ED25519` (corresponding to the
|
||||||
|
OpenSSH public key algorithm names `sk-ecdsa-sha2-nistp256@openssh.com` and
|
||||||
|
`sk-ssh-ed25519@openssh.com`). In addition to standard key handling, libssh
|
||||||
|
exposes the following helper functions to retrieve embedded SK metadata:
|
||||||
|
|
||||||
|
- ssh_key_get_sk_application(): Returns the relying party / application
|
||||||
|
(RP ID) string. The Relying Party ID (RP ID) is a string
|
||||||
|
that identifies the application or service requesting key enrollment. It
|
||||||
|
ensures that a credential is bound to a specific origin, preventing
|
||||||
|
phishing across sites. During registration, the authenticator associates
|
||||||
|
the credential with this RP ID so that it can later only be used for
|
||||||
|
authentication requests from the same relying party. For SSH keys, the
|
||||||
|
common format is "ssh:user@host".
|
||||||
|
|
||||||
|
- ssh_key_get_sk_user_id(): Returns a copy of the user ID associated with a key
|
||||||
|
which represents a unique identifier for the user within the relying
|
||||||
|
party (application) context. It is typically a string (such as an
|
||||||
|
email, or a random identifier) that helps distinguish credentials
|
||||||
|
belonging to different users for the same application.
|
||||||
|
|
||||||
|
Though the user ID can be binary data according to the FIDO2 spec, libssh only
|
||||||
|
supports NUL-terminated strings for enrolling new keys in order to remain compatible
|
||||||
|
with the OpenSSH's sk-api interface.
|
||||||
|
|
||||||
|
However, libssh does support loading existing resident keys with user IDs containing
|
||||||
|
arbitrary binary data. It does so by using an `ssh_string` to store the loaded key's
|
||||||
|
user_id, and an `ssh_string` can contain arbitrary binary data that can not be stored
|
||||||
|
in a traditional NUL-terminated string (like null bytes).
|
||||||
|
|
||||||
|
@note The user_id is NOT stored in the key file for non-resident keys. It is only
|
||||||
|
available for resident (discoverable) keys loaded from the authenticator via
|
||||||
|
ssh_sk_resident_keys_load(). For keys imported from files, this function returns
|
||||||
|
NULL.
|
||||||
|
|
||||||
|
- ssh_key_get_sk_flags(): Returns the flags associated with the key. The
|
||||||
|
following are the supported flags and they can be combined using
|
||||||
|
bitwise OR:
|
||||||
|
- SSH_SK_USER_PRESENCE_REQD : Require user presence (touch).
|
||||||
|
- SSH_SK_USER_VERIFICATION_REQD : Require user verification
|
||||||
|
(PIN/biometric).
|
||||||
|
- SSH_SK_RESIDENT_KEY : Request a resident discoverable credential.
|
||||||
|
- SSH_SK_FORCE_OPERATION : Force resident (discoverable) credential
|
||||||
|
creation even if one with same application and user_id already
|
||||||
|
exists.
|
||||||
|
|
||||||
|
These functions perform no additional communication with the
|
||||||
|
authenticator, this metadata is captured during enrollment/loading and
|
||||||
|
cached in the `ssh_key`.
|
||||||
|
|
||||||
|
@subsection fido2_options Setting Security Key Context Options
|
||||||
|
|
||||||
|
Options are set via ssh_pki_ctx_options_set().
|
||||||
|
|
||||||
|
Representative security key options:
|
||||||
|
- SSH_PKI_OPTION_SK_APPLICATION (const char *): Required relying party ID
|
||||||
|
If not set, a default value of "ssh:" is used.
|
||||||
|
- SSH_PKI_OPTION_SK_FLAGS (uint8_t *): Flags described above. If not set,
|
||||||
|
defaults to SSH_SK_USER_PRESENCE_REQD. This is because OpenSSH `sshd`
|
||||||
|
requires user presence for security key authentication by default.
|
||||||
|
- SSH_PKI_OPTION_SK_USER_ID (const char *): Represents a unique identifier
|
||||||
|
for the user within the relying party (application) context.
|
||||||
|
It is typically a string (such as an email, or a random identifier) that
|
||||||
|
helps distinguish credentials belonging to different users for the same
|
||||||
|
application. If not set, defaults to 64 zeros.
|
||||||
|
- SSH_PKI_OPTION_SK_CHALLENGE (ssh_buffer): Custom challenge; if omitted a
|
||||||
|
random 32-byte challenge is generated.
|
||||||
|
- SSH_PKI_OPTION_SK_CALLBACKS (ssh_sk_callbacks): Replace the default
|
||||||
|
callbacks with custom callbacks.
|
||||||
|
|
||||||
|
PIN callback: Use ssh_pki_ctx_set_sk_pin_callback() to register a function
|
||||||
|
matching `ssh_auth_callback` to prompt for and supply a PIN. The callback may
|
||||||
|
be called multiple times to ask for the pin depending on the authenticator policy.
|
||||||
|
|
||||||
|
Callback options: Callback implementations may accept additional configuration
|
||||||
|
name/value options such as the path to the fido device. These options can be provided via
|
||||||
|
`ssh_pki_ctx_sk_callbacks_option_set()`. Refer @ref fido2_custom_callbacks_options
|
||||||
|
for additional details.
|
||||||
|
|
||||||
|
The built-in callback implementation provided by libssh supports additional options,
|
||||||
|
with their names defined in `libssh.h` prefixed with `SSH_SK_OPTION_NAME_*`, such as:
|
||||||
|
|
||||||
|
SSH_SK_OPTION_NAME_DEVICE_PATH: Used for specifying a device path.
|
||||||
|
If the device path is not specified and multiple devices are connected, then
|
||||||
|
depending upon the operation and the flags set, the callback implementation may
|
||||||
|
automatically select a suitable device, or the user may be prompted to touch the
|
||||||
|
device they want to use.
|
||||||
|
|
||||||
|
SSH_SK_OPTION_NAME_USER_ID: Used for setting the user ID.
|
||||||
|
Note that the user ID can also be set using the ssh_pki_ctx_options_set() API.
|
||||||
|
|
||||||
|
@subsection fido2_enrollment Enrollment Example
|
||||||
|
|
||||||
|
An enrollment operation creates a new credential on the authenticator and
|
||||||
|
returns an ssh_key object representing it. The application and user_id
|
||||||
|
fields are required for creating the credential. The other options are
|
||||||
|
optional. A successful enrollment returns the public key, key handle, and
|
||||||
|
metadata which are stored in the ssh_key object, and may optionally return
|
||||||
|
attestation data which is used for verifying the authenticator model and
|
||||||
|
firmware version.
|
||||||
|
|
||||||
|
Below is a simple example enrolling an Ed25519 security key (non-resident)
|
||||||
|
requiring user presence only:
|
||||||
|
|
||||||
|
@code
|
||||||
|
#include <libssh/libssh.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static int pin_cb(const char *prompt,
|
||||||
|
char *buf,
|
||||||
|
size_t len,
|
||||||
|
int echo,
|
||||||
|
int verify,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
(void)prompt;
|
||||||
|
(void)echo;
|
||||||
|
(void)verify;
|
||||||
|
(void)userdata;
|
||||||
|
|
||||||
|
/* In a real application, the user would be prompted to enter the PIN */
|
||||||
|
const char *pin = "4242";
|
||||||
|
size_t l = strlen(pin);
|
||||||
|
if (l + 1 > len) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buf, pin, l + 1);
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int enroll_sk_key()
|
||||||
|
{
|
||||||
|
const char *app = "ssh:user@host";
|
||||||
|
const char *user_id = "alice";
|
||||||
|
uint8_t flags = SSH_SK_USER_PRESENCE_REQD | SSH_SK_USER_VERIFICATION_REQD;
|
||||||
|
const char *device_path = "/dev/hidraw6"; /* Optional device path */
|
||||||
|
|
||||||
|
ssh_pki_ctx pki_ctx = ssh_pki_ctx_new();
|
||||||
|
ssh_pki_ctx_options_set(pki_ctx, SSH_PKI_OPTION_SK_APPLICATION, app);
|
||||||
|
ssh_pki_ctx_options_set(pki_ctx, SSH_PKI_OPTION_SK_USER_ID, user_id);
|
||||||
|
ssh_pki_ctx_options_set(pki_ctx, SSH_PKI_OPTION_SK_FLAGS, &flags);
|
||||||
|
|
||||||
|
ssh_pki_ctx_set_sk_pin_callback(pki_ctx, pin_cb, NULL);
|
||||||
|
|
||||||
|
ssh_pki_ctx_sk_callbacks_option_set(pki_ctx,
|
||||||
|
SSH_SK_OPTION_NAME_DEVICE_PATH,
|
||||||
|
device_path,
|
||||||
|
true);
|
||||||
|
|
||||||
|
ssh_key enrolled = NULL;
|
||||||
|
int rc = ssh_pki_generate_key(SSH_KEYTYPE_SK_ED25519,
|
||||||
|
pki_ctx,
|
||||||
|
&enrolled); /* produces sk-ed25519 key */
|
||||||
|
|
||||||
|
/* Save enrolled key using ssh_pki_export_privkey_file, retrieve attestation
|
||||||
|
* buffer etc. */
|
||||||
|
|
||||||
|
/* Free context and key when done */
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
After a successful enrollment, you can retrieve the attestation buffer
|
||||||
|
(if provided by the authenticator) from the PKI context:
|
||||||
|
|
||||||
|
@code
|
||||||
|
ssh_buffer att_buf = NULL;
|
||||||
|
rc = ssh_pki_ctx_get_sk_attestation_buffer(pki_ctx, &att_buf);
|
||||||
|
if (rc == SSH_OK && att_buf != NULL) {
|
||||||
|
/* att_buf now contains the serialized attestation
|
||||||
|
* ("ssh-sk-attest-v01"). You can inspect, save, or
|
||||||
|
* parse the buffer as needed
|
||||||
|
*/
|
||||||
|
ssh_buffer_free(att_buf);
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- The attestation buffer is only populated if the enrollment operation
|
||||||
|
succeeds and the authenticator provides attestation data.
|
||||||
|
- `ssh_pki_ctx_get_sk_attestation_buffer()` returns a copy of the attestation
|
||||||
|
buffer; the caller must free it with `ssh_buffer_free()`.
|
||||||
|
|
||||||
|
@subsection fido2_signing Authenticating with a Stored Security Key Public Key
|
||||||
|
|
||||||
|
To authenticate using a security key, the application typically loads the
|
||||||
|
previously enrolled sk-* private key, establishes an SSH connection, and
|
||||||
|
calls `ssh_userauth_publickey()`. libssh automatically recognizes security
|
||||||
|
key types and transparently handles the required hardware-backed
|
||||||
|
authentication steps such as prompting for a touch or PIN using the
|
||||||
|
configured security key callbacks.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
@code
|
||||||
|
#include <libssh/libssh.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int auth_with_sk_file(const char *host,
|
||||||
|
const char *user,
|
||||||
|
const char *privkey_path)
|
||||||
|
{
|
||||||
|
ssh_session session = NULL;
|
||||||
|
ssh_key privkey = NULL;
|
||||||
|
int rc = SSH_ERROR;
|
||||||
|
|
||||||
|
session = ssh_new();
|
||||||
|
ssh_options_set(session, SSH_OPTIONS_HOST, host);
|
||||||
|
ssh_options_set(session, SSH_OPTIONS_USER, user);
|
||||||
|
ssh_connect(session);
|
||||||
|
|
||||||
|
ssh_pki_import_privkey_file(privkey_path, NULL, NULL, NULL, &privkey);
|
||||||
|
|
||||||
|
ssh_pki_ctx pki_ctx = ssh_pki_ctx_new();
|
||||||
|
/* Optionally set PIN callback, device path, etc. */
|
||||||
|
/* ssh_pki_ctx_set_sk_pin_callback(pki_ctx, pin_cb, NULL); */
|
||||||
|
|
||||||
|
ssh_options_set(session, SSH_OPTIONS_PKI_CONTEXT, pki_ctx);
|
||||||
|
|
||||||
|
rc = ssh_userauth_publickey(session, user, privkey);
|
||||||
|
if (rc == SSH_AUTH_SUCCESS) {
|
||||||
|
printf("Authenticated with security key.\n");
|
||||||
|
rc = SSH_OK;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Authentication failed rc=%d err=%s\n",
|
||||||
|
rc,
|
||||||
|
ssh_get_error(session));
|
||||||
|
rc = SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free resources */
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@subsection fido2_resident Resident Key Enumeration
|
||||||
|
|
||||||
|
Resident keys stored on the device can be discovered and loaded with
|
||||||
|
ssh_sk_resident_keys_load() which takes a PKI context (configured with
|
||||||
|
a PIN callback) and returns each key as an ssh_key and the number of keys loaded.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
@code
|
||||||
|
#include <libssh/libssh.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static int pin_cb(const char *prompt,
|
||||||
|
char *buf,
|
||||||
|
size_t len,
|
||||||
|
int echo,
|
||||||
|
int verify,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
(void)prompt;
|
||||||
|
(void)echo;
|
||||||
|
(void)verify;
|
||||||
|
(void)userdata;
|
||||||
|
const char *pin = "4242";
|
||||||
|
size_t l = strlen(pin);
|
||||||
|
|
||||||
|
if (l + 1 > len) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buf, pin, l + 1);
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int auth_with_resident(const char *host,
|
||||||
|
const char *user,
|
||||||
|
const char *application,
|
||||||
|
const char *user_id)
|
||||||
|
{
|
||||||
|
ssh_pki_ctx pki_ctx = NULL;
|
||||||
|
size_t num_found = 0;
|
||||||
|
ssh_key *keys = NULL;
|
||||||
|
ssh_key final_key = NULL;
|
||||||
|
int rc = SSH_ERROR;
|
||||||
|
|
||||||
|
ssh_string cur_application = NULL;
|
||||||
|
ssh_string cur_user_id = NULL;
|
||||||
|
ssh_string expected_application = NULL;
|
||||||
|
ssh_string expected_user_id = NULL;
|
||||||
|
|
||||||
|
pki_ctx = ssh_pki_ctx_new();
|
||||||
|
ssh_pki_ctx_set_sk_pin_callback(pki_ctx, pin_cb, NULL);
|
||||||
|
|
||||||
|
expected_application = ssh_string_from_char(application);
|
||||||
|
expected_user_id = ssh_string_from_char(user_id);
|
||||||
|
|
||||||
|
rc = ssh_sk_resident_keys_load(pki_ctx, &keys, &num_found);
|
||||||
|
for (size_t i = 0; i < num_found; i++) {
|
||||||
|
cur_application = ssh_key_get_sk_application(keys[i]);
|
||||||
|
cur_user_id = ssh_key_get_sk_user_id(keys[i]);
|
||||||
|
|
||||||
|
if (ssh_string_cmp(cur_application, expected_application) == 0 &&
|
||||||
|
ssh_string_cmp(cur_user_id, expected_user_id) == 0) {
|
||||||
|
SSH_STRING_FREE(cur_application);
|
||||||
|
SSH_STRING_FREE(cur_user_id);
|
||||||
|
final_key = keys[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SSH_STRING_FREE(cur_application);
|
||||||
|
SSH_STRING_FREE(cur_user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
SSH_STRING_FREE(expected_application);
|
||||||
|
SSH_STRING_FREE(expected_user_id);
|
||||||
|
|
||||||
|
/* Continue with authentication using the ssh_key with
|
||||||
|
* ssh_userauth_publickey as usual, and free resources when done. */
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@subsection fido2_sshsig Signing using the sshsig API
|
||||||
|
|
||||||
|
Security keys can also be used for general-purpose signing of arbitrary data
|
||||||
|
(without SSH authentication) using the existing `sshsig_sign()` and `sshsig_verify()`
|
||||||
|
functions. These functions work seamlessly with security key types
|
||||||
|
(`SSH_KEYTYPE_SK_ECDSA` and `SSH_KEYTYPE_SK_ED25519`) and will automatically
|
||||||
|
invoke the configured security key callbacks to perform hardware-backed signing
|
||||||
|
operations.
|
||||||
|
|
||||||
|
@subsection fido2_custom_callbacks Implementing Custom Callback Implementations
|
||||||
|
|
||||||
|
Users may need to implement custom callback implementations to support
|
||||||
|
different transport protocols (e.g., NFC, Bluetooth) beyond the default USB-HID
|
||||||
|
support. This section describes how to implement and integrate custom callback
|
||||||
|
implementations.
|
||||||
|
|
||||||
|
To implement custom callbacks, you must include the following headers:
|
||||||
|
|
||||||
|
@code
|
||||||
|
#include <libssh/callbacks.h> /* For ssh_sk_callbacks_struct */
|
||||||
|
#include <libssh/sk_api.h> /* For SK API constants and data structures */
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
The `libssh/sk_api.h` header provides the complete interface specification including
|
||||||
|
request/response structures, flags, and version macros.
|
||||||
|
|
||||||
|
@subsubsection fido2_custom_callbacks_version API Version Compatibility
|
||||||
|
|
||||||
|
libssh validates callback implementations by checking the API version returned by
|
||||||
|
the `api_version()` callback. To ensure compatibility, libssh compares the major
|
||||||
|
version (upper 16 bits) of the returned value with `LIBSSH_SK_API_VERSION_MAJOR`.
|
||||||
|
If they don't match, libssh will reject the callback implementation.
|
||||||
|
This ensures that the callbacks' SK API matches the major version expected by libssh,
|
||||||
|
while allowing minor version differences.
|
||||||
|
|
||||||
|
@subsubsection fido2_custom_callbacks_implementation Implementation Example
|
||||||
|
|
||||||
|
Here's a minimal example of defining and using custom callbacks:
|
||||||
|
|
||||||
|
@code
|
||||||
|
#include <libssh/libssh.h>
|
||||||
|
#include <libssh/callbacks.h>
|
||||||
|
#include <libssh/sk_api.h>
|
||||||
|
|
||||||
|
/* Your custom API version callback */
|
||||||
|
static uint32_t my_sk_api_version(void)
|
||||||
|
{
|
||||||
|
/* Match the major version, set your own minor version */
|
||||||
|
return SSH_SK_VERSION_MAJOR | 0x0001;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Your custom enroll callback */
|
||||||
|
static int my_sk_enroll(uint32_t alg,
|
||||||
|
const uint8_t *challenge,
|
||||||
|
size_t challenge_len,
|
||||||
|
const char *application,
|
||||||
|
uint8_t flags,
|
||||||
|
const char *pin,
|
||||||
|
struct sk_option **options,
|
||||||
|
struct sk_enroll_response **enroll_response)
|
||||||
|
{
|
||||||
|
/* Parse options array to extract custom parameters */
|
||||||
|
if (options != NULL) {
|
||||||
|
for (size_t i = 0; options[i] != NULL; i++) {
|
||||||
|
if (strcmp(options[i]->name, "my_custom_option") == 0) {
|
||||||
|
/* Use options[i]->value */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implement your enroll logic here */
|
||||||
|
/* ... */
|
||||||
|
|
||||||
|
return SSH_SK_ERR_GENERAL; /* Return appropriate error code */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implement other required callbacks: sign, load_resident_keys */
|
||||||
|
/* ... */
|
||||||
|
|
||||||
|
/* Define your callback structure */
|
||||||
|
static struct ssh_sk_callbacks_struct my_sk_callbacks = {
|
||||||
|
.size = sizeof(struct ssh_sk_callbacks_struct),
|
||||||
|
.api_version = my_sk_api_version,
|
||||||
|
.enroll = my_sk_enroll,
|
||||||
|
.sign = my_sk_sign, /* Your implementation */
|
||||||
|
.load_resident_keys = my_sk_load_resident_keys, /* Your implementation */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Usage example */
|
||||||
|
void use_custom_callbacks(void)
|
||||||
|
{
|
||||||
|
ssh_pki_ctx pki_ctx = ssh_pki_ctx_new();
|
||||||
|
|
||||||
|
/* Set your custom callbacks */
|
||||||
|
ssh_pki_ctx_options_set(pki_ctx,
|
||||||
|
SSH_PKI_OPTION_SK_CALLBACKS,
|
||||||
|
&my_sk_callbacks);
|
||||||
|
|
||||||
|
/* Pass custom options to your callbacks */
|
||||||
|
ssh_pki_ctx_sk_callbacks_option_set(pki_ctx,
|
||||||
|
"my_custom_option",
|
||||||
|
"my_custom_value",
|
||||||
|
false);
|
||||||
|
|
||||||
|
/* Use the context for enrollment, signing, etc. */
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@subsubsection fido2_custom_callbacks_options Passing Custom Options
|
||||||
|
|
||||||
|
The `ssh_pki_ctx_sk_callbacks_option_set()` function allows you to pass
|
||||||
|
implementation-specific options as name/value string pairs:
|
||||||
|
|
||||||
|
@code
|
||||||
|
ssh_pki_ctx_sk_callbacks_option_set(pki_ctx,
|
||||||
|
"option_name",
|
||||||
|
"option_value",
|
||||||
|
required);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- `option_name`: The name of the option (e.g., "device_path", "my_custom_param")
|
||||||
|
- `option_value`: The string value for this option
|
||||||
|
- `required`: If true, this option must be processed by the callback implementation
|
||||||
|
and cannot be ignored. If false, the option is advisory and can be skipped if the
|
||||||
|
callback implementation does not support it.
|
||||||
|
|
||||||
|
These options are passed to your callbacks in the `struct sk_option **options`
|
||||||
|
parameter as a NULL-terminated array. Each `sk_option` has the following fields:
|
||||||
|
- `name`: The option name (char *)
|
||||||
|
- `value`: The option value (char *)
|
||||||
|
- `required`: Whether the option must be processed (uint8_t, non-zero = required)
|
||||||
|
|
||||||
|
@subsubsection fido2_custom_callbacks_openssh OpenSSH Middleware Compatibility
|
||||||
|
|
||||||
|
Since libssh uses the same SK API as OpenSSH, middleware implementations developed
|
||||||
|
for OpenSSH can be adapted with minimal changes.
|
||||||
|
To adapt an OpenSSH middleware for libssh, create a wrapper that populates
|
||||||
|
`ssh_sk_callbacks_struct` with pointers to the middleware's functions.
|
||||||
|
|
||||||
|
@subsection fido2_testing Testing and Environment Variables
|
||||||
|
|
||||||
|
Unit tests covering USB-HID enroll/sign/load_resident_keys operations can be found
|
||||||
|
in the `tests/unittests/torture_sk_usbhid.c` file. To run these tests you
|
||||||
|
must have libfido2 installed and the WITH_FIDO2=ON build option set.
|
||||||
|
Additionally, you must ensure the following:
|
||||||
|
|
||||||
|
- An actual FIDO2 device must be connected to the test machine.
|
||||||
|
- The TORTURE_SK_USBHID environment variable must be set.
|
||||||
|
- The environment variable TORTURE_SK_PIN=<device PIN> must be set.
|
||||||
|
|
||||||
|
If these are not set, the tests are skipped.
|
||||||
|
|
||||||
|
The higher level PKI integration tests can be found in
|
||||||
|
`tests/unittests/torture_pki_sk.c` and the tests related to the sshsig API
|
||||||
|
can be found in `tests/unittests/torture_pki_sshsig.c`.
|
||||||
|
These use the callback implementation provided by OpenSSH's sk-dummy.so,
|
||||||
|
which simulates an authenticator without requiring any hardware. Hence, these tests
|
||||||
|
can be run in the CI environment.
|
||||||
|
However, these tests can also be configured to use the default USB-HID callbacks
|
||||||
|
by setting the same environment variables as described above.
|
||||||
|
|
||||||
|
The following devices were tested during development:
|
||||||
|
|
||||||
|
- Yubico Security Key NFC - USB-A
|
||||||
|
|
||||||
|
*/
|
||||||
@@ -100,7 +100,7 @@ used to retrieve google's home page from the remote SSH server.
|
|||||||
@code
|
@code
|
||||||
int direct_forwarding(ssh_session session)
|
int direct_forwarding(ssh_session session)
|
||||||
{
|
{
|
||||||
ssh_channel forwarding_channel;
|
ssh_channel forwarding_channel = NULL;
|
||||||
int rc = SSH_ERROR;
|
int rc = SSH_ERROR;
|
||||||
char *http_get = "GET / HTTP/1.1\nHost: www.google.com\n\n";
|
char *http_get = "GET / HTTP/1.1\nHost: www.google.com\n\n";
|
||||||
int nbytes, nwritten;
|
int nbytes, nwritten;
|
||||||
@@ -161,7 +161,7 @@ local libssh application, which handles them:
|
|||||||
int web_server(ssh_session session)
|
int web_server(ssh_session session)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
ssh_channel channel;
|
ssh_channel channel = NULL;
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
int nbytes, nwritten;
|
int nbytes, nwritten;
|
||||||
int port = 0;
|
int port = 0;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
A SSH session goes through the following steps:
|
A SSH session goes through the following steps:
|
||||||
|
|
||||||
- Before connecting to the server, you can set up if you wish one or other
|
- Before connecting to the server, you can set up if you wish one or other
|
||||||
server public key authentication, i.e. DSA or RSA. You can choose
|
server public key authentication, i.e. RSA, ED25519 or ECDSA. You can choose
|
||||||
cryptographic algorithms you trust and compression algorithms if any. You
|
cryptographic algorithms you trust and compression algorithms if any. You
|
||||||
must of course set up the hostname.
|
must of course set up the hostname.
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ A SSH session goes through the following steps:
|
|||||||
file.
|
file.
|
||||||
|
|
||||||
- The client must authenticate: the classical ways are password, or
|
- The client must authenticate: the classical ways are password, or
|
||||||
public keys (from dsa and rsa key-pairs generated by openssh).
|
public keys (from ecdsa, ed25519 and rsa key-pairs generated by openssh).
|
||||||
If a SSH agent is running, it is possible to use it.
|
If a SSH agent is running, it is possible to use it.
|
||||||
|
|
||||||
- Now that the user has been authenticated, you must open one or several
|
- Now that the user has been authenticated, you must open one or several
|
||||||
@@ -79,7 +79,7 @@ Here is a small example of how to use it:
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
ssh_session my_ssh_session;
|
ssh_session my_ssh_session = NULL;
|
||||||
int verbosity = SSH_LOG_PROTOCOL;
|
int verbosity = SSH_LOG_PROTOCOL;
|
||||||
int port = 22;
|
int port = 22;
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ Here's an example:
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
ssh_session my_ssh_session;
|
ssh_session my_ssh_session = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
my_ssh_session = ssh_new();
|
my_ssh_session = ssh_new();
|
||||||
@@ -190,8 +190,8 @@ int verify_knownhost(ssh_session session)
|
|||||||
ssh_key srv_pubkey = NULL;
|
ssh_key srv_pubkey = NULL;
|
||||||
size_t hlen;
|
size_t hlen;
|
||||||
char buf[10];
|
char buf[10];
|
||||||
char *hexa;
|
char *hexa = NULL;
|
||||||
char *p;
|
char *p = NULL;
|
||||||
int cmp;
|
int cmp;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -317,9 +317,9 @@ The example below shows an authentication with password:
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
ssh_session my_ssh_session;
|
ssh_session my_ssh_session = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
char *password;
|
char *password = NULL;
|
||||||
|
|
||||||
// Open session and set options
|
// Open session and set options
|
||||||
my_ssh_session = ssh_new();
|
my_ssh_session = ssh_new();
|
||||||
@@ -380,7 +380,7 @@ The example below shows how to execute a remote command:
|
|||||||
@code
|
@code
|
||||||
int show_remote_processes(ssh_session session)
|
int show_remote_processes(ssh_session session)
|
||||||
{
|
{
|
||||||
ssh_channel channel;
|
ssh_channel channel = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
int nbytes;
|
int nbytes;
|
||||||
|
|||||||
92
doc/header.html
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<!-- HTML header for doxygen 1.14.0-->
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="$langISO">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
|
||||||
|
<meta name="generator" content="Doxygen $doxygenversion"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
|
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
|
||||||
|
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
|
||||||
|
<!--BEGIN PROJECT_ICON-->
|
||||||
|
<link rel="icon" href="$relpath^$projecticon" type="image/x-icon" />
|
||||||
|
<!--END PROJECT_ICON-->
|
||||||
|
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
|
||||||
|
<!--BEGIN FULL_SIDEBAR-->
|
||||||
|
<script type="text/javascript">var page_layout=1;</script>
|
||||||
|
<!--END FULL_SIDEBAR-->
|
||||||
|
<script type="text/javascript" src="$relpath^jquery.js"></script>
|
||||||
|
<script type="text/javascript" src="$relpath^dynsections.js"></script>
|
||||||
|
<!--BEGIN COPY_CLIPBOARD-->
|
||||||
|
<script type="text/javascript" src="$relpath^clipboard.js"></script>
|
||||||
|
<!--END COPY_CLIPBOARD-->
|
||||||
|
$treeview
|
||||||
|
$search
|
||||||
|
$mathjax
|
||||||
|
$darkmode
|
||||||
|
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
|
||||||
|
$extrastylesheet
|
||||||
|
<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
DoxygenAwesomeDarkModeToggle.init()
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript" src="$relpath^doxygen-awesome-fragment-copy-button.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
DoxygenAwesomeFragmentCopyButton.init()
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript" src="$relpath^doxygen-awesome-paragraph-link.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
DoxygenAwesomeParagraphLink.init()
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript" src="$relpath^doxygen-awesome-interactive-toc.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
DoxygenAwesomeInteractiveToc.init()
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!--BEGIN FULL_SIDEBAR-->
|
||||||
|
<div id="side-nav" class="ui-resizable side-nav-resizable"><!-- do not remove this div, it is closed by doxygen! -->
|
||||||
|
<!--END FULL_SIDEBAR-->
|
||||||
|
|
||||||
|
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||||
|
|
||||||
|
<!--BEGIN TITLEAREA-->
|
||||||
|
<div id="titlearea">
|
||||||
|
<table cellspacing="0" cellpadding="0">
|
||||||
|
<tbody>
|
||||||
|
<tr id="projectrow">
|
||||||
|
<!--BEGIN PROJECT_LOGO-->
|
||||||
|
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"$logosize/></td>
|
||||||
|
<!--END PROJECT_LOGO-->
|
||||||
|
<!--BEGIN PROJECT_NAME-->
|
||||||
|
<td id="projectalign">
|
||||||
|
<div id="projectname">$projectname<!--BEGIN PROJECT_NUMBER--><span id="projectnumber"> $projectnumber</span><!--END PROJECT_NUMBER-->
|
||||||
|
</div>
|
||||||
|
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
|
||||||
|
</td>
|
||||||
|
<!--END PROJECT_NAME-->
|
||||||
|
<!--BEGIN !PROJECT_NAME-->
|
||||||
|
<!--BEGIN PROJECT_BRIEF-->
|
||||||
|
<td>
|
||||||
|
<div id="projectbrief">$projectbrief</div>
|
||||||
|
</td>
|
||||||
|
<!--END PROJECT_BRIEF-->
|
||||||
|
<!--END !PROJECT_NAME-->
|
||||||
|
<!--BEGIN DISABLE_INDEX-->
|
||||||
|
<!--BEGIN SEARCHENGINE-->
|
||||||
|
<!--BEGIN !FULL_SIDEBAR-->
|
||||||
|
<td>$searchbox</td>
|
||||||
|
<!--END !FULL_SIDEBAR-->
|
||||||
|
<!--END SEARCHENGINE-->
|
||||||
|
<!--END DISABLE_INDEX-->
|
||||||
|
</tr>
|
||||||
|
<!--BEGIN SEARCHENGINE-->
|
||||||
|
<!--BEGIN FULL_SIDEBAR-->
|
||||||
|
<tr><td colspan="2">$searchbox</td></tr>
|
||||||
|
<!--END FULL_SIDEBAR-->
|
||||||
|
<!--END SEARCHENGINE-->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--END TITLEAREA-->
|
||||||
|
<!-- end header part -->
|
||||||
@@ -14,8 +14,8 @@ libssh is a Free Software / Open Source project. The libssh library
|
|||||||
is distributed under LGPL license. The libssh project has nothing to do with
|
is distributed under LGPL license. The libssh project has nothing to do with
|
||||||
"libssh2", which is a completely different and independent project.
|
"libssh2", which is a completely different and independent project.
|
||||||
|
|
||||||
libssh can run on top of either libgcrypt or libcrypto,
|
libssh can run on top of either libcrypto, mbedtls or libgcrypt (deprecated)
|
||||||
two general-purpose cryptographic libraries.
|
general-purpose cryptographic libraries.
|
||||||
|
|
||||||
This tutorial concentrates for its main part on the "client" side of libssh.
|
This tutorial concentrates for its main part on the "client" side of libssh.
|
||||||
To learn how to accept incoming SSH connections (how to write a SSH server),
|
To learn how to accept incoming SSH connections (how to write a SSH server),
|
||||||
@@ -44,6 +44,12 @@ Table of contents:
|
|||||||
|
|
||||||
@subpage libssh_tutor_threads
|
@subpage libssh_tutor_threads
|
||||||
|
|
||||||
|
@subpage libssh_tutor_pkcs11
|
||||||
|
|
||||||
|
@subpage libssh_tutor_sftp_aio
|
||||||
|
|
||||||
|
@subpage libssh_tutor_fido2
|
||||||
|
|
||||||
@subpage libssh_tutor_todo
|
@subpage libssh_tutor_todo
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -19,12 +19,13 @@ the interesting functions as you go.
|
|||||||
|
|
||||||
The libssh library provides:
|
The libssh library provides:
|
||||||
|
|
||||||
- <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>Key Exchange Methods</strong>: <i>sntrup761x25519-sha512, sntrup761x25519-sha512@openssh.com, mlkem768x25519-sha256, mlkem768nistp256-sha256, mlkem1024nistp384-sha384, 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>Public Key Algorithms</strong>: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, ssh-rsa, rsa-sha2-512, rsa-sha2-256,ssh-dss
|
- <strong>GSSAPI Key Exchange Methods</strong>: gss-group14-sha256-*, gss-group16-sha512-*, gss-nistp256-sha256-*, gss-curve25519-sha256-*
|
||||||
|
- <strong>Public Key Algorithms</strong>: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, ssh-rsa, rsa-sha2-512, rsa-sha2-256
|
||||||
- <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
|
- <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
|
||||||
- <strong>Compression Schemes</strong>: zlib, <i>zlib@openssh.com</i>, none
|
- <strong>Compression Schemes</strong>: zlib, <i>zlib@openssh.com</i>, none
|
||||||
- <strong>MAC hashes</strong>: hmac-sha1, hmac-sha2-256, hmac-sha2-512, hmac-md5
|
- <strong>MAC hashes</strong>: hmac-sha1, hmac-sha2-256, hmac-sha2-512, hmac-md5
|
||||||
- <strong>Authentication</strong>: none, password, public-key, keyboard-interactive, <i>gssapi-with-mic</i>
|
- <strong>Authentication</strong>: none, password, public-key, keyboard-interactive, <i>gssapi-with-mic, gssapi-keyex</i>
|
||||||
- <strong>Channels</strong>: shell, exec (incl. SCP wrapper), direct-tcpip, subsystem, <i>auth-agent-req@openssh.com</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>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>Channel Requests</strong>: x11, pty, <i>exit-status, signal, exit-signal, keepalive@openssh.com, auth-agent-req@openssh.com</i>
|
||||||
@@ -33,7 +34,7 @@ The libssh library provides:
|
|||||||
- <strong>Thread-safe</strong>: Just don't share sessions
|
- <strong>Thread-safe</strong>: Just don't share sessions
|
||||||
- <strong>Non-blocking</strong>: it can be used both blocking and non-blocking
|
- <strong>Non-blocking</strong>: it can be used both blocking and non-blocking
|
||||||
- <strong>Your sockets</strong>: the app hands over the socket, or uses libssh sockets
|
- <strong>Your sockets</strong>: the app hands over the socket, or uses libssh sockets
|
||||||
- <b>OpenSSL</b> or <b>gcrypt</b>: builds with either
|
- <b>OpenSSL</b>, <b>MBedTLS</b> or <b>gcrypt</b> (deprecated): builds with either
|
||||||
|
|
||||||
@section main-additional-features Additional Features
|
@section main-additional-features Additional Features
|
||||||
|
|
||||||
@@ -149,7 +150,7 @@ The libssh Team
|
|||||||
|
|
||||||
@subsection main-rfc-secsh Secure Shell (SSH)
|
@subsection main-rfc-secsh Secure Shell (SSH)
|
||||||
|
|
||||||
The following RFC documents described SSH-2 protcol as an Internet standard.
|
The following RFC documents described SSH-2 protocol as an Internet standard.
|
||||||
|
|
||||||
- <a href="https://tools.ietf.org/html/rfc4250" target="_blank">RFC 4250</a>,
|
- <a href="https://tools.ietf.org/html/rfc4250" target="_blank">RFC 4250</a>,
|
||||||
The Secure Shell (SSH) Protocol Assigned Numbers
|
The Secure Shell (SSH) Protocol Assigned Numbers
|
||||||
@@ -170,21 +171,15 @@ The following RFC documents described SSH-2 protcol as an Internet standard.
|
|||||||
The Secure Shell (SSH) Session Channel Break Extension
|
The Secure Shell (SSH) Session Channel Break Extension
|
||||||
- <a href="https://tools.ietf.org/html/rfc4344" target="_blank">RFC 4344</a>,
|
- <a href="https://tools.ietf.org/html/rfc4344" target="_blank">RFC 4344</a>,
|
||||||
The Secure Shell (SSH) Transport Layer Encryption Modes
|
The Secure Shell (SSH) Transport Layer Encryption Modes
|
||||||
- <a href="https://tools.ietf.org/html/rfc4345" target="_blank">RFC 4345</a>,
|
|
||||||
Improved Arcfour Modes for the Secure Shell (SSH) Transport Layer Protocol
|
|
||||||
|
|
||||||
It was later modified and expanded by the following RFCs.
|
It was later modified and expanded by the following RFCs.
|
||||||
|
|
||||||
- <a href="https://tools.ietf.org/html/rfc4419" target="_blank">RFC 4419</a>,
|
- <a href="https://tools.ietf.org/html/rfc4419" target="_blank">RFC 4419</a>,
|
||||||
Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer
|
Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer
|
||||||
Protocol
|
Protocol
|
||||||
- <a href="https://tools.ietf.org/html/rfc4432" target="_blank">RFC 4432</a>,
|
|
||||||
RSA Key Exchange for the Secure Shell (SSH) Transport Layer Protocol
|
|
||||||
(not implemented in libssh)
|
|
||||||
- <a href="https://tools.ietf.org/html/rfc4462" target="_blank">RFC 4462</a>,
|
- <a href="https://tools.ietf.org/html/rfc4462" target="_blank">RFC 4462</a>,
|
||||||
Generic Security Service Application Program Interface (GSS-API)
|
Generic Security Service Application Program Interface (GSS-API)
|
||||||
Authentication and Key Exchange for the Secure Shell (SSH) Protocol
|
Authentication and Key Exchange for the Secure Shell (SSH) Protocol
|
||||||
(only the authentication implemented in libssh)
|
|
||||||
- <a href="https://tools.ietf.org/html/rfc4716" target="_blank">RFC 4716</a>,
|
- <a href="https://tools.ietf.org/html/rfc4716" target="_blank">RFC 4716</a>,
|
||||||
The Secure Shell (SSH) Public Key File Format
|
The Secure Shell (SSH) Public Key File Format
|
||||||
(not implemented in libssh)
|
(not implemented in libssh)
|
||||||
@@ -203,7 +198,6 @@ It was later modified and expanded by the following RFCs.
|
|||||||
(not implemented in libssh)
|
(not implemented in libssh)
|
||||||
- <a href="https://tools.ietf.org/html/rfc8160" target="_blank">RFC 8160</a>,
|
- <a href="https://tools.ietf.org/html/rfc8160" target="_blank">RFC 8160</a>,
|
||||||
IUTF8 Terminal Mode in Secure Shell (SSH)
|
IUTF8 Terminal Mode in Secure Shell (SSH)
|
||||||
(not handled in libssh)
|
|
||||||
- <a href="https://tools.ietf.org/html/rfc8270" target="_blank">RFC 8270</a>,
|
- <a href="https://tools.ietf.org/html/rfc8270" target="_blank">RFC 8270</a>,
|
||||||
Increase the Secure Shell Minimum Recommended Diffie-Hellman Modulus Size to 2048 Bits
|
Increase the Secure Shell Minimum Recommended Diffie-Hellman Modulus Size to 2048 Bits
|
||||||
- <a href="https://tools.ietf.org/html/rfc8308" target="_blank">RFC 8308</a>,
|
- <a href="https://tools.ietf.org/html/rfc8308" target="_blank">RFC 8308</a>,
|
||||||
@@ -213,15 +207,23 @@ It was later modified and expanded by the following RFCs.
|
|||||||
Use of RSA Keys with SHA-256 and SHA-512 in the Secure Shell (SSH) Protocol
|
Use of RSA Keys with SHA-256 and SHA-512 in the Secure Shell (SSH) Protocol
|
||||||
- <a href="https://tools.ietf.org/html/rfc8709" target="_blank">RFC 8709</a>,
|
- <a href="https://tools.ietf.org/html/rfc8709" target="_blank">RFC 8709</a>,
|
||||||
Ed25519 and Ed448 Public Key Algorithms for the Secure Shell (SSH) Protocol
|
Ed25519 and Ed448 Public Key Algorithms for the Secure Shell (SSH) Protocol
|
||||||
|
- <a href="https://tools.ietf.org/html/rfc8709" target="_blank">RFC 8731</a>,
|
||||||
|
Secure Shell (SSH) Key Exchange Method Using Curve25519 and Curve448
|
||||||
|
- <a href="https://tools.ietf.org/html/rfc9142" target="_blank">RFC 9142</a>,
|
||||||
|
Key Exchange (KEX) Method Updates and Recommendations for Secure Shell (SSH)
|
||||||
|
|
||||||
There are also drafts that are being currently developed and followed.
|
There are also drafts that are being currently developed and followed.
|
||||||
|
|
||||||
- <a href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-kex-sha2-10" target="_blank">draft-ietf-curdle-ssh-kex-sha2-10</a>
|
- <a href="https://tools.ietf.org/html/draft-miller-ssh-agent-03" target="_blank">draft-miller-ssh-agent-08</a>
|
||||||
Key Exchange (KEX) Method Updates and Recommendations for Secure Shell (SSH)
|
|
||||||
- <a href="https://tools.ietf.org/html/draft-miller-ssh-agent-03" target="_blank">draft-miller-ssh-agent-03</a>
|
|
||||||
SSH Agent Protocol
|
SSH Agent Protocol
|
||||||
- <a href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-curves-12" target="_blank">draft-ietf-curdle-ssh-curves-12</a>
|
- <a href="https://tools.ietf.org/html/draft-ietf-sshm-mlkem-hybrid-kex-09" target="_blank">draft-ietf-sshm-mlkem-hybrid-kex-09</a>
|
||||||
Secure Shell (SSH) Key Exchange Method using Curve25519 and Curve448
|
PQ/T Hybrid Key Exchange with ML-KEM in SSH
|
||||||
|
- <a href="https://tools.ietf.org/html/draft-ietf-sshm-ntruprime-ssh-06" target="_blank">draft-ietf-sshm-ntruprime-ssh-06</a>
|
||||||
|
Secure Shell (SSH) Key Exchange Method Using Hybrid Streamlined NTRU Prime sntrup761 and X25519 with SHA-512: sntrup761x25519-sha512
|
||||||
|
- <a href="https://tools.ietf.org/html/draft-ietf-sshm-chacha20-poly1305-02" target="_blank">draft-ietf-sshm-chacha20-poly1305-02</a>
|
||||||
|
Secure Shell (SSH) authenticated encryption cipher: chacha20-poly1305
|
||||||
|
- <a href="https://tools.ietf.org/html/draft-ietf-sshm-strict-kex-01" target="_blank">draft-ietf-sshm-strict-kex-01</a>
|
||||||
|
SSH Strict KEX extension
|
||||||
|
|
||||||
Interesting cryptography documents:
|
Interesting cryptography documents:
|
||||||
|
|
||||||
@@ -246,8 +248,6 @@ them like the statvfs calls in SFTP or the ssh-agent.
|
|||||||
OpenSSH's deviations and extensions</a>
|
OpenSSH's deviations and extensions</a>
|
||||||
- <a href="https://api.libssh.org/rfc/PROTOCOL.certkeys" target="_blank">
|
- <a href="https://api.libssh.org/rfc/PROTOCOL.certkeys" target="_blank">
|
||||||
OpenSSH's pubkey certificate authentication</a>
|
OpenSSH's pubkey certificate authentication</a>
|
||||||
- <a href="https://api.libssh.org/rfc/PROTOCOL.chacha20poly1305" target="_blank">
|
|
||||||
chacha20-poly1305@openssh.com authenticated encryption mode</a>
|
|
||||||
- <a href="https://api.libssh.org/rfc/PROTOCOL.key" target="_blank">
|
- <a href="https://api.libssh.org/rfc/PROTOCOL.key" target="_blank">
|
||||||
OpenSSH private key format (openssh-key-v1)</a>
|
OpenSSH private key format (openssh-key-v1)</a>
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ objects stored on the tokens can be uniquely identified is called PKCS #11 URI
|
|||||||
(Uniform Resource Identifier) and is defined in RFC 7512
|
(Uniform Resource Identifier) and is defined in RFC 7512
|
||||||
(https://tools.ietf.org/html/rfc7512).
|
(https://tools.ietf.org/html/rfc7512).
|
||||||
|
|
||||||
Pre-requisites:
|
# Pre-requisites (OpenSSL < 3.0):
|
||||||
|
|
||||||
OpenSSL defines an abstract layer called the "engine" to achieve cryptographic
|
OpenSSL 1.x defines an abstract layer called the "engine" to achieve
|
||||||
acceleration. The engine_pkcs11 module acts like an interface between the PKCS #11
|
cryptographic acceleration. The engine_pkcs11 module acts like an interface
|
||||||
modules and the OpenSSL engine.
|
between the PKCS #11 modules and the OpenSSL application.
|
||||||
|
|
||||||
To build and use libssh with PKCS #11 support:
|
To build and use libssh with PKCS #11 support:
|
||||||
1. Enable the cmake option: $ cmake -DWITH_PKCS11_URI=ON
|
1. Enable the cmake option: $ cmake -DWITH_PKCS11_URI=ON
|
||||||
@@ -21,6 +21,23 @@ To build and use libssh with PKCS #11 support:
|
|||||||
3. Install and configure engine_pkcs11 (https://github.com/OpenSC/libp11).
|
3. Install and configure engine_pkcs11 (https://github.com/OpenSC/libp11).
|
||||||
4. Plug in a working smart card or configure softhsm (https://www.opendnssec.org/softhsm).
|
4. Plug in a working smart card or configure softhsm (https://www.opendnssec.org/softhsm).
|
||||||
|
|
||||||
|
@warning The support for Engines was deprecated in OpenSSL 3.0 so this approach
|
||||||
|
is deprecated in libssh 0.11.x.
|
||||||
|
|
||||||
|
# Pre-requisites (OpenSSL 3.0.8+)
|
||||||
|
|
||||||
|
The OpenSSL 3.0 is deprecating usage of low-level engines in favor of high-level
|
||||||
|
"providers" to provide alternative implementation of cryptographic operations
|
||||||
|
or acceleration.
|
||||||
|
|
||||||
|
To build and use libssh with PKCS #11 support using OpenSSL providers:
|
||||||
|
1. Install and configure pkcs11 provider (https://github.com/latchset/pkcs11-provider).
|
||||||
|
2. Enable the cmake options: $ cmake -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
|
||||||
|
3. Build with OpenSSL.
|
||||||
|
4. Plug in a working smart card or configure softhsm (https://www.opendnssec.org/softhsm).
|
||||||
|
|
||||||
|
# New API functions
|
||||||
|
|
||||||
The functions ssh_pki_import_pubkey_file() and ssh_pki_import_privkey_file() that
|
The functions ssh_pki_import_pubkey_file() and ssh_pki_import_privkey_file() that
|
||||||
import the public and private keys from files respectively are now modified to support
|
import the public and private keys from files respectively are now modified to support
|
||||||
PKCS #11 URIs. These functions automatically detect if the provided filename is a file path
|
PKCS #11 URIs. These functions automatically detect if the provided filename is a file path
|
||||||
@@ -31,7 +48,7 @@ corresponding to the PKCS #11 URI are loaded from the PKCS #11 device.
|
|||||||
If you wish to authenticate using public keys on your own, follow the steps mentioned under
|
If you wish to authenticate using public keys on your own, follow the steps mentioned under
|
||||||
"Authentication with public keys" in Chapter 2 - A deeper insight into authentication.
|
"Authentication with public keys" in Chapter 2 - A deeper insight into authentication.
|
||||||
|
|
||||||
The function pki_uri_import() is used to populate the public/private ssh_key from the
|
The function pki_uri_import() is used to populate the public/private ssh_key from the
|
||||||
engine with PKCS #11 URIs as the look up.
|
engine with PKCS #11 URIs as the look up.
|
||||||
|
|
||||||
Here is a minimalistic example of public key authentication using PKCS #11 URIs:
|
Here is a minimalistic example of public key authentication using PKCS #11 URIs:
|
||||||
@@ -64,4 +81,6 @@ We recommend the users to provide a specific PKCS #11 URI so that it matches onl
|
|||||||
If the engine discovers multiple slots that could potentially contain the private keys referenced
|
If the engine discovers multiple slots that could potentially contain the private keys referenced
|
||||||
by the provided PKCS #11 URI, the engine will not try to authenticate.
|
by the provided PKCS #11 URI, the engine will not try to authenticate.
|
||||||
|
|
||||||
|
For testing, the SoftHSM PKCS#11 library is used.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|||||||
114
doc/sftp.dox
@@ -139,7 +139,7 @@ Unlike its equivalent in the SCP subsystem, this function does NOT change the
|
|||||||
current directory to the newly created subdirectory.
|
current directory to the newly created subdirectory.
|
||||||
|
|
||||||
|
|
||||||
@subsection sftp_write Copying a file to the remote computer
|
@subsection sftp_write Writing to a file on the remote computer
|
||||||
|
|
||||||
You handle the contents of a remote file just like you would do with a
|
You handle the contents of a remote file just like you would do with a
|
||||||
local file: you open the file in a given mode, move the file pointer in it,
|
local file: you open the file in a given mode, move the file pointer in it,
|
||||||
@@ -203,16 +203,14 @@ int sftp_helloworld(ssh_session session, sftp_session sftp)
|
|||||||
|
|
||||||
@subsection sftp_read Reading a file from the remote computer
|
@subsection sftp_read Reading a file from the remote computer
|
||||||
|
|
||||||
The nice thing with reading a file over the network through SFTP is that it
|
A synchronous read from a remote file is done using sftp_read(). This
|
||||||
can be done both in a synchronous way or an asynchronous way. If you read the file
|
section describes how to download a remote file using sftp_read(). The
|
||||||
asynchronously, your program can do something else while it waits for the
|
next section will discuss more about synchronous/asynchronous read/write
|
||||||
results to come.
|
operations using libssh sftp API.
|
||||||
|
|
||||||
Synchronous read is done with sftp_read().
|
|
||||||
|
|
||||||
Files are normally transferred in chunks. A good chunk size is 16 KB. The following
|
Files are normally transferred in chunks. A good chunk size is 16 KB. The following
|
||||||
example transfers the remote file "/etc/profile" in 16 KB chunks. For each chunk we
|
example transfers the remote file "/etc/profile" in 16 KB chunks. For each chunk we
|
||||||
request, sftp_read blocks till the data has been received:
|
request, sftp_read() blocks till the data has been received:
|
||||||
|
|
||||||
@code
|
@code
|
||||||
// Good chunk size
|
// Good chunk size
|
||||||
@@ -273,87 +271,39 @@ int sftp_read_sync(ssh_session session, sftp_session sftp)
|
|||||||
}
|
}
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
Asynchronous read is done in two steps, first sftp_async_read_begin(), which
|
@subsection sftp_aio Performing an asynchronous read/write on a file on the remote computer
|
||||||
returns a "request handle", and then sftp_async_read(), which uses that request handle.
|
|
||||||
If the file has been opened in nonblocking mode, then sftp_async_read()
|
|
||||||
might return SSH_AGAIN, which means that the request hasn't completed yet
|
|
||||||
and that the function should be called again later on. Otherwise,
|
|
||||||
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
|
sftp_read() performs a "synchronous" read operation on a remote file.
|
||||||
time the data is not ready yet, a counter is incremented.
|
This means that sftp_read() will first request the server to read some
|
||||||
|
data from the remote file and then would wait until the server response
|
||||||
|
containing data to read (or an error) arrives at the client side.
|
||||||
|
|
||||||
@code
|
sftp_write() performs a "synchronous" write operation on a remote file.
|
||||||
// Good chunk size
|
This means that sftp_write() will first request the server to write some
|
||||||
#define MAX_XFER_BUF_SIZE 16384
|
data to the remote file and then would wait until the server response
|
||||||
|
containing information about the status of the write operation arrives at the
|
||||||
|
client side.
|
||||||
|
|
||||||
int sftp_read_async(ssh_session session, sftp_session sftp)
|
If your client program wants to do something other than waiting for the
|
||||||
{
|
response after requesting a read/write, the synchronous sftp_read() and
|
||||||
int access_type;
|
sftp_write() can't be used. In such a case the "asynchronous" sftp aio API
|
||||||
sftp_file file;
|
should be used.
|
||||||
char buffer[MAX_XFER_BUF_SIZE];
|
|
||||||
int async_request;
|
|
||||||
int nbytes;
|
|
||||||
long counter;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
access_type = O_RDONLY;
|
Please go through @ref libssh_tutor_sftp_aio for a detailed description
|
||||||
file = sftp_open(sftp, "some_very_big_file",
|
of the sftp aio API.
|
||||||
access_type, 0);
|
|
||||||
if (file == NULL) {
|
|
||||||
fprintf(stderr, "Can't open file for reading: %s\n",
|
|
||||||
ssh_get_error(session));
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
sftp_file_set_nonblocking(file);
|
|
||||||
|
|
||||||
async_request = sftp_async_read_begin(file, sizeof(buffer));
|
The sftp aio API provides two categories of functions :
|
||||||
counter = 0L;
|
- sftp_aio_begin_*() : For requesting a read/write from the server.
|
||||||
usleep(10000);
|
- sftp_aio_wait_*() : For waiting for the response of a previously
|
||||||
if (async_request >= 0) {
|
issued read/write request from the server.
|
||||||
nbytes = sftp_async_read(file, buffer, sizeof(buffer),
|
|
||||||
async_request);
|
|
||||||
} else {
|
|
||||||
nbytes = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (nbytes > 0 || nbytes == SSH_AGAIN) {
|
Hence, the client program can call sftp_aio_begin_*() to request a read/write
|
||||||
if (nbytes > 0) {
|
and then can perform any number of operations (other than waiting) before
|
||||||
write(1, buffer, nbytes);
|
calling sftp_aio_wait_*() for waiting for the response of the previously
|
||||||
async_request = sftp_async_read_begin(file, sizeof(buffer));
|
issued request.
|
||||||
} else {
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
usleep(10000);
|
|
||||||
|
|
||||||
if (async_request >= 0) {
|
We call read/write operations performed in the manner described above as
|
||||||
nbytes = sftp_async_read(file, buffer, sizeof(buffer),
|
"asynchronous" read/write operations on a remote file.
|
||||||
async_request);
|
|
||||||
} else {
|
|
||||||
nbytes = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbytes < 0) {
|
|
||||||
fprintf(stderr, "Error while reading file: %s\n",
|
|
||||||
ssh_get_error(session));
|
|
||||||
sftp_close(file);
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("The counter has reached value: %ld\n", counter);
|
|
||||||
|
|
||||||
rc = sftp_close(file);
|
|
||||||
if (rc != SSH_OK) {
|
|
||||||
fprintf(stderr, "Can't close the read file: %s\n",
|
|
||||||
ssh_get_error(session));
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SSH_OK;
|
|
||||||
}
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
@subsection sftp_ls Listing the contents of a directory
|
@subsection sftp_ls Listing the contents of a directory
|
||||||
|
|
||||||
|
|||||||
705
doc/sftp_aio.dox
Normal file
@@ -0,0 +1,705 @@
|
|||||||
|
/**
|
||||||
|
|
||||||
|
@page libssh_tutor_sftp_aio Chapter 10: The SFTP asynchronous I/O
|
||||||
|
|
||||||
|
@section sftp_aio_api The SFTP asynchronous I/O
|
||||||
|
|
||||||
|
NOTE : Please read @ref libssh_tutor_sftp before reading this page. The
|
||||||
|
synchronous sftp_read() and sftp_write() have been described there.
|
||||||
|
|
||||||
|
SFTP AIO stands for "SFTP Asynchronous Input/Output". This API contains
|
||||||
|
functions which perform async read/write operations on remote files.
|
||||||
|
|
||||||
|
File transfers performed using the asynchronous sftp aio API can be
|
||||||
|
significantly faster than the file transfers performed using the synchronous
|
||||||
|
sftp read/write API (see sftp_read() and sftp_write()).
|
||||||
|
|
||||||
|
The sftp aio API functions are divided into two categories :
|
||||||
|
- sftp_aio_begin_*() [see sftp_aio_begin_read(), sftp_aio_begin_write()]:
|
||||||
|
These functions send a request for an i/o operation to the server and
|
||||||
|
provide the caller an sftp aio handle corresponding to the sent request.
|
||||||
|
|
||||||
|
- sftp_aio_wait_*() [see sftp_aio_wait_read(), sftp_aio_wait_write()]:
|
||||||
|
These functions wait for the server response corresponding to a previously
|
||||||
|
issued request. Which request ? the request corresponding to the sftp aio
|
||||||
|
handle supplied by the caller to these functions.
|
||||||
|
|
||||||
|
Conceptually, you can think of the sftp aio handle as a request identifier.
|
||||||
|
|
||||||
|
Technically, the sftp_aio_begin_*() functions dynamically allocate memory to
|
||||||
|
store information about the i/o request they send and provide the caller a
|
||||||
|
handle to this memory, we call this handle an sftp aio handle.
|
||||||
|
|
||||||
|
sftp_aio_wait_*() functions use the information stored in that memory (handled
|
||||||
|
by the caller supplied sftp aio handle) to identify a request, and then they
|
||||||
|
wait for that request's response. These functions also release the memory
|
||||||
|
handled by the caller supplied sftp aio handle (except when they return
|
||||||
|
SSH_AGAIN).
|
||||||
|
|
||||||
|
sftp_aio_free() can also be used to release the memory handled by an sftp aio
|
||||||
|
handle but unlike the sftp_aio_wait_*() functions, it doesn't wait for a
|
||||||
|
response. This should be used to release the memory corresponding to an sftp
|
||||||
|
aio handle when some failure occurs. An example has been provided at the
|
||||||
|
end of this page to show the usage of sftp_aio_free().
|
||||||
|
|
||||||
|
To begin with, this tutorial will provide basic examples that describe the
|
||||||
|
usage of sftp aio API to perform a single read/write operation.
|
||||||
|
|
||||||
|
The later sections describe the usage of the sftp aio API to obtain faster file
|
||||||
|
transfers as compared to the transfers performed using the synchronous sftp
|
||||||
|
read/write API.
|
||||||
|
|
||||||
|
On encountering an error, the sftp aio API functions set the sftp and ssh
|
||||||
|
errors just like any other libssh sftp API function. These errors can be
|
||||||
|
obtained using sftp_get_error(), ssh_get_error() and ssh_get_error_code().
|
||||||
|
The code examples provided on this page ignore error handling for the sake of
|
||||||
|
brevity.
|
||||||
|
|
||||||
|
@subsection sftp_aio_read Using the sftp aio API for reading (a basic example)
|
||||||
|
|
||||||
|
For performing an async read operation on a sftp file (see sftp_open()),
|
||||||
|
the first step is to call sftp_aio_begin_read() to send a read request to the
|
||||||
|
server. The caller is provided an sftp aio handle corresponding to the sent
|
||||||
|
read request.
|
||||||
|
|
||||||
|
The second step is to pass a pointer to this aio handle to
|
||||||
|
sftp_aio_wait_read(), this function waits for the server response which
|
||||||
|
indicates the success/failure of the read request. On success, the response
|
||||||
|
indicates EOF or contains the data read from the sftp file.
|
||||||
|
|
||||||
|
The following code example shows how a read operation can be performed
|
||||||
|
on an sftp file using the sftp aio API.
|
||||||
|
|
||||||
|
@code
|
||||||
|
ssize_t read_chunk(sftp_file file, void *buf, size_t to_read)
|
||||||
|
{
|
||||||
|
ssize_t bytes_requested, bytes_read;
|
||||||
|
|
||||||
|
// Variable to store an sftp aio handle
|
||||||
|
sftp_aio aio = NULL;
|
||||||
|
|
||||||
|
// Send a read request to the sftp server
|
||||||
|
bytes_requested = sftp_aio_begin_read(file, to_read, &aio);
|
||||||
|
if (bytes_requested == SSH_ERROR) {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here its possible that (bytes_requested < to_read) as specified in
|
||||||
|
// the function documentation of sftp_aio_begin_read()
|
||||||
|
|
||||||
|
// Wait for the response of the read request corresponding to the
|
||||||
|
// sftp aio handle stored in the aio variable.
|
||||||
|
bytes_read = sftp_aio_wait_read(&aio, buf, to_read);
|
||||||
|
if (bytes_read == SSH_ERROR) {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@subsection sftp_aio_write Using the sftp aio API for writing (a basic example)
|
||||||
|
|
||||||
|
For performing an async write operation on a sftp file (see sftp_open()),
|
||||||
|
the first step is to call sftp_aio_begin_write() to send a write request to
|
||||||
|
the server. The caller is provided an sftp aio handle corresponding to the
|
||||||
|
sent write request.
|
||||||
|
|
||||||
|
The second step is to pass a pointer to this aio handle to
|
||||||
|
sftp_aio_wait_write(), this function waits for the server response which
|
||||||
|
indicates the success/failure of the write request.
|
||||||
|
|
||||||
|
The following code example shows how a write operation can be performed on an
|
||||||
|
sftp file using the sftp aio API.
|
||||||
|
|
||||||
|
@code
|
||||||
|
ssize_t write_chunk(sftp_file file, void *buf, size_t to_write)
|
||||||
|
{
|
||||||
|
ssize_t bytes_requested, bytes_written;
|
||||||
|
|
||||||
|
// Variable to store an sftp aio handle
|
||||||
|
sftp_aio aio = NULL;
|
||||||
|
|
||||||
|
// Send a write request to the sftp server
|
||||||
|
bytes_requested = sftp_aio_begin_write(file, buf, to_write, &aio);
|
||||||
|
if (bytes_requested == SSH_ERROR) {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here its possible that (bytes_requested < to_write) as specified in
|
||||||
|
// the function documentation of sftp_aio_begin_write()
|
||||||
|
|
||||||
|
// Wait for the response of the write request corresponding to
|
||||||
|
// the sftp aio handle stored in the aio variable.
|
||||||
|
bytes_written = sftp_aio_wait_write(&aio);
|
||||||
|
if (bytes_written == SSH_ERROR) {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes_written;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@subsection sftp_aio_actual_use Using the sftp aio API to speed up a transfer
|
||||||
|
|
||||||
|
The above examples were provided to introduce the sftp aio API.
|
||||||
|
This is not how the sftp aio API is intended to be used, because the
|
||||||
|
above usage offers no advantage over the synchronous sftp read/write API
|
||||||
|
which does the same thing i.e issue a request and then immediately wait for
|
||||||
|
its response.
|
||||||
|
|
||||||
|
The facility that the sftp aio API provides is that the user can do
|
||||||
|
anything between issuing a request and getting the corresponding response.
|
||||||
|
Any number of operations can be performed after calling sftp_aio_begin_*()
|
||||||
|
[which issues a request] and before calling sftp_aio_wait_*() [which waits
|
||||||
|
for a response]
|
||||||
|
|
||||||
|
The code can leverage this feature by calling sftp_aio_begin_*() multiple times
|
||||||
|
to issue multiple requests before calling sftp_aio_wait_*() to wait for the
|
||||||
|
response of an earlier issued request. This approach will keep a certain number
|
||||||
|
of requests outstanding at the client side.
|
||||||
|
|
||||||
|
After issuing those requests, while the client code does something else (for
|
||||||
|
example waiting for an outstanding request's response, processing an obtained
|
||||||
|
response, issuing another request or any other operation the client wants
|
||||||
|
to perform), at the same time :
|
||||||
|
|
||||||
|
- Some of those outstanding requests may be travelling over the
|
||||||
|
network towards the server.
|
||||||
|
|
||||||
|
- Some of the outstanding requests may have reached the server and may
|
||||||
|
be queued for processing at the server side.
|
||||||
|
|
||||||
|
- Some of the outstanding requests may have been processed and the
|
||||||
|
corresponding responses may be travelling over the network towards the
|
||||||
|
client.
|
||||||
|
|
||||||
|
- Some of the responses corresponding to the outstanding requests may
|
||||||
|
have already reached the client side.
|
||||||
|
|
||||||
|
Clearly in this case, operations that the client performs and operations
|
||||||
|
involved in transfer/processing of a outstanding request can occur in
|
||||||
|
parallel. Also, operations involved in transfer/processing of two or more
|
||||||
|
outstanding requests may also occur in parallel (for example when one request
|
||||||
|
travels to the server, another request's response may be incoming towards the
|
||||||
|
client). Such kind of parallelism makes the overall transfer faster as compared
|
||||||
|
to a transfer performed using the synchronous sftp read/write API.
|
||||||
|
|
||||||
|
When the synchronous sftp read/write API is used to perform a transfer,
|
||||||
|
a strict sequence is followed:
|
||||||
|
|
||||||
|
- The client issues a single read/write request.
|
||||||
|
- Then waits for its response.
|
||||||
|
- On obtaining the response, the client processes it.
|
||||||
|
- After the processing ends, the client issues the next read/write request.
|
||||||
|
|
||||||
|
A file transfer performed in this manner would be slower than the case where
|
||||||
|
multiple read/write requests are kept outstanding at the client side. Because
|
||||||
|
here at any given time, operations related to transfer/processing of only one
|
||||||
|
request/response pair occurs. This is in contrast to the multiple outstanding
|
||||||
|
requests scenario where operations related to transfer/processing of multiple
|
||||||
|
request/response pairs may occur at the same time.
|
||||||
|
|
||||||
|
Although it's true that keeping multiple requests outstanding can speed up a
|
||||||
|
transfer, those outstanding requests come at a cost of increased memory
|
||||||
|
consumption both at the client side and the server side. Hence care must be
|
||||||
|
taken to use a reasonable limit for the number of requests kept outstanding.
|
||||||
|
|
||||||
|
The further sections provide code examples to show how uploads/downloads
|
||||||
|
can be performed using the sftp aio API and the concept of outstanding requests
|
||||||
|
discussed in this section. In those code examples, error handling has been
|
||||||
|
ignored and at some places pseudo code has been used for the sake of brevity.
|
||||||
|
|
||||||
|
The complete code for performing uploads/downloads using the sftp aio API,
|
||||||
|
can be found at https://gitlab.com/libssh/libssh-mirror/-/tree/master.
|
||||||
|
|
||||||
|
- libssh benchmarks for uploads performed using the sftp aio API [See
|
||||||
|
tests/benchmarks/bench_sftp.c]
|
||||||
|
- libssh benchmarks for downloads performed using the sftp aio API. [See
|
||||||
|
tests/benchmarks/bench_sftp.c]
|
||||||
|
- libssh sftp ft API code for performing a local to remote transfer (upload).
|
||||||
|
[See src/sftp_ft.c]
|
||||||
|
- libssh sftp ft API code for performing a remote to local transfer
|
||||||
|
(download). [See src/sftp_ft.c]
|
||||||
|
|
||||||
|
@subsection sftp_aio_cap Capping applied by the sftp aio API
|
||||||
|
|
||||||
|
Before the code examples for uploads and downloads, its important
|
||||||
|
to know about the capping applied by the sftp aio API.
|
||||||
|
|
||||||
|
sftp_aio_begin_read() caps the number of bytes the caller can request
|
||||||
|
to read from the remote file. That cap is the value of the max_read_length
|
||||||
|
field of the sftp_limits_t returned by sftp_limits(). Say that cap is LIM
|
||||||
|
and the caller passes x as the number of bytes to read to
|
||||||
|
sftp_aio_begin_read(), then (assuming no error occurs) :
|
||||||
|
|
||||||
|
- if x <= LIM, then sftp_aio_begin_read() will request the server
|
||||||
|
to read x bytes from the remote file, and will return x.
|
||||||
|
|
||||||
|
- if x > LIM, then sftp_aio_begin_read() will request the server
|
||||||
|
to read LIM bytes from the remote file and will return LIM.
|
||||||
|
|
||||||
|
Hence to request server to read x bytes (> LIM), the caller would have
|
||||||
|
to call sftp_aio_begin_read() multiple times, typically in a loop and
|
||||||
|
break out of the loop when the summation of return values of the multiple
|
||||||
|
sftp_aio_begin_read() calls becomes equal to x.
|
||||||
|
|
||||||
|
For the sake of simplicity, the code example for download in the upcoming
|
||||||
|
section would always ask sftp_aio_begin_read() to read x <= LIM bytes,
|
||||||
|
so that its return value is guaranteed to be x, unless an error occurs.
|
||||||
|
|
||||||
|
Similarly, sftp_aio_begin_write() caps the number of bytes the caller
|
||||||
|
can request to write to the remote file. That cap is the value of
|
||||||
|
max_write_length field of the sftp_limits_t returned by sftp_limits().
|
||||||
|
Say that cap is LIM and the caller passes x as the number of bytes to
|
||||||
|
write to sftp_aio_begin_write(), then (assuming no error occurs) :
|
||||||
|
|
||||||
|
- if x <= LIM, then sftp_aio_begin_write() will request the server
|
||||||
|
to write x bytes to the remote file, and will return x.
|
||||||
|
|
||||||
|
- if x > LIM, then sftp_aio_begin_write() will request the server
|
||||||
|
to write LIM bytes to the remote file and will return LIM.
|
||||||
|
|
||||||
|
Hence to request server to write x bytes (> LIM), the caller would have
|
||||||
|
to call sftp_aio_begin_write() multiple times, typically in a loop and
|
||||||
|
break out of the loop when the summation of return values of the multiple
|
||||||
|
sftp_aio_begin_write() calls becomes equal to x.
|
||||||
|
|
||||||
|
For the sake of simplicity, the code example for upload in the upcoming
|
||||||
|
section would always ask sftp_aio_begin_write() to write x <= LIM bytes,
|
||||||
|
so that its return value is guaranteed to be x, unless an error occurs.
|
||||||
|
|
||||||
|
@subsection sftp_aio_download_example Performing a download using the sftp aio API
|
||||||
|
|
||||||
|
Terminologies used in the following code snippets :
|
||||||
|
|
||||||
|
- sftp : The sftp_session opened using sftp_new() and initialised using
|
||||||
|
sftp_init()
|
||||||
|
|
||||||
|
- file : The sftp file handle of the remote file to download data
|
||||||
|
from. (See sftp_open())
|
||||||
|
|
||||||
|
- file_size : the size of the sftp file to download. This size can be obtained
|
||||||
|
by statting the remote file to download (e.g by using sftp_stat())
|
||||||
|
|
||||||
|
- We will need to maintain a queue which will be used to store the sftp aio
|
||||||
|
handles corresponding to the outstanding requests.
|
||||||
|
|
||||||
|
First, we issue the read requests while ensuring that their count
|
||||||
|
doesn't exceed a particular limit decided by us, and the number of bytes
|
||||||
|
requested don't exceed the size of the file to download.
|
||||||
|
|
||||||
|
@code
|
||||||
|
sftp_aio aio = NULL;
|
||||||
|
|
||||||
|
// Chunk size to use for the transfer
|
||||||
|
size_t chunk_size;
|
||||||
|
|
||||||
|
// For the limits structure that would be used
|
||||||
|
// by the code to set the chunk size
|
||||||
|
sftp_limits_t lim = NULL;
|
||||||
|
|
||||||
|
// Max number of requests to keep outstanding at a time
|
||||||
|
size_t in_flight_requests = 5;
|
||||||
|
|
||||||
|
// Number of bytes for which requests have been sent
|
||||||
|
size_t total_bytes_requested = 0;
|
||||||
|
|
||||||
|
// Number of bytes which have been downloaded
|
||||||
|
size_t bytes_downloaded = 0;
|
||||||
|
|
||||||
|
// Buffer to use for the download
|
||||||
|
char *buffer = NULL;
|
||||||
|
|
||||||
|
// Helper variables
|
||||||
|
size_t to_read;
|
||||||
|
ssize_t bytes_requested;
|
||||||
|
|
||||||
|
// Get the sftp limits
|
||||||
|
lim = sftp_limits(sftp);
|
||||||
|
if (lim == NULL) {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the chunk size for download = the max limit for reading
|
||||||
|
// The reason for this has been given in the "Capping applied by
|
||||||
|
// the sftp aio API" section (Its to make the code simpler)
|
||||||
|
//
|
||||||
|
// Assigning a size_t type variable a uint64_t type value here,
|
||||||
|
// theoretically could cause an overflow, but practically
|
||||||
|
// max_read_length would never exceed SIZE_MAX so its okay.
|
||||||
|
chunk_size = lim->max_read_length;
|
||||||
|
|
||||||
|
buffer = malloc(chunk_size);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
... // Code to open the remote file (to download) using sftp_open().
|
||||||
|
... // Code to stat the remote file's file size.
|
||||||
|
... // Code to open the local file in which downloaded data is to be stored.
|
||||||
|
... // Code to initialize the queue which will be used to store sftp aio
|
||||||
|
// handles.
|
||||||
|
|
||||||
|
for (i = 0;
|
||||||
|
i < in_flight_requests && total_bytes_requested < file_size;
|
||||||
|
++i) {
|
||||||
|
to_read = file_size - total_bytes_requested;
|
||||||
|
if (to_read > chunk_size) {
|
||||||
|
to_read = chunk_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue a read request
|
||||||
|
bytes_requested = sftp_aio_begin_read(file, to_read, &aio);
|
||||||
|
if (bytes_requested == SSH_ERROR) {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size_t)bytes_requested < to_read) {
|
||||||
|
// Should not happen for this code, as the to_read is <=
|
||||||
|
// max limit for reading (chunk size), so there is no reason
|
||||||
|
// for sftp_aio_begin_read() to return a lesser value.
|
||||||
|
}
|
||||||
|
|
||||||
|
total_bytes_requested += (size_t)bytes_requested;
|
||||||
|
|
||||||
|
// Pseudo code
|
||||||
|
ENQUEUE aio in the queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
At this point, at max in_flight_requests number of requests may be
|
||||||
|
outstanding. Now we wait for the response corresponding to the earliest
|
||||||
|
issued outstanding request.
|
||||||
|
|
||||||
|
On getting that response, we issue another read request if there are
|
||||||
|
still some bytes in the sftp file (to download) for which we haven't sent the
|
||||||
|
read request. (This happens when total_bytes_requested < file_size)
|
||||||
|
|
||||||
|
This issuing of another read request (under a condition) is done to
|
||||||
|
keep the number of outstanding requests equal to the value of the
|
||||||
|
in_flight_requests variable.
|
||||||
|
|
||||||
|
This process has to be repeated for every remaining outstanding request.
|
||||||
|
|
||||||
|
@code
|
||||||
|
while (the queue is not empty) {
|
||||||
|
// Pseudo code
|
||||||
|
aio = DEQUEUE an sftp aio handle from the queue of sftp aio handles;
|
||||||
|
|
||||||
|
// Wait for the response of the request corresponding to the aio
|
||||||
|
bytes_read = sftp_aio_wait_read(&aio, buffer, chunk_size);
|
||||||
|
if (bytes_read == SSH_ERROR) {
|
||||||
|
//handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_downloaded += bytes_read;
|
||||||
|
if (bytes_read != chunk_size && bytes_downloaded != file_size) {
|
||||||
|
// A short read encountered on the remote file before reaching EOF,
|
||||||
|
// short read before reaching EOF should never happen for the sftp aio
|
||||||
|
// API which respects the max limit for reading. This probably
|
||||||
|
// indicates a bad server.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pseudo code
|
||||||
|
WRITE bytes_read bytes from the buffer into the local file
|
||||||
|
in which downloaded data is to be stored ;
|
||||||
|
|
||||||
|
if (total_bytes_requested == file_size) {
|
||||||
|
// no need to issue more read requests
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// else issue a read request
|
||||||
|
to_read = file_size - total_bytes_requested;
|
||||||
|
if (to_read > chunk_size) {
|
||||||
|
to_read = chunk_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_requested = sftp_aio_begin_read(file, to_read, &aio);
|
||||||
|
if (bytes_requested == SSH_ERROR) {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size_t)bytes_requested < to_read) {
|
||||||
|
// Should not happen for this code, as the to_read is <=
|
||||||
|
// max limit for reading (chunk size), so there is no reason
|
||||||
|
// for sftp_aio_begin_read() to return a lesser value.
|
||||||
|
}
|
||||||
|
|
||||||
|
total_bytes_requested += bytes_requested;
|
||||||
|
|
||||||
|
// Pseudo code
|
||||||
|
ENQUEUE aio in the queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
sftp_limits_free(lim);
|
||||||
|
|
||||||
|
... // Code to destroy the queue which was used to store the sftp aio
|
||||||
|
// handles.
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
After exiting the while (the queue is not empty) loop, the download
|
||||||
|
would've been complete (assuming no error occurs).
|
||||||
|
|
||||||
|
@subsection sftp_aio_upload_example Performing an upload using the sftp aio API
|
||||||
|
|
||||||
|
Terminologies used in the following code snippets :
|
||||||
|
|
||||||
|
- sftp : The sftp_session opened using sftp_new() and initialised using
|
||||||
|
sftp_init()
|
||||||
|
|
||||||
|
- file : The sftp file handle of the remote file in which uploaded data
|
||||||
|
is to be stored. (See sftp_open())
|
||||||
|
|
||||||
|
- file_size : The size of the local file to upload. This size can be
|
||||||
|
obtained by statting the local file to upload (e.g by using stat())
|
||||||
|
|
||||||
|
- We will need maintain a queue which will be used to store the sftp aio
|
||||||
|
handles corresponding to the outstanding requests.
|
||||||
|
|
||||||
|
First, we issue the write requests while ensuring that their count
|
||||||
|
doesn't exceed a particular limit decided by us, and the number of bytes
|
||||||
|
requested to write don't exceed the size of the file to upload.
|
||||||
|
|
||||||
|
@code
|
||||||
|
sftp_aio aio = NULL;
|
||||||
|
|
||||||
|
// The chunk size to use for the transfer
|
||||||
|
size_t chunk_size;
|
||||||
|
|
||||||
|
// For the limits structure that would be used by
|
||||||
|
// the code to set the chunk size
|
||||||
|
sftp_limits_t lim = NULL;
|
||||||
|
|
||||||
|
// Max number of requests to keep outstanding at a time
|
||||||
|
size_t in_flight_requests = 5;
|
||||||
|
|
||||||
|
// Total number of bytes for which write requests have been sent
|
||||||
|
size_t total_bytes_requested = 0;
|
||||||
|
|
||||||
|
// Buffer to use for the upload
|
||||||
|
char *buffer = NULL;
|
||||||
|
|
||||||
|
// Helper variables
|
||||||
|
size_t to_write;
|
||||||
|
ssize_t bytes_requested;
|
||||||
|
|
||||||
|
// Get the sftp limits
|
||||||
|
lim = sftp_limits(sftp);
|
||||||
|
if (lim == NULL) {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the chunk size for upload = the max limit for writing.
|
||||||
|
// The reason for this has been given in the "Capping applied by
|
||||||
|
// the sftp aio API" section (Its to make the code simpler)
|
||||||
|
//
|
||||||
|
// Assigning a size_t type variable a uint64_t type value here,
|
||||||
|
// theoretically could cause an overflow, but practically
|
||||||
|
// max_write_length would never exceed SIZE_MAX so its okay.
|
||||||
|
chunk_size = lim->max_write_length;
|
||||||
|
|
||||||
|
buffer = malloc(chunk_size);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
... // Code to open the local file (to upload) [e.g using open(), fopen()].
|
||||||
|
... // Code to stat the local file's file size [e.g using stat()].
|
||||||
|
... // Code to open the remote file in which uploaded data will be stored [see
|
||||||
|
// sftp_open()].
|
||||||
|
... // Code to initialize the queue which will be used to store sftp aio
|
||||||
|
// handles.
|
||||||
|
|
||||||
|
for (i = 0;
|
||||||
|
i < in_flight_requests && total_bytes_requested < file_size;
|
||||||
|
++i) {
|
||||||
|
to_write = file_size - total_bytes_requested;
|
||||||
|
if (to_write > chunk_size) {
|
||||||
|
to_write = chunk_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pseudo code
|
||||||
|
READ to_write bytes from the local file (to upload) into the buffer;
|
||||||
|
|
||||||
|
bytes_requested = sftp_aio_begin_write(file, buffer, to_write, &aio);
|
||||||
|
if (bytes_requested == SSH_ERROR) {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size_t)bytes_requested < to_write) {
|
||||||
|
// Should not happen for this code, as the to_write is <=
|
||||||
|
// max limit for writing (chunk size), so there is no reason
|
||||||
|
// for sftp_aio_begin_write() to return a lesser value.
|
||||||
|
}
|
||||||
|
|
||||||
|
total_bytes_requested += (size_t)bytes_requested;
|
||||||
|
|
||||||
|
// Pseudo code
|
||||||
|
ENQUEUE aio in the queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
At this point, at max in_flight_requests number of requests may be
|
||||||
|
outstanding. Now we wait for the response corresponding to the earliest
|
||||||
|
issued outstanding request.
|
||||||
|
|
||||||
|
On getting that response, we issue another write request if there are
|
||||||
|
still some bytes in the local file (to upload) for which we haven't sent
|
||||||
|
the write request. (This happens when total_bytes_requested < file_size)
|
||||||
|
|
||||||
|
This issuing of another write request (under a condition) is done to
|
||||||
|
keep the number of outstanding requests equal to the value of the
|
||||||
|
in_flight_requests variable.
|
||||||
|
|
||||||
|
This process has to be repeated for every remaining outstanding request.
|
||||||
|
|
||||||
|
@code
|
||||||
|
while (the queue is not empty) {
|
||||||
|
// Pseudo code
|
||||||
|
aio = DEQUEUE an sftp aio handle from the queue of sftp aio handles;
|
||||||
|
|
||||||
|
// Wait for the response of the request corresponding to the aio
|
||||||
|
bytes_written = sftp_aio_wait_write(&aio);
|
||||||
|
if (bytes_written == SSH_ERROR) {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
// sftp_aio_wait_write() won't report a short write, so no need
|
||||||
|
// to check for a short write here.
|
||||||
|
|
||||||
|
if (total_bytes_requested == file_size) {
|
||||||
|
// no need to issue more write requests
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// else issue a write request
|
||||||
|
to_write = file_size - total_bytes_requested;
|
||||||
|
if (to_write > chunk_size) {
|
||||||
|
to_write = chunk_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pseudo code
|
||||||
|
READ to_write bytes from the local file (to upload) into a buffer;
|
||||||
|
|
||||||
|
bytes_requested = sftp_aio_begin_write(file, buffer, to_write, &aio);
|
||||||
|
if (bytes_requested == SSH_ERROR) {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size_t)bytes_requested < to_write) {
|
||||||
|
// Should not happen for this code, as the to_write is <=
|
||||||
|
// max limit for writing (chunk size), so there is no reason
|
||||||
|
// for sftp_aio_begin_write() to return a lesser value.
|
||||||
|
}
|
||||||
|
|
||||||
|
total_bytes_requested += (size_t)bytes_requested;
|
||||||
|
|
||||||
|
// Pseudo code
|
||||||
|
ENQUEUE aio in the queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
... // Code to destroy the queue which was used to store the sftp aio
|
||||||
|
// handles.
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
After exiting the while (the queue is not empty) loop, the upload
|
||||||
|
would've been complete (assuming no error occurs).
|
||||||
|
|
||||||
|
@subsection sftp_aio_free Example showing the usage of sftp_aio_free()
|
||||||
|
|
||||||
|
The purpose of sftp_aio_free() was discussed at the beginning of this page,
|
||||||
|
the following code example shows how it can be used during cleanup.
|
||||||
|
|
||||||
|
@code
|
||||||
|
void print_sftp_error(sftp_session sftp)
|
||||||
|
{
|
||||||
|
if (sftp == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "sftp error : %d\n", sftp_get_error(sftp));
|
||||||
|
fprintf(stderr, "ssh error : %s\n", ssh_get_error(sftp->session));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 0 on success, -1 on error
|
||||||
|
int write_strings(sftp_file file)
|
||||||
|
{
|
||||||
|
const char * strings[] = {
|
||||||
|
"This is the first string",
|
||||||
|
"This is the second string",
|
||||||
|
"This is the third string",
|
||||||
|
"This is the fourth string"
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t string_count = sizeof(strings) / sizeof(strings[0]);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
sftp_session sftp = NULL;
|
||||||
|
sftp_aio aio = NULL;
|
||||||
|
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (file == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
... // Code to initialize the queue which will be used to store sftp aio
|
||||||
|
// handles
|
||||||
|
|
||||||
|
sftp = file->sftp;
|
||||||
|
for (i = 0; i < string_count; ++i) {
|
||||||
|
rc = sftp_aio_begin_write(file,
|
||||||
|
strings[i],
|
||||||
|
strlen(strings[i]),
|
||||||
|
&aio);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
print_sftp_error(sftp);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pseudo code
|
||||||
|
ENQUEUE aio in the queue of sftp aio handles
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < string_count; ++i) {
|
||||||
|
// Pseudo code
|
||||||
|
aio = DEQUEUE an sftp aio handle from the queue of sftp aio handles;
|
||||||
|
|
||||||
|
rc = sftp_aio_wait_write(&aio);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
print_sftp_error(sftp);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
... // Code to destroy the queue in which sftp aio handles were
|
||||||
|
// stored
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
|
||||||
|
while (queue is not empty) {
|
||||||
|
// Pseudo code
|
||||||
|
aio = DEQUEUE an sftp aio handle from the queue of sftp aio handles;
|
||||||
|
|
||||||
|
sftp_aio_free(aio);
|
||||||
|
}
|
||||||
|
|
||||||
|
... // Code to destroy the queue in which sftp aio handles were
|
||||||
|
// stored.
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
*/
|
||||||
@@ -26,7 +26,7 @@ The code sample below achieves these tasks:
|
|||||||
@code
|
@code
|
||||||
int shell_session(ssh_session session)
|
int shell_session(ssh_session session)
|
||||||
{
|
{
|
||||||
ssh_channel channel;
|
ssh_channel channel = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
channel = ssh_channel_new(session);
|
channel = ssh_channel_new(session);
|
||||||
@@ -65,8 +65,17 @@ to as a "pty", for "pseudo-teletype". The remote processes won't see the
|
|||||||
difference with a real text-oriented terminal.
|
difference with a real text-oriented terminal.
|
||||||
|
|
||||||
If needed, you request the pty with the function ssh_channel_request_pty().
|
If needed, you request the pty with the function ssh_channel_request_pty().
|
||||||
Then you define its dimensions (number of rows and columns)
|
If you want define its dimensions (number of rows and columns),
|
||||||
with ssh_channel_change_pty_size().
|
call ssh_channel_request_pty_size() instead. It's also possible to change
|
||||||
|
the dimensions after creating the pty with ssh_channel_change_pty_size().
|
||||||
|
|
||||||
|
These two functions configure the pty using the same terminal modes that
|
||||||
|
stdin has. If stdin isn't a TTY, they use default modes that configure
|
||||||
|
the pty with in canonical mode and e.g. preserving CR and LF characters.
|
||||||
|
If you want to change the terminal modes used by the pty (e.g. to change
|
||||||
|
CRLF handling), use ssh_channel_request_pty_size_modes(). This function
|
||||||
|
accepts an additional "modes" buffer that is expected to contain encoded
|
||||||
|
terminal modes according to RFC 4254 section 8.
|
||||||
|
|
||||||
Be your session interactive or not, the next step is to request a
|
Be your session interactive or not, the next step is to request a
|
||||||
shell with ssh_channel_request_shell().
|
shell with ssh_channel_request_shell().
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2017 Jan-Lukas Wynen
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# that style
|
|
||||||
A plain, more modern HTML style for Doxygen
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
- Doxygen (tested with version 1.8.13)
|
|
||||||
- *optional*: a sass/scss compiler if you want to modify the style
|
|
||||||
|
|
||||||
## Simple usage
|
|
||||||
Tell Doxygen about the files for that style as shown in [doxyfile.conf](doxyfile.conf). You might need to adjust the
|
|
||||||
paths depending on where you installed that style.
|
|
||||||
When you run Doxygen, all files are copied into to generated HTML folder. So you don't need to keep the originals around
|
|
||||||
unless you want to re-generate the documentation.
|
|
||||||
|
|
||||||
## Advanced
|
|
||||||
that style uses a custom javascript to hack some nice stripes into some tables. It has to be loaded from HTML. Hence you need
|
|
||||||
to use the provided custom header. Since its default content may change when Doxygen is updated, there might be syntax error in
|
|
||||||
the generated HTML. If this is the case, you can remove the custom header (adjust your doxyfile.conf). This has no
|
|
||||||
disadvantages other than removing the stripes.
|
|
||||||
|
|
||||||
[that_style.css](that_style.css) was generated from the scss files in the folder [sass](sass). If you want to change the style,
|
|
||||||
use those files in order to have better control. For instance, you can easily change most colors by modifying the variables
|
|
||||||
in the beginning of [that_style.scss](sass/that_style.scss).
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
<!-- HTML header for doxygen 1.8.13-->
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
|
||||||
<meta name="generator" content="Doxygen $doxygenversion"/>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
||||||
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
|
|
||||||
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
|
|
||||||
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
|
|
||||||
<script type="text/javascript" src="$relpath^jquery.js"></script>
|
|
||||||
<script type="text/javascript" src="$relpath^dynsections.js"></script>
|
|
||||||
$treeview
|
|
||||||
$search
|
|
||||||
$mathjax
|
|
||||||
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
|
|
||||||
<script src="$relpath^striped_bg.js"></script>
|
|
||||||
$extrastylesheet
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
|
||||||
|
|
||||||
<!--BEGIN TITLEAREA-->
|
|
||||||
<div id="titlearea">
|
|
||||||
<table cellspacing="0" cellpadding="0">
|
|
||||||
<tbody>
|
|
||||||
<tr style="height: 56px;">
|
|
||||||
<!--BEGIN PROJECT_LOGO-->
|
|
||||||
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
|
|
||||||
<!--END PROJECT_LOGO-->
|
|
||||||
<!--BEGIN PROJECT_NAME-->
|
|
||||||
<td id="projectalign" style="padding-left: 0.5em;">
|
|
||||||
<div id="projectname">$projectname
|
|
||||||
<!--BEGIN PROJECT_NUMBER--> <span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
|
|
||||||
</div>
|
|
||||||
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
|
|
||||||
</td>
|
|
||||||
<!--END PROJECT_NAME-->
|
|
||||||
<!--BEGIN !PROJECT_NAME-->
|
|
||||||
<!--BEGIN PROJECT_BRIEF-->
|
|
||||||
<td style="padding-left: 0.5em;">
|
|
||||||
<div id="projectbrief">$projectbrief</div>
|
|
||||||
</td>
|
|
||||||
<!--END PROJECT_BRIEF-->
|
|
||||||
<!--END !PROJECT_NAME-->
|
|
||||||
<!--BEGIN DISABLE_INDEX-->
|
|
||||||
<!--BEGIN SEARCHENGINE-->
|
|
||||||
<td>$searchbox</td>
|
|
||||||
<!--END SEARCHENGINE-->
|
|
||||||
<!--END DISABLE_INDEX-->
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<!--END TITLEAREA-->
|
|
||||||
<!-- end header part -->
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="24"
|
|
||||||
height="22"
|
|
||||||
viewBox="0 0 6.3499999 5.8208335"
|
|
||||||
version="1.1"
|
|
||||||
id="svg8"
|
|
||||||
sodipodi:docname="doc.svg"
|
|
||||||
inkscape:version="0.92.1 r">
|
|
||||||
<defs
|
|
||||||
id="defs2" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1.0"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="32"
|
|
||||||
inkscape:cx="11.139212"
|
|
||||||
inkscape:cy="14.811193"
|
|
||||||
inkscape:document-units="mm"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:showpageshadow="false"
|
|
||||||
units="px"
|
|
||||||
inkscape:window-width="2560"
|
|
||||||
inkscape:window-height="1357"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="1" />
|
|
||||||
<metadata
|
|
||||||
id="metadata5">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title />
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(0,-291.17915)">
|
|
||||||
<path
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#4d4d4d;stroke-width:0.26458329;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="M 3.315043,291.8406 H 1.4552083 v 4.49792 h 3.1749999 v -3.10055 z"
|
|
||||||
id="path5095"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#4d4d4d;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 3.1837239,291.84114 v 1.71186 h 1.4472656 v -0.31418 H 3.4473958 v -1.39768 z"
|
|
||||||
id="path5128"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<rect
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="rect5132"
|
|
||||||
width="2.1166668"
|
|
||||||
height="0.26458332"
|
|
||||||
x="1.8520833"
|
|
||||||
y="293.82498" />
|
|
||||||
<rect
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="rect5136"
|
|
||||||
width="1.0583334"
|
|
||||||
height="0.26458332"
|
|
||||||
x="1.8520832"
|
|
||||||
y="294.35416" />
|
|
||||||
<rect
|
|
||||||
y="294.88333"
|
|
||||||
x="1.8520832"
|
|
||||||
height="0.26458332"
|
|
||||||
width="1.8520833"
|
|
||||||
id="rect5138"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
<rect
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="rect4543"
|
|
||||||
width="1.5875"
|
|
||||||
height="0.26458332"
|
|
||||||
x="1.8520832"
|
|
||||||
y="295.41248" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 6.5 KiB |
@@ -1,77 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="24"
|
|
||||||
height="22"
|
|
||||||
viewBox="0 0 6.3499998 5.8208335"
|
|
||||||
version="1.1"
|
|
||||||
id="svg8"
|
|
||||||
inkscape:version="0.92.1 r"
|
|
||||||
sodipodi:docname="folderclosed.svg"
|
|
||||||
inkscape:export-filename="/home/jl/Prog/doxygen_style/folderclosed.png"
|
|
||||||
inkscape:export-xdpi="96"
|
|
||||||
inkscape:export-ydpi="96">
|
|
||||||
<defs
|
|
||||||
id="defs2" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1.0"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="51.113139"
|
|
||||||
inkscape:cx="7.7057751"
|
|
||||||
inkscape:cy="12.584171"
|
|
||||||
inkscape:document-units="mm"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:snap-global="false"
|
|
||||||
units="px"
|
|
||||||
inkscape:showpageshadow="false"
|
|
||||||
inkscape:window-width="2560"
|
|
||||||
inkscape:window-height="1357"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:measure-start="0,0"
|
|
||||||
inkscape:measure-end="0,0" />
|
|
||||||
<metadata
|
|
||||||
id="metadata5">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title />
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(0,-291.17915)">
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 0.52916667,292.2374 -0.26458334,0.52925 v 3.43958 H 4.7625001 v -3.43958 H 2.38125 L 2.1166667,292.2374 Z"
|
|
||||||
id="rect4498"
|
|
||||||
sodipodi:nodetypes="cccccccc" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.66145831;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="M 2.9104167,292.76665 2.38125,293.56034 H 0.26458333 v 0.26464 H 2.38125 l 0.5291667,-0.79375 h 1.8520834 v -0.26458 z"
|
|
||||||
id="rect4500"
|
|
||||||
sodipodi:nodetypes="ccccccccc" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.4 KiB |
@@ -1,83 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="24"
|
|
||||||
height="22"
|
|
||||||
viewBox="0 0 6.3499998 5.8208335"
|
|
||||||
version="1.1"
|
|
||||||
id="svg8"
|
|
||||||
inkscape:version="0.92.1 r"
|
|
||||||
sodipodi:docname="folderopen.svg"
|
|
||||||
inkscape:export-filename="/home/jl/Prog/doxygen_style/folderopen.png"
|
|
||||||
inkscape:export-xdpi="96"
|
|
||||||
inkscape:export-ydpi="96">
|
|
||||||
<defs
|
|
||||||
id="defs2" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1.0"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="43.725861"
|
|
||||||
inkscape:cx="8.2043861"
|
|
||||||
inkscape:cy="13.464183"
|
|
||||||
inkscape:document-units="mm"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:snap-global="false"
|
|
||||||
units="px"
|
|
||||||
inkscape:showpageshadow="false"
|
|
||||||
inkscape:window-width="2560"
|
|
||||||
inkscape:window-height="1357"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:measure-start="0,0"
|
|
||||||
inkscape:measure-end="0,0" />
|
|
||||||
<metadata
|
|
||||||
id="metadata5">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title />
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(0,-291.17915)">
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.66145831;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 0.52916667,292.23748 -0.26458334,0.52917 v 3.43958 H 4.762461 l 7.8e-5,-3.43958 H 2.38125 l -0.2645833,-0.52917 z"
|
|
||||||
id="path5228"
|
|
||||||
sodipodi:nodetypes="cccccccc" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path5279"
|
|
||||||
d="M 1.0583333,293.5604 H 5.55625 L 4.7625,296.20603 H 0.26458333 Z"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ececec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.66145831;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
sodipodi:nodetypes="ccccc" />
|
|
||||||
<path
|
|
||||||
sodipodi:nodetypes="ccccccc"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path5234"
|
|
||||||
d="M 1.0583333,294.35415 H 3.175 l 0.5291667,-0.52917 H 5.55625 L 4.7625,296.20603 H 0.26458333 Z"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.66145831;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 4.1 KiB |
@@ -1,73 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="22"
|
|
||||||
height="22"
|
|
||||||
viewBox="0 0 5.8208332 5.8208335"
|
|
||||||
version="1.1"
|
|
||||||
id="svg8"
|
|
||||||
inkscape:version="0.92.1 r"
|
|
||||||
sodipodi:docname="mag_glass.svg">
|
|
||||||
<defs
|
|
||||||
id="defs2" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1.0"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="32"
|
|
||||||
inkscape:cx="8.961936"
|
|
||||||
inkscape:cy="10.205344"
|
|
||||||
inkscape:document-units="mm"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
units="px"
|
|
||||||
inkscape:showpageshadow="false"
|
|
||||||
inkscape:snap-bbox="false"
|
|
||||||
inkscape:bbox-nodes="true"
|
|
||||||
inkscape:window-width="2560"
|
|
||||||
inkscape:window-height="1357"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:snap-global="false" />
|
|
||||||
<metadata
|
|
||||||
id="metadata5">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(0,-291.17915)">
|
|
||||||
<path
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#333333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="M 6.9101562 2.4082031 C 3.1105656 2.4082031 -5.9211895e-16 5.5081643 0 9.3027344 C 0 13.097342 3.1105656 16.197266 6.9101562 16.197266 C 8.2869348 16.197266 9.5698699 15.787508 10.650391 15.087891 L 15.162109 19.587891 L 16.636719 18.115234 L 12.214844 13.707031 C 13.214837 12.510659 13.818359 10.974238 13.818359 9.3027344 C 13.818359 5.5081643 10.709747 2.4082031 6.9101562 2.4082031 z M 6.9101562 4.9101562 C 9.3624717 4.9101562 11.324219 6.8631249 11.324219 9.3027344 C 11.324219 11.742382 9.3624717 13.695312 6.9101562 13.695312 C 4.4578408 13.695312 2.5019531 11.742382 2.5019531 9.3027344 C 2.5019531 6.8631249 4.4578408 4.9101562 6.9101562 4.9101562 z "
|
|
||||||
transform="matrix(0.26458333,0,0,0.26458333,0,291.17915)"
|
|
||||||
id="rect4524" />
|
|
||||||
<path
|
|
||||||
transform="matrix(0.99422295,0,0,0.68955299,-0.83134947,91.755588)"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#333333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.63466448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
inkscape:transform-center-y="0.25905895"
|
|
||||||
d="m 5.6074138,294.49889 -1.0836583,-1.87695 2.1673165,0 z"
|
|
||||||
id="path4491" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.8 KiB |
@@ -1,73 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="10.53333"
|
|
||||||
height="32"
|
|
||||||
viewBox="0 0 9.8749964 30"
|
|
||||||
id="svg2"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.92.1 r"
|
|
||||||
sodipodi:docname="nav_edge_inter.svg">
|
|
||||||
<defs
|
|
||||||
id="defs4" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1.0"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="32"
|
|
||||||
inkscape:cx="8.6823304"
|
|
||||||
inkscape:cy="16.225639"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
units="px"
|
|
||||||
inkscape:snap-bbox="true"
|
|
||||||
inkscape:bbox-paths="false"
|
|
||||||
inkscape:bbox-nodes="true"
|
|
||||||
inkscape:snap-bbox-edge-midpoints="true"
|
|
||||||
inkscape:object-nodes="true"
|
|
||||||
inkscape:window-width="2560"
|
|
||||||
inkscape:window-height="1357"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="1" />
|
|
||||||
<metadata
|
|
||||||
id="metadata7">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(0,-1022.3622)">
|
|
||||||
<path
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 0,1022.3622 v 15 15 l 8,-15 z"
|
|
||||||
id="path4143"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#333333;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.9375px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 1.2910156,1022.3496 -0.82421872,0.4473 7.87890622,14.5527 -7.87890622,14.5527 0.82421872,0.4473 8.1210938,-15 z"
|
|
||||||
id="path5240"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.8 KiB |
@@ -1,73 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="8.5333338"
|
|
||||||
height="32"
|
|
||||||
viewBox="0 0 8.0000001 30"
|
|
||||||
id="svg2"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.92.1 r"
|
|
||||||
sodipodi:docname="nav_edge_left.svg">
|
|
||||||
<defs
|
|
||||||
id="defs4" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1.0"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="32"
|
|
||||||
inkscape:cx="5.3721385"
|
|
||||||
inkscape:cy="14.16429"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
units="px"
|
|
||||||
inkscape:snap-bbox="true"
|
|
||||||
inkscape:bbox-paths="false"
|
|
||||||
inkscape:bbox-nodes="false"
|
|
||||||
inkscape:snap-bbox-edge-midpoints="false"
|
|
||||||
inkscape:object-nodes="true"
|
|
||||||
inkscape:window-width="2560"
|
|
||||||
inkscape:window-height="1357"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="1" />
|
|
||||||
<metadata
|
|
||||||
id="metadata7">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(0,-1022.3622)">
|
|
||||||
<path
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="M 0 0 L 0 32 L 8.5332031 16 L 0 0 z "
|
|
||||||
transform="matrix(0.93749998,0,0,0.93749998,0,1022.3622)"
|
|
||||||
id="rect4586" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 0,1022.3622 v 15 15 l 8,-15 z"
|
|
||||||
id="path4143"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.1 KiB |
@@ -1,73 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="8"
|
|
||||||
height="30"
|
|
||||||
viewBox="0 0 8.0000001 30"
|
|
||||||
id="svg2"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.91 r13725"
|
|
||||||
sodipodi:docname="nav_edge.svg">
|
|
||||||
<defs
|
|
||||||
id="defs4" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1.0"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="32"
|
|
||||||
inkscape:cx="5.3721385"
|
|
||||||
inkscape:cy="14.16429"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
units="px"
|
|
||||||
inkscape:snap-bbox="true"
|
|
||||||
inkscape:bbox-paths="false"
|
|
||||||
inkscape:bbox-nodes="false"
|
|
||||||
inkscape:snap-bbox-edge-midpoints="false"
|
|
||||||
inkscape:object-nodes="true"
|
|
||||||
inkscape:window-width="2560"
|
|
||||||
inkscape:window-height="1357"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="1" />
|
|
||||||
<metadata
|
|
||||||
id="metadata7">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(0,-1022.3622)">
|
|
||||||
<path
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 0,1022.3622 0,15 0,15 8,-15 -8,-15 z"
|
|
||||||
id="path4143"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 1e-8,1022.3622 7.99999999,15 0,-15 -8,0 z m 7.99999999,15 -8,15 8,0 0,-15 z"
|
|
||||||
id="rect4136"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.1 KiB |
@@ -1,120 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="6"
|
|
||||||
height="9"
|
|
||||||
viewBox="0 0 1.5875 2.3812501"
|
|
||||||
version="1.1"
|
|
||||||
id="svg8"
|
|
||||||
inkscape:version="0.92.1 r"
|
|
||||||
sodipodi:docname="splitbar_handle.svg">
|
|
||||||
<defs
|
|
||||||
id="defs2" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1.0"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="32"
|
|
||||||
inkscape:cx="8.7681488"
|
|
||||||
inkscape:cy="-2.7929517"
|
|
||||||
inkscape:document-units="mm"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
units="px"
|
|
||||||
inkscape:showpageshadow="false"
|
|
||||||
showguides="false"
|
|
||||||
inkscape:window-width="2560"
|
|
||||||
inkscape:window-height="1357"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="1">
|
|
||||||
<inkscape:grid
|
|
||||||
type="xygrid"
|
|
||||||
id="grid4487" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<metadata
|
|
||||||
id="metadata5">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(0,-294.61873)">
|
|
||||||
<rect
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="rect4485"
|
|
||||||
width="0.26458335"
|
|
||||||
height="0.26458332"
|
|
||||||
x="0.26458332"
|
|
||||||
y="294.8833" />
|
|
||||||
<rect
|
|
||||||
y="294.8833"
|
|
||||||
x="1.0583333"
|
|
||||||
height="0.26458332"
|
|
||||||
width="0.26458335"
|
|
||||||
id="rect4489"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
<rect
|
|
||||||
y="295.41248"
|
|
||||||
x="0.26458329"
|
|
||||||
height="0.26458332"
|
|
||||||
width="0.26458335"
|
|
||||||
id="rect4491"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
<rect
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="rect4493"
|
|
||||||
width="0.26458335"
|
|
||||||
height="0.26458332"
|
|
||||||
x="1.0583333"
|
|
||||||
y="295.41248" />
|
|
||||||
<rect
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="rect4495"
|
|
||||||
width="0.26458335"
|
|
||||||
height="0.26458332"
|
|
||||||
x="0.26458332"
|
|
||||||
y="295.94165" />
|
|
||||||
<rect
|
|
||||||
y="295.94165"
|
|
||||||
x="1.0583333"
|
|
||||||
height="0.26458332"
|
|
||||||
width="0.26458335"
|
|
||||||
id="rect4497"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
<rect
|
|
||||||
y="296.47079"
|
|
||||||
x="0.26458329"
|
|
||||||
height="0.26458332"
|
|
||||||
width="0.26458335"
|
|
||||||
id="rect4499"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
<rect
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="rect4501"
|
|
||||||
width="0.26458335"
|
|
||||||
height="0.26458332"
|
|
||||||
x="1.0583333"
|
|
||||||
y="296.47079" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 483 B |
|
Before Width: | Height: | Size: 488 B |
@@ -1,32 +0,0 @@
|
|||||||
// Adds extra CSS classes "even" and "odd" to .memberdecls to allow
|
|
||||||
// striped backgrounds.
|
|
||||||
function MemberDeclsStriper () {
|
|
||||||
var counter = 0;
|
|
||||||
|
|
||||||
this.stripe = function() {
|
|
||||||
$(".memberdecls tbody").children().each(function(i) {
|
|
||||||
|
|
||||||
// reset counter at every heading -> always start with even
|
|
||||||
if ($(this).is(".heading")) {
|
|
||||||
counter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add extra classes
|
|
||||||
if (counter % 2 == 1) {
|
|
||||||
$(this).addClass("odd");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$(this).addClass("even");
|
|
||||||
}
|
|
||||||
|
|
||||||
// advance counter at every separator
|
|
||||||
// this is the only way to reliably detect which table rows belong together
|
|
||||||
if ($(this).is('[class^="separator"]')) {
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// execute the function
|
|
||||||
$(document).ready(new MemberDeclsStriper().stripe);
|
|
||||||
@@ -29,6 +29,12 @@ if (UNIX AND NOT WIN32)
|
|||||||
add_executable(samplesftp samplesftp.c ${examples_SRCS})
|
add_executable(samplesftp samplesftp.c ${examples_SRCS})
|
||||||
target_compile_options(samplesftp PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
target_compile_options(samplesftp PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||||
target_link_libraries(samplesftp ssh::ssh)
|
target_link_libraries(samplesftp ssh::ssh)
|
||||||
|
|
||||||
|
if (WITH_SERVER)
|
||||||
|
add_executable(sample_sftpserver sample_sftpserver.c ${examples_SRCS})
|
||||||
|
target_compile_options(sample_sftpserver PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||||
|
target_link_libraries(sample_sftpserver ssh::ssh ${ARGP_LIBRARIES})
|
||||||
|
endif (WITH_SERVER)
|
||||||
endif (WITH_SFTP)
|
endif (WITH_SFTP)
|
||||||
|
|
||||||
add_executable(ssh-client ssh_client.c ${examples_SRCS})
|
add_executable(ssh-client ssh_client.c ${examples_SRCS})
|
||||||
@@ -39,34 +45,34 @@ if (UNIX AND NOT WIN32)
|
|||||||
target_compile_options(ssh-X11-client PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
target_compile_options(ssh-X11-client PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||||
target_link_libraries(ssh-X11-client ssh::ssh)
|
target_link_libraries(ssh-X11-client ssh::ssh)
|
||||||
|
|
||||||
if (WITH_SERVER AND (ARGP_LIBRARY OR HAVE_ARGP_H))
|
if (WITH_SERVER AND (ARGP_LIBRARIES OR HAVE_ARGP_H))
|
||||||
if (HAVE_LIBUTIL)
|
if (HAVE_LIBUTIL)
|
||||||
add_executable(ssh_server_fork ssh_server.c)
|
add_executable(ssh_server_fork ssh_server.c)
|
||||||
target_compile_options(ssh_server_fork PRIVATE ${DEFAULT_C_COMPILE_FLAGS} -DWITH_FORK)
|
target_compile_options(ssh_server_fork PRIVATE ${DEFAULT_C_COMPILE_FLAGS} -DWITH_FORK)
|
||||||
target_link_libraries(ssh_server_fork ssh::ssh ${ARGP_LIBRARY} util)
|
target_link_libraries(ssh_server_fork ssh::ssh ${ARGP_LIBRARIES} util)
|
||||||
|
|
||||||
add_executable(ssh_server_pthread ssh_server.c)
|
add_executable(ssh_server_pthread ssh_server.c)
|
||||||
target_compile_options(ssh_server_pthread PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
target_compile_options(ssh_server_pthread PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||||
target_link_libraries(ssh_server_pthread ssh::ssh ${ARGP_LIBRARY} pthread util)
|
target_link_libraries(ssh_server_pthread ssh::ssh ${ARGP_LIBRARIES} pthread util)
|
||||||
endif (HAVE_LIBUTIL)
|
endif (HAVE_LIBUTIL)
|
||||||
|
|
||||||
if (WITH_GSSAPI AND GSSAPI_FOUND)
|
if (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||||
add_executable(proxy proxy.c)
|
add_executable(proxy proxy.c)
|
||||||
target_compile_options(proxy PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
target_compile_options(proxy PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||||
target_link_libraries(proxy ssh::ssh ${ARGP_LIBRARY})
|
target_link_libraries(proxy ssh::ssh ${ARGP_LIBRARIES})
|
||||||
|
|
||||||
add_executable(sshd_direct-tcpip sshd_direct-tcpip.c)
|
add_executable(sshd_direct-tcpip sshd_direct-tcpip.c)
|
||||||
target_compile_options(sshd_direct-tcpip PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
target_compile_options(sshd_direct-tcpip PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||||
target_link_libraries(sshd_direct-tcpip ssh::ssh ${ARGP_LIBRARY})
|
target_link_libraries(sshd_direct-tcpip ssh::ssh ${ARGP_LIBRARIES})
|
||||||
endif (WITH_GSSAPI AND GSSAPI_FOUND)
|
endif (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||||
|
|
||||||
add_executable(samplesshd-kbdint samplesshd-kbdint.c)
|
add_executable(samplesshd-kbdint samplesshd-kbdint.c)
|
||||||
target_compile_options(samplesshd-kbdint PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
target_compile_options(samplesshd-kbdint PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||||
target_link_libraries(samplesshd-kbdint ssh::ssh ${ARGP_LIBRARY})
|
target_link_libraries(samplesshd-kbdint ssh::ssh ${ARGP_LIBRARIES})
|
||||||
|
|
||||||
add_executable(keygen2 keygen2.c ${examples_SRCS})
|
add_executable(keygen2 keygen2.c ${examples_SRCS})
|
||||||
target_compile_options(keygen2 PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
target_compile_options(keygen2 PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||||
target_link_libraries(keygen2 ssh::ssh ${ARGP_LIBRARY})
|
target_link_libraries(keygen2 ssh::ssh ${ARGP_LIBRARIES})
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
endif (UNIX AND NOT WIN32)
|
endif (UNIX AND NOT WIN32)
|
||||||
@@ -75,9 +81,9 @@ if (WITH_SERVER)
|
|||||||
add_executable(samplesshd-cb samplesshd-cb.c)
|
add_executable(samplesshd-cb samplesshd-cb.c)
|
||||||
target_compile_options(samplesshd-cb PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
target_compile_options(samplesshd-cb PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||||
target_link_libraries(samplesshd-cb ssh::ssh)
|
target_link_libraries(samplesshd-cb ssh::ssh)
|
||||||
if (ARGP_LIBRARY OR HAVE_ARGP_H)
|
if (ARGP_LIBRARIES OR HAVE_ARGP_H)
|
||||||
target_link_libraries(samplesshd-cb ${ARGP_LIBRARY})
|
target_link_libraries(samplesshd-cb ${ARGP_LIBRARIES})
|
||||||
endif(ARGP_LIBRARY OR HAVE_ARGP_H)
|
endif(ARGP_LIBRARIES OR HAVE_ARGP_H)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(exec exec.c ${examples_SRCS})
|
add_executable(exec exec.c ${examples_SRCS})
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ int authenticate_kbdint(ssh_session session, const char *password)
|
|||||||
|
|
||||||
err = ssh_userauth_kbdint(session, NULL, NULL);
|
err = ssh_userauth_kbdint(session, NULL, NULL);
|
||||||
while (err == SSH_AUTH_INFO) {
|
while (err == SSH_AUTH_INFO) {
|
||||||
const char *instruction;
|
const char *instruction = NULL;
|
||||||
const char *name;
|
const char *name = NULL;
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
int i, n;
|
int i, n;
|
||||||
|
|
||||||
@@ -48,8 +48,8 @@ int authenticate_kbdint(ssh_session session, const char *password)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
const char *answer;
|
const char *answer = NULL;
|
||||||
const char *prompt;
|
const char *prompt = NULL;
|
||||||
char echo;
|
char echo;
|
||||||
|
|
||||||
prompt = ssh_userauth_kbdint_getprompt(session, i, &echo);
|
prompt = ssh_userauth_kbdint_getprompt(session, i, &echo);
|
||||||
@@ -58,7 +58,7 @@ int authenticate_kbdint(ssh_session session, const char *password)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (echo) {
|
if (echo) {
|
||||||
char *p;
|
char *p = NULL;
|
||||||
|
|
||||||
printf("%s", prompt);
|
printf("%s", prompt);
|
||||||
|
|
||||||
@@ -66,7 +66,6 @@ int authenticate_kbdint(ssh_session session, const char *password)
|
|||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[sizeof(buffer) - 1] = '\0';
|
|
||||||
if ((p = strchr(buffer, '\n'))) {
|
if ((p = strchr(buffer, '\n'))) {
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
}
|
}
|
||||||
@@ -75,7 +74,7 @@ int authenticate_kbdint(ssh_session session, const char *password)
|
|||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(buffer, 0, strlen(buffer));
|
memset(buffer, 0, sizeof(buffer));
|
||||||
} else {
|
} else {
|
||||||
if (password && strstr(prompt, "Password:")) {
|
if (password && strstr(prompt, "Password:")) {
|
||||||
answer = password;
|
answer = password;
|
||||||
@@ -143,11 +142,11 @@ int authenticate_console(ssh_session session)
|
|||||||
int rc;
|
int rc;
|
||||||
int method;
|
int method;
|
||||||
char password[128] = {0};
|
char password[128] = {0};
|
||||||
char *banner;
|
char *banner = NULL;
|
||||||
|
|
||||||
// Try to authenticate
|
// Try to authenticate
|
||||||
rc = ssh_userauth_none(session, NULL);
|
rc = ssh_userauth_none(session, NULL);
|
||||||
if (rc == SSH_AUTH_ERROR) {
|
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||||
error(session);
|
error(session);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -156,7 +155,7 @@ int authenticate_console(ssh_session session)
|
|||||||
while (rc != SSH_AUTH_SUCCESS) {
|
while (rc != SSH_AUTH_SUCCESS) {
|
||||||
if (method & SSH_AUTH_METHOD_GSSAPI_MIC){
|
if (method & SSH_AUTH_METHOD_GSSAPI_MIC){
|
||||||
rc = ssh_userauth_gssapi(session);
|
rc = ssh_userauth_gssapi(session);
|
||||||
if(rc == SSH_AUTH_ERROR) {
|
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||||
error(session);
|
error(session);
|
||||||
return rc;
|
return rc;
|
||||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||||
@@ -166,7 +165,7 @@ int authenticate_console(ssh_session session)
|
|||||||
// Try to authenticate with public key first
|
// Try to authenticate with public key first
|
||||||
if (method & SSH_AUTH_METHOD_PUBLICKEY) {
|
if (method & SSH_AUTH_METHOD_PUBLICKEY) {
|
||||||
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
|
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
|
||||||
if (rc == SSH_AUTH_ERROR) {
|
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||||
error(session);
|
error(session);
|
||||||
return rc;
|
return rc;
|
||||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||||
@@ -206,7 +205,7 @@ int authenticate_console(ssh_session session)
|
|||||||
// Try to authenticate with keyboard interactive";
|
// Try to authenticate with keyboard interactive";
|
||||||
if (method & SSH_AUTH_METHOD_INTERACTIVE) {
|
if (method & SSH_AUTH_METHOD_INTERACTIVE) {
|
||||||
rc = authenticate_kbdint(session, NULL);
|
rc = authenticate_kbdint(session, NULL);
|
||||||
if (rc == SSH_AUTH_ERROR) {
|
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||||
error(session);
|
error(session);
|
||||||
return rc;
|
return rc;
|
||||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||||
@@ -221,7 +220,7 @@ int authenticate_console(ssh_session session)
|
|||||||
// Try to authenticate with password
|
// Try to authenticate with password
|
||||||
if (method & SSH_AUTH_METHOD_PASSWORD) {
|
if (method & SSH_AUTH_METHOD_PASSWORD) {
|
||||||
rc = ssh_userauth_password(session, NULL, password);
|
rc = ssh_userauth_password(session, NULL, password);
|
||||||
if (rc == SSH_AUTH_ERROR) {
|
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||||
error(session);
|
error(session);
|
||||||
return rc;
|
return rc;
|
||||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||||
|
|||||||
@@ -21,47 +21,57 @@ clients must be made or how a client should react.
|
|||||||
#include "examples_common.h"
|
#include "examples_common.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
ssh_session connect_ssh(const char *host, const char *user,int verbosity){
|
ssh_session connect_ssh(const char *host, const char *port, const char *user, int verbosity)
|
||||||
ssh_session session;
|
{
|
||||||
int auth=0;
|
ssh_session session = NULL;
|
||||||
|
int auth = 0;
|
||||||
|
|
||||||
session=ssh_new();
|
session = ssh_new();
|
||||||
if (session == NULL) {
|
if (session == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
if(user != NULL){
|
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
|
|
||||||
ssh_free(session);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
|
if (user != NULL) {
|
||||||
ssh_free(session);
|
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
|
||||||
return NULL;
|
ssh_free(session);
|
||||||
}
|
return NULL;
|
||||||
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
}
|
||||||
if(ssh_connect(session)){
|
}
|
||||||
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
|
|
||||||
|
if (port != NULL) {
|
||||||
|
if (ssh_options_set(session, SSH_OPTIONS_PORT_STR, port) < 0) {
|
||||||
|
ssh_free(session);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
|
||||||
|
ssh_free(session);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||||
|
if (ssh_connect(session)) {
|
||||||
|
fprintf(stderr, "Connection failed : %s\n", ssh_get_error(session));
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (verify_knownhost(session) < 0) {
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
auth = authenticate_console(session);
|
||||||
|
if (auth == SSH_AUTH_SUCCESS) {
|
||||||
|
return session;
|
||||||
|
} else if (auth == SSH_AUTH_DENIED) {
|
||||||
|
fprintf(stderr, "Authentication failed\n");
|
||||||
|
} else {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error while authenticating : %s\n",
|
||||||
|
ssh_get_error(session));
|
||||||
|
}
|
||||||
ssh_disconnect(session);
|
ssh_disconnect(session);
|
||||||
ssh_free(session);
|
ssh_free(session);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
if(verify_knownhost(session)<0){
|
|
||||||
ssh_disconnect(session);
|
|
||||||
ssh_free(session);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
auth=authenticate_console(session);
|
|
||||||
if(auth==SSH_AUTH_SUCCESS){
|
|
||||||
return session;
|
|
||||||
} else if(auth==SSH_AUTH_DENIED){
|
|
||||||
fprintf(stderr,"Authentication failed\n");
|
|
||||||
} else {
|
|
||||||
fprintf(stderr,"Error while authenticating : %s\n",ssh_get_error(session));
|
|
||||||
}
|
|
||||||
ssh_disconnect(session);
|
|
||||||
ssh_free(session);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ clients must be made or how a client should react.
|
|||||||
#include <libssh/libssh.h>
|
#include <libssh/libssh.h>
|
||||||
|
|
||||||
/** Zero a structure */
|
/** Zero a structure */
|
||||||
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
|
#define ZERO_STRUCT(x) memset(&(x), 0, sizeof(x))
|
||||||
|
|
||||||
int authenticate_console(ssh_session session);
|
int authenticate_console(ssh_session session);
|
||||||
int authenticate_kbdint(ssh_session session, const char *password);
|
int authenticate_kbdint(ssh_session session, const char *password);
|
||||||
int verify_knownhost(ssh_session session);
|
int verify_knownhost(ssh_session session);
|
||||||
ssh_session connect_ssh(const char *hostname, const char *user, int verbosity);
|
ssh_session connect_ssh(const char *hostname, const char *port, const char *user, int verbosity);
|
||||||
|
|
||||||
#endif /* EXAMPLES_COMMON_H_ */
|
#endif /* EXAMPLES_COMMON_H_ */
|
||||||
|
|||||||
@@ -5,13 +5,13 @@
|
|||||||
#include "examples_common.h"
|
#include "examples_common.h"
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
ssh_session session;
|
ssh_session session = NULL;
|
||||||
ssh_channel channel;
|
ssh_channel channel = NULL;
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
int rbytes, wbytes, total = 0;
|
int rbytes, wbytes, total = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
session = connect_ssh("localhost", NULL, 0);
|
session = connect_ssh("localhost", NULL, NULL, 0);
|
||||||
if (session == NULL) {
|
if (session == NULL) {
|
||||||
ssh_finalize();
|
ssh_finalize();
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -27,14 +27,14 @@ int main(void)
|
|||||||
rv = ssh_pki_generate(SSH_KEYTYPE_ED25519, 0, &key);
|
rv = ssh_pki_generate(SSH_KEYTYPE_ED25519, 0, &key);
|
||||||
if (rv != SSH_OK) {
|
if (rv != SSH_OK) {
|
||||||
fprintf(stderr, "Failed to generate private key");
|
fprintf(stderr, "Failed to generate private key");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write it to a file testkey in the current dirrectory */
|
/* Write it to a file testkey in the current directory */
|
||||||
rv = ssh_pki_export_privkey_file(key, NULL, NULL, NULL, "testkey");
|
rv = ssh_pki_export_privkey_file(key, NULL, NULL, NULL, "testkey");
|
||||||
if (rv != SSH_OK) {
|
if (rv != SSH_OK) {
|
||||||
fprintf(stderr, "Failed to write private key file");
|
fprintf(stderr, "Failed to write private key file");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ struct arguments_st {
|
|||||||
unsigned long bits;
|
unsigned long bits;
|
||||||
char *file;
|
char *file;
|
||||||
char *passphrase;
|
char *passphrase;
|
||||||
|
char *format;
|
||||||
|
int action_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct argp_option options[] = {
|
static struct argp_option options[] = {
|
||||||
@@ -51,7 +53,6 @@ static struct argp_option options[] = {
|
|||||||
"Accepted values are: "
|
"Accepted values are: "
|
||||||
"1024, 2048, 3072 (default), 4096, and 8192 for TYPE=\"rsa\"; "
|
"1024, 2048, 3072 (default), 4096, and 8192 for TYPE=\"rsa\"; "
|
||||||
"256 (default), 384, and 521 for TYPE=\"ecdsa\"; "
|
"256 (default), 384, and 521 for TYPE=\"ecdsa\"; "
|
||||||
"1024 (default) and 2048 for TYPE=\"dsa\"; "
|
|
||||||
"can be omitted for TYPE=\"ed25519\" "
|
"can be omitted for TYPE=\"ed25519\" "
|
||||||
"(it will be ignored if provided).\n",
|
"(it will be ignored if provided).\n",
|
||||||
.group = 0
|
.group = 0
|
||||||
@@ -85,7 +86,25 @@ static struct argp_option options[] = {
|
|||||||
.flags = 0,
|
.flags = 0,
|
||||||
.doc = "The type of the key to be generated. "
|
.doc = "The type of the key to be generated. "
|
||||||
"Accepted values are: "
|
"Accepted values are: "
|
||||||
"\"rsa\", \"ecdsa\", \"ed25519\", and \"dsa\".\n",
|
"\"rsa\", \"ecdsa\", and \"ed25519\".\n",
|
||||||
|
.group = 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "list",
|
||||||
|
.key = 'l',
|
||||||
|
.arg = NULL,
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "List the Fingerprint of the given key\n",
|
||||||
|
.group = 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "format",
|
||||||
|
.key = 'm',
|
||||||
|
.arg = "FORMAT",
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "Write the file in specific format. The supported values are "
|
||||||
|
"'PEM'and 'OpenSSH' file format. By default Ed25519 "
|
||||||
|
"keys are exported in OpenSSH format and others in PEM.\n",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -144,9 +163,6 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
|
|||||||
if (!strcmp(arg, "rsa")) {
|
if (!strcmp(arg, "rsa")) {
|
||||||
arguments->type = SSH_KEYTYPE_RSA;
|
arguments->type = SSH_KEYTYPE_RSA;
|
||||||
}
|
}
|
||||||
else if (!strcmp(arg, "dsa")) {
|
|
||||||
arguments->type = SSH_KEYTYPE_DSS;
|
|
||||||
}
|
|
||||||
else if (!strcmp(arg, "ecdsa")) {
|
else if (!strcmp(arg, "ecdsa")) {
|
||||||
arguments->type = SSH_KEYTYPE_ECDSA;
|
arguments->type = SSH_KEYTYPE_ECDSA;
|
||||||
}
|
}
|
||||||
@@ -160,6 +176,12 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'l':
|
||||||
|
arguments->action_list = 1;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
arguments->format = strdup(arg);
|
||||||
|
break;
|
||||||
case ARGP_KEY_ARG:
|
case ARGP_KEY_ARG:
|
||||||
if (state->arg_num > 0) {
|
if (state->arg_num > 0) {
|
||||||
/* Too many arguments. */
|
/* Too many arguments. */
|
||||||
@@ -185,98 +207,80 @@ static int validate_args(struct arguments_st *args)
|
|||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(args->type) {
|
/* no other arguments needed for listing key fingerprints */
|
||||||
case SSH_KEYTYPE_RSA:
|
if (args->action_list) {
|
||||||
switch(args->bits) {
|
return 0;
|
||||||
case 0:
|
}
|
||||||
/* If not provided, use default value */
|
|
||||||
args->bits = 3072;
|
|
||||||
break;
|
|
||||||
case 1024:
|
|
||||||
case 2048:
|
|
||||||
case 3072:
|
|
||||||
case 4096:
|
|
||||||
case 8192:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Error: Invalid bits parameter provided\n");
|
|
||||||
rc = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args->file == NULL) {
|
|
||||||
args->file = strdup("id_rsa");
|
|
||||||
if (args->file == NULL) {
|
|
||||||
rc = ENOMEM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
switch (args->type) {
|
||||||
|
case SSH_KEYTYPE_RSA:
|
||||||
|
switch (args->bits) {
|
||||||
|
case 0:
|
||||||
|
/* If not provided, use default value */
|
||||||
|
args->bits = 3072;
|
||||||
break;
|
break;
|
||||||
case SSH_KEYTYPE_ECDSA:
|
case 1024:
|
||||||
switch(args->bits) {
|
case 2048:
|
||||||
case 0:
|
case 3072:
|
||||||
/* If not provided, use default value */
|
case 4096:
|
||||||
args->bits = 256;
|
case 8192:
|
||||||
break;
|
|
||||||
case 256:
|
|
||||||
case 384:
|
|
||||||
case 521:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Error: Invalid bits parameter provided\n");
|
|
||||||
rc = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (args->file == NULL) {
|
|
||||||
args->file = strdup("id_ecdsa");
|
|
||||||
if (args->file == NULL) {
|
|
||||||
rc = ENOMEM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case SSH_KEYTYPE_DSS:
|
|
||||||
switch(args->bits) {
|
|
||||||
case 0:
|
|
||||||
/* If not provided, use default value */
|
|
||||||
args->bits = 1024;
|
|
||||||
break;
|
|
||||||
case 1024:
|
|
||||||
case 2048:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Error: Invalid bits parameter provided\n");
|
|
||||||
rc = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (args->file == NULL) {
|
|
||||||
args->file = strdup("id_dsa");
|
|
||||||
if (args->file == NULL) {
|
|
||||||
rc = ENOMEM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case SSH_KEYTYPE_ED25519:
|
|
||||||
/* Ignore value and overwrite with a zero */
|
|
||||||
args->bits = 0;
|
|
||||||
|
|
||||||
if (args->file == NULL) {
|
|
||||||
args->file = strdup("id_ed25519");
|
|
||||||
if (args->file == NULL) {
|
|
||||||
rc = ENOMEM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "Error: unknown key type\n");
|
fprintf(stderr, "Error: Invalid bits parameter provided\n");
|
||||||
rc = EINVAL;
|
rc = EINVAL;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args->file == NULL) {
|
||||||
|
args->file = strdup("id_rsa");
|
||||||
|
if (args->file == NULL) {
|
||||||
|
rc = ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case SSH_KEYTYPE_ECDSA:
|
||||||
|
switch (args->bits) {
|
||||||
|
case 0:
|
||||||
|
/* If not provided, use default value */
|
||||||
|
args->bits = 256;
|
||||||
|
break;
|
||||||
|
case 256:
|
||||||
|
case 384:
|
||||||
|
case 521:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Error: Invalid bits parameter provided\n");
|
||||||
|
rc = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (args->file == NULL) {
|
||||||
|
args->file = strdup("id_ecdsa");
|
||||||
|
if (args->file == NULL) {
|
||||||
|
rc = ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case SSH_KEYTYPE_ED25519:
|
||||||
|
/* Ignore value and overwrite with a zero */
|
||||||
|
args->bits = 0;
|
||||||
|
|
||||||
|
if (args->file == NULL) {
|
||||||
|
args->file = strdup("id_ed25519");
|
||||||
|
if (args->file == NULL) {
|
||||||
|
rc = ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Error: unknown key type\n");
|
||||||
|
rc = EINVAL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@@ -289,6 +293,32 @@ static char doc[] = "Generate an SSH key pair. "
|
|||||||
/* Our argp parser */
|
/* Our argp parser */
|
||||||
static struct argp argp = {options, parse_opt, NULL, doc, NULL, NULL, NULL};
|
static struct argp argp = {options, parse_opt, NULL, doc, NULL, NULL, NULL};
|
||||||
|
|
||||||
|
static void
|
||||||
|
list_fingerprint(char *file)
|
||||||
|
{
|
||||||
|
ssh_key key = NULL;
|
||||||
|
unsigned char *hash = NULL;
|
||||||
|
size_t hlen = 0;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = ssh_pki_import_privkey_file(file, NULL, NULL, NULL, &key);
|
||||||
|
if (rc != SSH_OK) {
|
||||||
|
fprintf(stderr, "Failed to import private key %s\n", file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_get_publickey_hash(key, SSH_PUBLICKEY_HASH_SHA256, &hash, &hlen);
|
||||||
|
if (rc != SSH_OK) {
|
||||||
|
fprintf(stderr, "Failed to get key fingerprint\n");
|
||||||
|
ssh_key_free(key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ssh_print_hash(SSH_PUBLICKEY_HASH_SHA256, hash, hlen);
|
||||||
|
|
||||||
|
ssh_clean_pubkey_hash(&hash);
|
||||||
|
ssh_key_free(key);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
ssh_key key = NULL;
|
ssh_key key = NULL;
|
||||||
@@ -302,6 +332,7 @@ int main(int argc, char *argv[])
|
|||||||
.bits = 0,
|
.bits = 0,
|
||||||
.file = NULL,
|
.file = NULL,
|
||||||
.passphrase = NULL,
|
.passphrase = NULL,
|
||||||
|
.action_list = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
@@ -319,6 +350,16 @@ int main(int argc, char *argv[])
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arguments.file == NULL) {
|
||||||
|
fprintf(stderr, "Error: Missing argument file\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments.action_list) {
|
||||||
|
list_fingerprint(arguments.file);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
rc = open(arguments.file, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
|
rc = open(arguments.file, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
@@ -361,8 +402,36 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write the private key */
|
/* Write the private key */
|
||||||
rc = ssh_pki_export_privkey_file(key, arguments.passphrase, NULL, NULL,
|
if (arguments.format != NULL) {
|
||||||
arguments.file);
|
if (strcasecmp(arguments.format, "PEM") == 0) {
|
||||||
|
rc = ssh_pki_export_privkey_file_format(key,
|
||||||
|
arguments.passphrase,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
arguments.file,
|
||||||
|
SSH_FILE_FORMAT_PEM);
|
||||||
|
} else if (strcasecmp(arguments.format, "OpenSSH") == 0) {
|
||||||
|
rc = ssh_pki_export_privkey_file_format(key,
|
||||||
|
arguments.passphrase,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
arguments.file,
|
||||||
|
SSH_FILE_FORMAT_OPENSSH);
|
||||||
|
} else {
|
||||||
|
rc = ssh_pki_export_privkey_file_format(key,
|
||||||
|
arguments.passphrase,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
arguments.file,
|
||||||
|
SSH_FILE_FORMAT_DEFAULT);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rc = ssh_pki_export_privkey_file(key,
|
||||||
|
arguments.passphrase,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
arguments.file);
|
||||||
|
}
|
||||||
if (rc != SSH_OK) {
|
if (rc != SSH_OK) {
|
||||||
fprintf(stderr, "Error: Failed to write private key file");
|
fprintf(stderr, "Error: Failed to write private key file");
|
||||||
goto end;
|
goto end;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ int verify_knownhost(ssh_session session)
|
|||||||
char buf[10];
|
char buf[10];
|
||||||
unsigned char *hash = NULL;
|
unsigned char *hash = NULL;
|
||||||
size_t hlen;
|
size_t hlen;
|
||||||
ssh_key srv_pubkey;
|
ssh_key srv_pubkey = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = ssh_get_server_publickey(session, &srv_pubkey);
|
rc = ssh_get_server_publickey(session, &srv_pubkey);
|
||||||
|
|||||||
@@ -26,10 +26,11 @@ program.
|
|||||||
#define BUF_SIZE 16384
|
#define BUF_SIZE 16384
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static char **sources;
|
static char **sources = NULL;
|
||||||
static int nsources;
|
static int nsources;
|
||||||
static char *destination;
|
static char *destination = NULL;
|
||||||
static int verbosity = 0;
|
static int verbosity = 0;
|
||||||
|
static char *port = NULL;
|
||||||
|
|
||||||
struct location {
|
struct location {
|
||||||
int is_ssh;
|
int is_ssh;
|
||||||
@@ -49,9 +50,10 @@ enum {
|
|||||||
static void usage(const char *argv0) {
|
static void usage(const char *argv0) {
|
||||||
fprintf(stderr, "Usage : %s [options] [[user@]host1:]file1 ... \n"
|
fprintf(stderr, "Usage : %s [options] [[user@]host1:]file1 ... \n"
|
||||||
" [[user@]host2:]destination\n"
|
" [[user@]host2:]destination\n"
|
||||||
"sample scp client - libssh-%s\n",
|
"sample scp client - libssh-%s\n"
|
||||||
// "Options :\n",
|
"Options :\n"
|
||||||
// " -r : use RSA to verify host public key\n",
|
" -P : use port to connect to remote host\n"
|
||||||
|
" -v : increase verbosity of libssh. Can be used multiple times\n",
|
||||||
argv0,
|
argv0,
|
||||||
ssh_version(0));
|
ssh_version(0));
|
||||||
exit(0);
|
exit(0);
|
||||||
@@ -60,11 +62,14 @@ static void usage(const char *argv0) {
|
|||||||
static int opts(int argc, char **argv) {
|
static int opts(int argc, char **argv) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
while((i = getopt(argc, argv, "v")) != -1) {
|
while((i = getopt(argc, argv, "P:v")) != -1) {
|
||||||
switch(i) {
|
switch(i) {
|
||||||
case 'v':
|
case 'v':
|
||||||
verbosity++;
|
verbosity++;
|
||||||
break;
|
break;
|
||||||
|
case 'P':
|
||||||
|
port = optarg;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "unknown option %c\n", optopt);
|
fprintf(stderr, "unknown option %c\n", optopt);
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
@@ -114,9 +119,14 @@ static void location_free(struct location *loc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct location *parse_location(char *loc) {
|
static struct location *parse_location(char *loc)
|
||||||
struct location *location;
|
{
|
||||||
char *ptr;
|
struct location *location = NULL;
|
||||||
|
char *ptr = NULL;
|
||||||
|
|
||||||
|
if (loc == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
location = malloc(sizeof(struct location));
|
location = malloc(sizeof(struct location));
|
||||||
if (location == NULL) {
|
if (location == NULL) {
|
||||||
@@ -178,7 +188,7 @@ static void close_location(struct location *loc) {
|
|||||||
|
|
||||||
static int open_location(struct location *loc, int flag) {
|
static int open_location(struct location *loc, int flag) {
|
||||||
if (loc->is_ssh && flag == WRITE) {
|
if (loc->is_ssh && flag == WRITE) {
|
||||||
loc->session = connect_ssh(loc->host, loc->user, verbosity);
|
loc->session = connect_ssh(loc->host, port, loc->user, verbosity);
|
||||||
if (!loc->session) {
|
if (!loc->session) {
|
||||||
fprintf(stderr, "Couldn't connect to %s\n", loc->host);
|
fprintf(stderr, "Couldn't connect to %s\n", loc->host);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -204,7 +214,7 @@ static int open_location(struct location *loc, int flag) {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else if (loc->is_ssh && flag == READ) {
|
} else if (loc->is_ssh && flag == READ) {
|
||||||
loc->session = connect_ssh(loc->host, loc->user, verbosity);
|
loc->session = connect_ssh(loc->host, port, loc->user, verbosity);
|
||||||
if (!loc->session) {
|
if (!loc->session) {
|
||||||
fprintf(stderr, "Couldn't connect to %s\n", loc->host);
|
fprintf(stderr, "Couldn't connect to %s\n", loc->host);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -229,11 +239,11 @@ static int open_location(struct location *loc, int flag) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else if (loc->path != NULL) {
|
||||||
loc->file = fopen(loc->path, flag == READ ? "r":"w");
|
loc->file = fopen(loc->path, flag == READ ? "r":"w");
|
||||||
if (!loc->file) {
|
if (!loc->file) {
|
||||||
if (errno == EISDIR) {
|
if (errno == EISDIR) {
|
||||||
if (loc->path != NULL && chdir(loc->path)) {
|
if (chdir(loc->path)) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Error changing directory to %s: %s\n",
|
"Error changing directory to %s: %s\n",
|
||||||
loc->path, strerror(errno));
|
loc->path, strerror(errno));
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ clients must be made or how a client should react.
|
|||||||
static int authenticated=0;
|
static int authenticated=0;
|
||||||
static int tries = 0;
|
static int tries = 0;
|
||||||
static int error = 0;
|
static int error = 0;
|
||||||
static ssh_channel chan=NULL;
|
static ssh_channel chan = NULL;
|
||||||
static char *username;
|
static char *username = NULL;
|
||||||
static ssh_gssapi_creds client_creds = NULL;
|
static ssh_gssapi_creds client_creds = NULL;
|
||||||
|
|
||||||
static int auth_password(ssh_session session, const char *user,
|
static int auth_password(ssh_session session, const char *user,
|
||||||
@@ -142,20 +142,12 @@ static struct argp_option options[] = {
|
|||||||
.doc = "Set the host key.",
|
.doc = "Set the host key.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.name = "dsakey",
|
|
||||||
.key = 'd',
|
|
||||||
.arg = "FILE",
|
|
||||||
.flags = 0,
|
|
||||||
.doc = "Set the dsa key.",
|
|
||||||
.group = 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.name = "rsakey",
|
.name = "rsakey",
|
||||||
.key = 'r',
|
.key = 'r',
|
||||||
.arg = "FILE",
|
.arg = "FILE",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.doc = "Set the rsa key.",
|
.doc = "Set the rsa host key (deprecated alias to 'k').",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -180,15 +172,11 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
|||||||
case 'p':
|
case 'p':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'r':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg);
|
/* deprecated */
|
||||||
break;
|
|
||||||
case 'k':
|
case 'k':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg);
|
|
||||||
break;
|
|
||||||
case 'v':
|
case 'v':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
||||||
break;
|
break;
|
||||||
@@ -216,11 +204,12 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
|||||||
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||||
#endif /* HAVE_ARGP_H */
|
#endif /* HAVE_ARGP_H */
|
||||||
|
|
||||||
int main(int argc, char **argv){
|
int main(int argc, char **argv)
|
||||||
ssh_session session;
|
{
|
||||||
ssh_bind sshbind;
|
ssh_session session = NULL;
|
||||||
ssh_event mainloop;
|
ssh_bind sshbind = NULL;
|
||||||
ssh_session client_session;
|
ssh_event mainloop = NULL;
|
||||||
|
ssh_session client_session = NULL;
|
||||||
|
|
||||||
struct ssh_server_callbacks_struct cb = {
|
struct ssh_server_callbacks_struct cb = {
|
||||||
.userdata = NULL,
|
.userdata = NULL,
|
||||||
@@ -231,13 +220,13 @@ int main(int argc, char **argv){
|
|||||||
|
|
||||||
char buf[BUF_SIZE];
|
char buf[BUF_SIZE];
|
||||||
char host[128]="";
|
char host[128]="";
|
||||||
char *ptr;
|
char *ptr = NULL;
|
||||||
int i,r, rc;
|
int i,r, rc;
|
||||||
|
|
||||||
sshbind=ssh_bind_new();
|
sshbind=ssh_bind_new();
|
||||||
session=ssh_new();
|
session=ssh_new();
|
||||||
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, "sshd_rsa");
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, "sshd_rsa");
|
||||||
|
|
||||||
#ifdef HAVE_ARGP_H
|
#ifdef HAVE_ARGP_H
|
||||||
/*
|
/*
|
||||||
@@ -348,4 +337,3 @@ int main(int argc, char **argv){
|
|||||||
ssh_finalize();
|
ssh_finalize();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
508
examples/sample_sftpserver.c
Normal file
@@ -0,0 +1,508 @@
|
|||||||
|
/* This is a sample implementation of a libssh based SSH server */
|
||||||
|
/*
|
||||||
|
Copyright 2014 Audrius Butkevicius
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <libssh/callbacks.h>
|
||||||
|
#include <libssh/server.h>
|
||||||
|
#include <libssh/sftp.h>
|
||||||
|
#include <libssh/sftpserver.h>
|
||||||
|
|
||||||
|
#include <poll.h>
|
||||||
|
#ifdef HAVE_ARGP_H
|
||||||
|
#include <argp.h>
|
||||||
|
#endif
|
||||||
|
#include <fcntl.h>
|
||||||
|
#ifdef HAVE_LIBUTIL_H
|
||||||
|
#include <libutil.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_PTY_H
|
||||||
|
#include <pty.h>
|
||||||
|
#endif
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#ifdef HAVE_UTMP_H
|
||||||
|
#include <utmp.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_UTIL_H
|
||||||
|
#include <util.h>
|
||||||
|
#endif
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/* below are for sftp */
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#ifndef KEYS_FOLDER
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define KEYS_FOLDER
|
||||||
|
#else
|
||||||
|
#define KEYS_FOLDER "/etc/ssh/"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define USER "myuser"
|
||||||
|
#define PASS "mypassword"
|
||||||
|
#define BUF_SIZE 1048576
|
||||||
|
#define SESSION_END (SSH_CLOSED | SSH_CLOSED_ERROR)
|
||||||
|
|
||||||
|
static void set_default_keys(ssh_bind sshbind,
|
||||||
|
int rsa_already_set,
|
||||||
|
int ecdsa_already_set)
|
||||||
|
{
|
||||||
|
if (!rsa_already_set)
|
||||||
|
{
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY,
|
||||||
|
KEYS_FOLDER "ssh_host_rsa_key");
|
||||||
|
}
|
||||||
|
if (!ecdsa_already_set)
|
||||||
|
{
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY,
|
||||||
|
KEYS_FOLDER "ssh_host_ecdsa_key");
|
||||||
|
}
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY,
|
||||||
|
KEYS_FOLDER "ssh_host_ed25519_key");
|
||||||
|
}
|
||||||
|
#define DEF_STR_SIZE 1024
|
||||||
|
char authorizedkeys[DEF_STR_SIZE] = {0};
|
||||||
|
#ifdef HAVE_ARGP_H
|
||||||
|
const char *argp_program_version = "libssh sftp server example " SSH_STRINGIFY(LIBSSH_VERSION);
|
||||||
|
const char *argp_program_bug_address = "<libssh@libssh.org>";
|
||||||
|
|
||||||
|
/* Program documentation. */
|
||||||
|
static char doc[] = "Sftp server implemented with libssh -- a Secure Shell protocol implementation";
|
||||||
|
|
||||||
|
/* A description of the arguments we accept. */
|
||||||
|
static char args_doc[] = "BINDADDR";
|
||||||
|
|
||||||
|
/* The options we understand. */
|
||||||
|
static struct argp_option options[] = {
|
||||||
|
{.name = "port",
|
||||||
|
.key = 'p',
|
||||||
|
.arg = "PORT",
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "Set the port to bind.",
|
||||||
|
.group = 0},
|
||||||
|
{.name = "hostkey",
|
||||||
|
.key = 'k',
|
||||||
|
.arg = "FILE",
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "Set a host key. Can be used multiple times. "
|
||||||
|
"Implies no default keys.",
|
||||||
|
.group = 0},
|
||||||
|
{.name = "rsakey",
|
||||||
|
.key = 'r',
|
||||||
|
.arg = "FILE",
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "Set the rsa key.",
|
||||||
|
.group = 0},
|
||||||
|
{.name = "ecdsakey",
|
||||||
|
.key = 'e',
|
||||||
|
.arg = "FILE",
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "Set the ecdsa key.",
|
||||||
|
.group = 0},
|
||||||
|
{.name = "authorizedkeys",
|
||||||
|
.key = 'a',
|
||||||
|
.arg = "FILE",
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "Set the authorized keys file.",
|
||||||
|
.group = 0},
|
||||||
|
{.name = "no-default-keys",
|
||||||
|
.key = 'n',
|
||||||
|
.arg = NULL,
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "Do not set default key locations.",
|
||||||
|
.group = 0},
|
||||||
|
{.name = "verbose",
|
||||||
|
.key = 'v',
|
||||||
|
.arg = NULL,
|
||||||
|
.flags = 0,
|
||||||
|
.doc = "Get verbose output.",
|
||||||
|
.group = 0},
|
||||||
|
{NULL, 0, NULL, 0, NULL, 0}};
|
||||||
|
|
||||||
|
/* Parse a single option. */
|
||||||
|
static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||||
|
{
|
||||||
|
/* Get the input argument from argp_parse, which we
|
||||||
|
* know is a pointer to our arguments structure. */
|
||||||
|
ssh_bind sshbind = state->input;
|
||||||
|
static int no_default_keys = 0;
|
||||||
|
static int rsa_already_set = 0, ecdsa_already_set = 0;
|
||||||
|
static int verbosity = 0;
|
||||||
|
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case 'n':
|
||||||
|
no_default_keys = 1;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
|
/* We can't track the types of keys being added with this
|
||||||
|
option, so let's ensure we keep the keys we're adding
|
||||||
|
by just not setting the default keys */
|
||||||
|
no_default_keys = 1;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
|
rsa_already_set = 1;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
|
ecdsa_already_set = 1;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
strncpy(authorizedkeys, arg, DEF_STR_SIZE - 1);
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
verbosity++;
|
||||||
|
ssh_bind_options_set(sshbind,
|
||||||
|
SSH_BIND_OPTIONS_LOG_VERBOSITY,
|
||||||
|
&verbosity);
|
||||||
|
break;
|
||||||
|
case ARGP_KEY_ARG:
|
||||||
|
if (state->arg_num >= 1)
|
||||||
|
{
|
||||||
|
/* Too many arguments. */
|
||||||
|
argp_usage(state);
|
||||||
|
}
|
||||||
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg);
|
||||||
|
break;
|
||||||
|
case ARGP_KEY_END:
|
||||||
|
if (state->arg_num < 1)
|
||||||
|
{
|
||||||
|
/* Not enough arguments. */
|
||||||
|
argp_usage(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!no_default_keys)
|
||||||
|
{
|
||||||
|
set_default_keys(sshbind,
|
||||||
|
rsa_already_set,
|
||||||
|
ecdsa_already_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ARGP_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Our argp parser. */
|
||||||
|
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||||
|
#endif /* HAVE_ARGP_H */
|
||||||
|
|
||||||
|
/* A userdata struct for channel. */
|
||||||
|
struct channel_data_struct {
|
||||||
|
sftp_session sftp;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A userdata struct for session. */
|
||||||
|
struct session_data_struct
|
||||||
|
{
|
||||||
|
/* Pointer to the channel the session will allocate. */
|
||||||
|
ssh_channel channel;
|
||||||
|
int auth_attempts;
|
||||||
|
int authenticated;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int auth_password(ssh_session session, const char *user,
|
||||||
|
const char *pass, void *userdata)
|
||||||
|
{
|
||||||
|
struct session_data_struct *sdata = (struct session_data_struct *)userdata;
|
||||||
|
|
||||||
|
(void)session;
|
||||||
|
|
||||||
|
if (strcmp(user, USER) == 0 && strcmp(pass, PASS) == 0)
|
||||||
|
{
|
||||||
|
sdata->authenticated = 1;
|
||||||
|
return SSH_AUTH_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdata->auth_attempts++;
|
||||||
|
return SSH_AUTH_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int auth_publickey(ssh_session session,
|
||||||
|
const char *user,
|
||||||
|
struct ssh_key_struct *pubkey,
|
||||||
|
char signature_state,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
struct session_data_struct *sdata = (struct session_data_struct *)userdata;
|
||||||
|
|
||||||
|
(void)session;
|
||||||
|
(void)user;
|
||||||
|
|
||||||
|
if (signature_state == SSH_PUBLICKEY_STATE_NONE)
|
||||||
|
{
|
||||||
|
return SSH_AUTH_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signature_state != SSH_PUBLICKEY_STATE_VALID)
|
||||||
|
{
|
||||||
|
return SSH_AUTH_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// valid so far. Now look through authorized keys for a match
|
||||||
|
if (authorizedkeys[0])
|
||||||
|
{
|
||||||
|
ssh_key key = NULL;
|
||||||
|
int result;
|
||||||
|
struct stat buf;
|
||||||
|
|
||||||
|
if (stat(authorizedkeys, &buf) == 0)
|
||||||
|
{
|
||||||
|
result = ssh_pki_import_pubkey_file(authorizedkeys, &key);
|
||||||
|
if ((result != SSH_OK) || (key == NULL))
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Unable to import public key file %s\n",
|
||||||
|
authorizedkeys);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = ssh_key_cmp(key, pubkey, SSH_KEY_CMP_PUBLIC);
|
||||||
|
ssh_key_free(key);
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
sdata->authenticated = 1;
|
||||||
|
return SSH_AUTH_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no matches
|
||||||
|
sdata->authenticated = 0;
|
||||||
|
return SSH_AUTH_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssh_channel channel_open(ssh_session session, void *userdata)
|
||||||
|
{
|
||||||
|
struct session_data_struct *sdata = (struct session_data_struct *)userdata;
|
||||||
|
|
||||||
|
sdata->channel = ssh_channel_new(session);
|
||||||
|
return sdata->channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_session(ssh_event event, ssh_session session)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
/* Our struct holding information about the channel. */
|
||||||
|
struct channel_data_struct cdata = {
|
||||||
|
.sftp = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Our struct holding information about the session. */
|
||||||
|
struct session_data_struct sdata = {
|
||||||
|
.channel = NULL,
|
||||||
|
.auth_attempts = 0,
|
||||||
|
.authenticated = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ssh_channel_callbacks_struct channel_cb = {
|
||||||
|
.userdata = &(cdata.sftp),
|
||||||
|
.channel_data_function = sftp_channel_default_data_callback,
|
||||||
|
.channel_subsystem_request_function = sftp_channel_default_subsystem_request,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ssh_server_callbacks_struct server_cb = {
|
||||||
|
.userdata = &sdata,
|
||||||
|
.auth_password_function = auth_password,
|
||||||
|
.channel_open_request_session_function = channel_open,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (authorizedkeys[0])
|
||||||
|
{
|
||||||
|
server_cb.auth_pubkey_function = auth_publickey;
|
||||||
|
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
|
||||||
|
|
||||||
|
ssh_callbacks_init(&server_cb);
|
||||||
|
ssh_callbacks_init(&channel_cb);
|
||||||
|
|
||||||
|
ssh_set_server_callbacks(session, &server_cb);
|
||||||
|
|
||||||
|
if (ssh_handle_key_exchange(session) != SSH_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s\n", ssh_get_error(session));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_event_add_session(event, session);
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
while (sdata.authenticated == 0 || sdata.channel == NULL) {
|
||||||
|
/* If the user has used up all attempts, or if he hasn't been able to
|
||||||
|
* authenticate in 10 seconds (n * 100ms), disconnect. */
|
||||||
|
if (sdata.auth_attempts >= 3 || n >= 100) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssh_event_dopoll(event, 100) == SSH_ERROR) {
|
||||||
|
fprintf(stderr, "%s\n", ssh_get_error(session));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_set_channel_callbacks(sdata.channel, &channel_cb);
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* Poll the main event which takes care of the session, the channel and
|
||||||
|
* even our child process's stdout/stderr (once it's started). */
|
||||||
|
if (ssh_event_dopoll(event, 100) == SSH_ERROR) {
|
||||||
|
ssh_channel_close(sdata.channel);
|
||||||
|
}
|
||||||
|
} while (ssh_channel_is_open(sdata.channel) &&
|
||||||
|
!ssh_channel_is_eof(sdata.channel));
|
||||||
|
|
||||||
|
ssh_channel_send_eof(sdata.channel);
|
||||||
|
ssh_channel_close(sdata.channel);
|
||||||
|
|
||||||
|
/* Wait up to 5 seconds for the client to terminate the session. */
|
||||||
|
for (n = 0; n < 50 && (ssh_get_status(session) & SESSION_END) == 0; n++) {
|
||||||
|
ssh_event_dopoll(event, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SIGCHLD handler for cleaning up dead children. */
|
||||||
|
static void sigchld_handler(int signo)
|
||||||
|
{
|
||||||
|
(void)signo;
|
||||||
|
|
||||||
|
while (waitpid(-1, NULL, WNOHANG) > 0)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
ssh_bind sshbind = NULL;
|
||||||
|
ssh_session session = NULL;
|
||||||
|
ssh_event event = NULL;
|
||||||
|
struct sigaction sa;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Set up SIGCHLD handler. */
|
||||||
|
sa.sa_handler = sigchld_handler;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
|
||||||
|
if (sigaction(SIGCHLD, &sa, NULL) != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to register SIGCHLD handler\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_init();
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ssh_init failed\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
sshbind = ssh_bind_new();
|
||||||
|
if (sshbind == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ssh_bind_new failed\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_ARGP_H
|
||||||
|
argp_parse(&argp, argc, argv, 0, 0, sshbind);
|
||||||
|
#else
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
set_default_keys(sshbind, 0, 0);
|
||||||
|
#endif /* HAVE_ARGP_H */
|
||||||
|
|
||||||
|
if (ssh_bind_listen(sshbind) < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s\n", ssh_get_error(sshbind));
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
session = ssh_new();
|
||||||
|
if (session == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to allocate session\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Blocks until there is a new incoming connection. */
|
||||||
|
if (ssh_bind_accept(sshbind, session) != SSH_ERROR)
|
||||||
|
{
|
||||||
|
switch (fork())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
/* Remove the SIGCHLD handler inherited from parent. */
|
||||||
|
sa.sa_handler = SIG_DFL;
|
||||||
|
sigaction(SIGCHLD, &sa, NULL);
|
||||||
|
/* Remove socket binding, which allows us to restart the
|
||||||
|
* parent process, without terminating existing sessions. */
|
||||||
|
ssh_bind_free(sshbind);
|
||||||
|
|
||||||
|
event = ssh_event_new();
|
||||||
|
if (event != NULL)
|
||||||
|
{
|
||||||
|
/* Blocks until the SSH session ends by either
|
||||||
|
* child process exiting, or client disconnecting. */
|
||||||
|
handle_session(event, session);
|
||||||
|
ssh_event_free(event);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Could not create polling context\n");
|
||||||
|
}
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
case -1:
|
||||||
|
fprintf(stderr, "Failed to fork\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s\n", ssh_get_error(sshbind));
|
||||||
|
}
|
||||||
|
/* Since the session has been passed to a child fork, do some cleaning
|
||||||
|
* up at the parent process. */
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
ssh_bind_free(sshbind);
|
||||||
|
ssh_finalize();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -33,21 +33,18 @@ clients must be made or how a client should react.
|
|||||||
#define BUF_SIZE 65536
|
#define BUF_SIZE 65536
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int verbosity;
|
|
||||||
static char *destination;
|
|
||||||
|
|
||||||
static void do_sftp(ssh_session session) {
|
static void do_sftp(ssh_session session) {
|
||||||
sftp_session sftp = sftp_new(session);
|
sftp_session sftp = sftp_new(session);
|
||||||
sftp_dir dir;
|
sftp_dir dir;
|
||||||
sftp_attributes file;
|
sftp_attributes file;
|
||||||
sftp_statvfs_t sftpstatvfs;
|
sftp_statvfs_t sftpstatvfs;
|
||||||
struct statvfs sysstatvfs;
|
struct statvfs sysstatvfs;
|
||||||
sftp_file fichier;
|
sftp_file source;
|
||||||
sftp_file to;
|
sftp_file to;
|
||||||
int len = 1;
|
int len = 1;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
char data[BUF_SIZE] = {0};
|
char data[BUF_SIZE] = {0};
|
||||||
char *lnk;
|
char *lnk = NULL;
|
||||||
|
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
|
|
||||||
@@ -86,6 +83,7 @@ static void do_sftp(ssh_session session) {
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
printf("readlink /tmp/sftp_symlink_test: %s\n", lnk);
|
printf("readlink /tmp/sftp_symlink_test: %s\n", lnk);
|
||||||
|
ssh_string_free_char(lnk);
|
||||||
|
|
||||||
sftp_unlink(sftp, "/tmp/sftp_symlink_test");
|
sftp_unlink(sftp, "/tmp/sftp_symlink_test");
|
||||||
|
|
||||||
@@ -173,7 +171,7 @@ static void do_sftp(ssh_session session) {
|
|||||||
sftp_attributes_free(file);
|
sftp_attributes_free(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* when file = NULL, an error has occured OR the directory listing is end of
|
/* when file = NULL, an error has occurred OR the directory listing is end of
|
||||||
* file */
|
* file */
|
||||||
if (!sftp_dir_eof(dir)) {
|
if (!sftp_dir_eof(dir)) {
|
||||||
fprintf(stderr, "Error: %s\n", ssh_get_error(session));
|
fprintf(stderr, "Error: %s\n", ssh_get_error(session));
|
||||||
@@ -188,8 +186,8 @@ static void do_sftp(ssh_session session) {
|
|||||||
/* the small buffer size was intended to stress the library. of course, you
|
/* the small buffer size was intended to stress the library. of course, you
|
||||||
* can use a buffer till 20kbytes without problem */
|
* can use a buffer till 20kbytes without problem */
|
||||||
|
|
||||||
fichier = sftp_open(sftp, "/usr/bin/ssh", O_RDONLY, 0);
|
source = sftp_open(sftp, "/usr/bin/ssh", O_RDONLY, 0);
|
||||||
if (!fichier) {
|
if (!source) {
|
||||||
fprintf(stderr, "Error opening /usr/bin/ssh: %s\n",
|
fprintf(stderr, "Error opening /usr/bin/ssh: %s\n",
|
||||||
ssh_get_error(session));
|
ssh_get_error(session));
|
||||||
goto end;
|
goto end;
|
||||||
@@ -200,16 +198,16 @@ static void do_sftp(ssh_session session) {
|
|||||||
if (!to) {
|
if (!to) {
|
||||||
fprintf(stderr, "Error opening ssh-copy for writing: %s\n",
|
fprintf(stderr, "Error opening ssh-copy for writing: %s\n",
|
||||||
ssh_get_error(session));
|
ssh_get_error(session));
|
||||||
sftp_close(fichier);
|
sftp_close(source);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((len = sftp_read(fichier, data, 4096)) > 0) {
|
while ((len = sftp_read(source, data, 4096)) > 0) {
|
||||||
if (sftp_write(to, data, len) != len) {
|
if (sftp_write(to, data, len) != len) {
|
||||||
fprintf(stderr, "Error writing %d bytes: %s\n",
|
fprintf(stderr, "Error writing %d bytes: %s\n",
|
||||||
len, ssh_get_error(session));
|
len, ssh_get_error(session));
|
||||||
sftp_close(to);
|
sftp_close(to);
|
||||||
sftp_close(fichier);
|
sftp_close(source);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,10 +217,10 @@ static void do_sftp(ssh_session session) {
|
|||||||
fprintf(stderr, "Error reading file: %s\n", ssh_get_error(session));
|
fprintf(stderr, "Error reading file: %s\n", ssh_get_error(session));
|
||||||
}
|
}
|
||||||
|
|
||||||
sftp_close(fichier);
|
sftp_close(source);
|
||||||
sftp_close(to);
|
sftp_close(to);
|
||||||
printf("fichiers ferm\n");
|
printf("file closed\n");
|
||||||
to = sftp_open(sftp, "/tmp/grosfichier", O_WRONLY|O_CREAT, 0644);
|
to = sftp_open(sftp, "/tmp/large_file", O_WRONLY|O_CREAT, 0644);
|
||||||
|
|
||||||
for (i = 0; i < 1000; ++i) {
|
for (i = 0; i < 1000; ++i) {
|
||||||
len = sftp_write(to, data, sizeof(data));
|
len = sftp_write(to, data, sizeof(data));
|
||||||
@@ -243,50 +241,63 @@ static void usage(const char *argv0) {
|
|||||||
fprintf(stderr, "Usage : %s [-v] remotehost\n"
|
fprintf(stderr, "Usage : %s [-v] remotehost\n"
|
||||||
"sample sftp test client - libssh-%s\n"
|
"sample sftp test client - libssh-%s\n"
|
||||||
"Options :\n"
|
"Options :\n"
|
||||||
|
" -l user : log in as user\n"
|
||||||
|
" -p port : connect to port\n"
|
||||||
" -v : increase log verbosity\n",
|
" -v : increase log verbosity\n",
|
||||||
argv0,
|
argv0,
|
||||||
ssh_version(0));
|
ssh_version(0));
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int opts(int argc, char **argv) {
|
int main(int argc, char **argv)
|
||||||
int i;
|
{
|
||||||
|
ssh_session session = NULL;
|
||||||
|
char *destination = NULL;
|
||||||
|
int auth = 0;
|
||||||
|
int state;
|
||||||
|
|
||||||
while ((i = getopt(argc, argv, "v")) != -1) {
|
ssh_init();
|
||||||
switch(i) {
|
session = ssh_new();
|
||||||
case 'v':
|
|
||||||
verbosity++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "unknown option %c\n", optopt);
|
|
||||||
usage(argv[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destination = argv[optind];
|
if (ssh_options_getopt(session, &argc, argv)) {
|
||||||
if (destination == NULL) {
|
fprintf(stderr,
|
||||||
|
"Error parsing command line: %s\n",
|
||||||
|
ssh_get_error(session));
|
||||||
|
ssh_free(session);
|
||||||
|
ssh_finalize();
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if (argc < 1) {
|
||||||
|
usage(argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
destination = argv[1];
|
||||||
|
|
||||||
|
if (ssh_options_set(session, SSH_OPTIONS_HOST, destination) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
if (ssh_connect(session)) {
|
||||||
}
|
fprintf(stderr, "Connection failed : %s\n", ssh_get_error(session));
|
||||||
|
return -1;
|
||||||
int main(int argc, char **argv) {
|
|
||||||
ssh_session session;
|
|
||||||
|
|
||||||
if (opts(argc, argv) < 0) {
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
session = connect_ssh(destination, NULL, verbosity);
|
state = verify_knownhost(session);
|
||||||
if (session == NULL) {
|
if (state != 0) {
|
||||||
return EXIT_FAILURE;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auth = authenticate_console(session);
|
||||||
|
if (auth != SSH_AUTH_SUCCESS) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
do_sftp(session);
|
do_sftp(session);
|
||||||
ssh_disconnect(session);
|
ssh_disconnect(session);
|
||||||
ssh_free(session);
|
ssh_free(session);
|
||||||
|
|
||||||
|
ssh_finalize();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -172,20 +172,12 @@ static struct argp_option options[] = {
|
|||||||
.doc = "Set the host key.",
|
.doc = "Set the host key.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.name = "dsakey",
|
|
||||||
.key = 'd',
|
|
||||||
.arg = "FILE",
|
|
||||||
.flags = 0,
|
|
||||||
.doc = "Set the dsa key.",
|
|
||||||
.group = 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.name = "rsakey",
|
.name = "rsakey",
|
||||||
.key = 'r',
|
.key = 'r',
|
||||||
.arg = "FILE",
|
.arg = "FILE",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.doc = "Set the rsa key.",
|
.doc = "Set the rsa key (deprecated alias for 'k').",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -218,15 +210,10 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
|||||||
case 'p':
|
case 'p':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'r':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg);
|
|
||||||
break;
|
|
||||||
case 'k':
|
case 'k':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg);
|
|
||||||
break;
|
|
||||||
case 'v':
|
case 'v':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
||||||
break;
|
break;
|
||||||
@@ -257,10 +244,11 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
|||||||
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||||
#endif /* HAVE_ARGP_H */
|
#endif /* HAVE_ARGP_H */
|
||||||
|
|
||||||
int main(int argc, char **argv){
|
int main(int argc, char **argv)
|
||||||
ssh_session session;
|
{
|
||||||
ssh_bind sshbind;
|
ssh_session session = NULL;
|
||||||
ssh_event mainloop;
|
ssh_bind sshbind = NULL;
|
||||||
|
ssh_event mainloop = NULL;
|
||||||
struct ssh_server_callbacks_struct cb = {
|
struct ssh_server_callbacks_struct cb = {
|
||||||
.userdata = NULL,
|
.userdata = NULL,
|
||||||
.auth_none_function = auth_none,
|
.auth_none_function = auth_none,
|
||||||
@@ -278,8 +266,7 @@ int main(int argc, char **argv){
|
|||||||
sshbind=ssh_bind_new();
|
sshbind=ssh_bind_new();
|
||||||
session=ssh_new();
|
session=ssh_new();
|
||||||
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, KEYS_FOLDER "ssh_host_dsa_key");
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, KEYS_FOLDER "ssh_host_rsa_key");
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, KEYS_FOLDER "ssh_host_rsa_key");
|
|
||||||
|
|
||||||
#ifdef HAVE_ARGP_H
|
#ifdef HAVE_ARGP_H
|
||||||
/*
|
/*
|
||||||
@@ -353,4 +340,3 @@ int main(int argc, char **argv){
|
|||||||
ssh_finalize();
|
ssh_finalize();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,20 +112,12 @@ static struct argp_option options[] = {
|
|||||||
.doc = "Set the host key.",
|
.doc = "Set the host key.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.name = "dsakey",
|
|
||||||
.key = 'd',
|
|
||||||
.arg = "FILE",
|
|
||||||
.flags = 0,
|
|
||||||
.doc = "Set the dsa key.",
|
|
||||||
.group = 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.name = "rsakey",
|
.name = "rsakey",
|
||||||
.key = 'r',
|
.key = 'r',
|
||||||
.arg = "FILE",
|
.arg = "FILE",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.doc = "Set the rsa key.",
|
.doc = "Set the rsa key (deprecated alias for 'k').",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -151,15 +143,10 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
|||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
||||||
port = atoi(arg);
|
port = atoi(arg);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'r':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg);
|
|
||||||
break;
|
|
||||||
case 'k':
|
case 'k':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg);
|
|
||||||
break;
|
|
||||||
case 'v':
|
case 'v':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
||||||
break;
|
break;
|
||||||
@@ -187,8 +174,8 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
|||||||
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||||
#endif /* HAVE_ARGP_H */
|
#endif /* HAVE_ARGP_H */
|
||||||
|
|
||||||
static const char *name;
|
static const char *name = NULL;
|
||||||
static const char *instruction;
|
static const char *instruction = NULL;
|
||||||
static const char *prompts[2];
|
static const char *prompts[2];
|
||||||
static char echo[] = { 1, 0 };
|
static char echo[] = { 1, 0 };
|
||||||
|
|
||||||
@@ -292,11 +279,12 @@ static int authenticate(ssh_session session) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv){
|
int main(int argc, char **argv)
|
||||||
ssh_session session;
|
{
|
||||||
ssh_bind sshbind;
|
ssh_session session = NULL;
|
||||||
ssh_message message;
|
ssh_bind sshbind = NULL;
|
||||||
ssh_channel chan=0;
|
ssh_message message = NULL;
|
||||||
|
ssh_channel chan = NULL;
|
||||||
char buf[BUF_SIZE];
|
char buf[BUF_SIZE];
|
||||||
int auth=0;
|
int auth=0;
|
||||||
int shell=0;
|
int shell=0;
|
||||||
@@ -306,10 +294,8 @@ int main(int argc, char **argv){
|
|||||||
sshbind=ssh_bind_new();
|
sshbind=ssh_bind_new();
|
||||||
session=ssh_new();
|
session=ssh_new();
|
||||||
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY,
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY,
|
||||||
KEYS_FOLDER "ssh_host_dsa_key");
|
KEYS_FOLDER "ssh_host_rsa_key");
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY,
|
|
||||||
KEYS_FOLDER "ssh_host_rsa_key");
|
|
||||||
|
|
||||||
#ifdef HAVE_ARGP_H
|
#ifdef HAVE_ARGP_H
|
||||||
/*
|
/*
|
||||||
@@ -369,9 +355,9 @@ int main(int argc, char **argv){
|
|||||||
}
|
}
|
||||||
} while(!chan);
|
} while(!chan);
|
||||||
|
|
||||||
if(!chan) {
|
if (!chan) {
|
||||||
printf("Error: cleint did not ask for a channel session (%s)\n",
|
printf("Error: client did not ask for a channel session (%s)\n",
|
||||||
ssh_get_error(session));
|
ssh_get_error(session));
|
||||||
ssh_finalize();
|
ssh_finalize();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -426,4 +412,3 @@ int main(int argc, char **argv){
|
|||||||
ssh_finalize();
|
ssh_finalize();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,151 +32,163 @@ static const char *createcommand =
|
|||||||
"cd /tmp/libssh_tests && date > a && date > b && mkdir c && date > d";
|
"cd /tmp/libssh_tests && date > a && date > b && mkdir c && date > d";
|
||||||
static char *host = NULL;
|
static char *host = NULL;
|
||||||
|
|
||||||
static void usage(const char *argv0){
|
static void usage(const char *argv0)
|
||||||
fprintf(stderr,"Usage : %s [options] host\n"
|
{
|
||||||
"sample tiny scp downloader client - libssh-%s\n"
|
fprintf(stderr,
|
||||||
"This program will create files in /tmp and try to fetch them\n",
|
"Usage : %s [options] host\n"
|
||||||
// "Options :\n",
|
"sample tiny scp downloader client - libssh-%s\n"
|
||||||
// " -r : use RSA to verify host public key\n",
|
"This program will create files in /tmp and try to fetch them\n",
|
||||||
argv0,
|
argv0,
|
||||||
ssh_version(0));
|
ssh_version(0));
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int opts(int argc, char **argv){
|
static int opts(int argc, char **argv)
|
||||||
int i;
|
{
|
||||||
while((i=getopt(argc,argv,"v"))!=-1){
|
int i;
|
||||||
switch(i){
|
|
||||||
case 'v':
|
while ((i = getopt(argc, argv, "v")) != -1) {
|
||||||
verbosity++;
|
switch (i) {
|
||||||
break;
|
case 'v':
|
||||||
default:
|
verbosity++;
|
||||||
fprintf(stderr,"unknown option %c\n",optopt);
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "unknown option %c\n", optopt);
|
||||||
|
usage(argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
host = argv[optind];
|
||||||
|
if (host == NULL)
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_files(ssh_session session)
|
||||||
|
{
|
||||||
|
ssh_channel channel = ssh_channel_new(session);
|
||||||
|
char buffer[1];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (channel == NULL) {
|
||||||
|
fprintf(stderr, "Error creating channel: %s\n", ssh_get_error(session));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (ssh_channel_open_session(channel) != SSH_OK) {
|
||||||
|
fprintf(stderr, "Error creating channel: %s\n", ssh_get_error(session));
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (ssh_channel_request_exec(channel, createcommand) != SSH_OK) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error executing command: %s\n",
|
||||||
|
ssh_get_error(session));
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
while (!ssh_channel_is_eof(channel)) {
|
||||||
|
rc = ssh_channel_read(channel, buffer, 1, 1);
|
||||||
|
if (rc != 1) {
|
||||||
|
fprintf(stderr, "Error reading from channel\n");
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = write(1, buffer, 1);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "Error writing to buffer\n");
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fetch_files(ssh_session session)
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
char buffer[BUF_SIZE];
|
||||||
|
int mode;
|
||||||
|
char *filename = NULL;
|
||||||
|
int r;
|
||||||
|
ssh_scp scp = ssh_scp_new(session,
|
||||||
|
SSH_SCP_READ | SSH_SCP_RECURSIVE,
|
||||||
|
"/tmp/libssh_tests/*");
|
||||||
|
if (ssh_scp_init(scp) != SSH_OK) {
|
||||||
|
fprintf(stderr, "error initializing scp: %s\n", ssh_get_error(session));
|
||||||
|
ssh_scp_free(scp);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
printf("Trying to download 3 files (a,b,d) and 1 directory (c)\n");
|
||||||
host = argv[optind];
|
do {
|
||||||
if(host == NULL)
|
r = ssh_scp_pull_request(scp);
|
||||||
usage(argv[0]);
|
switch (r) {
|
||||||
return 0;
|
case SSH_SCP_REQUEST_NEWFILE:
|
||||||
|
size = ssh_scp_request_get_size(scp);
|
||||||
|
filename = strdup(ssh_scp_request_get_filename(scp));
|
||||||
|
mode = ssh_scp_request_get_permissions(scp);
|
||||||
|
printf("downloading file %s, size %d, perms 0%o\n",
|
||||||
|
filename,
|
||||||
|
size,
|
||||||
|
mode);
|
||||||
|
free(filename);
|
||||||
|
ssh_scp_accept_request(scp);
|
||||||
|
r = ssh_scp_read(scp, buffer, sizeof(buffer));
|
||||||
|
if (r == SSH_ERROR) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error reading scp: %s\n",
|
||||||
|
ssh_get_error(session));
|
||||||
|
ssh_scp_close(scp);
|
||||||
|
ssh_scp_free(scp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("done\n");
|
||||||
|
break;
|
||||||
|
case SSH_ERROR:
|
||||||
|
fprintf(stderr, "Error: %s\n", ssh_get_error(session));
|
||||||
|
ssh_scp_close(scp);
|
||||||
|
ssh_scp_free(scp);
|
||||||
|
return -1;
|
||||||
|
case SSH_SCP_REQUEST_WARNING:
|
||||||
|
fprintf(stderr, "Warning: %s\n", ssh_scp_request_get_warning(scp));
|
||||||
|
break;
|
||||||
|
case SSH_SCP_REQUEST_NEWDIR:
|
||||||
|
filename = strdup(ssh_scp_request_get_filename(scp));
|
||||||
|
mode = ssh_scp_request_get_permissions(scp);
|
||||||
|
printf("downloading directory %s, perms 0%o\n", filename, mode);
|
||||||
|
free(filename);
|
||||||
|
ssh_scp_accept_request(scp);
|
||||||
|
break;
|
||||||
|
case SSH_SCP_REQUEST_ENDDIR:
|
||||||
|
printf("End of directory\n");
|
||||||
|
break;
|
||||||
|
case SSH_SCP_REQUEST_EOF:
|
||||||
|
printf("End of requests\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
end:
|
||||||
|
ssh_scp_close(scp);
|
||||||
|
ssh_scp_free(scp);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_files(ssh_session session){
|
int main(int argc, char **argv)
|
||||||
ssh_channel channel=ssh_channel_new(session);
|
{
|
||||||
char buffer[1];
|
ssh_session session = NULL;
|
||||||
int rc;
|
if (opts(argc, argv) < 0)
|
||||||
|
return EXIT_FAILURE;
|
||||||
if(channel == NULL){
|
session = connect_ssh(host, NULL, NULL, verbosity);
|
||||||
fprintf(stderr,"Error creating channel: %s\n",ssh_get_error(session));
|
if (session == NULL)
|
||||||
exit(EXIT_FAILURE);
|
return EXIT_FAILURE;
|
||||||
}
|
create_files(session);
|
||||||
if(ssh_channel_open_session(channel) != SSH_OK){
|
fetch_files(session);
|
||||||
fprintf(stderr,"Error creating channel: %s\n",ssh_get_error(session));
|
ssh_disconnect(session);
|
||||||
ssh_channel_free(channel);
|
ssh_free(session);
|
||||||
exit(EXIT_FAILURE);
|
ssh_finalize();
|
||||||
}
|
return 0;
|
||||||
if(ssh_channel_request_exec(channel,createcommand) != SSH_OK){
|
|
||||||
fprintf(stderr,"Error executing command: %s\n",ssh_get_error(session));
|
|
||||||
ssh_channel_close(channel);
|
|
||||||
ssh_channel_free(channel);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
while(!ssh_channel_is_eof(channel)){
|
|
||||||
rc = ssh_channel_read(channel,buffer,1,1);
|
|
||||||
if (rc != 1) {
|
|
||||||
fprintf(stderr, "Error reading from channel\n");
|
|
||||||
ssh_channel_close(channel);
|
|
||||||
ssh_channel_free(channel);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = write(1, buffer, 1);
|
|
||||||
if (rc < 0) {
|
|
||||||
fprintf(stderr, "Error writing to buffer\n");
|
|
||||||
ssh_channel_close(channel);
|
|
||||||
ssh_channel_free(channel);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ssh_channel_close(channel);
|
|
||||||
ssh_channel_free(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int fetch_files(ssh_session session){
|
|
||||||
int size;
|
|
||||||
char buffer[BUF_SIZE];
|
|
||||||
int mode;
|
|
||||||
char *filename;
|
|
||||||
int r;
|
|
||||||
ssh_scp scp=ssh_scp_new(session, SSH_SCP_READ | SSH_SCP_RECURSIVE, "/tmp/libssh_tests/*");
|
|
||||||
if(ssh_scp_init(scp) != SSH_OK){
|
|
||||||
fprintf(stderr,"error initializing scp: %s\n",ssh_get_error(session));
|
|
||||||
ssh_scp_free(scp);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf("Trying to download 3 files (a,b,d) and 1 directory (c)\n");
|
|
||||||
do {
|
|
||||||
|
|
||||||
r=ssh_scp_pull_request(scp);
|
|
||||||
switch(r){
|
|
||||||
case SSH_SCP_REQUEST_NEWFILE:
|
|
||||||
size=ssh_scp_request_get_size(scp);
|
|
||||||
filename=strdup(ssh_scp_request_get_filename(scp));
|
|
||||||
mode=ssh_scp_request_get_permissions(scp);
|
|
||||||
printf("downloading file %s, size %d, perms 0%o\n",filename,size,mode);
|
|
||||||
free(filename);
|
|
||||||
ssh_scp_accept_request(scp);
|
|
||||||
r=ssh_scp_read(scp,buffer,sizeof(buffer));
|
|
||||||
if(r==SSH_ERROR){
|
|
||||||
fprintf(stderr,"Error reading scp: %s\n",ssh_get_error(session));
|
|
||||||
ssh_scp_close(scp);
|
|
||||||
ssh_scp_free(scp);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf("done\n");
|
|
||||||
break;
|
|
||||||
case SSH_ERROR:
|
|
||||||
fprintf(stderr,"Error: %s\n",ssh_get_error(session));
|
|
||||||
ssh_scp_close(scp);
|
|
||||||
ssh_scp_free(scp);
|
|
||||||
return -1;
|
|
||||||
case SSH_SCP_REQUEST_WARNING:
|
|
||||||
fprintf(stderr,"Warning: %s\n",ssh_scp_request_get_warning(scp));
|
|
||||||
break;
|
|
||||||
case SSH_SCP_REQUEST_NEWDIR:
|
|
||||||
filename=strdup(ssh_scp_request_get_filename(scp));
|
|
||||||
mode=ssh_scp_request_get_permissions(scp);
|
|
||||||
printf("downloading directory %s, perms 0%o\n",filename,mode);
|
|
||||||
free(filename);
|
|
||||||
ssh_scp_accept_request(scp);
|
|
||||||
break;
|
|
||||||
case SSH_SCP_REQUEST_ENDDIR:
|
|
||||||
printf("End of directory\n");
|
|
||||||
break;
|
|
||||||
case SSH_SCP_REQUEST_EOF:
|
|
||||||
printf("End of requests\n");
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
} while (1);
|
|
||||||
end:
|
|
||||||
ssh_scp_close(scp);
|
|
||||||
ssh_scp_free(scp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv){
|
|
||||||
ssh_session session;
|
|
||||||
if(opts(argc,argv)<0)
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
session=connect_ssh(host,NULL,verbosity);
|
|
||||||
if(session == NULL)
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
create_files(session);
|
|
||||||
fetch_files(session);
|
|
||||||
ssh_disconnect(session);
|
|
||||||
ssh_free(session);
|
|
||||||
ssh_finalize();
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,60 +5,60 @@
|
|||||||
|
|
||||||
#define LIMIT 0x100000000UL
|
#define LIMIT 0x100000000UL
|
||||||
|
|
||||||
int main(void) {
|
int main(void)
|
||||||
ssh_session session;
|
{
|
||||||
ssh_channel channel;
|
ssh_session session = NULL;
|
||||||
char buffer[1024*1024];
|
ssh_channel channel = NULL;
|
||||||
int rc;
|
char buffer[1024 * 1024] = {0};
|
||||||
uint64_t total=0;
|
int rc;
|
||||||
uint64_t lastshown=4096;
|
uint64_t total = 0;
|
||||||
session = connect_ssh("localhost", NULL, 0);
|
uint64_t lastshown = 4096;
|
||||||
if (session == NULL) {
|
session = connect_ssh("localhost", NULL, NULL, 0);
|
||||||
return 1;
|
if (session == NULL) {
|
||||||
}
|
return 1;
|
||||||
|
|
||||||
channel = ssh_channel_new(session);
|
|
||||||
if (channel == NULL) {
|
|
||||||
ssh_disconnect(session);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ssh_channel_open_session(channel);
|
|
||||||
if (rc < 0) {
|
|
||||||
ssh_channel_close(channel);
|
|
||||||
ssh_disconnect(session);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ssh_channel_request_exec(channel, "cat > /dev/null");
|
|
||||||
if (rc < 0) {
|
|
||||||
ssh_channel_close(channel);
|
|
||||||
ssh_disconnect(session);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
while ((rc = ssh_channel_write(channel, buffer, sizeof(buffer))) > 0) {
|
|
||||||
total += rc;
|
|
||||||
if(total/2 >= lastshown){
|
|
||||||
printf("written %llx\n", (long long unsigned int) total);
|
|
||||||
lastshown=total;
|
|
||||||
}
|
}
|
||||||
if(total > LIMIT)
|
|
||||||
break;
|
channel = ssh_channel_new(session);
|
||||||
}
|
if (channel == NULL) {
|
||||||
|
ssh_disconnect(session);
|
||||||
if (rc < 0) {
|
return 1;
|
||||||
printf("error : %s\n",ssh_get_error(session));
|
}
|
||||||
|
|
||||||
|
rc = ssh_channel_open_session(channel);
|
||||||
|
if (rc < 0) {
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
ssh_disconnect(session);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_channel_request_exec(channel, "cat > /dev/null");
|
||||||
|
if (rc < 0) {
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
ssh_disconnect(session);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((rc = ssh_channel_write(channel, buffer, sizeof(buffer))) > 0) {
|
||||||
|
total += rc;
|
||||||
|
if (total / 2 >= lastshown) {
|
||||||
|
printf("written %llx\n", (long long unsigned int)total);
|
||||||
|
lastshown = total;
|
||||||
|
}
|
||||||
|
if (total > LIMIT)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc < 0) {
|
||||||
|
printf("error : %s\n", ssh_get_error(session));
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
ssh_disconnect(session);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_channel_send_eof(channel);
|
||||||
ssh_channel_close(channel);
|
ssh_channel_close(channel);
|
||||||
|
|
||||||
ssh_disconnect(session);
|
ssh_disconnect(session);
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh_channel_send_eof(channel);
|
return 0;
|
||||||
ssh_channel_close(channel);
|
|
||||||
|
|
||||||
ssh_disconnect(session);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,6 @@
|
|||||||
|
|
||||||
#include <libssh/callbacks.h>
|
#include <libssh/callbacks.h>
|
||||||
#include <libssh/libssh.h>
|
#include <libssh/libssh.h>
|
||||||
#include <libssh/sftp.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include "examples_common.h"
|
#include "examples_common.h"
|
||||||
#define MAXCMD 10
|
#define MAXCMD 10
|
||||||
@@ -53,7 +51,7 @@ static struct termios terminal;
|
|||||||
|
|
||||||
static char *pcap_file = NULL;
|
static char *pcap_file = NULL;
|
||||||
|
|
||||||
static char *proxycommand;
|
static char *proxycommand = NULL;
|
||||||
|
|
||||||
static int auth_callback(const char *prompt,
|
static int auth_callback(const char *prompt,
|
||||||
char *buf,
|
char *buf,
|
||||||
@@ -88,23 +86,24 @@ static void add_cmd(char *cmd)
|
|||||||
|
|
||||||
static void usage(void)
|
static void usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(
|
||||||
"Usage : ssh [options] [login@]hostname\n"
|
stderr,
|
||||||
"sample client - libssh-%s\n"
|
"Usage : ssh [options] [login@]hostname\n"
|
||||||
"Options :\n"
|
"sample client - libssh-%s\n"
|
||||||
" -l user : log in as user\n"
|
"Options :\n"
|
||||||
" -p port : connect to port\n"
|
" -l user : log in as user\n"
|
||||||
" -d : use DSS to verify host public key\n"
|
" -p port : connect to port\n"
|
||||||
" -r : use RSA to verify host public key\n"
|
" -o option : set configuration option (e.g., -o Compression=yes)\n"
|
||||||
" -F file : parse configuration file instead of default one\n"
|
" -r : use RSA to verify host public key\n"
|
||||||
|
" -F file : parse configuration file instead of default one\n"
|
||||||
#ifdef WITH_PCAP
|
#ifdef WITH_PCAP
|
||||||
" -P file : create a pcap debugging file\n"
|
" -P file : create a pcap debugging file\n"
|
||||||
#endif
|
#endif
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
" -T proxycommand : command to execute as a socket proxy\n"
|
" -T proxycommand : command to execute as a socket proxy\n"
|
||||||
#endif
|
#endif
|
||||||
"\n",
|
"\n",
|
||||||
ssh_version(0));
|
ssh_version(0));
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
@@ -113,8 +112,8 @@ static int opts(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
while((i = getopt(argc,argv,"T:P:F:")) != -1) {
|
while ((i = getopt(argc, argv, "T:P:F:")) != -1) {
|
||||||
switch(i){
|
switch (i) {
|
||||||
case 'P':
|
case 'P':
|
||||||
pcap_file = optarg;
|
pcap_file = optarg;
|
||||||
break;
|
break;
|
||||||
@@ -160,16 +159,14 @@ static void cfmakeraw(struct termios *termios_p)
|
|||||||
|
|
||||||
static void do_cleanup(int i)
|
static void do_cleanup(int i)
|
||||||
{
|
{
|
||||||
/* unused variable */
|
(void)i;
|
||||||
(void) i;
|
|
||||||
|
|
||||||
tcsetattr(0, TCSANOW, &terminal);
|
tcsetattr(0, TCSANOW, &terminal);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_exit(int i)
|
static void do_exit(int i)
|
||||||
{
|
{
|
||||||
/* unused variable */
|
(void)i;
|
||||||
(void) i;
|
|
||||||
|
|
||||||
do_cleanup(0);
|
do_cleanup(0);
|
||||||
exit(0);
|
exit(0);
|
||||||
@@ -180,7 +177,7 @@ static int signal_delayed = 0;
|
|||||||
#ifdef SIGWINCH
|
#ifdef SIGWINCH
|
||||||
static void sigwindowchanged(int i)
|
static void sigwindowchanged(int i)
|
||||||
{
|
{
|
||||||
(void) i;
|
(void)i;
|
||||||
signal_delayed = 1;
|
signal_delayed = 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -214,18 +211,18 @@ static void select_loop(ssh_session session,ssh_channel channel)
|
|||||||
/* stdin */
|
/* stdin */
|
||||||
connector_in = ssh_connector_new(session);
|
connector_in = ssh_connector_new(session);
|
||||||
ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDINOUT);
|
ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDINOUT);
|
||||||
ssh_connector_set_in_fd(connector_in, 0);
|
ssh_connector_set_in_fd(connector_in, STDIN_FILENO);
|
||||||
ssh_event_add_connector(event, connector_in);
|
ssh_event_add_connector(event, connector_in);
|
||||||
|
|
||||||
/* stdout */
|
/* stdout */
|
||||||
connector_out = ssh_connector_new(session);
|
connector_out = ssh_connector_new(session);
|
||||||
ssh_connector_set_out_fd(connector_out, 1);
|
ssh_connector_set_out_fd(connector_out, STDOUT_FILENO);
|
||||||
ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDINOUT);
|
ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDINOUT);
|
||||||
ssh_event_add_connector(event, connector_out);
|
ssh_event_add_connector(event, connector_out);
|
||||||
|
|
||||||
/* stderr */
|
/* stderr */
|
||||||
connector_err = ssh_connector_new(session);
|
connector_err = ssh_connector_new(session);
|
||||||
ssh_connector_set_out_fd(connector_err, 2);
|
ssh_connector_set_out_fd(connector_err, STDERR_FILENO);
|
||||||
ssh_connector_set_in_channel(connector_err, channel, SSH_CONNECTOR_STDERR);
|
ssh_connector_set_in_channel(connector_err, channel, SSH_CONNECTOR_STDERR);
|
||||||
ssh_event_add_connector(event, connector_err);
|
ssh_event_add_connector(event, connector_err);
|
||||||
|
|
||||||
@@ -252,9 +249,9 @@ static void select_loop(ssh_session session,ssh_channel channel)
|
|||||||
|
|
||||||
static void shell(ssh_session session)
|
static void shell(ssh_session session)
|
||||||
{
|
{
|
||||||
ssh_channel channel;
|
ssh_channel channel = NULL;
|
||||||
struct termios terminal_local;
|
struct termios terminal_local;
|
||||||
int interactive=isatty(0);
|
int interactive = isatty(0);
|
||||||
|
|
||||||
channel = ssh_channel_new(session);
|
channel = ssh_channel_new(session);
|
||||||
if (channel == NULL) {
|
if (channel == NULL) {
|
||||||
@@ -298,25 +295,41 @@ static void shell(ssh_session session)
|
|||||||
static void batch_shell(ssh_session session)
|
static void batch_shell(ssh_session session)
|
||||||
{
|
{
|
||||||
ssh_channel channel;
|
ssh_channel channel;
|
||||||
char buffer[PATH_MAX];
|
char *buffer = NULL;
|
||||||
size_t i;
|
size_t i, s, n;
|
||||||
int s = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < MAXCMD && cmds[i]; ++i) {
|
|
||||||
s += snprintf(buffer + s, sizeof(buffer) - s, "%s ", cmds[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
channel = ssh_channel_new(session);
|
channel = ssh_channel_new(session);
|
||||||
if (channel == NULL) {
|
if (channel == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh_channel_open_session(channel);
|
n = 0;
|
||||||
if (ssh_channel_request_exec(channel, buffer)) {
|
for (i = 0; i < MAXCMD && cmds[i]; ++i) {
|
||||||
printf("Error executing '%s' : %s\n", buffer, ssh_get_error(session));
|
/* Including space after cmds[i] */
|
||||||
|
n += strlen(cmds[i]) + 1;
|
||||||
|
}
|
||||||
|
/* Trailing \0 */
|
||||||
|
n += 1;
|
||||||
|
|
||||||
|
buffer = malloc(n);
|
||||||
|
if (buffer == NULL) {
|
||||||
ssh_channel_free(channel);
|
ssh_channel_free(channel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s = 0;
|
||||||
|
for (i = 0; i < MAXCMD && cmds[i]; ++i) {
|
||||||
|
s += snprintf(buffer + s, n - s, "%s ", cmds[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_channel_open_session(channel);
|
||||||
|
if (ssh_channel_request_exec(channel, buffer)) {
|
||||||
|
printf("Error executing '%s' : %s\n", buffer, ssh_get_error(session));
|
||||||
|
free(buffer);
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free(buffer);
|
||||||
select_loop(session, channel);
|
select_loop(session, channel);
|
||||||
ssh_channel_free(channel);
|
ssh_channel_free(channel);
|
||||||
}
|
}
|
||||||
@@ -324,7 +337,7 @@ static void batch_shell(ssh_session session)
|
|||||||
static int client(ssh_session session)
|
static int client(ssh_session session)
|
||||||
{
|
{
|
||||||
int auth = 0;
|
int auth = 0;
|
||||||
char *banner;
|
char *banner = NULL;
|
||||||
int state;
|
int state;
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
@@ -342,10 +355,8 @@ static int client(ssh_session session)
|
|||||||
}
|
}
|
||||||
/* Parse configuration file if specified: The command-line options will
|
/* Parse configuration file if specified: The command-line options will
|
||||||
* overwrite items loaded from configuration file */
|
* overwrite items loaded from configuration file */
|
||||||
if (config_file != NULL) {
|
if (ssh_options_parse_config(session, config_file) < 0) {
|
||||||
ssh_options_parse_config(session, config_file);
|
return -1;
|
||||||
} else {
|
|
||||||
ssh_options_parse_config(session, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssh_connect(session)) {
|
if (ssh_connect(session)) {
|
||||||
@@ -408,7 +419,7 @@ static void cleanup_pcap(void)
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
ssh_session session;
|
ssh_session session = NULL;
|
||||||
|
|
||||||
ssh_init();
|
ssh_init();
|
||||||
session = ssh_new();
|
session = ssh_new();
|
||||||
|
|||||||
@@ -45,36 +45,10 @@ The goal is to show the API in action.
|
|||||||
#define BUF_SIZE 1048576
|
#define BUF_SIZE 1048576
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef KEYS_FOLDER
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define KEYS_FOLDER
|
|
||||||
#else
|
|
||||||
#define KEYS_FOLDER "/etc/ssh/"
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SESSION_END (SSH_CLOSED | SSH_CLOSED_ERROR)
|
#define SESSION_END (SSH_CLOSED | SSH_CLOSED_ERROR)
|
||||||
#define SFTP_SERVER_PATH "/usr/lib/sftp-server"
|
#define SFTP_SERVER_PATH "/usr/lib/sftp-server"
|
||||||
|
#define AUTH_KEYS_MAX_LINE_SIZE 2048
|
||||||
|
|
||||||
static void set_default_keys(ssh_bind sshbind,
|
|
||||||
int rsa_already_set,
|
|
||||||
int dsa_already_set,
|
|
||||||
int ecdsa_already_set) {
|
|
||||||
if (!rsa_already_set) {
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY,
|
|
||||||
KEYS_FOLDER "ssh_host_rsa_key");
|
|
||||||
}
|
|
||||||
if (!dsa_already_set) {
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY,
|
|
||||||
KEYS_FOLDER "ssh_host_dsa_key");
|
|
||||||
}
|
|
||||||
if (!ecdsa_already_set) {
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY,
|
|
||||||
KEYS_FOLDER "ssh_host_ecdsa_key");
|
|
||||||
}
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY,
|
|
||||||
KEYS_FOLDER "ssh_host_ed25519_key");
|
|
||||||
}
|
|
||||||
#define DEF_STR_SIZE 1024
|
#define DEF_STR_SIZE 1024
|
||||||
char authorizedkeys[DEF_STR_SIZE] = {0};
|
char authorizedkeys[DEF_STR_SIZE] = {0};
|
||||||
char username[128] = "myuser";
|
char username[128] = "myuser";
|
||||||
@@ -109,20 +83,12 @@ static struct argp_option options[] = {
|
|||||||
"Implies no default keys.",
|
"Implies no default keys.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.name = "dsakey",
|
|
||||||
.key = 'd',
|
|
||||||
.arg = "FILE",
|
|
||||||
.flags = 0,
|
|
||||||
.doc = "Set the dsa key.",
|
|
||||||
.group = 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.name = "rsakey",
|
.name = "rsakey",
|
||||||
.key = 'r',
|
.key = 'r',
|
||||||
.arg = "FILE",
|
.arg = "FILE",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.doc = "Set the rsa key.",
|
.doc = "Set the rsa key (deprecated alias for 'k').",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -130,7 +96,7 @@ static struct argp_option options[] = {
|
|||||||
.key = 'e',
|
.key = 'e',
|
||||||
.arg = "FILE",
|
.arg = "FILE",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.doc = "Set the ecdsa key.",
|
.doc = "Set the ecdsa key (deprecated alias for 'k').",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -157,14 +123,6 @@ static struct argp_option options[] = {
|
|||||||
.doc = "Set expected password.",
|
.doc = "Set expected password.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.name = "no-default-keys",
|
|
||||||
.key = 'n',
|
|
||||||
.arg = NULL,
|
|
||||||
.flags = 0,
|
|
||||||
.doc = "Do not set default key locations.",
|
|
||||||
.group = 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.name = "verbose",
|
.name = "verbose",
|
||||||
.key = 'v',
|
.key = 'v',
|
||||||
@@ -177,75 +135,53 @@ static struct argp_option options[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Parse a single option. */
|
/* Parse a single option. */
|
||||||
static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
static error_t
|
||||||
|
parse_opt(int key, char *arg, struct argp_state *state)
|
||||||
|
{
|
||||||
/* Get the input argument from argp_parse, which we
|
/* Get the input argument from argp_parse, which we
|
||||||
* know is a pointer to our arguments structure. */
|
* know is a pointer to our arguments structure. */
|
||||||
ssh_bind sshbind = state->input;
|
ssh_bind sshbind = state->input;
|
||||||
static int no_default_keys = 0;
|
|
||||||
static int rsa_already_set = 0, dsa_already_set = 0, ecdsa_already_set = 0;
|
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'n':
|
case 'p':
|
||||||
no_default_keys = 1;
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'k':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'r':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
dsa_already_set = 1;
|
break;
|
||||||
break;
|
case 'e':
|
||||||
case 'k':
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
break;
|
||||||
/* We can't track the types of keys being added with this
|
case 'a':
|
||||||
option, so let's ensure we keep the keys we're adding
|
strncpy(authorizedkeys, arg, DEF_STR_SIZE - 1);
|
||||||
by just not setting the default keys */
|
break;
|
||||||
no_default_keys = 1;
|
case 'u':
|
||||||
break;
|
strncpy(username, arg, sizeof(username) - 1);
|
||||||
case 'r':
|
break;
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg);
|
case 'P':
|
||||||
rsa_already_set = 1;
|
strncpy(password, arg, sizeof(password) - 1);
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'v':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3");
|
||||||
ecdsa_already_set = 1;
|
break;
|
||||||
break;
|
case ARGP_KEY_ARG:
|
||||||
case 'a':
|
if (state->arg_num >= 1) {
|
||||||
strncpy(authorizedkeys, arg, DEF_STR_SIZE-1);
|
/* Too many arguments. */
|
||||||
break;
|
argp_usage(state);
|
||||||
case 'u':
|
}
|
||||||
strncpy(username, arg, sizeof(username) - 1);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg);
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case ARGP_KEY_END:
|
||||||
strncpy(password, arg, sizeof(password) - 1);
|
if (state->arg_num < 1) {
|
||||||
break;
|
/* Not enough arguments. */
|
||||||
case 'v':
|
argp_usage(state);
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
|
}
|
||||||
"3");
|
break;
|
||||||
break;
|
default:
|
||||||
case ARGP_KEY_ARG:
|
return ARGP_ERR_UNKNOWN;
|
||||||
if (state->arg_num >= 1) {
|
|
||||||
/* Too many arguments. */
|
|
||||||
argp_usage (state);
|
|
||||||
}
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg);
|
|
||||||
break;
|
|
||||||
case ARGP_KEY_END:
|
|
||||||
if (state->arg_num < 1) {
|
|
||||||
/* Not enough arguments. */
|
|
||||||
argp_usage (state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!no_default_keys) {
|
|
||||||
set_default_keys(sshbind,
|
|
||||||
rsa_already_set,
|
|
||||||
dsa_already_set,
|
|
||||||
ecdsa_already_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return ARGP_ERR_UNKNOWN;
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -253,33 +189,20 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
|||||||
/* Our argp parser. */
|
/* Our argp parser. */
|
||||||
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||||
#else
|
#else
|
||||||
static int parse_opt(int argc, char **argv, ssh_bind sshbind) {
|
static int
|
||||||
int no_default_keys = 0;
|
parse_opt(int argc, char **argv, ssh_bind sshbind)
|
||||||
int rsa_already_set = 0;
|
{
|
||||||
int dsa_already_set = 0;
|
|
||||||
int ecdsa_already_set = 0;
|
|
||||||
int key;
|
int key;
|
||||||
|
|
||||||
while((key = getopt(argc, argv, "a:d:e:k:np:P:r:u:v")) != -1) {
|
while((key = getopt(argc, argv, "a:e:k:p:P:r:u:v")) != -1) {
|
||||||
if (key == 'n') {
|
if (key == 'p') {
|
||||||
no_default_keys = 1;
|
|
||||||
} else if (key == 'p') {
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, optarg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, optarg);
|
||||||
} else if (key == 'd') {
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, optarg);
|
|
||||||
dsa_already_set = 1;
|
|
||||||
} else if (key == 'k') {
|
} else if (key == 'k') {
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
|
||||||
/* We can't track the types of keys being added with this
|
|
||||||
option, so let's ensure we keep the keys we're adding
|
|
||||||
by just not setting the default keys */
|
|
||||||
no_default_keys = 1;
|
|
||||||
} else if (key == 'r') {
|
} else if (key == 'r') {
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, optarg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
|
||||||
rsa_already_set = 1;
|
|
||||||
} else if (key == 'e') {
|
} else if (key == 'e') {
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY, optarg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
|
||||||
ecdsa_already_set = 1;
|
|
||||||
} else if (key == 'a') {
|
} else if (key == 'a') {
|
||||||
strncpy(authorizedkeys, optarg, DEF_STR_SIZE-1);
|
strncpy(authorizedkeys, optarg, DEF_STR_SIZE-1);
|
||||||
} else if (key == 'u') {
|
} else if (key == 'u') {
|
||||||
@@ -299,14 +222,12 @@ static int parse_opt(int argc, char **argv, ssh_bind sshbind) {
|
|||||||
"libssh %s -- a Secure Shell protocol implementation\n"
|
"libssh %s -- a Secure Shell protocol implementation\n"
|
||||||
"\n"
|
"\n"
|
||||||
" -a, --authorizedkeys=FILE Set the authorized keys file.\n"
|
" -a, --authorizedkeys=FILE Set the authorized keys file.\n"
|
||||||
" -d, --dsakey=FILE Set the dsa key.\n"
|
" -e, --ecdsakey=FILE Set the ecdsa key (deprecated alias for 'k').\n"
|
||||||
" -e, --ecdsakey=FILE Set the ecdsa key.\n"
|
|
||||||
" -k, --hostkey=FILE Set a host key. Can be used multiple times.\n"
|
" -k, --hostkey=FILE Set a host key. Can be used multiple times.\n"
|
||||||
" Implies no default keys.\n"
|
" Implies no default keys.\n"
|
||||||
" -n, --no-default-keys Do not set default key locations.\n"
|
|
||||||
" -p, --port=PORT Set the port to bind.\n"
|
" -p, --port=PORT Set the port to bind.\n"
|
||||||
" -P, --pass=PASSWORD Set expected password.\n"
|
" -P, --pass=PASSWORD Set expected password.\n"
|
||||||
" -r, --rsakey=FILE Set the rsa key.\n"
|
" -r, --rsakey=FILE Set the rsa key (deprecated alias for 'k').\n"
|
||||||
" -u, --user=USERNAME Set expected username.\n"
|
" -u, --user=USERNAME Set expected username.\n"
|
||||||
" -v, --verbose Get verbose output.\n"
|
" -v, --verbose Get verbose output.\n"
|
||||||
" -?, --help Give this help list\n"
|
" -?, --help Give this help list\n"
|
||||||
@@ -326,13 +247,6 @@ static int parse_opt(int argc, char **argv, ssh_bind sshbind) {
|
|||||||
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, argv[optind]);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, argv[optind]);
|
||||||
|
|
||||||
if (!no_default_keys) {
|
|
||||||
set_default_keys(sshbind,
|
|
||||||
rsa_already_set,
|
|
||||||
dsa_already_set,
|
|
||||||
ecdsa_already_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* HAVE_ARGP_H */
|
#endif /* HAVE_ARGP_H */
|
||||||
@@ -363,49 +277,74 @@ struct session_data_struct {
|
|||||||
int authenticated;
|
int authenticated;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int data_function(ssh_session session, ssh_channel channel, void *data,
|
static int
|
||||||
uint32_t len, int is_stderr, void *userdata) {
|
data_function(ssh_session session,
|
||||||
struct channel_data_struct *cdata = (struct channel_data_struct *) userdata;
|
ssh_channel channel,
|
||||||
|
void *data,
|
||||||
|
uint32_t len,
|
||||||
|
int is_stderr,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
|
||||||
|
|
||||||
(void) session;
|
(void)session;
|
||||||
(void) channel;
|
(void)channel;
|
||||||
(void) is_stderr;
|
(void)is_stderr;
|
||||||
|
|
||||||
if (len == 0 || cdata->pid < 1 || kill(cdata->pid, 0) < 0) {
|
if (len == 0 || cdata->pid < 1 || kill(cdata->pid, 0) < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return write(cdata->child_stdin, (char *) data, len);
|
return write(cdata->child_stdin, (char *)data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pty_request(ssh_session session, ssh_channel channel,
|
static int
|
||||||
const char *term, int cols, int rows, int py, int px,
|
pty_request(ssh_session session,
|
||||||
void *userdata) {
|
ssh_channel channel,
|
||||||
|
const char *term,
|
||||||
|
int cols,
|
||||||
|
int rows,
|
||||||
|
int py,
|
||||||
|
int px,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
|
struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
|
||||||
|
int rc;
|
||||||
|
|
||||||
(void) session;
|
(void)session;
|
||||||
(void) channel;
|
(void)channel;
|
||||||
(void) term;
|
(void)term;
|
||||||
|
|
||||||
cdata->winsize->ws_row = rows;
|
cdata->winsize->ws_row = rows;
|
||||||
cdata->winsize->ws_col = cols;
|
cdata->winsize->ws_col = cols;
|
||||||
cdata->winsize->ws_xpixel = px;
|
cdata->winsize->ws_xpixel = px;
|
||||||
cdata->winsize->ws_ypixel = py;
|
cdata->winsize->ws_ypixel = py;
|
||||||
|
|
||||||
if (openpty(&cdata->pty_master, &cdata->pty_slave, NULL, NULL,
|
rc = openpty(&cdata->pty_master,
|
||||||
cdata->winsize) != 0) {
|
&cdata->pty_slave,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
cdata->winsize);
|
||||||
|
if (rc != 0) {
|
||||||
fprintf(stderr, "Failed to open pty\n");
|
fprintf(stderr, "Failed to open pty\n");
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pty_resize(ssh_session session, ssh_channel channel, int cols,
|
static int
|
||||||
int rows, int py, int px, void *userdata) {
|
pty_resize(ssh_session session,
|
||||||
|
ssh_channel channel,
|
||||||
|
int cols,
|
||||||
|
int rows,
|
||||||
|
int py,
|
||||||
|
int px,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
|
struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
|
||||||
|
|
||||||
(void) session;
|
(void)session;
|
||||||
(void) channel;
|
(void)channel;
|
||||||
|
|
||||||
cdata->winsize->ws_row = rows;
|
cdata->winsize->ws_row = rows;
|
||||||
cdata->winsize->ws_col = cols;
|
cdata->winsize->ws_col = cols;
|
||||||
@@ -419,30 +358,36 @@ static int pty_resize(ssh_session session, ssh_channel channel, int cols,
|
|||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exec_pty(const char *mode, const char *command,
|
static int
|
||||||
struct channel_data_struct *cdata) {
|
exec_pty(const char *mode,
|
||||||
switch(cdata->pid = fork()) {
|
const char *command,
|
||||||
case -1:
|
struct channel_data_struct *cdata)
|
||||||
close(cdata->pty_master);
|
{
|
||||||
close(cdata->pty_slave);
|
cdata->pid = fork();
|
||||||
fprintf(stderr, "Failed to fork\n");
|
switch (cdata->pid) {
|
||||||
return SSH_ERROR;
|
case -1:
|
||||||
case 0:
|
close(cdata->pty_master);
|
||||||
close(cdata->pty_master);
|
close(cdata->pty_slave);
|
||||||
if (login_tty(cdata->pty_slave) != 0) {
|
fprintf(stderr, "Failed to fork\n");
|
||||||
exit(1);
|
return SSH_ERROR;
|
||||||
}
|
case 0:
|
||||||
execl("/bin/sh", "sh", mode, command, NULL);
|
close(cdata->pty_master);
|
||||||
exit(0);
|
if (login_tty(cdata->pty_slave) != 0) {
|
||||||
default:
|
exit(1);
|
||||||
close(cdata->pty_slave);
|
}
|
||||||
/* pty fd is bi-directional */
|
execl("/bin/sh", "sh", mode, command, NULL);
|
||||||
cdata->child_stdout = cdata->child_stdin = cdata->pty_master;
|
exit(0);
|
||||||
|
default:
|
||||||
|
close(cdata->pty_slave);
|
||||||
|
/* pty fd is bi-directional */
|
||||||
|
cdata->child_stdout = cdata->child_stdin = cdata->pty_master;
|
||||||
}
|
}
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exec_nopty(const char *command, struct channel_data_struct *cdata) {
|
static int
|
||||||
|
exec_nopty(const char *command, struct channel_data_struct *cdata)
|
||||||
|
{
|
||||||
int in[2], out[2], err[2];
|
int in[2], out[2], err[2];
|
||||||
|
|
||||||
/* Do the plumbing to be able to talk with the child process. */
|
/* Do the plumbing to be able to talk with the child process. */
|
||||||
@@ -456,23 +401,24 @@ static int exec_nopty(const char *command, struct channel_data_struct *cdata) {
|
|||||||
goto stderr_failed;
|
goto stderr_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(cdata->pid = fork()) {
|
cdata->pid = fork();
|
||||||
case -1:
|
switch (cdata->pid) {
|
||||||
goto fork_failed;
|
case -1:
|
||||||
case 0:
|
goto fork_failed;
|
||||||
/* Finish the plumbing in the child process. */
|
case 0:
|
||||||
close(in[1]);
|
/* Finish the plumbing in the child process. */
|
||||||
close(out[0]);
|
close(in[1]);
|
||||||
close(err[0]);
|
close(out[0]);
|
||||||
dup2(in[0], STDIN_FILENO);
|
close(err[0]);
|
||||||
dup2(out[1], STDOUT_FILENO);
|
dup2(in[0], STDIN_FILENO);
|
||||||
dup2(err[1], STDERR_FILENO);
|
dup2(out[1], STDOUT_FILENO);
|
||||||
close(in[0]);
|
dup2(err[1], STDERR_FILENO);
|
||||||
close(out[1]);
|
close(in[0]);
|
||||||
close(err[1]);
|
close(out[1]);
|
||||||
/* exec the requested command. */
|
close(err[1]);
|
||||||
execl("/bin/sh", "sh", "-c", command, NULL);
|
/* exec the requested command. */
|
||||||
exit(0);
|
execl("/bin/sh", "sh", "-c", command, NULL);
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(in[0]);
|
close(in[0]);
|
||||||
@@ -498,15 +444,18 @@ stdin_failed:
|
|||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exec_request(ssh_session session, ssh_channel channel,
|
static int
|
||||||
const char *command, void *userdata) {
|
exec_request(ssh_session session,
|
||||||
struct channel_data_struct *cdata = (struct channel_data_struct *) userdata;
|
ssh_channel channel,
|
||||||
|
const char *command,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
|
||||||
|
|
||||||
|
(void)session;
|
||||||
|
(void)channel;
|
||||||
|
|
||||||
(void) session;
|
if (cdata->pid > 0) {
|
||||||
(void) channel;
|
|
||||||
|
|
||||||
if(cdata->pid > 0) {
|
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,14 +465,15 @@ static int exec_request(ssh_session session, ssh_channel channel,
|
|||||||
return exec_nopty(command, cdata);
|
return exec_nopty(command, cdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int shell_request(ssh_session session, ssh_channel channel,
|
static int
|
||||||
void *userdata) {
|
shell_request(ssh_session session, ssh_channel channel, void *userdata)
|
||||||
struct channel_data_struct *cdata = (struct channel_data_struct *) userdata;
|
{
|
||||||
|
struct channel_data_struct *cdata = (struct channel_data_struct *)userdata;
|
||||||
|
|
||||||
(void) session;
|
(void)session;
|
||||||
(void) channel;
|
(void)channel;
|
||||||
|
|
||||||
if(cdata->pid > 0) {
|
if (cdata->pid > 0) {
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -534,20 +484,28 @@ static int shell_request(ssh_session session, ssh_channel channel,
|
|||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int subsystem_request(ssh_session session, ssh_channel channel,
|
static int
|
||||||
const char *subsystem, void *userdata) {
|
subsystem_request(ssh_session session,
|
||||||
/* subsystem requests behave simillarly to exec requests. */
|
ssh_channel channel,
|
||||||
|
const char *subsystem,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
/* subsystem requests behave similarly to exec requests. */
|
||||||
if (strcmp(subsystem, "sftp") == 0) {
|
if (strcmp(subsystem, "sftp") == 0) {
|
||||||
return exec_request(session, channel, SFTP_SERVER_PATH, userdata);
|
return exec_request(session, channel, SFTP_SERVER_PATH, userdata);
|
||||||
}
|
}
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int auth_password(ssh_session session, const char *user,
|
static int
|
||||||
const char *pass, void *userdata) {
|
auth_password(ssh_session session,
|
||||||
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
|
const char *user,
|
||||||
|
const char *pass,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
struct session_data_struct *sdata = (struct session_data_struct *)userdata;
|
||||||
|
|
||||||
(void) session;
|
(void)session;
|
||||||
|
|
||||||
if (strcmp(user, username) == 0 && strcmp(pass, password) == 0) {
|
if (strcmp(user, username) == 0 && strcmp(pass, password) == 0) {
|
||||||
sdata->authenticated = 1;
|
sdata->authenticated = 1;
|
||||||
@@ -558,16 +516,26 @@ static int auth_password(ssh_session session, const char *user,
|
|||||||
return SSH_AUTH_DENIED;
|
return SSH_AUTH_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int auth_publickey(ssh_session session,
|
static int
|
||||||
const char *user,
|
auth_publickey(ssh_session session,
|
||||||
struct ssh_key_struct *pubkey,
|
const char *user,
|
||||||
char signature_state,
|
struct ssh_key_struct *pubkey,
|
||||||
void *userdata)
|
char signature_state,
|
||||||
|
void *userdata)
|
||||||
{
|
{
|
||||||
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
|
struct session_data_struct *sdata = (struct session_data_struct *)userdata;
|
||||||
|
ssh_key key = NULL;
|
||||||
|
FILE *fp = NULL;
|
||||||
|
char line[AUTH_KEYS_MAX_LINE_SIZE] = {0};
|
||||||
|
char *p = NULL;
|
||||||
|
const char *q = NULL;
|
||||||
|
unsigned int lineno = 0;
|
||||||
|
int result;
|
||||||
|
int i;
|
||||||
|
enum ssh_keytypes_e type;
|
||||||
|
|
||||||
(void) user;
|
(void)user;
|
||||||
(void) session;
|
(void)session;
|
||||||
|
|
||||||
if (signature_state == SSH_PUBLICKEY_STATE_NONE) {
|
if (signature_state == SSH_PUBLICKEY_STATE_NONE) {
|
||||||
return SSH_AUTH_SUCCESS;
|
return SSH_AUTH_SUCCESS;
|
||||||
@@ -577,45 +545,159 @@ static int auth_publickey(ssh_session session,
|
|||||||
return SSH_AUTH_DENIED;
|
return SSH_AUTH_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// valid so far. Now look through authorized keys for a match
|
fp = fopen(authorizedkeys, "r");
|
||||||
if (authorizedkeys[0]) {
|
if (fp == NULL) {
|
||||||
ssh_key key = NULL;
|
fprintf(stderr, "Error: opening authorized keys file %s failed, reason: %s\n",
|
||||||
int result;
|
authorizedkeys, strerror(errno));
|
||||||
struct stat buf;
|
return SSH_AUTH_DENIED;
|
||||||
|
|
||||||
if (stat(authorizedkeys, &buf) == 0) {
|
|
||||||
result = ssh_pki_import_pubkey_file( authorizedkeys, &key );
|
|
||||||
if ((result != SSH_OK) || (key==NULL)) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Unable to import public key file %s\n",
|
|
||||||
authorizedkeys);
|
|
||||||
} else {
|
|
||||||
result = ssh_key_cmp( key, pubkey, SSH_KEY_CMP_PUBLIC );
|
|
||||||
ssh_key_free(key);
|
|
||||||
if (result == 0) {
|
|
||||||
sdata->authenticated = 1;
|
|
||||||
return SSH_AUTH_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// no matches
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
sdata->authenticated = 0;
|
lineno++;
|
||||||
|
|
||||||
|
/* Skip leading whitespace and ignore comments */
|
||||||
|
p = line;
|
||||||
|
|
||||||
|
for (i = 0; i < AUTH_KEYS_MAX_LINE_SIZE; i++) {
|
||||||
|
if (!isspace((int)p[i])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= AUTH_KEYS_MAX_LINE_SIZE) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"warning: The line %d in %s too long! Skipping.\n",
|
||||||
|
lineno,
|
||||||
|
authorizedkeys);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p[i] == '#' || p[i] == '\0' || p[i] == '\n') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
q = &p[i];
|
||||||
|
for (; i < AUTH_KEYS_MAX_LINE_SIZE; i++) {
|
||||||
|
if (isspace((int)p[i])) {
|
||||||
|
p[i] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type = ssh_key_type_from_name(q);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
if (i >= AUTH_KEYS_MAX_LINE_SIZE) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"warning: The line %d in %s too long! Skipping.\n",
|
||||||
|
lineno,
|
||||||
|
authorizedkeys);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
q = &p[i];
|
||||||
|
for (; i < AUTH_KEYS_MAX_LINE_SIZE; i++) {
|
||||||
|
if (isspace((int)p[i])) {
|
||||||
|
p[i] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = ssh_pki_import_pubkey_base64(q, type, &key);
|
||||||
|
if (result != SSH_OK) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Warning: Cannot import key on line no. %d in authorized keys file: %s\n",
|
||||||
|
lineno,
|
||||||
|
authorizedkeys);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = ssh_key_cmp(key, pubkey, SSH_KEY_CMP_PUBLIC);
|
||||||
|
ssh_key_free(key);
|
||||||
|
if (result == 0) {
|
||||||
|
sdata->authenticated = 1;
|
||||||
|
fclose(fp);
|
||||||
|
return SSH_AUTH_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ferror(fp) != 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error: Reading from authorized keys file %s failed, reason: %s\n",
|
||||||
|
authorizedkeys, strerror(errno));
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
/* no matches */
|
||||||
return SSH_AUTH_DENIED;
|
return SSH_AUTH_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssh_channel channel_open(ssh_session session, void *userdata) {
|
static int kbdint_check_response(ssh_session session)
|
||||||
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
|
{
|
||||||
|
int count, cmp;
|
||||||
|
const char *answer = NULL;
|
||||||
|
|
||||||
|
count = ssh_userauth_kbdint_getnanswers(session);
|
||||||
|
if (count != 2) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
answer = ssh_userauth_kbdint_getanswer(session, 0);
|
||||||
|
cmp = strcasecmp("omnitrix", answer);
|
||||||
|
if (cmp != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
answer = ssh_userauth_kbdint_getanswer(session, 1);
|
||||||
|
cmp = strcmp("000", answer);
|
||||||
|
if (cmp != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
auth_kbdint(ssh_message message, ssh_session session, void *userdata)
|
||||||
|
{
|
||||||
|
struct session_data_struct *sdata = (struct session_data_struct *)userdata;
|
||||||
|
const char *name = "\n\nKeyboard-Interactive Fancy Authentication\n";
|
||||||
|
const char *instruction = "Most powerful weapon in the galaxy";
|
||||||
|
const char *prompts[2] = {"Name of the weapon: ", "Destruct Code: "};
|
||||||
|
char echo[] = {1, 0};
|
||||||
|
if (!ssh_message_auth_kbdint_is_response(message)) {
|
||||||
|
printf("User %s wants to auth with kbdint\n",
|
||||||
|
ssh_message_auth_user(message));
|
||||||
|
ssh_message_auth_interactive_request(message,
|
||||||
|
name,
|
||||||
|
instruction,
|
||||||
|
2,
|
||||||
|
prompts,
|
||||||
|
echo);
|
||||||
|
return SSH_AUTH_INFO;
|
||||||
|
} else {
|
||||||
|
if (kbdint_check_response(session)) {
|
||||||
|
sdata->authenticated = 1;
|
||||||
|
return SSH_AUTH_SUCCESS;
|
||||||
|
}
|
||||||
|
return SSH_AUTH_DENIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssh_channel
|
||||||
|
channel_open(ssh_session session, void *userdata)
|
||||||
|
{
|
||||||
|
struct session_data_struct *sdata = (struct session_data_struct *)userdata;
|
||||||
|
|
||||||
sdata->channel = ssh_channel_new(session);
|
sdata->channel = ssh_channel_new(session);
|
||||||
return sdata->channel;
|
return sdata->channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_stdout(socket_t fd, int revents, void *userdata) {
|
static int
|
||||||
|
process_stdout(socket_t fd, int revents, void *userdata)
|
||||||
|
{
|
||||||
char buf[BUF_SIZE];
|
char buf[BUF_SIZE];
|
||||||
int n = -1;
|
int n = -1;
|
||||||
ssh_channel channel = (ssh_channel) userdata;
|
ssh_channel channel = (ssh_channel)userdata;
|
||||||
|
|
||||||
if (channel != NULL && (revents & POLLIN) != 0) {
|
if (channel != NULL && (revents & POLLIN) != 0) {
|
||||||
n = read(fd, buf, BUF_SIZE);
|
n = read(fd, buf, BUF_SIZE);
|
||||||
@@ -627,10 +709,12 @@ static int process_stdout(socket_t fd, int revents, void *userdata) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_stderr(socket_t fd, int revents, void *userdata) {
|
static int
|
||||||
|
process_stderr(socket_t fd, int revents, void *userdata)
|
||||||
|
{
|
||||||
char buf[BUF_SIZE];
|
char buf[BUF_SIZE];
|
||||||
int n = -1;
|
int n = -1;
|
||||||
ssh_channel channel = (ssh_channel) userdata;
|
ssh_channel channel = (ssh_channel)userdata;
|
||||||
|
|
||||||
if (channel != NULL && (revents & POLLIN) != 0) {
|
if (channel != NULL && (revents & POLLIN) != 0) {
|
||||||
n = read(fd, buf, BUF_SIZE);
|
n = read(fd, buf, BUF_SIZE);
|
||||||
@@ -642,7 +726,9 @@ static int process_stderr(socket_t fd, int revents, void *userdata) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_session(ssh_event event, ssh_session session) {
|
static void
|
||||||
|
handle_session(ssh_event event, ssh_session session)
|
||||||
|
{
|
||||||
int n;
|
int n;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
@@ -686,14 +772,15 @@ static void handle_session(ssh_event event, ssh_session session) {
|
|||||||
struct ssh_server_callbacks_struct server_cb = {
|
struct ssh_server_callbacks_struct server_cb = {
|
||||||
.userdata = &sdata,
|
.userdata = &sdata,
|
||||||
.auth_password_function = auth_password,
|
.auth_password_function = auth_password,
|
||||||
|
.auth_kbdint_function = auth_kbdint,
|
||||||
.channel_open_request_session_function = channel_open,
|
.channel_open_request_session_function = channel_open,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (authorizedkeys[0]) {
|
if (authorizedkeys[0]) {
|
||||||
server_cb.auth_pubkey_function = auth_publickey;
|
server_cb.auth_pubkey_function = auth_publickey;
|
||||||
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY);
|
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_INTERACTIVE);
|
||||||
} else
|
} else
|
||||||
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
|
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_INTERACTIVE);
|
||||||
|
|
||||||
ssh_callbacks_init(&server_cb);
|
ssh_callbacks_init(&server_cb);
|
||||||
ssh_callbacks_init(&channel_cb);
|
ssh_callbacks_init(&channel_cb);
|
||||||
@@ -755,8 +842,8 @@ static void handle_session(ssh_event event, ssh_session session) {
|
|||||||
ssh_channel_close(sdata.channel);
|
ssh_channel_close(sdata.channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while(ssh_channel_is_open(sdata.channel) &&
|
} while (ssh_channel_is_open(sdata.channel) &&
|
||||||
(cdata.pid == 0 || waitpid(cdata.pid, &rc, WNOHANG) == 0));
|
(cdata.pid == 0 || waitpid(cdata.pid, &rc, WNOHANG) == 0));
|
||||||
|
|
||||||
close(cdata.pty_master);
|
close(cdata.pty_master);
|
||||||
close(cdata.child_stdin);
|
close(cdata.child_stdin);
|
||||||
@@ -789,12 +876,14 @@ static void handle_session(ssh_event event, ssh_session session) {
|
|||||||
|
|
||||||
#ifdef WITH_FORK
|
#ifdef WITH_FORK
|
||||||
/* SIGCHLD handler for cleaning up dead children. */
|
/* SIGCHLD handler for cleaning up dead children. */
|
||||||
static void sigchld_handler(int signo) {
|
static void sigchld_handler(int signo)
|
||||||
(void) signo;
|
{
|
||||||
|
(void)signo;
|
||||||
while (waitpid(-1, NULL, WNOHANG) > 0);
|
while (waitpid(-1, NULL, WNOHANG) > 0);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static void *session_thread(void *arg) {
|
static void *session_thread(void *arg)
|
||||||
|
{
|
||||||
ssh_session session = arg;
|
ssh_session session = arg;
|
||||||
ssh_event event;
|
ssh_event event;
|
||||||
|
|
||||||
@@ -813,9 +902,10 @@ static void *session_thread(void *arg) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv)
|
||||||
ssh_bind sshbind;
|
{
|
||||||
ssh_session session;
|
ssh_bind sshbind = NULL;
|
||||||
|
ssh_session session = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
#ifdef WITH_FORK
|
#ifdef WITH_FORK
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
@@ -853,7 +943,8 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
#endif /* HAVE_ARGP_H */
|
#endif /* HAVE_ARGP_H */
|
||||||
|
|
||||||
if(ssh_bind_listen(sshbind) < 0) {
|
rc = ssh_bind_listen(sshbind);
|
||||||
|
if (rc < 0) {
|
||||||
fprintf(stderr, "%s\n", ssh_get_error(sshbind));
|
fprintf(stderr, "%s\n", ssh_get_error(sshbind));
|
||||||
ssh_bind_free(sshbind);
|
ssh_bind_free(sshbind);
|
||||||
ssh_finalize();
|
ssh_finalize();
|
||||||
@@ -868,34 +959,36 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Blocks until there is a new incoming connection. */
|
/* Blocks until there is a new incoming connection. */
|
||||||
if(ssh_bind_accept(sshbind, session) != SSH_ERROR) {
|
rc = ssh_bind_accept(sshbind, session);
|
||||||
|
if (rc != SSH_ERROR) {
|
||||||
#ifdef WITH_FORK
|
#ifdef WITH_FORK
|
||||||
ssh_event event;
|
ssh_event event;
|
||||||
|
|
||||||
switch(fork()) {
|
pid_t pid = fork();
|
||||||
case 0:
|
switch (pid) {
|
||||||
/* Remove the SIGCHLD handler inherited from parent. */
|
case 0:
|
||||||
sa.sa_handler = SIG_DFL;
|
/* Remove the SIGCHLD handler inherited from parent. */
|
||||||
sigaction(SIGCHLD, &sa, NULL);
|
sa.sa_handler = SIG_DFL;
|
||||||
/* Remove socket binding, which allows us to restart the
|
sigaction(SIGCHLD, &sa, NULL);
|
||||||
* parent process, without terminating existing sessions. */
|
/* Remove socket binding, which allows us to restart the
|
||||||
ssh_bind_free(sshbind);
|
* parent process, without terminating existing sessions. */
|
||||||
|
ssh_bind_free(sshbind);
|
||||||
|
|
||||||
event = ssh_event_new();
|
event = ssh_event_new();
|
||||||
if (event != NULL) {
|
if (event != NULL) {
|
||||||
/* Blocks until the SSH session ends by either
|
/* Blocks until the SSH session ends by either
|
||||||
* child process exiting, or client disconnecting. */
|
* child process exiting, or client disconnecting. */
|
||||||
handle_session(event, session);
|
handle_session(event, session);
|
||||||
ssh_event_free(event);
|
ssh_event_free(event);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Could not create polling context\n");
|
fprintf(stderr, "Could not create polling context\n");
|
||||||
}
|
}
|
||||||
ssh_disconnect(session);
|
ssh_disconnect(session);
|
||||||
ssh_free(session);
|
ssh_free(session);
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
case -1:
|
case -1:
|
||||||
fprintf(stderr, "Failed to fork\n");
|
fprintf(stderr, "Failed to fork\n");
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
pthread_t tid;
|
pthread_t tid;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ clients must be made or how a client should react.
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Example:
|
Example:
|
||||||
./sshd_direct-tcpip -v -p 2022 -d serverkey.dsa -r serverkey.rsa 127.0.0.1
|
./sshd_direct-tcpip -v -p 2022 -r serverkey.rsa 127.0.0.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -27,6 +27,9 @@ clients must be made or how a client should react.
|
|||||||
#ifdef HAVE_ARGP_H
|
#ifdef HAVE_ARGP_H
|
||||||
#include <argp.h>
|
#include <argp.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#endif
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -91,8 +94,11 @@ cleanup_push(struct cleanup_node_struct** head_ref,
|
|||||||
{
|
{
|
||||||
// Allocate memory for node
|
// Allocate memory for node
|
||||||
struct cleanup_node_struct *new_node = malloc(sizeof *new_node);
|
struct cleanup_node_struct *new_node = malloc(sizeof *new_node);
|
||||||
|
if (new_node == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (head_ref != NULL) {
|
if (*head_ref != NULL) {
|
||||||
new_node->next = *head_ref;
|
new_node->next = *head_ref;
|
||||||
} else {
|
} else {
|
||||||
new_node->next = NULL;
|
new_node->next = NULL;
|
||||||
@@ -197,7 +203,7 @@ subsystem_request(UNUSED_PARAM(ssh_session session),
|
|||||||
UNUSED_PARAM(void *userdata))
|
UNUSED_PARAM(void *userdata))
|
||||||
{
|
{
|
||||||
_ssh_log(SSH_LOG_PROTOCOL,
|
_ssh_log(SSH_LOG_PROTOCOL,
|
||||||
"=== subsystem_request", "Channel subsystem reqeuest: %s",
|
"=== subsystem_request", "Channel subsystem request: %s",
|
||||||
subsystem);
|
subsystem);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -293,7 +299,7 @@ my_channel_eof_function(ssh_session session,
|
|||||||
|
|
||||||
_ssh_log(SSH_LOG_PROTOCOL,
|
_ssh_log(SSH_LOG_PROTOCOL,
|
||||||
"=== my_channel_eof_function",
|
"=== my_channel_eof_function",
|
||||||
"Got EOF on channel. Shuting down write on socket (fd = %d).",
|
"Got EOF on channel. Shutting down write on socket (fd = %d).",
|
||||||
*event_fd_data->p_fd);
|
*event_fd_data->p_fd);
|
||||||
|
|
||||||
stack_socket_close(session, event_fd_data);
|
stack_socket_close(session, event_fd_data);
|
||||||
@@ -355,7 +361,7 @@ my_fd_data_function(UNUSED_PARAM(socket_t fd),
|
|||||||
{
|
{
|
||||||
struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
|
struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
|
||||||
ssh_channel channel = event_fd_data->channel;
|
ssh_channel channel = event_fd_data->channel;
|
||||||
ssh_session session;
|
ssh_session session = NULL;
|
||||||
int len, i, wr;
|
int len, i, wr;
|
||||||
char buf[BUF_SIZE];
|
char buf[BUF_SIZE];
|
||||||
int blocking;
|
int blocking;
|
||||||
@@ -449,8 +455,8 @@ open_tcp_socket(ssh_message msg)
|
|||||||
{
|
{
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
int forwardsock = -1;
|
int forwardsock = -1;
|
||||||
struct hostent *host;
|
struct hostent *host = NULL;
|
||||||
const char *dest_hostname;
|
const char *dest_hostname = NULL;
|
||||||
int dest_port;
|
int dest_port;
|
||||||
|
|
||||||
forwardsock = socket(AF_INET, SOCK_STREAM, 0);
|
forwardsock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
@@ -493,8 +499,8 @@ message_callback(UNUSED_PARAM(ssh_session session),
|
|||||||
UNUSED_PARAM(void *userdata))
|
UNUSED_PARAM(void *userdata))
|
||||||
{
|
{
|
||||||
ssh_channel channel;
|
ssh_channel channel;
|
||||||
int socket_fd, *pFd;
|
int socket_fd, *pFd = NULL;
|
||||||
struct ssh_channel_callbacks_struct *cb_chan;
|
struct ssh_channel_callbacks_struct *cb_chan = NULL;
|
||||||
struct event_fd_data_struct *event_fd_data;
|
struct event_fd_data_struct *event_fd_data;
|
||||||
|
|
||||||
_ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message type: %d",
|
_ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message type: %d",
|
||||||
@@ -520,7 +526,7 @@ message_callback(UNUSED_PARAM(ssh_session session),
|
|||||||
}
|
}
|
||||||
|
|
||||||
pFd = malloc(sizeof *pFd);
|
pFd = malloc(sizeof *pFd);
|
||||||
cb_chan = malloc(sizeof *cb_chan);
|
cb_chan = calloc(1, sizeof *cb_chan);
|
||||||
event_fd_data = malloc(sizeof *event_fd_data);
|
event_fd_data = malloc(sizeof *event_fd_data);
|
||||||
if (pFd == NULL || cb_chan == NULL || event_fd_data == NULL) {
|
if (pFd == NULL || cb_chan == NULL || event_fd_data == NULL) {
|
||||||
SAFE_FREE(pFd);
|
SAFE_FREE(pFd);
|
||||||
@@ -583,20 +589,12 @@ static struct argp_option options[] = {
|
|||||||
.doc = "Set the host key.",
|
.doc = "Set the host key.",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.name = "dsakey",
|
|
||||||
.key = 'd',
|
|
||||||
.arg = "FILE",
|
|
||||||
.flags = 0,
|
|
||||||
.doc = "Set the dsa key.",
|
|
||||||
.group = 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.name = "rsakey",
|
.name = "rsakey",
|
||||||
.key = 'r',
|
.key = 'r',
|
||||||
.arg = "FILE",
|
.arg = "FILE",
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.doc = "Set the rsa key.",
|
.doc = "Set the rsa key (deprecated alias for 'k').",
|
||||||
.group = 0
|
.group = 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -623,15 +621,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
|||||||
case 'p':
|
case 'p':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'r':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg);
|
|
||||||
break;
|
|
||||||
case 'k':
|
case 'k':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg);
|
|
||||||
break;
|
|
||||||
case 'v':
|
case 'v':
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "1");
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "1");
|
||||||
break;
|
break;
|
||||||
@@ -662,8 +655,8 @@ static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
|||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
ssh_session session;
|
ssh_session session = NULL;
|
||||||
ssh_bind sshbind;
|
ssh_bind sshbind = NULL;
|
||||||
struct ssh_server_callbacks_struct cb = {
|
struct ssh_server_callbacks_struct cb = {
|
||||||
.userdata = NULL,
|
.userdata = NULL,
|
||||||
.auth_password_function = auth_password,
|
.auth_password_function = auth_password,
|
||||||
@@ -682,8 +675,7 @@ main(int argc, char **argv)
|
|||||||
session = ssh_new();
|
session = ssh_new();
|
||||||
mainloop = ssh_event_new();
|
mainloop = ssh_event_new();
|
||||||
|
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, KEYS_FOLDER "ssh_host_dsa_key");
|
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, KEYS_FOLDER "ssh_host_rsa_key");
|
||||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, KEYS_FOLDER "ssh_host_rsa_key");
|
|
||||||
|
|
||||||
#ifdef HAVE_ARGP_H
|
#ifdef HAVE_ARGP_H
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -39,222 +39,237 @@ clients must be made or how a client should react.
|
|||||||
#define BUF_SIZE 4096
|
#define BUF_SIZE 4096
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char *host;
|
char *host = NULL;
|
||||||
const char *desthost="localhost";
|
const char *desthost = "localhost";
|
||||||
const char *port="22";
|
const char *port = "22";
|
||||||
|
|
||||||
#ifdef WITH_PCAP
|
#ifdef WITH_PCAP
|
||||||
#include <libssh/pcap.h>
|
#include <libssh/pcap.h>
|
||||||
char *pcap_file=NULL;
|
char *pcap_file = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void usage(void)
|
static void usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr,"Usage : sshnetcat [user@]host forwarded_host forwarded_port\n");
|
fprintf(stderr,
|
||||||
exit(1);
|
"Usage : sshnetcat [user@]host forwarded_host forwarded_port\n");
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int opts(int argc, char **argv){
|
static int opts(int argc, char **argv)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
while((i=getopt(argc,argv,"P:"))!=-1){
|
while ((i = getopt(argc, argv, "P:")) != -1) {
|
||||||
switch(i){
|
switch (i) {
|
||||||
#ifdef WITH_PCAP
|
#ifdef WITH_PCAP
|
||||||
case 'P':
|
case 'P':
|
||||||
pcap_file=optarg;
|
pcap_file = optarg;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
fprintf(stderr,"unknown option %c\n",optopt);
|
fprintf(stderr, "unknown option %c\n", optopt);
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(optind < argc)
|
if (optind < argc)
|
||||||
host=argv[optind++];
|
host = argv[optind++];
|
||||||
if(optind < argc)
|
if (optind < argc)
|
||||||
desthost=argv[optind++];
|
desthost = argv[optind++];
|
||||||
if(optind < argc)
|
if (optind < argc)
|
||||||
port=argv[optind++];
|
port = argv[optind++];
|
||||||
if(host==NULL)
|
if (host == NULL)
|
||||||
usage();
|
usage();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void select_loop(ssh_session session,ssh_channel channel){
|
static void select_loop(ssh_session session, ssh_channel channel)
|
||||||
fd_set fds;
|
{
|
||||||
struct timeval timeout;
|
fd_set fds;
|
||||||
char buffer[BUF_SIZE];
|
struct timeval timeout;
|
||||||
/* channels will be set to the channels to poll.
|
char buffer[BUF_SIZE];
|
||||||
* outchannels will contain the result of the poll
|
/* 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;
|
ssh_channel channels[2], outchannels[2];
|
||||||
int eof=0;
|
int lus;
|
||||||
int maxfd;
|
int eof = 0;
|
||||||
int ret;
|
int maxfd;
|
||||||
while(channel){
|
int ret;
|
||||||
do{
|
while (channel) {
|
||||||
|
do {
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
ZERO_STRUCT(fds);
|
ZERO_STRUCT(fds);
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
if(!eof)
|
if (!eof)
|
||||||
FD_SET(0,&fds);
|
FD_SET(0, &fds);
|
||||||
timeout.tv_sec=30;
|
timeout.tv_sec = 30;
|
||||||
timeout.tv_usec=0;
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
fd = ssh_get_fd(session);
|
fd = ssh_get_fd(session);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
fprintf(stderr, "Error getting the session file descriptor: %s\n",
|
fprintf(stderr,
|
||||||
ssh_get_error(session));
|
"Error getting the session file descriptor: %s\n",
|
||||||
|
ssh_get_error(session));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FD_SET(fd, &fds);
|
FD_SET(fd, &fds);
|
||||||
maxfd = fd + 1;
|
maxfd = fd + 1;
|
||||||
|
|
||||||
channels[0]=channel; // set the first channel we want to read from
|
channels[0] = channel; // set the first channel we want to read from
|
||||||
channels[1]=NULL;
|
channels[1] = NULL;
|
||||||
ret=ssh_select(channels,outchannels,maxfd,&fds,&timeout);
|
ret = ssh_select(channels, outchannels, maxfd, &fds, &timeout);
|
||||||
if(ret==EINTR)
|
if (ret == EINTR)
|
||||||
continue;
|
continue;
|
||||||
if(FD_ISSET(0,&fds)){
|
if (FD_ISSET(0, &fds)) {
|
||||||
lus=read(0,buffer,sizeof(buffer));
|
lus = read(0, buffer, sizeof(buffer));
|
||||||
if(lus)
|
if (lus)
|
||||||
ssh_channel_write(channel,buffer,lus);
|
ssh_channel_write(channel, buffer, lus);
|
||||||
else {
|
else {
|
||||||
eof=1;
|
eof = 1;
|
||||||
ssh_channel_send_eof(channel);
|
ssh_channel_send_eof(channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(channel && ssh_channel_is_closed(channel)){
|
if (channel && ssh_channel_is_closed(channel)) {
|
||||||
ssh_channel_free(channel);
|
ssh_channel_free(channel);
|
||||||
channel=NULL;
|
channel = NULL;
|
||||||
channels[0]=NULL;
|
channels[0] = NULL;
|
||||||
}
|
}
|
||||||
if(outchannels[0]){
|
if (outchannels[0]) {
|
||||||
while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,0)){
|
while (channel && ssh_channel_is_open(channel) &&
|
||||||
lus = ssh_channel_read(channel,buffer,sizeof(buffer),0);
|
ssh_channel_poll(channel, 0)) {
|
||||||
if(lus==-1){
|
lus = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
|
||||||
fprintf(stderr, "Error reading channel: %s\n",
|
if (lus == -1) {
|
||||||
ssh_get_error(session));
|
fprintf(stderr,
|
||||||
return;
|
"Error reading channel: %s\n",
|
||||||
}
|
ssh_get_error(session));
|
||||||
if(lus==0){
|
return;
|
||||||
ssh_channel_free(channel);
|
|
||||||
channel=channels[0]=NULL;
|
|
||||||
} else {
|
|
||||||
ret = write(1, buffer, lus);
|
|
||||||
if (ret < 0) {
|
|
||||||
fprintf(stderr, "Error writing to stdin: %s",
|
|
||||||
strerror(errno));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,1)){ /* stderr */
|
|
||||||
lus = ssh_channel_read(channel, buffer, 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 {
|
|
||||||
ret = write(2, buffer, lus);
|
|
||||||
if (ret < 0) {
|
|
||||||
fprintf(stderr, "Error writing to stderr: %s",
|
|
||||||
strerror(errno));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
if (lus == 0) {
|
||||||
}
|
ssh_channel_free(channel);
|
||||||
if(channel && ssh_channel_is_closed(channel)){
|
channel = channels[0] = NULL;
|
||||||
ssh_channel_free(channel);
|
} else {
|
||||||
channel=NULL;
|
ret = write(1, buffer, lus);
|
||||||
}
|
if (ret < 0) {
|
||||||
} while (ret==EINTR || ret==SSH_EINTR);
|
fprintf(stderr,
|
||||||
|
"Error writing to stdin: %s",
|
||||||
}
|
strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (channel && ssh_channel_is_open(channel) &&
|
||||||
|
ssh_channel_poll(channel, 1)) { /* stderr */
|
||||||
|
lus = ssh_channel_read(channel, buffer, 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 {
|
||||||
|
ret = write(2, buffer, lus);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error writing to stderr: %s",
|
||||||
|
strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (channel && ssh_channel_is_closed(channel)) {
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
channel = NULL;
|
||||||
|
}
|
||||||
|
} while (ret == EINTR || ret == SSH_EINTR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void forwarding(ssh_session session){
|
static void forwarding(ssh_session session)
|
||||||
|
{
|
||||||
ssh_channel channel;
|
ssh_channel channel;
|
||||||
int r;
|
int r;
|
||||||
channel = ssh_channel_new(session);
|
channel = ssh_channel_new(session);
|
||||||
r = ssh_channel_open_forward(channel, desthost, atoi(port), "localhost", 22);
|
r = ssh_channel_open_forward(channel, desthost, atoi(port), "localhost", 22);
|
||||||
if(r<0) {
|
if (r < 0) {
|
||||||
printf("error forwarding port : %s\n",ssh_get_error(session));
|
printf("error forwarding port : %s\n", ssh_get_error(session));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
select_loop(session,channel);
|
select_loop(session, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int client(ssh_session session){
|
static int client(ssh_session session)
|
||||||
int auth=0;
|
{
|
||||||
char *banner;
|
int auth = 0;
|
||||||
int state;
|
char *banner = NULL;
|
||||||
|
int state;
|
||||||
|
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0)
|
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
ssh_options_parse_config(session, NULL);
|
ssh_options_parse_config(session, NULL);
|
||||||
|
|
||||||
if(ssh_connect(session)){
|
if (ssh_connect(session)) {
|
||||||
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
|
fprintf(stderr, "Connection failed : %s\n", ssh_get_error(session));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
state=verify_knownhost(session);
|
state = verify_knownhost(session);
|
||||||
if (state != 0)
|
if (state != 0)
|
||||||
return -1;
|
return -1;
|
||||||
ssh_userauth_none(session, NULL);
|
ssh_userauth_none(session, NULL);
|
||||||
banner=ssh_get_issue_banner(session);
|
banner = ssh_get_issue_banner(session);
|
||||||
if(banner){
|
if (banner) {
|
||||||
printf("%s\n",banner);
|
printf("%s\n", banner);
|
||||||
free(banner);
|
free(banner);
|
||||||
}
|
}
|
||||||
auth=authenticate_console(session);
|
auth = authenticate_console(session);
|
||||||
if(auth != SSH_AUTH_SUCCESS){
|
if (auth != SSH_AUTH_SUCCESS) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
forwarding(session);
|
forwarding(session);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_PCAP
|
#ifdef WITH_PCAP
|
||||||
ssh_pcap_file pcap;
|
ssh_pcap_file pcap;
|
||||||
void set_pcap(ssh_session session);
|
void set_pcap(ssh_session session);
|
||||||
void set_pcap(ssh_session session){
|
void set_pcap(ssh_session session)
|
||||||
if(!pcap_file)
|
{
|
||||||
return;
|
if (!pcap_file)
|
||||||
pcap=ssh_pcap_file_new();
|
return;
|
||||||
if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){
|
pcap = ssh_pcap_file_new();
|
||||||
printf("Error opening pcap file\n");
|
if (ssh_pcap_file_open(pcap, pcap_file) == SSH_ERROR) {
|
||||||
ssh_pcap_file_free(pcap);
|
printf("Error opening pcap file\n");
|
||||||
pcap=NULL;
|
ssh_pcap_file_free(pcap);
|
||||||
return;
|
pcap = NULL;
|
||||||
}
|
return;
|
||||||
ssh_set_pcap_file(session,pcap);
|
}
|
||||||
|
ssh_set_pcap_file(session, pcap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_pcap(void);
|
void cleanup_pcap(void);
|
||||||
void cleanup_pcap(){
|
void cleanup_pcap(void)
|
||||||
ssh_pcap_file_free(pcap);
|
{
|
||||||
pcap=NULL;
|
ssh_pcap_file_free(pcap);
|
||||||
|
pcap = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, char **argv){
|
int main(int argc, char **argv)
|
||||||
ssh_session session;
|
{
|
||||||
|
ssh_session session = NULL;
|
||||||
|
|
||||||
session = ssh_new();
|
session = ssh_new();
|
||||||
|
|
||||||
if(ssh_options_getopt(session, &argc, argv)) {
|
if (ssh_options_getopt(session, &argc, argv)) {
|
||||||
fprintf(stderr, "error parsing command line :%s\n",
|
fprintf(stderr,
|
||||||
ssh_get_error(session));
|
"error parsing command line :%s\n",
|
||||||
usage();
|
ssh_get_error(session));
|
||||||
|
usage();
|
||||||
}
|
}
|
||||||
opts(argc,argv);
|
opts(argc, argv);
|
||||||
#ifdef WITH_PCAP
|
#ifdef WITH_PCAP
|
||||||
set_pcap(session);
|
set_pcap(session);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -20,8 +20,22 @@ if (WITH_SERVER)
|
|||||||
${libssh_HDRS}
|
${libssh_HDRS}
|
||||||
server.h
|
server.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (WITH_SFTP)
|
||||||
|
set(libssh_HDRS
|
||||||
|
${libssh_HDRS}
|
||||||
|
sftpserver.h
|
||||||
|
)
|
||||||
|
endif (WITH_SFTP)
|
||||||
endif (WITH_SERVER)
|
endif (WITH_SERVER)
|
||||||
|
|
||||||
|
if (WITH_FIDO2)
|
||||||
|
set(libssh_HDRS
|
||||||
|
${libssh_HDRS}
|
||||||
|
sk_api.h
|
||||||
|
)
|
||||||
|
endif (WITH_FIDO2)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
FILES
|
FILES
|
||||||
${libssh_HDRS}
|
${libssh_HDRS}
|
||||||
|
|||||||
@@ -70,6 +70,10 @@
|
|||||||
#define SSH_AGENT_RSA_SHA2_256 0x02
|
#define SSH_AGENT_RSA_SHA2_256 0x02
|
||||||
#define SSH_AGENT_RSA_SHA2_512 0x04
|
#define SSH_AGENT_RSA_SHA2_512 0x04
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
struct ssh_agent_struct {
|
struct ssh_agent_struct {
|
||||||
struct ssh_socket_struct *sock;
|
struct ssh_socket_struct *sock;
|
||||||
ssh_buffer ident;
|
ssh_buffer ident;
|
||||||
@@ -115,4 +119,8 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
|||||||
const ssh_key pubkey,
|
const ssh_key pubkey,
|
||||||
struct ssh_buffer_struct *data);
|
struct ssh_buffer_struct *data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __AGENT_H */
|
#endif /* __AGENT_H */
|
||||||
|
|||||||
@@ -23,6 +23,10 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "libssh/callbacks.h"
|
#include "libssh/callbacks.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_banner);
|
SSH_PACKET_CALLBACK(ssh_packet_userauth_banner);
|
||||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_failure);
|
SSH_PACKET_CALLBACK(ssh_packet_userauth_failure);
|
||||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_success);
|
SSH_PACKET_CALLBACK(ssh_packet_userauth_success);
|
||||||
@@ -48,42 +52,45 @@ typedef struct ssh_kbdint_struct* ssh_kbdint;
|
|||||||
ssh_kbdint ssh_kbdint_new(void);
|
ssh_kbdint ssh_kbdint_new(void);
|
||||||
void ssh_kbdint_clean(ssh_kbdint kbd);
|
void ssh_kbdint_clean(ssh_kbdint kbd);
|
||||||
void ssh_kbdint_free(ssh_kbdint kbd);
|
void ssh_kbdint_free(ssh_kbdint kbd);
|
||||||
|
int ssh_userauth_gssapi_keyex(ssh_session session);
|
||||||
|
|
||||||
/** @internal
|
/** @internal
|
||||||
* States of authentication in the client-side. They describe
|
* States of authentication in the client-side. They describe
|
||||||
* what was the last response from the server
|
* what was the last response from the server
|
||||||
*/
|
*/
|
||||||
enum ssh_auth_state_e {
|
enum ssh_auth_state_e {
|
||||||
/** No authentication asked */
|
/** No authentication asked */
|
||||||
SSH_AUTH_STATE_NONE=0,
|
SSH_AUTH_STATE_NONE = 0,
|
||||||
/** Last authentication response was a partial success */
|
/** Last authentication response was a partial success */
|
||||||
SSH_AUTH_STATE_PARTIAL,
|
SSH_AUTH_STATE_PARTIAL,
|
||||||
/** Last authentication response was a success */
|
/** Last authentication response was a success */
|
||||||
SSH_AUTH_STATE_SUCCESS,
|
SSH_AUTH_STATE_SUCCESS,
|
||||||
/** Last authentication response was failed */
|
/** Last authentication response was failed */
|
||||||
SSH_AUTH_STATE_FAILED,
|
SSH_AUTH_STATE_FAILED,
|
||||||
/** Last authentication was erroneous */
|
/** Last authentication was erroneous */
|
||||||
SSH_AUTH_STATE_ERROR,
|
SSH_AUTH_STATE_ERROR,
|
||||||
/** Last state was a keyboard-interactive ask for info */
|
/** Last state was a keyboard-interactive ask for info */
|
||||||
SSH_AUTH_STATE_INFO,
|
SSH_AUTH_STATE_INFO,
|
||||||
/** Last state was a public key accepted for authentication */
|
/** Last state was a public key accepted for authentication */
|
||||||
SSH_AUTH_STATE_PK_OK,
|
SSH_AUTH_STATE_PK_OK,
|
||||||
/** We asked for a keyboard-interactive authentication */
|
/** We asked for a keyboard-interactive authentication */
|
||||||
SSH_AUTH_STATE_KBDINT_SENT,
|
SSH_AUTH_STATE_KBDINT_SENT,
|
||||||
/** We have sent an userauth request with gssapi-with-mic */
|
/** We have sent an userauth request with gssapi-with-mic */
|
||||||
SSH_AUTH_STATE_GSSAPI_REQUEST_SENT,
|
SSH_AUTH_STATE_GSSAPI_REQUEST_SENT,
|
||||||
/** We are exchanging tokens until authentication */
|
/** We are exchanging tokens until authentication */
|
||||||
SSH_AUTH_STATE_GSSAPI_TOKEN,
|
SSH_AUTH_STATE_GSSAPI_TOKEN,
|
||||||
/** We have sent the MIC and expecting to be authenticated */
|
/** We have sent the MIC and expecting to be authenticated */
|
||||||
SSH_AUTH_STATE_GSSAPI_MIC_SENT,
|
SSH_AUTH_STATE_GSSAPI_MIC_SENT,
|
||||||
/** We have offered a pubkey to check if it is supported */
|
/** We have offered a pubkey to check if it is supported */
|
||||||
SSH_AUTH_STATE_PUBKEY_OFFER_SENT,
|
SSH_AUTH_STATE_PUBKEY_OFFER_SENT,
|
||||||
/** We have sent pubkey and signature expecting to be authenticated */
|
/** We have sent pubkey and signature expecting to be authenticated */
|
||||||
SSH_AUTH_STATE_PUBKEY_AUTH_SENT,
|
SSH_AUTH_STATE_PUBKEY_AUTH_SENT,
|
||||||
/** We have sent a password expecting to be authenticated */
|
/** We have sent a password expecting to be authenticated */
|
||||||
SSH_AUTH_STATE_PASSWORD_AUTH_SENT,
|
SSH_AUTH_STATE_PASSWORD_AUTH_SENT,
|
||||||
/** We have sent a request without auth information (method 'none') */
|
/** We have sent a request without auth information (method 'none') */
|
||||||
SSH_AUTH_STATE_AUTH_NONE_SENT,
|
SSH_AUTH_STATE_AUTH_NONE_SENT,
|
||||||
|
/** We have sent the MIC and expecting to be authenticated */
|
||||||
|
SSH_AUTH_STATE_GSSAPI_KEYEX_MIC_SENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @internal
|
/** @internal
|
||||||
@@ -100,4 +107,8 @@ enum ssh_auth_service_state_e {
|
|||||||
SSH_AUTH_SERVICE_DENIED,
|
SSH_AUTH_SERVICE_DENIED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* AUTH_H_ */
|
#endif /* AUTH_H_ */
|
||||||
|
|||||||
@@ -25,9 +25,17 @@
|
|||||||
#include "libssh/libgcrypt.h"
|
#include "libssh/libgcrypt.h"
|
||||||
#include "libssh/libmbedcrypto.h"
|
#include "libssh/libmbedcrypto.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
bignum ssh_make_string_bn(ssh_string string);
|
bignum ssh_make_string_bn(ssh_string string);
|
||||||
ssh_string ssh_make_bignum_string(bignum num);
|
ssh_string ssh_make_bignum_string(bignum num);
|
||||||
|
ssh_string ssh_make_padded_bignum_string(bignum num, size_t pad_len);
|
||||||
void ssh_print_bignum(const char *which, const_bignum num);
|
void ssh_print_bignum(const char *which, const_bignum num);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* BIGNUM_H_ */
|
#endif /* BIGNUM_H_ */
|
||||||
|
|||||||
@@ -25,6 +25,10 @@
|
|||||||
#include "libssh/kex.h"
|
#include "libssh/kex.h"
|
||||||
#include "libssh/session.h"
|
#include "libssh/session.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
struct ssh_bind_struct {
|
struct ssh_bind_struct {
|
||||||
struct ssh_common_struct common; /* stuff common to ssh_bind and ssh_session */
|
struct ssh_common_struct common; /* stuff common to ssh_bind and ssh_session */
|
||||||
struct ssh_bind_callbacks_struct *bind_callbacks;
|
struct ssh_bind_callbacks_struct *bind_callbacks;
|
||||||
@@ -35,11 +39,9 @@ struct ssh_bind_struct {
|
|||||||
char *wanted_methods[SSH_KEX_METHODS];
|
char *wanted_methods[SSH_KEX_METHODS];
|
||||||
char *banner;
|
char *banner;
|
||||||
char *ecdsakey;
|
char *ecdsakey;
|
||||||
char *dsakey;
|
|
||||||
char *rsakey;
|
char *rsakey;
|
||||||
char *ed25519key;
|
char *ed25519key;
|
||||||
ssh_key ecdsa;
|
ssh_key ecdsa;
|
||||||
ssh_key dsa;
|
|
||||||
ssh_key rsa;
|
ssh_key rsa;
|
||||||
ssh_key ed25519;
|
ssh_key ed25519;
|
||||||
char *bindaddr;
|
char *bindaddr;
|
||||||
@@ -52,10 +54,15 @@ struct ssh_bind_struct {
|
|||||||
char *pubkey_accepted_key_types;
|
char *pubkey_accepted_key_types;
|
||||||
char* moduli_file;
|
char* moduli_file;
|
||||||
int rsa_min_size;
|
int rsa_min_size;
|
||||||
|
bool gssapi_key_exchange;
|
||||||
|
char *gssapi_key_exchange_algs;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ssh_poll_handle_struct *ssh_bind_get_poll(struct ssh_bind_struct
|
struct ssh_poll_handle_struct *ssh_bind_get_poll(struct ssh_bind_struct
|
||||||
*sshbind);
|
*sshbind);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* BIND_H_ */
|
#endif /* BIND_H_ */
|
||||||
|
|||||||
@@ -28,6 +28,10 @@
|
|||||||
|
|
||||||
#include "libssh/server.h"
|
#include "libssh/server.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
enum ssh_bind_config_opcode_e {
|
enum ssh_bind_config_opcode_e {
|
||||||
/* Known but not allowed in Match block */
|
/* Known but not allowed in Match block */
|
||||||
BIND_CFG_NOT_ALLOWED_IN_MATCH = -4,
|
BIND_CFG_NOT_ALLOWED_IN_MATCH = -4,
|
||||||
@@ -48,6 +52,7 @@ enum ssh_bind_config_opcode_e {
|
|||||||
BIND_CFG_MATCH,
|
BIND_CFG_MATCH,
|
||||||
BIND_CFG_PUBKEY_ACCEPTED_KEY_TYPES,
|
BIND_CFG_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||||
BIND_CFG_HOSTKEY_ALGORITHMS,
|
BIND_CFG_HOSTKEY_ALGORITHMS,
|
||||||
|
BIND_CFG_REQUIRED_RSA_SIZE,
|
||||||
|
|
||||||
BIND_CFG_MAX /* Keep this one last in the list */
|
BIND_CFG_MAX /* Keep this one last in the list */
|
||||||
};
|
};
|
||||||
@@ -71,4 +76,8 @@ int ssh_bind_config_parse_file(ssh_bind sshbind, const char *filename);
|
|||||||
*/
|
*/
|
||||||
int ssh_bind_config_parse_string(ssh_bind bind, const char *input);
|
int ssh_bind_config_parse_string(ssh_bind bind, const char *input);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* BIND_CONFIG_H_ */
|
#endif /* BIND_CONFIG_H_ */
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: blf.h,v 1.7 2007/03/14 17:59:41 grunk Exp $ */
|
/* $OpenBSD: blf.h,v 1.8 2021/11/29 01:04:45 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Blowfish - a fast block cipher designed by Bruce Schneier
|
* Blowfish - a fast block cipher designed by Bruce Schneier
|
||||||
*
|
*
|
||||||
@@ -13,10 +13,7 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. All advertising materials mentioning features or use of this software
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
* must display the following acknowledgement:
|
|
||||||
* This product includes software developed by Niels Provos.
|
|
||||||
* 4. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
@@ -49,6 +46,10 @@
|
|||||||
#define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */
|
#define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */
|
||||||
#define BLF_MAXUTILIZED ((BLF_N+2)*4) /* 576 bits */
|
#define BLF_MAXUTILIZED ((BLF_N+2)*4) /* 576 bits */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Blowfish context */
|
/* Blowfish context */
|
||||||
typedef struct BlowfishContext {
|
typedef struct BlowfishContext {
|
||||||
uint32_t S[4][256]; /* S-Boxes */
|
uint32_t S[4][256]; /* S-Boxes */
|
||||||
@@ -84,4 +85,9 @@ void ssh_blf_cbc_decrypt(ssh_blf_ctx *, uint8_t *, uint8_t *, uint32_t);
|
|||||||
uint32_t Blowfish_stream2word(const uint8_t *, uint16_t , uint16_t *);
|
uint32_t Blowfish_stream2word(const uint8_t *, uint16_t , uint16_t *);
|
||||||
|
|
||||||
#endif /* !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H) */
|
#endif /* !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H) */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _BLF_H */
|
#endif /* _BLF_H */
|
||||||
|
|||||||
@@ -27,6 +27,10 @@
|
|||||||
|
|
||||||
#define SSH_BUFFER_PACK_END ((uint32_t) 0x4f65feb3)
|
#define SSH_BUFFER_PACK_END ((uint32_t) 0x4f65feb3)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
void ssh_buffer_set_secure(ssh_buffer buffer);
|
void ssh_buffer_set_secure(ssh_buffer buffer);
|
||||||
int ssh_buffer_add_ssh_string(ssh_buffer buffer, ssh_string string);
|
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_u8(ssh_buffer buffer, uint8_t data);
|
||||||
@@ -38,10 +42,6 @@ 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);
|
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_allocate_size(struct ssh_buffer_struct *buffer, uint32_t len);
|
||||||
int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
|
||||||
const char *format,
|
|
||||||
size_t argc,
|
|
||||||
va_list ap);
|
|
||||||
int _ssh_buffer_pack(struct ssh_buffer_struct *buffer,
|
int _ssh_buffer_pack(struct ssh_buffer_struct *buffer,
|
||||||
const char *format,
|
const char *format,
|
||||||
size_t argc,
|
size_t argc,
|
||||||
@@ -74,4 +74,10 @@ ssh_string ssh_buffer_get_ssh_string(ssh_buffer buffer);
|
|||||||
uint32_t ssh_buffer_pass_bytes_end(ssh_buffer buffer, uint32_t len);
|
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);
|
uint32_t ssh_buffer_pass_bytes(ssh_buffer buffer, uint32_t len);
|
||||||
|
|
||||||
|
ssh_buffer ssh_buffer_dup(const ssh_buffer buffer);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* BUFFER_H_ */
|
#endif /* BUFFER_H_ */
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include <libssh/libssh.h>
|
#include <libssh/libssh.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -81,9 +82,9 @@ typedef void (*ssh_log_callback) (ssh_session session, int priority,
|
|||||||
*
|
*
|
||||||
* @param priority Priority of the log, the smaller being the more important.
|
* @param priority Priority of the log, the smaller being the more important.
|
||||||
*
|
*
|
||||||
* @param function The function name calling the the logging fucntions.
|
* @param function The function name calling the logging functions.
|
||||||
*
|
*
|
||||||
* @param message The actual message
|
* @param buffer The actual message
|
||||||
*
|
*
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
*/
|
*/
|
||||||
@@ -112,11 +113,24 @@ typedef void (*ssh_status_callback) (ssh_session session, float status,
|
|||||||
typedef void (*ssh_global_request_callback) (ssh_session session,
|
typedef void (*ssh_global_request_callback) (ssh_session session,
|
||||||
ssh_message message, void *userdata);
|
ssh_message message, void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SSH connect status callback. These are functions that report the
|
||||||
|
* status of the connection i,e. a function indicating the completed percentage
|
||||||
|
* of the connection
|
||||||
|
* steps.
|
||||||
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
|
* @param status Percentage of connection status, going from 0.0 to 1.0
|
||||||
|
* once connection is done.
|
||||||
|
*/
|
||||||
|
typedef void (*ssh_connect_status_callback)(void *userdata, float status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handles an SSH new channel open X11 request. This happens when the server
|
* @brief Handles an SSH new channel open X11 request. This happens when the server
|
||||||
* sends back an X11 connection attempt. This is a client-side API
|
* sends back an X11 connection attempt. This is a client-side API
|
||||||
* @param session current session handler
|
* @param session current session handler
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
|
* @param originator_address IP address of the machine who sent the request
|
||||||
|
* @param originator_port port number of the machine who sent the request
|
||||||
* @returns a valid ssh_channel handle if the request is to be allowed
|
* @returns a valid ssh_channel handle if the request is to be allowed
|
||||||
* @returns NULL if the request should not 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.
|
* @warning The channel pointer returned by this callback must be closed by the application.
|
||||||
@@ -136,6 +150,26 @@ typedef ssh_channel (*ssh_channel_open_request_x11_callback) (ssh_session sessio
|
|||||||
typedef ssh_channel (*ssh_channel_open_request_auth_agent_callback) (ssh_session session,
|
typedef ssh_channel (*ssh_channel_open_request_auth_agent_callback) (ssh_session session,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles an SSH new channel open "forwarded-tcpip" request. This
|
||||||
|
* happens when the server forwards an incoming TCP connection on a port it was
|
||||||
|
* previously requested to listen on. This is a client-side API
|
||||||
|
* @param session current session handler
|
||||||
|
* @param destination_address the address that the TCP connection connected to
|
||||||
|
* @param destination_port the port that the TCP connection connected to
|
||||||
|
* @param originator_address the originator IP address
|
||||||
|
* @param originator_port the originator port
|
||||||
|
* @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_forwarded_tcpip_callback) (ssh_session session,
|
||||||
|
const char *destination_address, int destination_port,
|
||||||
|
const char *originator_address, int originator_port,
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The structure to replace libssh functions with appropriate callbacks.
|
* The structure to replace libssh functions with appropriate callbacks.
|
||||||
*/
|
*/
|
||||||
@@ -158,7 +192,7 @@ struct ssh_callbacks_struct {
|
|||||||
* This function gets called during connection time to indicate the
|
* This function gets called during connection time to indicate the
|
||||||
* percentage of connection steps completed.
|
* percentage of connection steps completed.
|
||||||
*/
|
*/
|
||||||
void (*connect_status_function)(void *userdata, float status);
|
ssh_connect_status_callback connect_status_function;
|
||||||
/**
|
/**
|
||||||
* This function will be called each time a global request is received.
|
* This function will be called each time a global request is received.
|
||||||
*/
|
*/
|
||||||
@@ -169,6 +203,11 @@ struct ssh_callbacks_struct {
|
|||||||
/** This function will be called when an incoming "auth-agent" request is received.
|
/** 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;
|
ssh_channel_open_request_auth_agent_callback channel_open_request_auth_agent_function;
|
||||||
|
/**
|
||||||
|
* This function will be called when an incoming "forwarded-tcpip"
|
||||||
|
* request is received.
|
||||||
|
*/
|
||||||
|
ssh_channel_open_request_forwarded_tcpip_callback channel_open_request_forwarded_tcpip_function;
|
||||||
};
|
};
|
||||||
typedef struct ssh_callbacks_struct *ssh_callbacks;
|
typedef struct ssh_callbacks_struct *ssh_callbacks;
|
||||||
|
|
||||||
@@ -181,36 +220,41 @@ typedef struct ssh_callbacks_struct *ssh_callbacks;
|
|||||||
* @param user User that wants to authenticate
|
* @param user User that wants to authenticate
|
||||||
* @param password Password used for authentication
|
* @param password Password used for authentication
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
* @returns SSH_AUTH_SUCCESS Authentication is accepted.
|
* @returns `SSH_AUTH_SUCCESS` Authentication is accepted.
|
||||||
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
|
* @returns `SSH_AUTH_PARTIAL` Partial authentication, more authentication means
|
||||||
* @returns SSH_AUTH_DENIED Authentication failed.
|
* are needed.
|
||||||
|
* @returns `SSH_AUTH_DENIED` Authentication failed.
|
||||||
*/
|
*/
|
||||||
typedef int (*ssh_auth_password_callback) (ssh_session session, const char *user, const char *password,
|
typedef int (*ssh_auth_password_callback) (ssh_session session, const char *user, const char *password,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief SSH authentication callback. Tries to authenticates user with the "none" method
|
* @brief SSH authentication callback. Tries to authenticates user with the
|
||||||
* which is anonymous or passwordless.
|
* "none" method which is anonymous or passwordless.
|
||||||
* @param session Current session handler
|
* @param session Current session handler
|
||||||
* @param user User that wants to authenticate
|
* @param user User that wants to authenticate
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
* @returns SSH_AUTH_SUCCESS Authentication is accepted.
|
* @returns `SSH_AUTH_SUCCESS` Authentication is accepted.
|
||||||
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
|
* @returns `SSH_AUTH_PARTIAL` Partial authentication, more authentication means
|
||||||
* @returns SSH_AUTH_DENIED Authentication failed.
|
* are needed.
|
||||||
|
* @returns `SSH_AUTH_DENIED` Authentication failed.
|
||||||
*/
|
*/
|
||||||
typedef int (*ssh_auth_none_callback) (ssh_session session, const char *user, void *userdata);
|
typedef int (*ssh_auth_none_callback) (ssh_session session, const char *user, void *userdata);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief SSH authentication callback. Tries to authenticates user with the "gssapi-with-mic" method
|
* @brief SSH authentication callback. Tries to authenticates user with the
|
||||||
|
* "gssapi-with-mic" method
|
||||||
* @param session Current session handler
|
* @param session Current session handler
|
||||||
* @param user Username of the user (can be spoofed)
|
* @param user Username of the user (can be spoofed)
|
||||||
* @param principal Authenticated principal of the user, including realm.
|
* @param principal Authenticated principal of the user, including realm.
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
* @returns SSH_AUTH_SUCCESS Authentication is accepted.
|
* @returns `SSH_AUTH_SUCCESS` Authentication is accepted.
|
||||||
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
|
* @returns `SSH_AUTH_PARTIAL` Partial authentication, more authentication means
|
||||||
* @returns SSH_AUTH_DENIED Authentication failed.
|
* are needed.
|
||||||
* @warning Implementations should verify that parameter user matches in some way the principal.
|
* @returns `SSH_AUTH_DENIED` Authentication failed.
|
||||||
* user and principal can be different. Only the latter is guaranteed to be safe.
|
* @warning Implementations should verify that parameter user matches in some
|
||||||
|
* way the principal. user and principal can be different. Only the latter is
|
||||||
|
* guaranteed to be safe.
|
||||||
*/
|
*/
|
||||||
typedef int (*ssh_auth_gssapi_mic_callback) (ssh_session session, const char *user, const char *principal,
|
typedef int (*ssh_auth_gssapi_mic_callback) (ssh_session session, const char *user, const char *principal,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
@@ -220,17 +264,29 @@ typedef int (*ssh_auth_gssapi_mic_callback) (ssh_session session, const char *us
|
|||||||
* @param session Current session handler
|
* @param session Current session handler
|
||||||
* @param user User that wants to authenticate
|
* @param user User that wants to authenticate
|
||||||
* @param pubkey public key used for authentication
|
* @param pubkey public key used for authentication
|
||||||
* @param signature_state SSH_PUBLICKEY_STATE_NONE if the key is not signed (simple public key probe),
|
* @param signature_state `SSH_PUBLICKEY_STATE_NONE` if the key is not signed
|
||||||
* SSH_PUBLICKEY_STATE_VALID if the signature is valid. Others values should be
|
* (simple public key probe), `SSH_PUBLICKEY_STATE_VALID` if the signature is
|
||||||
* replied with a SSH_AUTH_DENIED.
|
* valid. Others values should be replied with a `SSH_AUTH_DENIED`.
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
* @returns SSH_AUTH_SUCCESS Authentication is accepted.
|
* @returns `SSH_AUTH_SUCCESS` Authentication is accepted.
|
||||||
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
|
* @returns `SSH_AUTH_PARTIAL` Partial authentication, more authentication means
|
||||||
* @returns SSH_AUTH_DENIED Authentication failed.
|
* are needed.
|
||||||
|
* @returns `SSH_AUTH_DENIED` Authentication failed.
|
||||||
*/
|
*/
|
||||||
typedef int (*ssh_auth_pubkey_callback) (ssh_session session, const char *user, struct ssh_key_struct *pubkey,
|
typedef int (*ssh_auth_pubkey_callback) (ssh_session session, const char *user, struct ssh_key_struct *pubkey,
|
||||||
char signature_state, void *userdata);
|
char signature_state, void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SSH authentication callback. Tries to authenticates user with the "keyboard-interactive" method
|
||||||
|
* @param message Current message
|
||||||
|
* @param session Current session handler
|
||||||
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
|
* @returns SSH_AUTH_SUCCESS Authentication is accepted.
|
||||||
|
* @returns SSH_AUTH_INFO More info required for authentication.
|
||||||
|
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
|
||||||
|
* @returns SSH_AUTH_DENIED Authentication failed.
|
||||||
|
*/
|
||||||
|
typedef int (*ssh_auth_kbdint_callback) (ssh_message message, ssh_session session, void *userdata);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handles an SSH service request
|
* @brief Handles an SSH service request
|
||||||
@@ -240,7 +296,6 @@ typedef int (*ssh_auth_pubkey_callback) (ssh_session session, const char *user,
|
|||||||
* @returns 0 if the request is to be allowed
|
* @returns 0 if the request is to be allowed
|
||||||
* @returns -1 if the request should not be allowed
|
* @returns -1 if the request should not be allowed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef int (*ssh_service_request_callback) (ssh_session session, const char *service, void *userdata);
|
typedef int (*ssh_service_request_callback) (ssh_session session, const char *service, void *userdata);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -253,8 +308,9 @@ typedef int (*ssh_service_request_callback) (ssh_session session, const char *se
|
|||||||
*/
|
*/
|
||||||
typedef ssh_channel (*ssh_channel_open_request_session_callback) (ssh_session session, void *userdata);
|
typedef ssh_channel (*ssh_channel_open_request_session_callback) (ssh_session session, void *userdata);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief handle the beginning of a GSSAPI authentication, server side.
|
* @brief handle the beginning of a GSSAPI authentication, server side.
|
||||||
|
* Callback should select the oid and also acquire the server credential.
|
||||||
* @param session current session handler
|
* @param session current session handler
|
||||||
* @param user the username of the client
|
* @param user the username of the client
|
||||||
* @param n_oid number of available oids
|
* @param n_oid number of available oids
|
||||||
@@ -267,35 +323,57 @@ typedef ssh_channel (*ssh_channel_open_request_session_callback) (ssh_session se
|
|||||||
typedef ssh_string (*ssh_gssapi_select_oid_callback) (ssh_session session, const char *user,
|
typedef ssh_string (*ssh_gssapi_select_oid_callback) (ssh_session session, const char *user,
|
||||||
int n_oid, ssh_string *oids, void *userdata);
|
int n_oid, ssh_string *oids, void *userdata);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief handle the negociation of a security context, server side.
|
* @brief handle the negotiation of a security context, server side.
|
||||||
* @param session current session handler
|
* @param session current session handler
|
||||||
* @param[in] input_token input token provided by client
|
* @param[in] input_token input token provided by client
|
||||||
* @param[out] output_token output of the gssapi accept_sec_context method,
|
* @param[out] output_token output of the gssapi accept_sec_context method,
|
||||||
* NULL after completion.
|
* NULL after completion.
|
||||||
* @returns SSH_OK if the token was generated correctly or accept_sec_context
|
* @returns `SSH_OK` if the token was generated correctly or accept_sec_context
|
||||||
* returned GSS_S_COMPLETE
|
* returned GSS_S_COMPLETE
|
||||||
* @returns SSH_ERROR in case of error
|
* @returns `SSH_ERROR` in case of error
|
||||||
* @warning It is not necessary to fill this callback in if libssh is linked
|
* @warning It is not necessary to fill this callback in if libssh is linked
|
||||||
* with libgssapi.
|
* with libgssapi.
|
||||||
*/
|
*/
|
||||||
typedef int (*ssh_gssapi_accept_sec_ctx_callback) (ssh_session session,
|
typedef int (*ssh_gssapi_accept_sec_ctx_callback) (ssh_session session,
|
||||||
ssh_string input_token, ssh_string *output_token, void *userdata);
|
ssh_string input_token, ssh_string *output_token, void *userdata);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief Verify and authenticates a MIC, server side.
|
* @brief Verify and authenticates a MIC, server side.
|
||||||
* @param session current session handler
|
* @param session current session handler
|
||||||
* @param[in] mic input mic to be verified provided by client
|
* @param[in] mic input mic to be verified provided by client
|
||||||
* @param[in] mic_buffer buffer of data to be signed.
|
* @param[in] mic_buffer buffer of data to be signed.
|
||||||
* @param[in] mic_buffer_size size of mic_buffer
|
* @param[in] mic_buffer_size size of mic_buffer
|
||||||
* @returns SSH_OK if the MIC was authenticated correctly
|
* @returns `SSH_OK` if the MIC was authenticated correctly
|
||||||
* @returns SSH_ERROR in case of error
|
* @returns `SSH_ERROR` in case of error
|
||||||
* @warning It is not necessary to fill this callback in if libssh is linked
|
* @warning It is not necessary to fill this callback in if libssh is linked
|
||||||
* with libgssapi.
|
* with libgssapi.
|
||||||
*/
|
*/
|
||||||
typedef int (*ssh_gssapi_verify_mic_callback) (ssh_session session,
|
typedef int (*ssh_gssapi_verify_mic_callback) (ssh_session session,
|
||||||
ssh_string mic, void *mic_buffer, size_t mic_buffer_size, void *userdata);
|
ssh_string mic, void *mic_buffer, size_t mic_buffer_size, void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles an SSH new channel open "direct-tcpip" request. This
|
||||||
|
* happens when the client forwards an incoming TCP connection on a port it
|
||||||
|
* wants to forward to the destination. This is a server-side API
|
||||||
|
* @param session current session handler
|
||||||
|
* @param destination_address the address that the TCP connection connected to
|
||||||
|
* @param destination_port the port that the TCP connection connected to
|
||||||
|
* @param originator_address the originator IP address
|
||||||
|
* @param originator_port the originator port
|
||||||
|
* @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_direct_tcpip_callback)(
|
||||||
|
ssh_session session,
|
||||||
|
const char *destination_address,
|
||||||
|
int destination_port,
|
||||||
|
const char *originator_address,
|
||||||
|
int originator_port,
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This structure can be used to implement a libssh server, with appropriate callbacks.
|
* This structure can be used to implement a libssh server, with appropriate callbacks.
|
||||||
@@ -337,14 +415,27 @@ struct ssh_server_callbacks_struct {
|
|||||||
*/
|
*/
|
||||||
ssh_channel_open_request_session_callback channel_open_request_session_function;
|
ssh_channel_open_request_session_callback channel_open_request_session_function;
|
||||||
/** This function will be called when a new gssapi authentication is attempted.
|
/** This function will be called when a new gssapi authentication is attempted.
|
||||||
|
* This should select the oid and acquire credential for the server.
|
||||||
*/
|
*/
|
||||||
ssh_gssapi_select_oid_callback gssapi_select_oid_function;
|
ssh_gssapi_select_oid_callback gssapi_select_oid_function;
|
||||||
/** This function will be called when a gssapi token comes in.
|
/** This function will be called when a gssapi token comes in.
|
||||||
*/
|
*/
|
||||||
ssh_gssapi_accept_sec_ctx_callback gssapi_accept_sec_ctx_function;
|
ssh_gssapi_accept_sec_ctx_callback gssapi_accept_sec_ctx_function;
|
||||||
/* This function will be called when a MIC needs to be verified.
|
/** This function will be called when a MIC needs to be verified.
|
||||||
*/
|
*/
|
||||||
ssh_gssapi_verify_mic_callback gssapi_verify_mic_function;
|
ssh_gssapi_verify_mic_callback gssapi_verify_mic_function;
|
||||||
|
/**
|
||||||
|
* This function will be called when an incoming "direct-tcpip"
|
||||||
|
* request is received.
|
||||||
|
*/
|
||||||
|
ssh_channel_open_request_direct_tcpip_callback
|
||||||
|
channel_open_request_direct_tcpip_function;
|
||||||
|
|
||||||
|
/** This function gets called when a client tries to authenticate through
|
||||||
|
* keyboard interactive method.
|
||||||
|
*/
|
||||||
|
ssh_auth_kbdint_callback auth_kbdint_function;
|
||||||
|
|
||||||
};
|
};
|
||||||
typedef struct ssh_server_callbacks_struct *ssh_server_callbacks;
|
typedef struct ssh_server_callbacks_struct *ssh_server_callbacks;
|
||||||
|
|
||||||
@@ -370,7 +461,7 @@ typedef struct ssh_server_callbacks_struct *ssh_server_callbacks;
|
|||||||
*
|
*
|
||||||
* @param cb The callback structure itself.
|
* @param cb The callback structure itself.
|
||||||
*
|
*
|
||||||
* @return SSH_OK on success, SSH_ERROR on error.
|
* @return `SSH_OK` on success, `SSH_ERROR` on error.
|
||||||
*/
|
*/
|
||||||
LIBSSH_API int ssh_set_server_callbacks(ssh_session session, ssh_server_callbacks cb);
|
LIBSSH_API int ssh_set_server_callbacks(ssh_session session, ssh_server_callbacks cb);
|
||||||
|
|
||||||
@@ -397,7 +488,7 @@ struct ssh_socket_callbacks_struct {
|
|||||||
*/
|
*/
|
||||||
ssh_callback_int_int exception;
|
ssh_callback_int_int exception;
|
||||||
/** This function is called when the ssh_socket_connect was used on the socket
|
/** This function is called when the ssh_socket_connect was used on the socket
|
||||||
* on nonblocking state, and the connection successed.
|
* on nonblocking state, and the connection succeeded.
|
||||||
*/
|
*/
|
||||||
ssh_callback_int_int connected;
|
ssh_callback_int_int connected;
|
||||||
};
|
};
|
||||||
@@ -501,14 +592,17 @@ typedef struct ssh_socket_callbacks_struct *ssh_socket_callbacks;
|
|||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
/** @brief Prototype for a packet callback, to be called when a new packet arrives
|
/** @brief Prototype for a packet callback, to be called when a new packet
|
||||||
|
* arrives
|
||||||
* @param session The current session of the packet
|
* @param session The current session of the packet
|
||||||
* @param type packet type (see ssh2.h)
|
* @param type packet type (see ssh2.h)
|
||||||
* @param packet buffer containing the packet, excluding size, type and padding fields
|
* @param packet buffer containing the packet, excluding size, type and padding
|
||||||
|
* fields
|
||||||
* @param user user argument to the callback
|
* @param user user argument to the callback
|
||||||
* and are called each time a packet shows up
|
* and are called each time a packet shows up
|
||||||
* @returns SSH_PACKET_USED Packet was parsed and used
|
* @returns `SSH_PACKET_USED` Packet was parsed and used
|
||||||
* @returns SSH_PACKET_NOT_USED Packet was not used or understood, processing must continue
|
* @returns `SSH_PACKET_NOT_USED` Packet was not used or understood, processing
|
||||||
|
* must continue
|
||||||
*/
|
*/
|
||||||
typedef int (*ssh_packet_callback) (ssh_session session, uint8_t type, ssh_buffer packet, void *user);
|
typedef int (*ssh_packet_callback) (ssh_session session, uint8_t type, ssh_buffer packet, void *user);
|
||||||
|
|
||||||
@@ -567,7 +661,7 @@ typedef struct ssh_packet_callbacks_struct *ssh_packet_callbacks;
|
|||||||
*
|
*
|
||||||
* @param cb The callback structure itself.
|
* @param cb The callback structure itself.
|
||||||
*
|
*
|
||||||
* @return SSH_OK on success, SSH_ERROR on error.
|
* @return `SSH_OK` on success, `SSH_ERROR` on error.
|
||||||
*/
|
*/
|
||||||
LIBSSH_API int ssh_set_callbacks(ssh_session session, ssh_callbacks cb);
|
LIBSSH_API int ssh_set_callbacks(ssh_session session, ssh_callbacks cb);
|
||||||
|
|
||||||
@@ -625,6 +719,7 @@ typedef void (*ssh_channel_signal_callback) (ssh_session session,
|
|||||||
* @brief SSH channel exit status callback. Called when a channel has received an exit status
|
* @brief SSH channel exit status callback. Called when a channel has received an exit status
|
||||||
* @param session Current session handler
|
* @param session Current session handler
|
||||||
* @param channel the actual channel
|
* @param channel the actual channel
|
||||||
|
* @param exit_status Exit status of the ran command
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
*/
|
*/
|
||||||
typedef void (*ssh_channel_exit_status_callback) (ssh_session session,
|
typedef void (*ssh_channel_exit_status_callback) (ssh_session session,
|
||||||
@@ -637,7 +732,7 @@ typedef void (*ssh_channel_exit_status_callback) (ssh_session session,
|
|||||||
* @param session Current session handler
|
* @param session Current session handler
|
||||||
* @param channel the actual channel
|
* @param channel the actual channel
|
||||||
* @param signal the signal name (without the SIG prefix)
|
* @param signal the signal name (without the SIG prefix)
|
||||||
* @param core a boolean telling wether a core has been dumped or not
|
* @param core a boolean telling whether a core has been dumped or not
|
||||||
* @param errmsg the description of the exception
|
* @param errmsg the description of the exception
|
||||||
* @param lang the language of the description (format: RFC 3066)
|
* @param lang the language of the description (format: RFC 3066)
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
@@ -652,12 +747,13 @@ typedef void (*ssh_channel_exit_signal_callback) (ssh_session session,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief SSH channel PTY request from a client.
|
* @brief SSH channel PTY request from a client.
|
||||||
|
* @param session the session
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
* @param term The type of terminal emulation
|
* @param term The type of terminal emulation
|
||||||
* @param width width of the terminal, in characters
|
* @param width width of the terminal, in characters
|
||||||
* @param height height of the terminal, in characters
|
* @param height height of the terminal, in characters
|
||||||
* @param pxwidth width of the terminal, in pixels
|
* @param pxwidth width of the terminal, in pixels
|
||||||
* @param pxheight height of the terminal, in pixels
|
* @param pwheight height of the terminal, in pixels
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
* @returns 0 if the pty request is accepted
|
* @returns 0 if the pty request is accepted
|
||||||
* @returns -1 if the request is denied
|
* @returns -1 if the request is denied
|
||||||
@@ -671,6 +767,7 @@ typedef int (*ssh_channel_pty_request_callback) (ssh_session session,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief SSH channel Shell request from a client.
|
* @brief SSH channel Shell request from a client.
|
||||||
|
* @param session the session
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
* @returns 0 if the shell request is accepted
|
* @returns 0 if the shell request is accepted
|
||||||
@@ -683,6 +780,7 @@ typedef int (*ssh_channel_shell_request_callback) (ssh_session session,
|
|||||||
* @brief SSH auth-agent-request from the client. This request is
|
* @brief SSH auth-agent-request from the client. This request is
|
||||||
* sent by a client when agent forwarding is available.
|
* sent by a client when agent forwarding is available.
|
||||||
* Server is free to ignore this callback, no answer is expected.
|
* Server is free to ignore this callback, no answer is expected.
|
||||||
|
* @param session the session
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
*/
|
*/
|
||||||
@@ -694,7 +792,12 @@ typedef void (*ssh_channel_auth_agent_req_callback) (ssh_session session,
|
|||||||
* @brief SSH X11 request from the client. This request is
|
* @brief SSH X11 request from the client. This request is
|
||||||
* sent by a client when X11 forwarding is requested(and available).
|
* sent by a client when X11 forwarding is requested(and available).
|
||||||
* Server is free to ignore this callback, no answer is expected.
|
* Server is free to ignore this callback, no answer is expected.
|
||||||
|
* @param session the session
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
|
* @param single_connection If true, only one channel should be forwarded
|
||||||
|
* @param auth_protocol The X11 authentication method to be used
|
||||||
|
* @param auth_cookie Authentication cookie encoded hexadecimal
|
||||||
|
* @param screen_number Screen number
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
*/
|
*/
|
||||||
typedef void (*ssh_channel_x11_req_callback) (ssh_session session,
|
typedef void (*ssh_channel_x11_req_callback) (ssh_session session,
|
||||||
@@ -706,11 +809,12 @@ typedef void (*ssh_channel_x11_req_callback) (ssh_session session,
|
|||||||
void *userdata);
|
void *userdata);
|
||||||
/**
|
/**
|
||||||
* @brief SSH channel PTY windows change (terminal size) from a client.
|
* @brief SSH channel PTY windows change (terminal size) from a client.
|
||||||
|
* @param session the session
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
* @param width width of the terminal, in characters
|
* @param width width of the terminal, in characters
|
||||||
* @param height height of the terminal, in characters
|
* @param height height of the terminal, in characters
|
||||||
* @param pxwidth width of the terminal, in pixels
|
* @param pxwidth width of the terminal, in pixels
|
||||||
* @param pxheight height of the terminal, in pixels
|
* @param pwheight height of the terminal, in pixels
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
* @returns 0 if the pty request is accepted
|
* @returns 0 if the pty request is accepted
|
||||||
* @returns -1 if the request is denied
|
* @returns -1 if the request is denied
|
||||||
@@ -723,6 +827,7 @@ typedef int (*ssh_channel_pty_window_change_callback) (ssh_session session,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief SSH channel Exec request from a client.
|
* @brief SSH channel Exec request from a client.
|
||||||
|
* @param session the session
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
* @param command the shell command to be executed
|
* @param command the shell command to be executed
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
@@ -736,6 +841,7 @@ typedef int (*ssh_channel_exec_request_callback) (ssh_session session,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief SSH channel environment request from a client.
|
* @brief SSH channel environment request from a client.
|
||||||
|
* @param session the session
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
* @param env_name name of the environment value to be set
|
* @param env_name name of the environment value to be set
|
||||||
* @param env_value value of the environment value to be set
|
* @param env_value value of the environment value to be set
|
||||||
@@ -752,6 +858,7 @@ typedef int (*ssh_channel_env_request_callback) (ssh_session session,
|
|||||||
void *userdata);
|
void *userdata);
|
||||||
/**
|
/**
|
||||||
* @brief SSH channel subsystem request from a client.
|
* @brief SSH channel subsystem request from a client.
|
||||||
|
* @param session the session
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
* @param subsystem the subsystem required
|
* @param subsystem the subsystem required
|
||||||
* @param userdata Userdata to be passed to the callback function.
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
@@ -766,6 +873,8 @@ typedef int (*ssh_channel_subsystem_request_callback) (ssh_session session,
|
|||||||
/**
|
/**
|
||||||
* @brief SSH channel write will not block (flow control).
|
* @brief SSH channel write will not block (flow control).
|
||||||
*
|
*
|
||||||
|
* @param session the session
|
||||||
|
*
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
*
|
*
|
||||||
* @param[in] bytes size of the remote window in bytes. Writing as much data
|
* @param[in] bytes size of the remote window in bytes. Writing as much data
|
||||||
@@ -780,6 +889,28 @@ typedef int (*ssh_channel_write_wontblock_callback) (ssh_session session,
|
|||||||
uint32_t bytes,
|
uint32_t bytes,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SSH channel open callback. Called when a channel open succeeds or fails.
|
||||||
|
* @param session Current session handler
|
||||||
|
* @param channel the actual channel
|
||||||
|
* @param is_success is 1 when the open succeeds, and 0 otherwise.
|
||||||
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
|
*/
|
||||||
|
typedef void (*ssh_channel_open_resp_callback) (ssh_session session,
|
||||||
|
ssh_channel channel,
|
||||||
|
bool is_success,
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SSH channel request response callback. Called when a response to the pending request is received.
|
||||||
|
* @param session Current session handler
|
||||||
|
* @param channel the actual channel
|
||||||
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
|
*/
|
||||||
|
typedef void (*ssh_channel_request_resp_callback) (ssh_session session,
|
||||||
|
ssh_channel channel,
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
struct ssh_channel_callbacks_struct {
|
struct ssh_channel_callbacks_struct {
|
||||||
/** DON'T SET THIS use ssh_callbacks_init() instead. */
|
/** DON'T SET THIS use ssh_callbacks_init() instead. */
|
||||||
size_t size;
|
size_t size;
|
||||||
@@ -847,6 +978,14 @@ struct ssh_channel_callbacks_struct {
|
|||||||
* not to block.
|
* not to block.
|
||||||
*/
|
*/
|
||||||
ssh_channel_write_wontblock_callback channel_write_wontblock_function;
|
ssh_channel_write_wontblock_callback channel_write_wontblock_function;
|
||||||
|
/**
|
||||||
|
* This functions will be called when the channel has received a channel open confirmation or failure.
|
||||||
|
*/
|
||||||
|
ssh_channel_open_resp_callback channel_open_response_function;
|
||||||
|
/**
|
||||||
|
* This functions will be called when the channel has received the response to the pending request.
|
||||||
|
*/
|
||||||
|
ssh_channel_request_resp_callback channel_request_response_function;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct ssh_channel_callbacks_struct *ssh_channel_callbacks;
|
typedef struct ssh_channel_callbacks_struct *ssh_channel_callbacks;
|
||||||
@@ -874,7 +1013,7 @@ typedef struct ssh_channel_callbacks_struct *ssh_channel_callbacks;
|
|||||||
*
|
*
|
||||||
* @param cb The callback structure itself.
|
* @param cb The callback structure itself.
|
||||||
*
|
*
|
||||||
* @return SSH_OK on success, SSH_ERROR on error.
|
* @return `SSH_OK` on success, `SSH_ERROR` on error.
|
||||||
* @warning this function will not replace existing callbacks but set the
|
* @warning this function will not replace existing callbacks but set the
|
||||||
* new one atop of them.
|
* new one atop of them.
|
||||||
*/
|
*/
|
||||||
@@ -893,7 +1032,7 @@ LIBSSH_API int ssh_set_channel_callbacks(ssh_channel channel,
|
|||||||
*
|
*
|
||||||
* @param cb The callback structure itself.
|
* @param cb The callback structure itself.
|
||||||
*
|
*
|
||||||
* @return SSH_OK on success, SSH_ERROR on error.
|
* @return `SSH_OK` on success, `SSH_ERROR` on error.
|
||||||
*
|
*
|
||||||
* @see ssh_set_channel_callbacks
|
* @see ssh_set_channel_callbacks
|
||||||
*/
|
*/
|
||||||
@@ -910,14 +1049,14 @@ LIBSSH_API int ssh_add_channel_callbacks(ssh_channel channel,
|
|||||||
*
|
*
|
||||||
* @param cb The callback structure to remove
|
* @param cb The callback structure to remove
|
||||||
*
|
*
|
||||||
* @returns SSH_OK on success, SSH_ERROR on error.
|
* @returns `SSH_OK` on success, `SSH_ERROR` on error.
|
||||||
*/
|
*/
|
||||||
LIBSSH_API int ssh_remove_channel_callbacks(ssh_channel channel,
|
LIBSSH_API int ssh_remove_channel_callbacks(ssh_channel channel,
|
||||||
ssh_channel_callbacks cb);
|
ssh_channel_callbacks cb);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/** @group libssh_threads
|
/** @addtogroup libssh_threads
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -943,7 +1082,7 @@ struct ssh_threads_callbacks_struct {
|
|||||||
* @param[in] cb A pointer to a ssh_threads_callbacks_struct structure, which
|
* @param[in] cb A pointer to a ssh_threads_callbacks_struct structure, which
|
||||||
* contains the different callbacks to be set.
|
* contains the different callbacks to be set.
|
||||||
*
|
*
|
||||||
* @returns Always returns SSH_OK.
|
* @returns Always returns `SSH_OK`.
|
||||||
*
|
*
|
||||||
* @see ssh_threads_callbacks_struct
|
* @see ssh_threads_callbacks_struct
|
||||||
* @see SSH_THREADS_PTHREAD
|
* @see SSH_THREADS_PTHREAD
|
||||||
@@ -983,13 +1122,14 @@ LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_pthread(void);
|
|||||||
* @see ssh_threads_set_callbacks
|
* @see ssh_threads_set_callbacks
|
||||||
*/
|
*/
|
||||||
LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void);
|
LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void);
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the logging callback function.
|
* @brief Set the logging callback function.
|
||||||
*
|
*
|
||||||
* @param[in] cb The callback to set.
|
* @param[in] cb The callback to set.
|
||||||
*
|
*
|
||||||
* @return 0 on success, < 0 on errror.
|
* @return 0 on success, < 0 on error.
|
||||||
*/
|
*/
|
||||||
LIBSSH_API int ssh_set_log_callback(ssh_logging_callback cb);
|
LIBSSH_API int ssh_set_log_callback(ssh_logging_callback cb);
|
||||||
|
|
||||||
@@ -1000,7 +1140,216 @@ LIBSSH_API int ssh_set_log_callback(ssh_logging_callback cb);
|
|||||||
*/
|
*/
|
||||||
LIBSSH_API ssh_logging_callback ssh_get_log_callback(void);
|
LIBSSH_API ssh_logging_callback ssh_get_log_callback(void);
|
||||||
|
|
||||||
/** @} */
|
/**
|
||||||
|
* @brief SSH proxyjump before connection callback. Called before calling
|
||||||
|
* ssh_connect()
|
||||||
|
* @param session Jump session handler
|
||||||
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
|
*
|
||||||
|
* @return 0 on success, < 0 on error.
|
||||||
|
*/
|
||||||
|
typedef int (*ssh_jump_before_connection_callback)(ssh_session session,
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SSH proxyjump verify knownhost callback. Verify the host.
|
||||||
|
* If not specified default function will be used.
|
||||||
|
* @param session Jump session handler
|
||||||
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
|
*
|
||||||
|
* @return 0 on success, < 0 on error.
|
||||||
|
*/
|
||||||
|
typedef int (*ssh_jump_verify_knownhost_callback)(ssh_session session,
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SSH proxyjump user authentication callback. Authenticate the user.
|
||||||
|
* @param session Jump session handler
|
||||||
|
* @param userdata Userdata to be passed to the callback function.
|
||||||
|
*
|
||||||
|
* @return 0 on success, < 0 on error.
|
||||||
|
*/
|
||||||
|
typedef int (*ssh_jump_authenticate_callback)(ssh_session session,
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
|
struct ssh_jump_callbacks_struct {
|
||||||
|
void *userdata;
|
||||||
|
ssh_jump_before_connection_callback before_connection;
|
||||||
|
ssh_jump_verify_knownhost_callback verify_knownhost;
|
||||||
|
ssh_jump_authenticate_callback authenticate;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Security key callbacks */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Forward declarations for structs that have been defined in sk_api.h.
|
||||||
|
* If you need to work with the fields inside them, please include
|
||||||
|
* libssh/sk_api.h
|
||||||
|
*/
|
||||||
|
struct sk_enroll_response;
|
||||||
|
struct sk_sign_response;
|
||||||
|
struct sk_resident_key;
|
||||||
|
struct sk_option;
|
||||||
|
|
||||||
|
#define LIBSSH_SK_API_VERSION_MAJOR 0x000a0000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FIDO2/U2F SK API version callback.
|
||||||
|
*
|
||||||
|
* Returns the version of the FIDO2/U2F API that the callbacks implement.
|
||||||
|
* This callback allows custom callback implementations to specify their
|
||||||
|
* SK API version for compatibility checking with libssh's security key
|
||||||
|
* interface.
|
||||||
|
*
|
||||||
|
* @details Version compatibility is determined by comparing the major version
|
||||||
|
* portion (upper 16 bits) of the returned value with SSH_SK_VERSION_MAJOR.
|
||||||
|
*
|
||||||
|
* For compatibility, implementations should return a version where:
|
||||||
|
* (returned_version & SSH_SK_VERSION_MAJOR_MASK) == SSH_SK_VERSION_MAJOR
|
||||||
|
*
|
||||||
|
* This ensures that the callbacks' SK API matches the major version expected
|
||||||
|
* by libssh, while allowing minor version differences for backward
|
||||||
|
* compatibility.
|
||||||
|
*
|
||||||
|
* @see LIBSSH_SK_API_VERSION_MAJOR Current expected major API version
|
||||||
|
* @see SSH_SK_VERSION_MAJOR_MASK Mask for extracting major version (0xffff0000)
|
||||||
|
*/
|
||||||
|
typedef uint32_t (*sk_api_version_callback)(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FIDO2/U2F key enrollment callback.
|
||||||
|
*
|
||||||
|
* Enrolls a new FIDO2/U2F security key credential (private key generation).
|
||||||
|
* This callback handles the creation of new FIDO2/U2F credentials, including
|
||||||
|
* both resident and non-resident keys.
|
||||||
|
*
|
||||||
|
* @param[in] alg The cryptographic algorithm to use
|
||||||
|
* @param[in] challenge Random challenge data for enrollment
|
||||||
|
* @param[in] challenge_len Length of the challenge data
|
||||||
|
* @param[in] application Application identifier (relying party ID)
|
||||||
|
* @param[in] flags Enrollment flags
|
||||||
|
* @param[in] pin PIN for user verification (may be NULL)
|
||||||
|
* @param[in] options Array of enrollment options (device path, user ID, etc.)
|
||||||
|
* @param[out] enroll_response Enrollment response containing public key,
|
||||||
|
* key handle, signature, and attestation data
|
||||||
|
*
|
||||||
|
* @returns SSH_OK on success, SSH_SK_ERR_* codes on failure.
|
||||||
|
*/
|
||||||
|
typedef int (*sk_enroll_callback)(uint32_t alg,
|
||||||
|
const uint8_t *challenge,
|
||||||
|
size_t challenge_len,
|
||||||
|
const char *application,
|
||||||
|
uint8_t flags,
|
||||||
|
const char *pin,
|
||||||
|
struct sk_option **options,
|
||||||
|
struct sk_enroll_response **enroll_response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FIDO2/U2F security key signing callback.
|
||||||
|
*
|
||||||
|
* Signs data using a FIDO2 security key credential. This callback performs
|
||||||
|
* cryptographic signing operations using previously enrolled FIDO2/U2F
|
||||||
|
* credentials.
|
||||||
|
*
|
||||||
|
* @param[in] alg The cryptographic algorithm used by the key
|
||||||
|
* @param[in] data Data to be signed
|
||||||
|
* @param[in] data_len Length of the data to sign
|
||||||
|
* @param[in] application Application identifier (relying party ID)
|
||||||
|
* @param[in] key_handle Key handle identifying the credential
|
||||||
|
* @param[in] key_handle_len Length of the key handle
|
||||||
|
* @param[in] flags Signing flags
|
||||||
|
* @param[in] pin PIN for user verification (may be NULL)
|
||||||
|
* @param[in] options Array of signing options (device path, etc.)
|
||||||
|
* @param[out] sign_response Signature response containing signature data,
|
||||||
|
* flags, and counter information
|
||||||
|
*
|
||||||
|
* @returns SSH_OK on success, SSH_SK_ERR_* codes on failure.
|
||||||
|
*/
|
||||||
|
typedef int (*sk_sign_callback)(uint32_t alg,
|
||||||
|
const uint8_t *data,
|
||||||
|
size_t data_len,
|
||||||
|
const char *application,
|
||||||
|
const uint8_t *key_handle,
|
||||||
|
size_t key_handle_len,
|
||||||
|
uint8_t flags,
|
||||||
|
const char *pin,
|
||||||
|
struct sk_option **options,
|
||||||
|
struct sk_sign_response **sign_response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FIDO2 security key resident keys loading callback.
|
||||||
|
*
|
||||||
|
* Enumerates and loads all resident keys (discoverable credentials) stored
|
||||||
|
* on FIDO2 devices. Resident keys are credentials stored directly on
|
||||||
|
* the device itself and can be discovered without prior knowledge
|
||||||
|
* of key handles.
|
||||||
|
*
|
||||||
|
* @param[in] pin PIN for accessing resident keys (required for most operations)
|
||||||
|
* @param[in] options Array of options (device path, etc.)
|
||||||
|
* @param[out] resident_keys Array of resident key structures containing key
|
||||||
|
* data, application IDs, user information, and metadata
|
||||||
|
* @param[out] num_keys_found Number of resident keys found and loaded
|
||||||
|
*
|
||||||
|
* @returns SSH_OK on success, SSH_SK_ERR_* codes on failure.
|
||||||
|
*/
|
||||||
|
typedef int (*sk_load_resident_keys_callback)(
|
||||||
|
const char *pin,
|
||||||
|
struct sk_option **options,
|
||||||
|
struct sk_resident_key ***resident_keys,
|
||||||
|
size_t *num_keys_found);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FIDO2/U2F security key callbacks structure.
|
||||||
|
*
|
||||||
|
* This structure contains callbacks for FIDO2/U2F operations.
|
||||||
|
* It allows applications to provide custom implementations of FIDO2/U2F
|
||||||
|
* operations to override the default libfido2-based implementation.
|
||||||
|
*
|
||||||
|
* @warning These callbacks will only be called if libssh was built with
|
||||||
|
* FIDO2/U2F support enabled. (WITH_FIDO2 = ON).
|
||||||
|
*/
|
||||||
|
struct ssh_sk_callbacks_struct {
|
||||||
|
/** DON'T SET THIS use ssh_callbacks_init() instead. */
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This callback returns the SK API version used by the callback
|
||||||
|
* implementation.
|
||||||
|
*
|
||||||
|
* @see sk_api_version_callback for detailed documentation
|
||||||
|
*/
|
||||||
|
sk_api_version_callback api_version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This callback enrolls a new FIDO2/U2F credential, generating
|
||||||
|
* a new key pair and optionally storing it on the device itself
|
||||||
|
* (resident keys).
|
||||||
|
*
|
||||||
|
* @see sk_enroll_callback for detailed documentation
|
||||||
|
*/
|
||||||
|
sk_enroll_callback enroll;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This callback performs cryptographic signing operations using a
|
||||||
|
* previously enrolled FIDO2/U2F credential.
|
||||||
|
*
|
||||||
|
* @see sk_sign_callback for detailed documentation
|
||||||
|
*/
|
||||||
|
sk_sign_callback sign;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This callback enumerates and loads all resident keys (discoverable
|
||||||
|
* credentials) stored on the FIDO2 device.
|
||||||
|
*
|
||||||
|
* @see sk_load_resident_keys_callback for detailed documentation
|
||||||
|
*/
|
||||||
|
sk_load_resident_keys_callback load_resident_keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ssh_sk_callbacks_struct *ssh_sk_callbacks;
|
||||||
|
|
||||||
|
const struct ssh_sk_callbacks_struct *ssh_sk_get_default_callbacks(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ struct chacha_ctx {
|
|||||||
#define CHACHA_CTRLEN 8
|
#define CHACHA_CTRLEN 8
|
||||||
#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN)
|
#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
void chacha_keysetup(struct chacha_ctx *x, const uint8_t *k, uint32_t kbits)
|
void chacha_keysetup(struct chacha_ctx *x, const uint8_t *k, uint32_t kbits)
|
||||||
#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE
|
#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE
|
||||||
__attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN)))
|
__attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN)))
|
||||||
@@ -37,4 +41,8 @@ void chacha_encrypt_bytes(struct chacha_ctx *x, const uint8_t *m,
|
|||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* CHACHA_H */
|
#endif /* CHACHA_H */
|
||||||
|
|||||||
@@ -22,6 +22,10 @@
|
|||||||
#define CHANNELS_H_
|
#define CHANNELS_H_
|
||||||
#include "libssh/priv.h"
|
#include "libssh/priv.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/** @internal
|
/** @internal
|
||||||
* Describes the different possible states in a
|
* Describes the different possible states in a
|
||||||
* outgoing (client) channel request
|
* outgoing (client) channel request
|
||||||
@@ -35,7 +39,7 @@ enum ssh_channel_request_state_e {
|
|||||||
SSH_CHANNEL_REQ_STATE_ACCEPTED,
|
SSH_CHANNEL_REQ_STATE_ACCEPTED,
|
||||||
/** A request has been replied and refused */
|
/** A request has been replied and refused */
|
||||||
SSH_CHANNEL_REQ_STATE_DENIED,
|
SSH_CHANNEL_REQ_STATE_DENIED,
|
||||||
/** A request has been replied and an error happend */
|
/** A request has been replied and an error happened */
|
||||||
SSH_CHANNEL_REQ_STATE_ERROR
|
SSH_CHANNEL_REQ_STATE_ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -76,7 +80,12 @@ struct ssh_channel_struct {
|
|||||||
ssh_buffer stdout_buffer;
|
ssh_buffer stdout_buffer;
|
||||||
ssh_buffer stderr_buffer;
|
ssh_buffer stderr_buffer;
|
||||||
void *userarg;
|
void *userarg;
|
||||||
int exit_status;
|
struct {
|
||||||
|
bool status;
|
||||||
|
uint32_t code;
|
||||||
|
char *signal;
|
||||||
|
bool core_dumped;
|
||||||
|
} exit;
|
||||||
enum ssh_channel_request_state_e request_state;
|
enum ssh_channel_request_state_e request_state;
|
||||||
struct ssh_list *callbacks; /* list of ssh_channel_callbacks */
|
struct ssh_list *callbacks; /* list of ssh_channel_callbacks */
|
||||||
|
|
||||||
@@ -109,4 +118,8 @@ int ssh_global_request(ssh_session session,
|
|||||||
ssh_buffer buffer,
|
ssh_buffer buffer,
|
||||||
int reply);
|
int reply);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* CHANNELS_H_ */
|
#endif /* CHANNELS_H_ */
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#ifndef LIBSSH_CONFIG_H_
|
#ifndef LIBSSH_CONFIG_H_
|
||||||
#define LIBSSH_CONFIG_H_
|
#define LIBSSH_CONFIG_H_
|
||||||
|
|
||||||
|
#include "libssh/libssh.h"
|
||||||
|
|
||||||
enum ssh_config_opcode_e {
|
enum ssh_config_opcode_e {
|
||||||
/* Unknown opcode */
|
/* Unknown opcode */
|
||||||
@@ -62,7 +63,18 @@ enum ssh_config_opcode_e {
|
|||||||
SOC_PUBKEYACCEPTEDKEYTYPES,
|
SOC_PUBKEYACCEPTEDKEYTYPES,
|
||||||
SOC_REKEYLIMIT,
|
SOC_REKEYLIMIT,
|
||||||
SOC_IDENTITYAGENT,
|
SOC_IDENTITYAGENT,
|
||||||
|
SOC_IDENTITIESONLY,
|
||||||
|
SOC_CONTROLMASTER,
|
||||||
|
SOC_CONTROLPATH,
|
||||||
|
SOC_CERTIFICATE,
|
||||||
|
SOC_REQUIRED_RSA_SIZE,
|
||||||
|
SOC_ADDRESSFAMILY,
|
||||||
|
SOC_GSSAPIKEYEXCHANGE,
|
||||||
|
SOC_GSSAPIKEXALGORITHMS,
|
||||||
|
|
||||||
SOC_MAX /* Keep this one last in the list */
|
SOC_MAX /* Keep this one last in the list */
|
||||||
};
|
};
|
||||||
|
enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword);
|
||||||
|
int ssh_config_parse_line_cli(ssh_session session, const char *line);
|
||||||
|
|
||||||
#endif /* LIBSSH_CONFIG_H_ */
|
#endif /* LIBSSH_CONFIG_H_ */
|
||||||
|
|||||||