Sessions
========

Session Management
------------------

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 (see 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:

     [client]                      [server]

         \____________________________/  SSH session

          ============================
          ============================   SSH channels
          ============================
          ____________________________
         /                            \

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 (ssh session) module.

 -- Scheme Procedure: session? x
     Returns #t if X is a Guile-SSH session, #f otherwise.

 -- Scheme Procedure: %make-session
     Create a new Guile-SSH session.

 -- 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 %make-session, but on other hand it should be a bit slower because of additional checks.

     Example:

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

     All options are described in detail in session-set! procedure description.  Options that are read from CONFIG file will be overwritten by the values passed to make-session.

     List of allowed keywords:

     add-identity

     callbacks

     ciphers-c-s

     ciphers-s-c

     compression

     compression-c-s

     compression-level

     compression-s-c

     config
          Set the configuration file path.  Note that HOST must be set to properly load configuration otherwise guile-ssh-error will be thrown.

          If this option is set to #t the default user configuration file ~/.ssh/config is read.

          On the other hand setting it to #f value means that no configuration file will be read (process-config? is set to #f.)  On older versions of libssh (prior to 0.9) setting #:config to #f is handled by setting the configuration file to /dev/null which in turn leads to ignoring the default configuration file.

     host

     identity

     knownhosts

     log-verbosity

     nodelay

     port

     proxycommand

     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.

     ssh-dir

     ssh1

     ssh2

     stricthostkeycheck

     timeout

     timeout-usec

     user

 -- Scheme Procedure: blocking-flush! session timeout
     Blocking flush of the outgoing buffer of SESSION.  Return on of the following symbols:

     ok
          Success.

     again
          TIMEOUT occurred.

     error
          An error occurred.

 -- Scheme Procedure: session-set! session option value
     Set a OPTION to value for the given Guile-SSH SESSION.  Throw a guile-ssh-error on error.  Return value is undefined.

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

     host
          The hostname or IP address to connect to.

          Expected type of VALUE: string.

     port
          The port to connect to.

          Expected type of VALUE: number.

     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 VALUE: number.

     bindaddr
          The address to bind the client to.

          Expected type of VALUE: string.

     user
          The username for authentication.

          Expected type of VALUE: string.

     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 %s which will be replaced by the user home directory.

          Expected type of VALUE: string.

     identity
          Set the identity file name.  In libssh prior version 0.10 id_dsa and id_rsa are checked by default.

          In libssh 0.10 or newer versions id_rsa, id_ecdsa and id_ed25519 are checked by default.

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

     knownhosts
          Set the known hosts file name.  Default value is ~/.ssh/known_hosts.

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

          Expected type of VALUE: string.

     timeout
          Set a timeout for the connection in seconds.

          Expected type of VALUE: number.

     timeout-usec
          Set a timeout for the connection in micro seconds.

          Expected type of VALUE: number.

     ssh1
          Allow or deny the connection to SSH1 servers.

          Expected type of VALUE: boolean.

     ssh2
          Allow or deny the connection to SSH2 servers

          Expected type of VALUE: boolean.

     log-verbosity
          Set the session logging verbosity.  Possible values:

          nolog
               No logging at all

          rare
               Only rare and noteworthy events

          protocol
               High level protocol information

          packet
               Lower level protocol infomations, packet level

          functions
               Every function path

          Expected type of VALUE: symbol.

     ciphers-c-s
          Set the symmetric cipher client to server.  The VALUE must be a string of comma-separated values.

     ciphers-s-c
          Set the symmetric cipher server to client.  The VALUE must be a string of comma-separated values.

     compression-c-s
          Set the compression to use for client to server.  The VALUE must be ``yes'', ``no'' or a specific algorithm name if needed ("zlib", "zlib.com", "none").

          Expected type of VALUE: string.

     compression-s-c
          Set the compression to use for server to client.  The VALUE must be ``yes'', ``no'' or a specific algorithm name if needed ("zlib", "zlib.com", "none").

          Expected type of VALUE: string.

     process-config?
          Set it to #f to disable automatic processing of per-user and system-wide OpenSSH configuration files.  LibSSH automatically uses these configuration files unless you provide it with this option or with different file.

          Compatibility: this option was added in libssh 0.9.0.

          Expected type of VALUE: boolean.

     proxycommand
          Set the command to be executed in order to connect to server.

          Expected type of VALUE: string.

     rsa-min-size
          Set the minimum RSA key size in bits to be accepted by the client for both authentication and hostkey verification.  The values under 768 bits are not accepted even with this configuration option as they are considered completely broken. Setting 0 will revert the value to defaults.  Default is 1024 bits or 2048 bits in FIPS mode.

          Expected type of VALUE: number.

     stricthostkeycheck
          Set the parameter StrictHostKeyChecking to avoid asking about a fingerprint.

     compression
          Set the compression to use for both directions communication.  The VALUE must be ``yes'', ``no'' or a specific algorithm name if needed ("zlib", "zlib.com", "none").

          Expected type of VALUE: string.

     compression-level
          Set the compression level to use for zlib functions.  The VALUE is expected to be a number from 1 to 9, 9 being the most efficient but slower.

     callbacks
          Set callbacks that will be called on related events (see Callbacks.)

          Expected type of VALUE: an association list (alist).

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

          Setting the VALUE to #t (the default value) means that the default ~/.ssh/config should be parsed; in turn, setting the option to #f 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 SESSION are set, overwriting those that were passed to the procedure.

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

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

          Expected types of VALUE: Either a string or a boolean value.

 -- Scheme Procedure: session-parse-config! session [file-name]
     Parse an SSH config FILE-NAME and set SESSION options.  If FILE-NAME is not set, the default SSH ~/.ssh/config is used. Throw guile-ssh-error on an error.  Return value is undefined.

 -- Scheme Procedure: session-get session option
     Get value of the OPTION for SESSION.  The 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:

     host

     port

     user

     identity

     proxycommand

     callbacks

 -- Scheme Procedure: connect! session
     Connect SESSION to a SSH server.  Return one of the following symbols: ok, again, error.

 -- Scheme Procedure: disconnect! session
     Disconnect the SESSION.  This procedure can be used by a client as well as by a server.

 -- Scheme Procedure: authenticate-server session
     Authenticate the server.

     Throw wrong-type-arg exception if a disconnected SESSION is passed as an argument.

     Return one of the following symbols:

     ok
          The server is known and has not changed.

     known-changed
          The server key has changed. Either you are under attack or the administrator changed the key. You have to warn the user about a possible attack.

     found-other
          The server gave use a key of a type while we had an other type recorded. It is a possible attack.

     not-known
          The server is unknown. User should confirm the MD5 is correct.

     file-not-found
          The known host file does not exist. The host is thus unknown. File will be created if host key is accepted.

     error
          An error occurred.

 -- Scheme Procedure: get-server-public-key session
     Get server public key from a SESSION.  Return the server's public key.  Throw guile-ssh-error on error.

     Also throw wrong-type-arg exception if a disconnected SESSION is passed as an argument.

     See also get-public-key-hash in see Keys.

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

 -- Scheme Procedure: connected? session
     Check if we are connected.  Return #f if we are connected to a server, #f if we aren't.

 -- Scheme Procedure: get-error session
     Retrieve the error text message from the last error related to SESSION.

 -- Scheme Procedure: get-protocol-version session
     Get version of SSH protocol.  Return 1 for SSH1, 2 for SSH2 or #f on error.

     Throw wrong-type-arg exception if a disconnected SESSION is passed as an argument.

Callbacks
---------

Guile-SSH uses an association list (see Association Lists (The GNU Guile Reference Manual)) 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 user-data argument which can be specified in the callbacks alist as well.

 -- 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 (see 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:

          (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)))

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

     Example:

          (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)))