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.RequestTypeType
primitive type RequestType <: Enum{Int32} 32

Enum for the types of SSH requests a client can send to a server:

  • RequestType_Auth
  • RequestType_ChannelOpen
  • RequestType_Channel
  • RequestType_Service
  • RequestType_Global
source

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.

Info

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.BindType
mutable struct Bind
  • ptr::Union{Nothing, Ptr{LibSSH.lib.ssh_bind_struct}}

  • addr::String

  • port::UInt64

  • hostkey::Union{Nothing, String}

  • key::Union{Nothing, LibSSH.PKI.SshKey}

  • auth_methods::Vector{LibSSH.AuthMethod}

  • log_verbosity::Int64

  • _listener_event::Base.Event

  • _listener_started::Bool

  • _lock::ReentrantLock

  • _message_callback::Union{Nothing, Function}

  • _message_callback_userdata::Any

Wrapper around lib.ssh_bind.

source
LibSSH.listenFunction
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.

source
LibSSH.Callbacks.ServerCallbacksMethod
ServerCallbacks(; ...) -> LibSSH.Callbacks.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.Callbacks.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_function
  • gssapi_accept_sec_ctx_function
  • gssapi_verify_mic_function

And lib.ssh_key arguments will be converted to a non-owning ssh.PKI.SshKey.

Warning

Do not use ssh.Session or ssh.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.

source
LibSSH.set_message_callbackFunction
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)::Bool

The 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.

source
Base.lockMethod
lock(bind::LibSSH.Bind)

Lock a bind for thread-safe operations.

source
Base.isopenMethod
isopen(bind::LibSSH.Bind) -> Bool

Check if the bind has been free'd yet.

source

Each Session accepted by a Bind must be polled for all the handlers to execute. This is possible through the SessionEvent type.

LibSSH.SessionEventType
mutable struct SessionEvent
  • ptr::Union{Nothing, Ptr{LibSSH.lib.ssh_event_struct}}

  • session::LibSSH.Session

  • lock::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.

source
LibSSH.SessionEventMethod
SessionEvent(session::LibSSH.Session) -> LibSSH.SessionEvent

Create an empty SessionEvent.

source
Base.isassignedMethod
isassigned(event::LibSSH.SessionEvent) -> Bool

Check if a SessionEvent holds a valid pointer to a lib.ssh_event.

source
Base.closeMethod
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.

source

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: and Token: and expect foo and bar as 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.Demo.DemoServerType
mutable struct DemoServer
  • bind::LibSSH.Bind

  • listener_task::Union{Nothing, Task}

  • sshchan::Union{Nothing, LibSSH.SshChannel}

  • verbose::Bool

  • password::Union{Nothing, String}

  • allow_auth_none::Bool

  • clients::Vector{LibSSH.Demo.Client}

source
LibSSH.Demo.DemoServerMethod
DemoServer(
    f::Function,
    args...;
    timeout,
    kill_timeout,
    kwargs...
) -> Tuple{Any, Any}

Do-constructor to execute a function f() while the server is running and have it safely cleaned up afterwards. There are two keyword arguments to be aware of:

  • timeout (default 10s): set a timeout in seconds for f(). If f() doesn't finish before the timeout an InterruptException will be thrown to it.
  • kill_timeout (default 3s): set a waiting time in seconds for f() to exit after throwing it an InterruptException. Sometimes you may want to cleanup things before exiting, and this gives some time to do that. If f() isn't finished after kill_timeout no futher action will be taken.

args and kwargs will all be passed to DemoServer(::Int).

Examples

julia> import LibSSH.Demo: DemoServer

julia> DemoServer(2222; password="foo") do
           run(`sshpass -p foo ssh -o NoHostAuthenticationForLocalhost=yes -p 2222 localhost echo 'Hello world!'`)
       end
Hello world!
source
LibSSH.Demo.DemoServerMethod
DemoServer(
    port::Int64;
    verbose,
    password,
    allow_auth_none,
    auth_methods,
    log_verbosity
) -> LibSSH.Demo.DemoServer

Creates a DemoServer.

Arguments

  • port: The port to listen to.
  • verbose=false: This verbosity doesn't refer to the log messages from libssh but from the DemoServer. If this is true it print messages on events like authentication etc. Useful for high-level debugging. The events can always be printed afterwards with Demo.print_timeline.
  • password=nothing: The password to use if password authentication is enabled.
  • allow_auth_none: Whether to allow authentication without any credentials being presented.
  • auth_methods=[AuthMethod_None, AuthMethod_Password]: A list of authentication methods to enable. See ssh.AuthMethod.
  • log_verbosity=nothing: Controls the logging of libssh itself. This could be e.g. lib.SSH_LOG_WARNING (see the upstream documentation).
source
LibSSH.Demo.print_timelineMethod
print_timeline(ds::LibSSH.Demo.DemoServer)

Print a nicely formatted timeline of callbacks and their logged data. Useful when debugging.

source