Skip to content

Commit aa32a26

Browse files
authored
Merge pull request #9 from JuliaWeb/verify-hostname
Implement hostkey verification
2 parents e49fbe8 + eaaff1b commit aa32a26

File tree

11 files changed

+337
-186
lines changed

11 files changed

+337
-186
lines changed

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "LibSSH"
22
uuid = "00483490-30f8-4353-8aba-35b82f51f4d0"
33
authors = ["James Wrigley <[email protected]> and contributors"]
4-
version = "0.3.0"
4+
version = "0.4.0"
55

66
[deps]
77
CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82"

docs/src/changelog.md

+21
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,27 @@ CurrentModule = LibSSH
77
This documents notable changes in LibSSH.jl. The format is based on [Keep a
88
Changelog](https://keepachangelog.com).
99

10+
## [v0.4.0] - 2024-03-12
11+
12+
### Added
13+
14+
- A `throw` argument to [`poll_loop()`](@ref) ([#9]).
15+
- Support for some more options in [`Session`](@ref) ([#9]).
16+
- A new method for [`PKI.get_fingerprint_hash(::PKI.SshKey)`](@ref) to get a
17+
public key fingerprint straight from a [`PKI.SshKey`](@ref) ([#9]).
18+
19+
### Changed
20+
21+
- Some automatically-wrapped low-level functions changed names back to retaining
22+
their `ssh_` prefixes, and they now have a `throw` argument to allow disabling
23+
throwing an exception upon error ([#9]).
24+
- [`authenticate()`](@ref) will now do host verification as well. This is
25+
critical for security so it is *strongly recommend* that all dependencies
26+
update to this release ([#9]).
27+
- All the `throw_on_*` arguments in the various `Session` and `SshChannel`
28+
methods have been renamed `throw` for consistency with `Base` and the new
29+
`throw` arguments in some auto-wrapped bindings ([#9]).
30+
1031
## [v0.3.0] - 2024-03-10
1132

1233
### Added

docs/src/examples.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ session = ssh.Session("127.0.0.1", 2222)
2828
# the server*, which means checking its host key. The easiest way to do this is
2929
# by checking the server key against the users known hosts file:
3030

31-
ssh.is_known_server(session; throw_on_failure=false)
31+
ssh.is_known_server(session; throw=false)
3232

3333
# Ok, we got back a `KnownHosts_Unknown` response. That's because the demo
3434
# server automatically creates a dummy key to use, and that definitely won't be

gen/gen.jl

+18-24
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ string_functions = [:ssh_message_auth_user, :ssh_message_auth_password,
1818
:ssh_userauth_kbdint_getprompt]
1919
bool_functions = [:ssh_message_auth_kbdint_is_response]
2020
ssh_ok_functions = [:ssh_message_auth_reply_success, :ssh_message_auth_set_methods,
21-
:ssh_message_reply_default]
21+
:ssh_message_reply_default,
22+
:ssh_options_get, :ssh_options_set, :ssh_options_get_port]
2223
all_rewritable_functions = vcat(string_functions, bool_functions, ssh_ok_functions)
2324

2425
"""
@@ -92,48 +93,41 @@ function rewrite!(ctx)
9293
# Look for function expressions
9394
if @capture(expr, function name_(args__) body_ end)
9495
wrapper = nothing
95-
ret_type = nothing
9696

9797
# Check if we can rewrite the function
9898
if name in string_functions
9999
wrapper = quote
100100
if ret == C_NULL
101-
throw(LibSSHException($("Error from $name, no string found (returned C_NULL)")))
102-
else
103-
return unsafe_string(Ptr{UInt8}(ret))
101+
if throw
102+
Base.throw(LibSSHException($("Error from $name, no string found (returned C_NULL)")))
103+
else
104+
return ret
105+
end
104106
end
107+
108+
return unsafe_string(Ptr{UInt8}(ret))
105109
end
106-
ret_type = String
107110
elseif name in bool_functions
108-
wrapper = :(return ret == 1)
109-
ret_type = Bool
111+
wrapper = :(return Bool(ret))
110112
elseif name in ssh_ok_functions
111113
wrapper = quote
112-
if ret != SSH_OK
114+
if ret != SSH_OK && throw
113115
# This ugly concatenation is necessary because we
114116
# have to interpolate the function name into the
115117
# error string but also keep the return value
116118
# interpolation from being escaped.
117-
throw(LibSSHException($("Error from $name, did not return SSH_OK: ") * "$(ret)"))
119+
Base.throw(LibSSHException($("Error from $name, did not return SSH_OK: ") * "$(ret)"))
118120
end
121+
122+
return ret
119123
end
120124
end
121125

122126
if !isnothing(wrapper)
123-
wrapper_name = Symbol(chopprefix(string(name), "ssh_"))
124-
new_expr = if isnothing(ret_type)
125-
quote
126-
function $wrapper_name($(args...))
127-
ret = $body
128-
$wrapper
129-
end
130-
end
131-
else
132-
quote
133-
function $wrapper_name($(args...))::$ret_type
134-
ret = $body
135-
$wrapper
136-
end
127+
new_expr = quote
128+
function $name($(args...); throw=true)
129+
ret = $body
130+
$wrapper
137131
end
138132
end
139133

src/LibSSH.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ using DocStringExtensions
99

1010
include("bindings.jl")
1111
using .lib
12-
import .lib: LibSSHException, ssh_options_get, ssh_options_set, SSH_OK, SSH_ERROR, SSH_AGAIN, SSH_EOF
12+
import .lib: LibSSHException, SSH_OK, SSH_ERROR, SSH_AGAIN, SSH_EOF
1313

1414

1515
"""

src/bindings.jl

+82-52
Original file line numberDiff line numberDiff line change
@@ -1386,30 +1386,42 @@ function ssh_options_parse_config(session, filename)
13861386
end
13871387

13881388
"""
1389-
ssh_options_set(session, type, value)
1389+
ssh_options_set(session, type, value; throw = true)
13901390
1391-
[Upstream documentation](https://api.libssh.org/stable/group__libssh__session.html#ga7a801b85800baa3f4e16f5b47db0a73d).
1391+
Auto-generated wrapper around [`ssh_options_set`](https://api.libssh.org/stable/group__libssh__session.html#ga7a801b85800baa3f4e16f5b47db0a73d).
13921392
"""
1393-
function ssh_options_set(session, type, value)
1394-
@ccall libssh.ssh_options_set(session::ssh_session, type::ssh_options_e, value::Ptr{Cvoid})::Cint
1393+
function ssh_options_set(session, type, value; throw = true)
1394+
ret = @ccall(libssh.ssh_options_set(session::ssh_session, type::ssh_options_e, value::Ptr{Cvoid})::Cint)
1395+
if ret != SSH_OK && throw
1396+
Base.throw(LibSSHException("Error from ssh_options_set, did not return SSH_OK: " * "$(ret)"))
1397+
end
1398+
return ret
13951399
end
13961400

13971401
"""
1398-
ssh_options_get(session, type, value)
1402+
ssh_options_get(session, type, value; throw = true)
13991403
1400-
[Upstream documentation](https://api.libssh.org/stable/group__libssh__session.html#gaaa9d400920cad4d6e4a0fb09ff8c7b01).
1404+
Auto-generated wrapper around [`ssh_options_get`](https://api.libssh.org/stable/group__libssh__session.html#gaaa9d400920cad4d6e4a0fb09ff8c7b01).
14011405
"""
1402-
function ssh_options_get(session, type, value)
1403-
@ccall libssh.ssh_options_get(session::ssh_session, type::ssh_options_e, value::Ptr{Ptr{Cchar}})::Cint
1406+
function ssh_options_get(session, type, value; throw = true)
1407+
ret = @ccall(libssh.ssh_options_get(session::ssh_session, type::ssh_options_e, value::Ptr{Ptr{Cchar}})::Cint)
1408+
if ret != SSH_OK && throw
1409+
Base.throw(LibSSHException("Error from ssh_options_get, did not return SSH_OK: " * "$(ret)"))
1410+
end
1411+
return ret
14041412
end
14051413

14061414
"""
1407-
ssh_options_get_port(session, port_target)
1415+
ssh_options_get_port(session, port_target; throw = true)
14081416
1409-
[Upstream documentation](https://api.libssh.org/stable/group__libssh__session.html#gaa298d8445355420d80f2d968477ba86f).
1417+
Auto-generated wrapper around [`ssh_options_get_port`](https://api.libssh.org/stable/group__libssh__session.html#gaa298d8445355420d80f2d968477ba86f).
14101418
"""
1411-
function ssh_options_get_port(session, port_target)
1412-
@ccall libssh.ssh_options_get_port(session::ssh_session, port_target::Ptr{Cuint})::Cint
1419+
function ssh_options_get_port(session, port_target; throw = true)
1420+
ret = @ccall(libssh.ssh_options_get_port(session::ssh_session, port_target::Ptr{Cuint})::Cint)
1421+
if ret != SSH_OK && throw
1422+
Base.throw(LibSSHException("Error from ssh_options_get_port, did not return SSH_OK: " * "$(ret)"))
1423+
end
1424+
return ret
14131425
end
14141426

14151427
function ssh_pcap_file_close(pcap)
@@ -1862,17 +1874,20 @@ function ssh_userauth_kbdint_getinstruction(session)
18621874
end
18631875

18641876
"""
1865-
userauth_kbdint_getname(session)::String
1877+
ssh_userauth_kbdint_getname(session; throw = true)
18661878
18671879
Auto-generated wrapper around [`ssh_userauth_kbdint_getname`](https://api.libssh.org/stable/group__libssh__auth.html#ga5d6f5eb0ed09fe2c7a2ac69b972e130e).
18681880
"""
1869-
function userauth_kbdint_getname(session)::String
1881+
function ssh_userauth_kbdint_getname(session; throw = true)
18701882
ret = @ccall(libssh.ssh_userauth_kbdint_getname(session::ssh_session)::Ptr{Cchar})
18711883
if ret == C_NULL
1872-
throw(LibSSHException("Error from ssh_userauth_kbdint_getname, no string found (returned C_NULL)"))
1873-
else
1874-
return unsafe_string(Ptr{UInt8}(ret))
1884+
if throw
1885+
Base.throw(LibSSHException("Error from ssh_userauth_kbdint_getname, no string found (returned C_NULL)"))
1886+
else
1887+
return ret
1888+
end
18751889
end
1890+
return unsafe_string(Ptr{UInt8}(ret))
18761891
end
18771892

18781893
"""
@@ -1885,17 +1900,20 @@ function ssh_userauth_kbdint_getnprompts(session)
18851900
end
18861901

18871902
"""
1888-
userauth_kbdint_getprompt(session, i, echo)::String
1903+
ssh_userauth_kbdint_getprompt(session, i, echo; throw = true)
18891904
18901905
Auto-generated wrapper around [`ssh_userauth_kbdint_getprompt`](https://api.libssh.org/stable/group__libssh__auth.html#ga15c0f954f79d73e1ac5981ac483efb75).
18911906
"""
1892-
function userauth_kbdint_getprompt(session, i, echo)::String
1907+
function ssh_userauth_kbdint_getprompt(session, i, echo; throw = true)
18931908
ret = @ccall(libssh.ssh_userauth_kbdint_getprompt(session::ssh_session, i::Cuint, echo::Ptr{Cchar})::Ptr{Cchar})
18941909
if ret == C_NULL
1895-
throw(LibSSHException("Error from ssh_userauth_kbdint_getprompt, no string found (returned C_NULL)"))
1896-
else
1897-
return unsafe_string(Ptr{UInt8}(ret))
1910+
if throw
1911+
Base.throw(LibSSHException("Error from ssh_userauth_kbdint_getprompt, no string found (returned C_NULL)"))
1912+
else
1913+
return ret
1914+
end
18981915
end
1916+
return unsafe_string(Ptr{UInt8}(ret))
18991917
end
19001918

19011919
"""
@@ -1908,17 +1926,20 @@ function ssh_userauth_kbdint_getnanswers(session)
19081926
end
19091927

19101928
"""
1911-
userauth_kbdint_getanswer(session, i)::String
1929+
ssh_userauth_kbdint_getanswer(session, i; throw = true)
19121930
19131931
Auto-generated wrapper around [`ssh_userauth_kbdint_getanswer`](https://api.libssh.org/stable/group__libssh__auth.html#ga4f55ed8bc6f553423ab1c92598d0194b).
19141932
"""
1915-
function userauth_kbdint_getanswer(session, i)::String
1933+
function ssh_userauth_kbdint_getanswer(session, i; throw = true)
19161934
ret = @ccall(libssh.ssh_userauth_kbdint_getanswer(session::ssh_session, i::Cuint)::Ptr{Cchar})
19171935
if ret == C_NULL
1918-
throw(LibSSHException("Error from ssh_userauth_kbdint_getanswer, no string found (returned C_NULL)"))
1919-
else
1920-
return unsafe_string(Ptr{UInt8}(ret))
1936+
if throw
1937+
Base.throw(LibSSHException("Error from ssh_userauth_kbdint_getanswer, no string found (returned C_NULL)"))
1938+
else
1939+
return ret
1940+
end
19211941
end
1942+
return unsafe_string(Ptr{UInt8}(ret))
19221943
end
19231944

19241945
"""
@@ -3847,7 +3868,7 @@ function ssh_send_issue_banner(session, banner)
38473868
end
38483869

38493870
"""
3850-
message_reply_default(msg)
3871+
ssh_message_reply_default(msg; throw = true)
38513872
38523873
Auto-generated wrapper around `ssh_message_reply_default`. Original upstream documentation is below.
38533874
@@ -3864,15 +3885,16 @@ Use this function if you don't know what to respond or if you want to reject a r
38643885
# See also
38653886
[`ssh_message_get`](@ref)()
38663887
"""
3867-
function message_reply_default(msg)
3888+
function ssh_message_reply_default(msg; throw = true)
38683889
ret = @ccall(libssh.ssh_message_reply_default(msg::ssh_message)::Cint)
3869-
if ret != SSH_OK
3870-
throw(LibSSHException("Error from ssh_message_reply_default, did not return SSH_OK: " * "$(ret)"))
3890+
if ret != SSH_OK && throw
3891+
Base.throw(LibSSHException("Error from ssh_message_reply_default, did not return SSH_OK: " * "$(ret)"))
38713892
end
3893+
return ret
38723894
end
38733895

38743896
"""
3875-
message_auth_user(msg)::String
3897+
ssh_message_auth_user(msg; throw = true)
38763898
38773899
Auto-generated wrapper around `ssh_message_auth_user`. Original upstream documentation is below.
38783900
@@ -3887,17 +3909,20 @@ The username or NULL if an error occurred.
38873909
# See also
38883910
[`ssh_message_get`](@ref)(), [`ssh_message_type`](@ref)()
38893911
"""
3890-
function message_auth_user(msg)::String
3912+
function ssh_message_auth_user(msg; throw = true)
38913913
ret = @ccall(libssh.ssh_message_auth_user(msg::ssh_message)::Ptr{Cchar})
38923914
if ret == C_NULL
3893-
throw(LibSSHException("Error from ssh_message_auth_user, no string found (returned C_NULL)"))
3894-
else
3895-
return unsafe_string(Ptr{UInt8}(ret))
3915+
if throw
3916+
Base.throw(LibSSHException("Error from ssh_message_auth_user, no string found (returned C_NULL)"))
3917+
else
3918+
return ret
3919+
end
38963920
end
3921+
return unsafe_string(Ptr{UInt8}(ret))
38973922
end
38983923

38993924
"""
3900-
message_auth_password(msg)::String
3925+
ssh_message_auth_password(msg; throw = true)
39013926
39023927
Auto-generated wrapper around `ssh_message_auth_password`. Original upstream documentation is below.
39033928
@@ -3916,13 +3941,16 @@ The username or NULL if an error occurred.
39163941
# See also
39173942
[`ssh_message_get`](@ref)(), [`ssh_message_type`](@ref)()
39183943
"""
3919-
function message_auth_password(msg)::String
3944+
function ssh_message_auth_password(msg; throw = true)
39203945
ret = @ccall(libssh.ssh_message_auth_password(msg::ssh_message)::Ptr{Cchar})
39213946
if ret == C_NULL
3922-
throw(LibSSHException("Error from ssh_message_auth_password, no string found (returned C_NULL)"))
3923-
else
3924-
return unsafe_string(Ptr{UInt8}(ret))
3947+
if throw
3948+
Base.throw(LibSSHException("Error from ssh_message_auth_password, no string found (returned C_NULL)"))
3949+
else
3950+
return ret
3951+
end
39253952
end
3953+
return unsafe_string(Ptr{UInt8}(ret))
39263954
end
39273955

39283956
"""
@@ -3948,13 +3976,13 @@ function ssh_message_auth_pubkey(msg)
39483976
end
39493977

39503978
"""
3951-
message_auth_kbdint_is_response(msg)::Bool
3979+
ssh_message_auth_kbdint_is_response(msg; throw = true)
39523980
39533981
Auto-generated wrapper around [`ssh_message_auth_kbdint_is_response`](https://api.libssh.org/stable/group__libssh__server.html#ga5132c82c49de985e9e10f51f393e52a4).
39543982
"""
3955-
function message_auth_kbdint_is_response(msg)::Bool
3983+
function ssh_message_auth_kbdint_is_response(msg; throw = true)
39563984
ret = @ccall(libssh.ssh_message_auth_kbdint_is_response(msg::ssh_message)::Cint)
3957-
return ret == 1
3985+
return Bool(ret)
39583986
end
39593987

39603988
"""
@@ -3972,15 +4000,16 @@ function ssh_message_auth_publickey_state(msg)
39724000
end
39734001

39744002
"""
3975-
message_auth_reply_success(msg, partial)
4003+
ssh_message_auth_reply_success(msg, partial; throw = true)
39764004
39774005
Auto-generated wrapper around `ssh_message_auth_reply_success`.
39784006
"""
3979-
function message_auth_reply_success(msg, partial)
4007+
function ssh_message_auth_reply_success(msg, partial; throw = true)
39804008
ret = @ccall(libssh.ssh_message_auth_reply_success(msg::ssh_message, partial::Cint)::Cint)
3981-
if ret != SSH_OK
3982-
throw(LibSSHException("Error from ssh_message_auth_reply_success, did not return SSH_OK: " * "$(ret)"))
4009+
if ret != SSH_OK && throw
4010+
Base.throw(LibSSHException("Error from ssh_message_auth_reply_success, did not return SSH_OK: " * "$(ret)"))
39834011
end
4012+
return ret
39844013
end
39854014

39864015
"""
@@ -4002,15 +4031,16 @@ function ssh_message_auth_reply_pk_ok_simple(msg)
40024031
end
40034032

40044033
"""
4005-
message_auth_set_methods(msg, methods)
4034+
ssh_message_auth_set_methods(msg, methods; throw = true)
40064035
40074036
Auto-generated wrapper around [`ssh_message_auth_set_methods`](https://api.libssh.org/stable/group__libssh__server.html#gab993157d98e5b4b3399d216c9243effc).
40084037
"""
4009-
function message_auth_set_methods(msg, methods)
4038+
function ssh_message_auth_set_methods(msg, methods; throw = true)
40104039
ret = @ccall(libssh.ssh_message_auth_set_methods(msg::ssh_message, methods::Cint)::Cint)
4011-
if ret != SSH_OK
4012-
throw(LibSSHException("Error from ssh_message_auth_set_methods, did not return SSH_OK: " * "$(ret)"))
4040+
if ret != SSH_OK && throw
4041+
Base.throw(LibSSHException("Error from ssh_message_auth_set_methods, did not return SSH_OK: " * "$(ret)"))
40134042
end
4043+
return ret
40144044
end
40154045

40164046
"""

0 commit comments

Comments
 (0)