@c -*-texinfo-*-
@c This file is part of Guile-SSH Reference Manual.
@c Copyright (C) 2014-2021 Artyom V. Poptsov
@c See the file guile-ssh.texi for copying conditions.

@node Sessions
@section Sessions

@menu
* Session Management::
* Callbacks::
@end menu

@c -----------------------------------------------------------------------------
@node Session Management
@subsection Session Management

@cindex sessions
@tindex session

A session is an object that holds all the information about connection
to a specified server or a client.  This information includes server's
port and address, name of the user, compression level, private keys
and so on.

A session may contain zero or more channels (@pxref{Channels}).
Channels are ``pipes'' that link the client and the server together
and that can be used for transferring of data in both directions.

So the overall picture can be thought like this:

@example
[client]                      [server]

    \____________________________/  SSH session

     ============================
     ============================   SSH channels
     ============================
     ____________________________
    /                            \
@end example


libssh docs say that there is no limit to number of channels for a
single session in theory.

This chapter describes session management.  The code is in the
@code{(ssh session)} module.


@deffn {Scheme Procedure} session? x
Returns @code{#t} if @var{x} is a Guile-SSH session, @code{#f}
otherwise.
@end deffn

@deffn {Scheme Procedure} %make-session
Create a new Guile-SSH session.
@end deffn

@deffn {Scheme Procedure} make-session [keywords]
Create a new Guile-SSH session and set its options.  Options can be
passed as keywords.

Return a new Guile-SSH session.

This procedure is more convenient than primitive @code{%make-session},
but on other hand it should be a bit slower because of additional
checks.

Example:

@lisp
(let ((s (make-session #:user          "alice"
                       #:host          "example.com"
                       #:port          12345
                       #:identity      "/home/alice/.ssh/id_rsa"
                       #:log-verbosity 'nolog)))
  ...)
@end lisp

List of allowed keywords:
@table @samp
@item add-identity
@item callbacks
@item ciphers-c-s
@item ciphers-s-c
@item compression
@item compression-c-s
@item compression-level
@item compression-s-c
@item config
@item host
@item identity
@item knownhosts
@item log-verbosity
@item nodelay
@item port
@item proxycommand
@item public-key-accepted-types
Preferred public key algorithms to be used for authentication (comma-separated
list as a string). Example:
``ssh-rsa,rsa-sha2-256,ssh-dss,ecdh-sha2-nistp256''

This option available only in libssh 0.8.3 or later versions.
@item ssh-dir
@item ssh1
@item ssh2
@item stricthostkeycheck
@item timeout
@item timeout-usec
@item user
@end table

@end deffn

@deffn {Scheme Procedure} blocking-flush! session timeout
Blocking flush of the outgoing buffer of @var{session}.  Return on of
the following symbols:

@table @samp
@item ok
Success.
@item again
@var{timeout} occurred.
@item error
An error occurred.
@end table
@end deffn

@deffn {Scheme Procedure} session-set! session option value
Set a @var{option} to @code{value} for the given Guile-SSH
@var{session}.  Throw a @code{guile-ssh-error} on error.  Return value
is undefined.

Here is the description of available options.  The description is
based on libssh documentation:

@table @samp
@item host
The hostname or @acronym{IP} address to connect to.

Expected type of @var{value}: string.
@item port
The port to connect to.

Expected type of @var{value}: number.
@item fd
The file descriptor to use.

If you wish to open the socket yourself for a reason or another, set
the file descriptor.  Don't forget to set the hostname as the hostname
is used as a key in the known_host mechanism.

Expected type of @var{value}: number.
@item bindaddr
The address to bind the client to.

Expected type of @var{value}: string.
@item user
The username for authentication.

Expected type of @var{value}: string.
@item ssh-dir
Set the SSH directory.

The ssh directory is used for files like known_hosts and identity
(private and public key).  It may include @code{%s} which will be
replaced by the user home directory.

Expected type of @var{value}: string.
@item identity
Set the identity file name.  By default identity, @file{id_dsa} and
@file{id_rsa} are checked.

The identity file used authenticate with public key.  It may include
@code{%s} which will be replaced by the user home directory.

@item knownhosts
Set the known hosts file name.  Default value is @file{~/.ssh/known_hosts}.

The known hosts file is used to certify remote hosts are genuine.  The
string may include @code{%s} which will be replaced by the user home
directory.

Expected type of @var{value}: string.
@item timeout
Set a timeout for the connection in seconds.

Expected type of @var{value}: number.
@item timeout-usec
Set a timeout for the connection in micro seconds.

Expected type of @var{value}: number.
@item ssh1
Allow or deny the connection to SSH1 servers.

Expected type of @var{value}: boolean.
@item ssh2
Allow or deny the connection to SSH2 servers

Expected type of @var{value}: boolean.
@item log-verbosity
Set the session logging verbosity.  Possible values:

@table @samp
@item nolog
No logging at all
@item rare
Only rare and noteworthy events
@item protocol
High level protocol information
@item packet
Lower level protocol infomations, packet level
@item functions
Every function path
@end table

Expected type of @var{value}: symbol.
@item ciphers-c-s
Set the symmetric cipher client to server.  The @var{value} must be a
string of comma-separated values.
@item ciphers-s-c
Set the symmetric cipher server to client.  The @var{value} must be a
string of comma-separated values.
@item compression-c-s
Set the compression to use for client to server.  The @var{value} must
be ``yes'', ``no'' or a specific algorithm name if needed ("zlib",
@verb{|"zlib@openssh.com"|}, "none").

Expected type of @var{value}: string.
@item compression-s-c
Set the compression to use for server to client.  The @var{value} must
be ``yes'', ``no'' or a specific algorithm name if needed ("zlib",
@verb{|"zlib@openssh.com"|}, "none").

Expected type of @var{value}: string.
@item proxycommand
Set the command to be executed in order to connect to server.

Expected type of @var{value}: string.
@item stricthostkeycheck
Set the parameter @code{StrictHostKeyChecking} to avoid asking about a
fingerprint.
@item compression
Set the compression to use for both directions communication.  The
@var{value} must be ``yes'', ``no'' or a specific algorithm name if
needed ("zlib", @verb{|"zlib@openssh.com"|}, "none").

Expected type of @var{value}: string.
@item compression-level
Set the compression level to use for zlib functions.  The @var{value}
is expected to be a number from 1 to 9, 9 being the most efficient but
slower.

@item callbacks
Set callbacks that will be called on related events (@pxref{Callbacks}.)

Expected type of @var{value}: an association list (alist).

@item config
The option specifies whether an SSH config should be parsed or not, and
optionally the path to a config file.

Setting the @var{value} to @code{#t} means that the default
@file{~/.ssh/config} should be parsed; in turn, setting the option to
@code{#f} (the default value) means that the config should not be parsed at
all.  If the value is a string, then the string is expected to be a path to
config file.

The procedure reads the config file after all other specified options are set.
When the config file is read, the options for @var{session} are set,
overwriting those that were passed to the procedure.

You @emph{must} specify at least a host name when using this option, otherwise
the procedure will fail.

Optionally you could use @code{session-parse-config!} procedure explicitly to
read the config (see below.)

Expected types of @var{value}: Either a string or a boolean value.
@end table

@end deffn

@deffn {Scheme Procedure} session-parse-config! session [file-name]
Parse an SSH config @var{file-name} and set @var{session} options.  If
@var{file-name} is not set, the default SSH @file{~/.ssh/config} is used.
Throw @code{guile-ssh-error} on an error.  Return value is undefined.
@end deffn

@deffn {Scheme Procedure} session-get session option
Get value of the @var{option} for @var{session}.  The @var{option} is expected
to be a symbol.

Please not that currently not all the possible session options can be gotten
with this procedure.  Here is the list of allowed options:

@table @samp
@item host
@item port
@item user
@item identity
@item proxycommand
@item callbacks
@end table
@end deffn

@deffn {Scheme Procedure} connect! session
Connect @var{session} to a SSH server.  Return one of the following symbols:
@code{ok}, @code{again}, @code{error}.
@end deffn

@deffn {Scheme Procedure} disconnect! session
Disconnect the @var{session}.  This procedure can be used by a client
as well as by a server.
@end deffn

@deffn {Scheme Procedure} authenticate-server session
Authenticate the server. 

Throw @code{wrong-type-arg} exception if a disconnected @var{session} is
passed as an argument.

Return one of the following symbols:

@table @samp
@item ok
The server is known and has not changed.
@item known-changed
The server key has changed. Either you are under attack or the
administrator changed the key. You @emph{have} to warn the user about
a possible attack.
@item found-other
The server gave use a key of a type while we had an other type
recorded. It is a possible attack.
@item not-known
The server is unknown. User should confirm the MD5 is correct.
@item file-not-found
The known host file does not exist. The host is thus unknown. File
will be created if host key is accepted.
@item error
An error occurred.
@end table

@end deffn

@deffn {Scheme Procedure} get-server-public-key session
Get server public key from a @var{session}.  Return the server's
public key.  Throw @code{guile-ssh-error} on error.

Also throw @code{wrong-type-arg} exception if a disconnected @var{session} is
passed as an argument.

See also @code{get-public-key-hash} in @pxref{Keys}.
@end deffn

@deffn {Scheme Procedure} write-known-host! session
Write the current server as known in the known hosts file.  Throw
@code{guile-ssh-error} on error.  Throw @code{wrong-type-arg} exception if a
disconnected session is passed as an argument.  Return value is undefined.
@end deffn

@deffn {Scheme Procedure} connected? session
Check if we are connected.  Return @code{#f} if we are connected to a
server, @code{#f} if we aren't.
@end deffn

@deffn {Scheme Procedure} get-error session
@cindex handling session errors
Retrieve the error text message from the last error related to
@var{session}.
@end deffn

@deffn {Scheme Procedure} get-protocol-version session
Get version of SSH protocol.  Return 1 for SSH1, 2 for SSH2 or
@code{#f} on error.

Throw @code{wrong-type-arg} exception if a disconnected @var{session} is
passed as an argument.
@end deffn

@c -----------------------------------------------------------------------------
@node Callbacks
@subsection Callbacks

Guile-SSH uses an association list (alist) to represent session callbacks; the
key is a callback name, and the value is expecting to be a procedure.

Session callbacks is the way to handle some events, notably the incoming
reverse port forwarding requests on the server side.  Each callback is called
with the optional @code{user-data} argument which can be specified in the
callbacks alist as well.

@deffn {Scheme Procedure} global-request-callback session message user-data
A server-side callback that is called on a global request (e.g. when an SSH
client asks for reverse port forwarding.)

The callback should be set on an accepted Guile-SSH session (@pxref{Servers})
in case when global requests must be handled; note that if the callback is not
set then the server will always deny global requests, which may be confusing.

Example:
@lisp
(define (handle-global-request session message user-data)
  (let ((port-number 12345))
    (message-reply-success message port-number)))

;; Let's suppose that the session was created earlier.

;; Now we can set our callback:
(session-set! session
              'callbacks 
              `((user-data               . #f)
                (global-request-callback . ,handle-global-request)))

;; Note that 'user-data' is optional, so the following example
;; is valid:
(session-set! session
              'callbacks
              `((global-request-callback . ,handle-global-request)))
@end lisp
@end deffn

@deffn {Scheme Procedure} connect-status-callback session status user-data
This callback is called during connection establishment process (that is,
after @code{connect!} is called) with a server.  A connection @var{status} is
a number that shows what percentage of connection esablishment is done.

Example:
@lisp
(define (print-status session status user-data)
  (let ((percentage (truncate (* status 100))))
    (format #t "~a: connecting ... ~a%~%" session percentage)))

;; Let's suppose that the session was created earlier.

(session-set! session
              'callbacks
              `((user-data               . #f)
                (connect-status-callback . ,print-status)))

;; Or we can set two callbacks simultaneously:

(define (handle-global-request session message user-data)
  (let ((port-number 12345))
    (message-reply-success message port-number)))

(session-set! session
              'callbacks
              `((user-data               . #f)
                (connect-status-callback . ,print-status)
                (global-request-callback . ,handle-global-request)))
@end lisp
@end deffn

@c Local Variables:
@c TeX-master: "guile-ssh.texi"
@c End:
