Server support
The symbols documented on this page are intended to be safe. They may throw exceptions but they should never cause memory corruptions or segfaults if used correctly.
LibSSH.RequestType — Type
primitive type RequestType <: Enum{Int32} 32Enum for the types of SSH requests a client can send to a server:
RequestType_AuthRequestType_ChannelOpenRequestType_ChannelRequestType_ServiceRequestType_Global
SSH Binds
The main type you care about for writing a server is the Bind, which is somewhat analogous to a listening socket. It can be bound to a port and when a connection is attempted by a client it can be accepted with lib.ssh_bind_accept(). Implementing everything else (including authentication) must be done yourself.
If you're writing a server and want to implement keyboard-interactive authentication, also see message_auth_interactive_request.
There are some examples of using libssh's C API to write a server here (using callbacks), and another one demonstrating keyboard-interactive authentication here (not using callbacks). You can also check the source for the Demo server.
LibSSH.Bind — Type
mutable struct BindWrapper around lib.ssh_bind.
LibSSH.listen — Function
listen(handler::Function, bind::LibSSH.Bind; poll_timeout)
High-level function to listen for incoming requests and pass them off to a handler function. This will already set the auth methods on the session (from Bind.auth_methods) before calling the handler.
The poll_timeout argument refers to the timeout for polling the bind socket for new connections. It must be >0 because otherwise it would never wake up if the socket was closed while waiting, but other than that the exact value doesn't matter much. It'll only control how frequently the listen loop wakes up to check if the bind has been closed yet.
LibSSH.handle_key_exchange — Function
handle_key_exchange(session::LibSSH.Session) -> Bool
Non-blocking wrapper around lib.ssh_handle_key_exchange(). Returns true or false depending on whether the exchange succeeded.
LibSSH.set_auth_methods — Method
set_auth_methods(
session::LibSSH.Session,
auth_methods::Vector{LibSSH.AuthMethod}
)
Set authentication methods on a Session.
Wrapper around lib.ssh_set_auth_methods().
LibSSH.set_auth_methods — Method
set_auth_methods(
msg::Ptr{LibSSH.lib.ssh_message_struct},
auth_methods::Vector{LibSSH.AuthMethod}
) -> Int32
Set authentication methods for a lib.ssh_message.
Wrapper around lib.ssh_message_auth_set_methods().
LibSSH.ServerCallbacks — Type
mutable struct ServerCallbacksWrapper around lib.ssh_server_callbacks_struct.
LibSSH.ServerCallbacks — Method
ServerCallbacks(; ...) -> LibSSH.ServerCallbacks
ServerCallbacks(
userdata;
on_auth_password,
on_auth_none,
on_auth_gssapi_mic,
on_auth_pubkey,
on_service_request,
on_channel_open_request_session
) -> LibSSH.ServerCallbacks
Create a callbacks object to set on a server. This has basically the same behaviour as ChannelCallbacks(), except that there are some callbacks that are unsupported due to lack of documentation:
gssapi_select_oid_functiongssapi_accept_sec_ctx_functiongssapi_verify_mic_function
And lib.ssh_key arguments will be converted to a non-owning PKI.SshKey.
Do not use Session or PKI.SshKey arguments outside the callback functions. They are temporary non-owning wrappers, and they will be unusable after the callback has been executed.
Arguments
All of these are also properties that can be set after creation.
userdata: An arbitrary object that will be passed to each callback.on_auth_password:f(::Session, ::String, ::String, userdata)::AuthStatuson_auth_none:f(::Session, ::String, userdata)::AuthStatuson_auth_gssapi_mic:f(::Session, ::String, ::String, userdata)::AuthStatuson_auth_pubkey:f(::Session, ::String, ::SshKey, ::Char, userdata)::AuthStatuson_service_request:f(::Session, ::String, userdata)::Boolon_channel_open_request_session:f(::Session, userdata)::Union{SshChannel, Nothing}
LibSSH.set_server_callbacks — Function
set_server_callbacks(
session::LibSSH.Session,
callbacks::LibSSH.ServerCallbacks
) -> LibSSH.ServerCallbacks
Set callbacks for a Session. Wrapper around lib.ssh_set_server_callbacks().
LibSSH.set_message_callback — Function
set_message_callback(
f::Function,
bind::LibSSH.Bind,
userdata
)
Set message callbacks for the sessions accepted by a Bind. This must be set before listen is called to take effect. listen will automatically set the callback before passing the session to the user handler.
The callback function must have the signature:
f(session::Session, msg::lib.ssh_message, userdata)::BoolThe return value indicates whether further handling of the message is necessary. It should be true if the message wasn't handled or needs to be handled by libssh, or false if the message was completely handled and doesn't need any more action from libssh.
LibSSH.get_error — Method
get_error(bind::LibSSH.Bind) -> String
Get the last error set by libssh. Wrapper around lib.ssh_get_error().
Base.close — Method
close(bind::LibSSH.Bind)
Close and free the bind.
Base.unlock — Method
unlock(bind::LibSSH.Bind)
Unlock a bind.
Base.isopen — Method
isopen(bind::LibSSH.Bind) -> Bool
Check if the bind has been free'd yet.
Each Session accepted by a Bind must be polled for all the handlers to execute. This is possible through the SessionEvent type.
LibSSH.SessionEvent — Type
mutable struct SessionEventptr::Union{Nothing, Ptr{LibSSH.lib.ssh_event_struct}}session::LibSSH.Sessionlock::ReentrantLock
This object wraps a lib.ssh_event, but it's designed to only allow adding a single session to it. Use this in a server to poll the session. It is threadsafe.
LibSSH.SessionEvent — Method
SessionEvent(session::LibSSH.Session) -> LibSSH.SessionEvent
Create an empty SessionEvent.
LibSSH.event_dopoll — Function
event_dopoll(event::LibSSH.SessionEvent) -> Any
Non-blocking wrapper around lib.ssh_event_dopoll(). This may trigger callbacks on the session and its channels.
Returns either SSH_OK or SSH_ERROR.
Base.isassigned — Method
isassigned(event::LibSSH.SessionEvent) -> Bool
Check if a SessionEvent holds a valid pointer to a lib.ssh_event.
Base.close — Method
close(event::LibSSH.SessionEvent; unsafe)
Removes the Session from the underlying ssh_event and frees the event memory. This function may be safely called multiple times, and the event will be unusable afterwards.
Demo server
The DemoServer is an extremely simple and limited implementation of an SSH server using the libssh server API. It's sole reason for existence is to be used in test suites to test client code. Do not expose this publicly! See the constructors docstrings for examples of how to use it (the LibSSH.jl test suite may also be informative).
Supported features:
- Password authentication: only the password is checked, not the username.
- Keyboard-interactive authentication: the server will give two prompts for a
Password:andToken:and expectfooandbaras answers, respectively. - Command execution: note that requested environment variables from the client are currently ignored, and the command output will only be sent back to the client after the command has finished.
- Direct port forwarding
Unsupported features (that may be implemented in the future):
- Public key authentication
- GSSAPI authentication
- Reverse port forwarding
One might ask the question, why use a demo server for testing instead of something battle-hardened like sshd? Well, turns out that it's impossible to run sshd as a non-root user unless you disable password authentication (because sshd needs to read /etc/passwd), which is definitely something we want to test. Plus, having a custom server makes it simpler to set up in just the way we want.
LibSSH.DemoServer — Type
mutable struct DemoServerbind::LibSSH.Bindlistener_task::Union{Nothing, Task}sshchan::Union{Nothing, LibSSH.SshChannel}verbose::Boolpassword::Union{Nothing, String}allow_auth_none::Boolauthorized_keys::Vector{LibSSH.PKI.SshKey}clients::Vector{LibSSH.Client}
LibSSH.print_timeline — Function
print_timeline(ds::LibSSH.DemoServer)
Print a nicely formatted timeline of callbacks and their logged data. Useful when debugging.