aboutsummaryrefslogtreecommitdiff
path: root/doc/guided_tour.dox
diff options
context:
space:
mode:
Diffstat (limited to 'doc/guided_tour.dox')
-rw-r--r--doc/guided_tour.dox428
1 files changed, 428 insertions, 0 deletions
diff --git a/doc/guided_tour.dox b/doc/guided_tour.dox
new file mode 100644
index 0000000..08c2058
--- /dev/null
+++ b/doc/guided_tour.dox
@@ -0,0 +1,428 @@
+@page guided_tour Chapter 1: A typical SSH session
+@section ssh_session A typical SSH session
+
+A SSH session goes through the following steps:
+
+ - Before connecting to the server, you can set up if you wish one or other
+ server public key authentication, i.e. DSA or RSA. You can choose
+ cryptographic algorithms you trust and compression algorithms if any. You
+ must of course set up the hostname.
+
+ - The connection is established. A secure handshake is made, and resulting from
+ it, a public key from the server is gained. You MUST verify that the public
+ key is legitimate, using for instance the MD5 fingerprint or the known hosts
+ file.
+
+ - The client must authenticate: the classical ways are password, or
+ public keys (from dsa and rsa key-pairs generated by openssh).
+ If a SSH agent is running, it is possible to use it.
+
+ - Now that the user has been authenticated, you must open one or several
+ channels. Channels are different subways for information into a single ssh
+ connection. Each channel has a standard stream (stdout) and an error stream
+ (stderr). You can theoretically open an infinity of channels.
+
+ - With the channel you opened, you can do several things:
+ - Execute a single command.
+ - Open a shell. You may want to request a pseudo-terminal before.
+ - Invoke the sftp subsystem to transfer files.
+ - Invoke the scp subsystem to transfer files.
+ - Invoke your own subsystem. This is outside the scope of this document,
+ but can be done.
+
+ - When everything is finished, just close the channels, and then the connection.
+
+The sftp and scp subsystems use channels, but libssh hides them to
+the programmer. If you want to use those subsystems, instead of a channel,
+you'll usually open a "sftp session" or a "scp session".
+
+All the libssh functions which return an error code also set an error message.
+Error codes are typically SSH_ERROR for integer values, or NULL for pointers.
+
+
+@subsection setup Creating the session and setting options
+
+The most important object in a SSH connection is the SSH session. In order
+to allocate a new SSH session, you use ssh_new(). Don't forget to
+always verify that the allocation successed.
+@code
+#include <libssh/libssh.h>
+#include <stdlib.h>
+
+int main()
+{
+ ssh_session my_ssh_session = ssh_new();
+ if (my_ssh_session == NULL)
+ exit(-1);
+ ...
+ ssh_free(my_ssh_session);
+}
+@endcode
+
+libssh follows the allocate-it-deallocate-it pattern. Each object that you allocate
+using xxxxx_new() must be deallocated using xxxxx_free(). In this case, ssh_new()
+does the allocation and ssh_free() does the contrary.
+
+The ssh_options_set() function sets the options of the session. The most important options are:
+ - SSH_OPTIONS_HOST: the name of the host you want to connect to
+ - SSH_OPTIONS_PORT: the used port (default is port 22)
+ - SSH_OPTIONS_USER: the system user under which you want to connect
+ - SSH_OPTIONS_LOG_VERBOSITY: the quantity of messages that are printed
+
+The complete list of options can be found in the documentation of ssh_options_set().
+The only mandatory option is SSH_OPTIONS_HOST. If you don't use SSH_OPTIONS_USER,
+the local username of your account will be used.
+
+Here is a small example of how to use it:
+
+@code
+#include <libssh/libssh.h>
+#include <stdlib.h>
+
+int main()
+{
+ ssh_session my_ssh_session;
+ int verbosity = SSH_LOG_PROTOCOL;
+ int port = 22;
+
+ my_ssh_session = ssh_new();
+ if (my_ssh_session == NULL)
+ exit(-1);
+
+ ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "localhost");
+ ssh_options_set(my_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
+ ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, &port);
+
+ ...
+
+ ssh_free(my_ssh_session);
+}
+@endcode
+
+Please notice that all parameters are passed to ssh_options_set() as pointers,
+even if you need to set an integer value.
+
+@see ssh_new
+@see ssh_free
+@see ssh_options_set
+@see ssh_options_parse_config
+@see ssh_options_copy
+@see ssh_options_getopt
+
+
+@subsection connect Connecting to the server
+
+Once all settings have been made, you can connect using ssh_connect(). That
+function will return SSH_OK if the connection worked, SSH_ERROR otherwise.
+
+You can get the English error string with ssh_get_error() in order to show the
+user what went wrong. Then, use ssh_disconnect() when you want to stop
+the session.
+
+Here's an example:
+
+@code
+#include <libssh/libssh.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int main()
+{
+ ssh_session my_ssh_session;
+ int rc;
+
+ my_ssh_session = ssh_new();
+ if (my_ssh_session == NULL)
+ exit(-1);
+
+ ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "localhost");
+
+ rc = ssh_connect(my_ssh_session);
+ if (rc != SSH_OK)
+ {
+ fprintf(stderr, "Error connecting to localhost: %s\n",
+ ssh_get_error(my_ssh_session));
+ exit(-1);
+ }
+
+ ...
+
+ ssh_disconnect(my_ssh_session);
+ ssh_free(my_ssh_session);
+}
+@endcode
+
+
+@subsection serverauth Authenticating the server
+
+Once you're connected, the following step is mandatory: you must check that the server
+you just connected to is known and safe to use (remember, SSH is about security and
+authentication).
+
+There are two ways of doing this:
+ - The first way (recommended) is to use the ssh_is_server_known()
+ function. This function will look into the known host file
+ (~/.ssh/known_hosts on UNIX), look for the server hostname's pattern,
+ and determine whether this host is present or not in the list.
+ - The second way is to use ssh_get_pubkey_hash() to get a binary version
+ of the public key hash value. You can then use your own database to check
+ if this public key is known and secure.
+
+You can also use the ssh_get_pubkey_hash() to show the public key hash
+value to the user, in case he knows what the public key hash value is
+(some paranoid people write their public key hash values on paper before
+going abroad, just in case ...).
+
+If the remote host is being used to for the first time, you can ask the user whether
+he/she trusts it. Once he/she concluded that the host is valid and worth being
+added in the known hosts file, you use ssh_write_knownhost() to register it in
+the known hosts file, or any other way if you use your own database.
+
+The following example is part of the examples suite available in the
+examples/ directory:
+
+@code
+#include <errno.h>
+#include <string.h>
+
+int verify_knownhost(ssh_session session)
+{
+ int state, hlen;
+ unsigned char *hash = NULL;
+ char *hexa;
+ char buf[10];
+
+ state = ssh_is_server_known(session);
+
+ hlen = ssh_get_pubkey_hash(session, &hash);
+ if (hlen < 0)
+ return -1;
+
+ switch (state)
+ {
+ case SSH_SERVER_KNOWN_OK:
+ break; /* ok */
+
+ case SSH_SERVER_KNOWN_CHANGED:
+ fprintf(stderr, "Host key for server changed: it is now:\n");
+ ssh_print_hexa("Public key hash", hash, hlen);
+ fprintf(stderr, "For security reasons, connection will be stopped\n");
+ free(hash);
+ return -1;
+
+ case SSH_SERVER_FOUND_OTHER:
+ fprintf(stderr, "The host key for this server was not found but an other"
+ "type of key exists.\n");
+ fprintf(stderr, "An attacker might change the default server key to"
+ "confuse your client into thinking the key does not exist\n");
+ free(hash);
+ return -1;
+
+ case SSH_SERVER_FILE_NOT_FOUND:
+ fprintf(stderr, "Could not find known host file.\n");
+ fprintf(stderr, "If you accept the host key here, the file will be"
+ "automatically created.\n");
+ /* fallback to SSH_SERVER_NOT_KNOWN behavior */
+
+ case SSH_SERVER_NOT_KNOWN:
+ hexa = ssh_get_hexa(hash, hlen);
+ fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
+ fprintf(stderr, "Public key hash: %s\n", hexa);
+ free(hexa);
+ if (fgets(buf, sizeof(buf), stdin) == NULL)
+ {
+ free(hash);
+ return -1;
+ }
+ if (strncasecmp(buf, "yes", 3) != 0)
+ {
+ free(hash);
+ return -1;
+ }
+ if (ssh_write_knownhost(session) < 0)
+ {
+ fprintf(stderr, "Error %s\n", strerror(errno));
+ free(hash);
+ return -1;
+ }
+ break;
+
+ case SSH_SERVER_ERROR:
+ fprintf(stderr, "Error %s", ssh_get_error(session));
+ free(hash);
+ return -1;
+ }
+
+ free(hash);
+ return 0;
+}
+@endcode
+
+@see ssh_connect
+@see ssh_disconnect
+@see ssh_get_error
+@see ssh_get_error_code
+@see ssh_get_pubkey_hash
+@see ssh_is_server_known
+@see ssh_write_knownhost
+
+
+@subsection auth Authenticating the user
+
+The authentication process is the way a service provider can identify a
+user and verify his/her identity. The authorization process is about enabling
+the authenticated user the access to ressources. In SSH, the two concepts
+are linked. After authentication, the server can grant the user access to
+several ressources such as port forwarding, shell, sftp subsystem, and so on.
+
+libssh supports several methods of authentication:
+ - "none" method. This method allows to get the available authentications
+ methods. It also gives the server a chance to authenticate the user with
+ just his/her login. Some very old hardware uses this feature to fallback
+ the user on a "telnet over SSH" style of login.
+ - password method. A password is sent to the server, which accepts it or not.
+ - keyboard-interactive method. The server sends several challenges to the
+ user, who must answer correctly. This makes possible the authentication
+ via a codebook for instance ("give code at 23:R on page 3").
+ - public key method. The host knows the public key of the user, and the
+ user must prove he knows the associated private key. This can be done
+ manually, or delegated to the SSH agent as we'll see later.
+
+All these methods can be combined. You can for instance force the user to
+authenticate with at least two of the authentication methods. In that case,
+one speaks of "Partial authentication". A partial authentication is a
+response from authentication functions stating that your credential was
+accepted, but yet another one is required to get in.
+
+The example below shows an authentication with password:
+
+@code
+#include <libssh/libssh.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int main()
+{
+ ssh_session my_ssh_session;
+ int rc;
+ char *password;
+
+ // Open session and set options
+ my_ssh_session = ssh_new();
+ if (my_ssh_session == NULL)
+ exit(-1);
+ ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "localhost");
+
+ // Connect to server
+ rc = ssh_connect(my_ssh_session);
+ if (rc != SSH_OK)
+ {
+ fprintf(stderr, "Error connecting to localhost: %s\n",
+ ssh_get_error(my_ssh_session));
+ ssh_free(my_ssh_session);
+ exit(-1);
+ }
+
+ // Verify the server's identity
+ // For the source code of verify_knowhost(), check previous example
+ if (verify_knownhost(my_ssh_session) < 0)
+ {
+ ssh_disconnect(my_ssh_session);
+ ssh_free(my_ssh_session);
+ exit(-1);
+ }
+
+ // Authenticate ourselves
+ password = getpass("Password: ");
+ rc = ssh_userauth_password(my_ssh_session, NULL, password);
+ if (rc != SSH_AUTH_SUCCESS)
+ {
+ fprintf(stderr, "Error authenticating with password: %s\n",
+ ssh_get_error(my_ssh_session));
+ ssh_disconnect(my_ssh_session);
+ ssh_free(my_ssh_session);
+ exit(-1);
+ }
+
+ ...
+
+ ssh_disconnect(my_ssh_session);
+ ssh_free(my_ssh_session);
+}
+@endcode
+
+@see @ref authentication_details
+
+
+@subsection using_ssh Doing something
+
+At this point, the authenticity of both server and client is established.
+Time has come to take advantage of the many possibilities offered by the SSH
+protocol: execute remote commands, open remote shells, transfer files,
+forward ports, etc.
+
+The example below shows how to execute a remote command:
+
+@code
+int show_remote_processes(ssh_session session)
+{
+ ssh_channel channel;
+ int rc;
+ char buffer[256];
+ unsigned int nbytes;
+
+ channel = ssh_channel_new(session);
+ if (channel == NULL)
+ return SSH_ERROR;
+
+ rc = ssh_channel_open_session(channel);
+ if (rc != SSH_OK)
+ {
+ ssh_channel_free(channel);
+ return rc;
+ }
+
+ rc = ssh_channel_request_exec(channel, "ps aux");
+ if (rc != SSH_OK)
+ {
+ ssh_channel_close(channel);
+ ssh_channel_free(channel);
+ return rc;
+ }
+
+ nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
+ while (nbytes > 0)
+ {
+ if (write(1, buffer, nbytes) != nbytes)
+ {
+ ssh_channel_close(channel);
+ ssh_channel_free(channel);
+ return SSH_ERROR;
+ }
+ nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
+ }
+
+ if (nbytes < 0)
+ {
+ ssh_channel_close(channel);
+ ssh_channel_free(channel);
+ return SSH_ERROR;
+ }
+
+ ssh_channel_send_eof(channel);
+ ssh_channel_close(channel);
+ ssh_channel_free(channel);
+
+ return SSH_OK;
+}
+@endcode
+
+That's the end of our step-by-step discovery of a SSH connection.
+The next chapter describes more in depth the authentication mechanisms.
+
+@see @ref opening_shell
+@see @ref remote_commands
+@see @ref sftp_subsystem
+@see @ref scp_subsystem
+
+