aboutsummaryrefslogtreecommitdiff
path: root/doc/tutorial.dox
diff options
context:
space:
mode:
Diffstat (limited to 'doc/tutorial.dox')
-rw-r--r--doc/tutorial.dox1022
1 files changed, 766 insertions, 256 deletions
diff --git a/doc/tutorial.dox b/doc/tutorial.dox
index fee1a9c0..862d4531 100644
--- a/doc/tutorial.dox
+++ b/doc/tutorial.dox
@@ -3,158 +3,286 @@
*
* @section introduction Introduction
*
- * Before inserting SSH hooks into your programs, you must know some basics
- * about the SSH protocol, and understand why the SSH library must implement
- * them. A lot of the protocol specifications are hidden by the SSH library API
- * (of course, that's the benefits of using a library) but some still needs an
- * attention from the programmer.
- *
- * The SSH protocol was designed for some goals which I state here :
- *
- * - Privacy of data
- * - Data integrity (alteration of data is always detected)
- * - Authentication of the server
- * - Authentication of the client
- *
- * The following document explains how to set up a client-side connection. libssh
- * supports both client and server side of the SSH protocol. If you are going to
- * program a server, I suggest you try first to code some client-side programs
- * in order to understand how libssh works.
- *
- * The client MUST be sure who's speaking to before entering into any
- * authentication way. That's where the end programmer must ensure the given
- * fingerprints *are* from the legitimate server. A SSH connection must follow
- * the following steps:
- *
- * - Before connecting the socket, 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 made. 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 of the known hosts
- * file.
- *
- * - The client must authenticate : the classical ways are password and
- * public keys (from dsa and rsa key-pairs generated by openssh). It is
- * harmless to authenticate to a fake server with these keys because the
- * protocol ensures the data you sign can't be used twice. It just avoids
- * man-in-the-middle attacks. 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 channel.
- *
- * - With the channel you opened, you can do several things :
- * - Open a shell. You may want to request a pseudo virtual terminal before,
- * - Execute a single command,
- * - Invoke the sftp subsystem.
- * - invoke your own subsystem. This is out the scope of this document but it is easy to do.
- *
- * - When everything is finished, just close the channels, and then the connection.
- *
- * At every place, a function which returns an error code (typically SSH_ERROR for int
- * values, NULL for pointers) also sets an error message and an error code.
+ * libssh is a C library that enables you to write a program that uses the
+ * SSH protocol. With it, you can remotely execute programs, transfer
+ * files, or use a secure and transparent tunnel for your remote programs.
+ * The SSH protocol is encrypted, ensures data integrity, and provides strong
+ * means of authenticating both the server of the client. The library hides
+ * a lot of technical details from the SSH protocol, but this does not
+ * mean that you should not try to know about and understand these details.
+ *
+ * libssh is a Free Software / Open Source project. The libssh library
+ * is distributed under LGPL license. The libssh project has nothing to do with
+ * "libssh2", which is a completly different and independant project.
+ *
+ * libssh supports both client and server sides of the SSH protocol.
+ * The following document explains how to set up a client-side connection.
+ * If you are going to program a server, you should try first to code some
+ * client-side programs in order to understand how libssh works.
+ *
+ * This tutorial describes libssh version 0.5.0.
+ *
+ *
+ * Table of contents:
+ *
+ * @subpage session
+ *
+ * @subpage details
+ *
+ * @subpage tbd
+ *
+ *
+ * @page session 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 virtual 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 it is easy to do.
+ *
+ * - When everything is finished, just close the channels, and then the connection.
+ *
+ * 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.
*
*
- * @section setup Creating the session and setting options
+ * @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 must use ssh_new(). Don't forget to always verify that the allocation
- * successed.
+ * 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>
- * int main(){
+ * #include <stdlib.h>
+ *
+ * int main()
+ * {
* ssh_session my_ssh_session = ssh_new();
- * if(my_ssh_session == NULL)
+ * 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_free() does this.
- *
- * The ssh_options_set() is a setter for the options of the session. The most important options are the
- * following :
- * - SSH_OPTIONS_HOST
- * - SSH_OPTIONS_PORT
- * - SSH_OPTIONS_USER
- * - SSH_OPTIONS_LOG_VERBOSITY
- * - ...
- *
- * The complete list 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.
+ * 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>
- * int main(){
+ * #include <stdlib.h>
+ *
+ * int main()
+ * {
+ * ssh_session my_ssh_session;
* int verbosity = SSH_LOG_PROTOCOL;
* int port = 22;
- * ssh_session my_ssh_session = ssh_new();
- * if(my_ssh_session == NULL)
+ *
+ * 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
- * It's no more complicated than that. A few pointers on additionnal functions related to the session
- * and options setting :
+ *
+ * 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
- * @section 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 error string using 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:
+ *
+ * @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 error string using 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(){
+ *
+ * int main()
+ * {
+ * ssh_session my_ssh_session;
* int ret;
- * ssh_session my_ssh_session = ssh_new();
- * if(my_ssh_session == NULL)
+ *
+ * my_ssh_session = ssh_new();
+ * if (my_ssh_session == NULL)
* exit(-1);
+ *
* ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "localhost");
+ *
* ret = ssh_connect(my_ssh_session);
- * if(ret != SSH_OK)
- * fprintf(stderr, "Error connecting to localhost : %s\n",
+ * if (ret != SSH_OK)
+ * {
+ * fprintf(stderr, "Error connecting to localhost: %s\n",
* ssh_get_error(my_ssh_session));
- * else
- * ssh_disconnect(my_ssh_session);
+ * exit(-1);
+ * }
+ *
+ * ...
+ *
+ * ssh_disconnect(my_ssh_session);
* ssh_free(my_ssh_session);
+ * }
* @endcode
- *
- * Once you're connected, the following step is mandatory : you must check that the server
+ *
+ *
+ * @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 check into the known host file (~/.ssh/known_hosts on unix)
- * for the server hostname's pattern and check that this host is present or not in the list.
- *
- * The second way is of using ssh_get_pubkey_hash() to get a binary version of the public key hash.
- * You can then use your own database to check if this public key is known and secure. You can also
- * use that function to show the public key hash to the user, in case he knows what the public
- * key hash is (some paranoid people writes their public key hashes on paper before going abroad,
- * just in case ...).
- *
- * Once you concluded that the host is valid and worth being added in the known hosts file, just use
- * ssh_write_knownhost(). The following example is part of the examples suite available in the examples/
- * directory.
- *
- * @include knownhosts.c
+ *
+ * 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
+ * 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
@@ -164,64 +292,237 @@
* @see ssh_is_server_known
* @see ssh_write_knownhost
*
- * @section auth Authentication
- *
- * The authentication process is the way a service provider can identify a user and verify its
- * identity. The authorization process is about authorizing the authenticated user the access
- * to ressources. In SSH, the two concepts are linked. After authentication, the server can
- * allow the user access to several ressources such as port forwarding, shell, sftp subsystem,
- * ...
- * libssh supports several authentication ways:
- * - "none" method. This method serves to get the available authentications methods, as well as
- * giving a chance to the server to authenticate the user with just his login. Some very old
- * hardware are using 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 at 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 by the SSH agent as we'll see
- * later.
- *
- * And last but not least, all of this methods can be combined. You can for instance force the user to
- * authenticate with at least two of the authentication methods. In that case, we speak 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.
- *
- *
- * @subsection pubkeys Public keys
- *
- * The public key authentication is the only method which does not compromise your key if the remote host
- * has been compromised (the server can't do anything more than getting your public key). This is not the
- * case of a password authentication (the server can get your plaintext password).
- * libssh is fully compatible with the openssh public and private keys. You can either use the automatic
- * public key authentication method provided by libssh, or roll your own using the public key functions.
- *
- * The process of authenticating by public key to a server is the following :
- * you scan a list of files which contain public keys. each key is sent to the SSH server, until the server
- * acknowledges a key (a key it knows can be used to authenticate the user).
- * Then, you retrieve the private key for this key and send a message proving you know that private key.
- * The function ssh_userauth_autopubkey() does this using the available keys in "~/.ssh/".
- * The return values are the following:
- * - SSH_AUTH_ERROR : some serious error happened during authentication
- * - SSH_AUTH_DENIED : no key matched
- * - SSH_AUTH_SUCCESS : you are now authenticated
- * - SSH_AUTH_PARTIAL : some key matched but you still have to give an other mean of authentication
- (like password).
- *
- * The ssh_userauth_autopubkey function also tries to authenticate using the SSH agent, if you have one
- * running, or the "none" method.
- *
- * If you wish to authenticate by public key by your own, follow these steps :
- * - Retrieve the public key in a ssh_string using publickey_from_file().
- * - Offer the public key to the SSH server using ssh_userauth_offer_pubkey(). If the return value is
- * SSH_AUTH_SUCCESS, the SSH server accepts to authenticate using the public key and you can
- * go to the next step.
- * - Retrieve the private key, using the privatekey_from_file() function. If a passphrase is needed, either
- * The passphrase specified as argument or a callback (see callbacks section) will be used.
- * - Authenticate using ssh_userauth_pubkey() with your public key string and private key.
- * - Do not forget cleaning up memory using string_free() and privatekey_free().
- *
+ *
+ * @subsection auth Authenticating yourself
+ *
+ * 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 ret;
+ * 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
+ * ret = ssh_connect(my_ssh_session);
+ * if (ret != 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: ");
+ * ret = ssh_userauth_password(my_ssh_session, NULL, password);
+ * if (ret != 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 puts the final touch to our step-by-step discovery
+ * of a SSH connection:
+ *
+ * @code
+ * /* *** To be replaced with something simpler *** */
+ * #include <sys/stat.h>
+ *
+ * int scp_helloworld(ssh_session session)
+ * {
+ * ssh_scp scp_session;
+ * int ret;
+ * const char *helloworld = "Hello, world!\n";
+ * int length = strlen(helloworld);
+ *
+ * // Open a scp session
+ * scp_session = ssh_scp_new
+ * (session, SSH_SCP_WRITE | SSH_SCP_RECURSIVE, ".");
+ * if (scp_session == NULL)
+ * {
+ * fprintf(stderr, "Error allocating scp session.\n");
+ * return SSH_ERROR;
+ * }
+ *
+ * // Initialize the scp session
+ * ret = ssh_scp_init(scp_session);
+ * if (ret != SSH_OK)
+ * {
+ * fprintf(stderr, "Error initializing scp session.\n");
+ * ssh_scp_free(scp_session);
+ * return ret;
+ * }
+ *
+ * // Open the remote file
+ * ret = ssh_scp_push_file
+ * (scp_session, "helloworld.txt", length, S_IRUSR | S_IWUSR);
+ * if (ret != SSH_OK)
+ * {
+ * fprintf(stderr, "Can't open remote file.\n");
+ * ssh_scp_close(scp_session);
+ * ssh_scp_free(scp_session);
+ * return ret;
+ * }
+ *
+ * // Write the data into the remote file
+ * ret = ssh_scp_write(scp_session, helloworld, length);
+ * if (ret != SSH_OK)
+ * {
+ * fprintf(stderr, "Can't write to remote file.\n");
+ * ssh_scp_close(scp_session);
+ * ssh_scp_free(scp_session);
+ * return ret;
+ * }
+ *
+ * ssh_scp_close(scp_session);
+ * ssh_scp_free(scp_session);
+ * return ret;
+ * }
+ * @endcode
+ *
+ * @see @ref opening_shell
+ * @see @ref remote_commands
+ * @see @ref sftp_subsystem
+ * @see @ref scp_subsystem
+ *
+ *
+ * @page details Chapter 2: A deeper insight on authentication
+ * @section authentication_details A deeper insight on authentication
+ *
+ *
+ * @subsection pubkeys Authenticating using public keys
+ *
+ * The public key authentication is the only method that does not compromise
+ * your key if the remote host has been compromised (the server can't do
+ * anything more than getting your public key). This is not the
+ * case of a password authentication (the server can get your plaintext
+ * password). On the other hand, if the client machine is compromised and
+ * the private key has no passphrase, then the attacker has gained automatic
+ * access to your server. It is not the purpose of this document to do
+ * a detailed review of the advantages and drawbacks of each authentication
+ * method, so refer to the abundant documentation on this topic on the
+ * Internet to fully understand the advantages and risks linked to each method.
+ *
+ * libssh is fully compatible with the openssh public and private keys. You
+ * can either use the automatic public key authentication method provided by
+ * libssh, or roll your own using the public key functions.
+ *
+ * The process of authenticating by public key to a server is the following:
+ * - you scan a list of files that contain public keys. each key is sent to
+ * the SSH server, until the server acknowledges a key (a key it knows can be
+ * used to authenticate the user).
+ * - then, you retrieve the private key for this key and send a message
+ * proving that you know that private key.
+ *
+ * The function ssh_userauth_autopubkey() does this using the available keys in
+ * "~/.ssh/". The return values are the following:
+ * - SSH_AUTH_ERROR: some serious error happened during authentication
+ * - SSH_AUTH_DENIED: no key matched
+ * - SSH_AUTH_SUCCESS: you are now authenticated
+ * - SSH_AUTH_PARTIAL: some key matched but you still have to provide an other
+ * mean of authentication (like a password).
+ *
+ * The ssh_userauth_autopubkey function also tries to authenticate using the
+ * SSH agent, if you have one running, or the "none" method otherwise.
+ *
+ * If you wish to authenticate with public key by your own, follow these steps:
+ * - Retrieve the public key in a ssh_string using publickey_from_file().
+ * - Offer the public key to the SSH server using ssh_userauth_offer_pubkey().
+ * If the return value is SSH_AUTH_SUCCESS, the SSH server accepts to
+ * authenticate using the public key and you can go to the next step.
+ * - Retrieve the private key, using the privatekey_from_file() function. If
+ * a passphrase is needed, either the passphrase specified as argument or
+ * a callback (see callbacks section) will be used.
+ * - Authenticate using ssh_userauth_pubkey() with your public key string
+ * and private key.
+ * - Do not forget cleaning up memory using string_free() and privatekey_free().
+ *
+ * Here is a minimalistic example of public key authentication:
+ *
+ * @code
+ * int authenticate_pubkey(ssh_session session)
+ * {
+ * int rc;
+ *
+ * rc = ssh_userauth_autopubkey(session, NULL);
+ *
+ * if (rc == SSH_AUTH_ERROR)
+ * {
+ * fprintf(stderr, "Authentication failed: %s\n",
+ * ssh_get_error(session));
+ * return SSH_AUTH_ERROR;
+ * }
+ *
+ * return rc;
+ * }
+ * @endcode
+ *
* @see ssh_userauth_autopubkey
* @see ssh_userauth_offer_pubkey
* @see ssh_userauth_pubkey
@@ -230,79 +531,185 @@
* @see string_free
* @see privatekey_from_file
* @see privatekey_free
- *
- * @subsection password Password
- *
- * The function ssh_userauth_password() serves the purpose of authenticating using a password.
- * It will return SSH_AUTH_SUCCESS if the password worked, one of other constants otherwise. It's
- * your work to ask the password and to deallocate it in a secure manner. If your server complains
- * that the password is wrong, but you can still authenticate using openssh's client (issuing password),
- * it's probably because openssh only accept keyboard-interactive.
- * Switch to keyboard-interactive authentication or try to configure plaintext-passwords into the SSH server.
- *
+ *
+ *
+ * @subsection password Authenticating using a password
+ *
+ * The function ssh_userauth_password() serves the purpose of authenticating
+ * using a password. It will return SSH_AUTH_SUCCESS if the password worked,
+ * or one of other constants otherwise. It's your work to ask the password
+ * and to deallocate it in a secure manner.
+ *
+ * If your server complains that the password is wrong, but you can still
+ * authenticate using openssh's client (issuing password), it's probably
+ * because openssh only accept keyboard-interactive. Switch to
+ * keyboard-interactive authentication, or try to configure plain text passwords
+ * on the SSH server.
+ *
+ * Here is a small example of password authentication:
+ *
+ * @code
+ * int authenticate_password(ssh_session session)
+ * {
+ * char *password;
+ * int rc;
+ *
+ * password = getpass("Enter your password: ");
+ * rc = ssh_userauth_password(session, NULL, password);
+ * if (rc == SSH_AUTH_ERROR)
+ * {
+ * fprintf(stderr, "Authentication failed: %s\n",
+ * ssh_get_error(session));
+ * return SSH_AUTH_ERROR;
+ * }
+ *
+ * return rc;
+ * }
+ * @endcode
+ *
* @see ssh_userauth_password
- *
- * @subsection keyb-int Keyboard-interactive
- *
- * The keyboard-interactive method is, as its name tells, interactive. The server will issue one or more
- * challenges, which the used has to answer, until the server takes an authentication decision.
+ *
+ *
+ * @subsection keyb_int The keyboard-interactive authentication method
+ *
+ * The keyboard-interactive method is, as its name tells, interactive. The
+ * server will issue one or more challenges that the user has to answer,
+ * until the server takes an authentication decision.
+ *
* ssh_userauth_kbdint() is the the main keyboard-interactive function.
- * It will return SSH_AUTH_SUCCESS,SSH_AUTH_DENIED, SSH_AUTH_PARTIAL, SSH_AUTH_ERROR, or SSH_AUTH_INFO depending
- * on the result of the request.
- *
- * The keyboard-interactive authentication method of SSH2 is a feature which permits the server
- * to ask a certain number of questions in an interactive manner to the client, until it decides to
- * accept or deny the login.
- *
- * To begin, you call this function (just put user and submethods to NULL) and store the answer. If the answer is
- * SSH_AUTH_INFO, it means the server has sent a few questions to ask your user, which you can retrieve with
- * the following functions : ssh_userauth_kbdint_getnprompts(), ssh_userauth_kbdint_getname(),
- * ssh_userauth_kbdint_getinstruction() and ssh_userauth_kbdint_getprompt().
- * Set the answer for each question in the challenge using ssh_userauth_kbdint_setanswer(). Then,
- * call back ssh_userauth_kbdint() and start the process again until this functions returns something else
- * than SSH_AUTH_INFO.
- *
- * Few remarks :
+ * It will return SSH_AUTH_SUCCESS,SSH_AUTH_DENIED, SSH_AUTH_PARTIAL,
+ * SSH_AUTH_ERROR, or SSH_AUTH_INFO, depending on the result of the request.
+ *
+ * The keyboard-interactive authentication method of SSH2 is a feature that
+ * permits the server to ask a certain number of questions in an interactive
+ * manner to the client, until it decides to accept or deny the login.
+ *
+ * To begin, you call ssh_userauth_kbdint() (just set user and submethods to
+ * NULL) and store the answer.
+ *
+ * If the answer is SSH_AUTH_INFO, it means that the server has sent a few
+ * questions that you should ask the user. You can retrieve these questions
+ * with the following functions: ssh_userauth_kbdint_getnprompts(),
+ * ssh_userauth_kbdint_getname(), ssh_userauth_kbdint_getinstruction(), and
+ * ssh_userauth_kbdint_getprompt().
+ *
+ * Set the answer for each question in the challenge using
+ * ssh_userauth_kbdint_setanswer().
+ *
+ * Then, call again ssh_userauth_kbdint() and start the process again until
+ * these functions returns something else than SSH_AUTH_INFO.
+ *
+ * Here are a few remarks:
* - Even the first call can return SSH_AUTH_DENIED or SSH_AUTH_SUCCESS.
- * - The server can send an empty question set (this is the default behavior on my system) after you have
- * sent the answers to the first questions. you must still parse the answer, it might contain some
- * message from the server saying hello or such things. Just call ssh_userauth_kbdint() until needed.
- * - The meaning of "name", "prompt", "instruction" may be a little confusing. And explanation is given
- * in the following documentation.
- * A little note about how to use the information from keyboard-interactive authentication, coming from
- * The RFC itself (rfc4256) :
- *
+ * - The server can send an empty question set (this is the default behavior
+ * on my system) after you have sent the answers to the first questions.
+ * You must still parse the answer, it might contain some
+ * message from the server saying hello or such things. Just call
+ * ssh_userauth_kbdint() until needed.
+ * - The meaning of "name", "prompt", "instruction" may be a little
+ * confusing. An explanation is given in the RFC section that follows.
+ *
+ * Here is a little note about how to use the information from
+ * keyboard-interactive authentication, coming from the RFC itself (rfc4256):
+ *
* @verbatim
-
- 3.3 User Interface Upon receiving a request message, the client SHOULD prompt the user as follows:
- A command line interface (CLI) client SHOULD print the name and instruction (if non-empty), adding newlines.
- Then for each prompt in turn, the client SHOULD display the prompt and read the user input.
-
- A graphical user interface (GUI) client has many choices on how to prompt the user. One possibility is to use
- the name field (possibly prefixed with the application's name) as the title of a dialog window in which
- the prompt(s) are presented. In that dialog window, the instruction field would be a text message, and the
- prompts would be labels for text entry fields. All fields SHOULD be presented to the user, for example an
- implementation SHOULD NOT discard the name field because its windows lack titles; it SHOULD instead find another
- way to display this information. If prompts are presented in a dialog window, then the client SHOULD NOT
- present each prompt in a separate window.
-
- All clients MUST properly handle an instruction field with embedded newlines. They SHOULD also be able to display
- at least 30 characters for the name and prompts. If the server presents names or prompts longer than 30
- characters, the client MAY truncate these fields to the length it can display. If the client does truncate any
- fields, there MUST be an obvious indication that such truncation has occured.
-
- The instruction field SHOULD NOT be truncated.
- Clients SHOULD use control character filtering as discussed in [SSH-ARCH] to avoid attacks by including terminal
- control characters in the fields to be displayed.
-
- For each prompt, the corresponding echo field indicates whether or not the user input should be echoed as
- characters are typed. Clients SHOULD correctly echo/mask user input for each prompt independently of other
- prompts in the request message. If a client does not honor the echo field for whatever reason, then the client
- MUST err on the side of masking input. A GUI client might like to have a checkbox toggling echo/mask. Clients
- SHOULD NOT add any additional characters to the prompt such as ": " (colon-space); the server is responsible for
- supplying all text to be displayed to the user. Clients MUST also accept empty responses from the user and pass
- them on as empty strings.
- @endverbatim
+ *
+ * 3.3 User Interface Upon receiving a request message, the client SHOULD
+ * prompt the user as follows: A command line interface (CLI) client SHOULD
+ * print the name and instruction (if non-empty), adding newlines. Then for
+ * each prompt in turn, the client SHOULD display the prompt and read the
+ * user input.
+ *
+ * A graphical user interface (GUI) client has many choices on how to prompt
+ * the user. One possibility is to use the name field (possibly prefixed
+ * with the application's name) as the title of a dialog window in which
+ * the prompt(s) are presented. In that dialog window, the instruction field
+ * would be a text message, and the prompts would be labels for text entry
+ * fields. All fields SHOULD be presented to the user, for example an
+ * implementation SHOULD NOT discard the name field because its windows lack
+ * titles; it SHOULD instead find another way to display this information. If
+ * prompts are presented in a dialog window, then the client SHOULD NOT
+ * present each prompt in a separate window.
+ *
+ * All clients MUST properly handle an instruction field with embedded
+ * newlines. They SHOULD also be able to display at least 30 characters for
+ * the name and prompts. If the server presents names or prompts longer than 30
+ * characters, the client MAY truncate these fields to the length it can
+ * display. If the client does truncate any fields, there MUST be an obvious
+ * indication that such truncation has occured.
+ *
+ * The instruction field SHOULD NOT be truncated. Clients SHOULD use control
+ * character filtering as discussed in [SSH-ARCH] to avoid attacks by
+ * including terminal control characters in the fields to be displayed.
+ *
+ * For each prompt, the corresponding echo field indicates whether or not
+ * the user input should be echoed as characters are typed. Clients SHOULD
+ * correctly echo/mask user input for each prompt independently of other
+ * prompts in the request message. If a client does not honor the echo field
+ * for whatever reason, then the client MUST err on the side of
+ * masking input. A GUI client might like to have a checkbox toggling
+ * echo/mask. Clients SHOULD NOT add any additional characters to the prompt
+ * such as ": " (colon-space); the server is responsible for supplying all
+ * text to be displayed to the user. Clients MUST also accept empty responses
+ * from the user and pass them on as empty strings.
+ * @endverbatim
+ *
+ * The following example shows how to perform keyboard-interactive authentication:
+ *
+ * @code
+ * int authenticate_kbdint(ssh_session session)
+ * {
+ * int rc;
+ *
+ * rc = ssh_userauth_kbdint(session, NULL, NULL);
+ * while (rc == SSH_AUTH_INFO)
+ * {
+ * const char *name, *instruction;
+ * int nprompts, iprompt;
+ *
+ * name = ssh_userauth_kbdint_getname(session);
+ * instruction = ssh_userauth_kbdint_getinstruction(session);
+ * nprompts = ssh_userauth_kbdint_getnprompts(session);
+ *
+ * if (strlen(name) > 0)
+ * printf("%s\n", name);
+ * if (strlen(instruction) > 0)
+ * printf("%s\n", instruction);
+ * for (iprompt = 0; iprompt < nprompts; iprompt++)
+ * {
+ * const char *prompt;
+ * char echo;
+ *
+ * prompt = ssh_userauth_kbdint_getprompt(session, iprompt, &echo);
+ * if (echo)
+ * {
+ * char buffer[128], *ptr;
+ *
+ * printf("%s", prompt);
+ * if (fgets(buffer, sizeof(buffer), stdin) == NULL)
+ * return SSH_AUTH_ERROR;
+ * buffer[sizeof(buffer) - 1] = '\0';
+ * if ((ptr = strchr(buffer, '\n')) != NULL)
+ * *ptr = '\0';
+ * if (ssh_userauth_kbdint_setanswer(session, iprompt, buffer) < 0)
+ * return SSH_AUTH_ERROR;
+ * memset(buffer, 0, strlen(buffer));
+ * }
+ * else
+ * {
+ * char *ptr;
+ *
+ * ptr = getpass(prompt);
+ * if (ssh_userauth_kbdint_setanswer(session, iprompt, ptr) < 0)
+ * return SSH_AUTH_ERROR;
+ * }
+ * }
+ * rc = ssh_userauth_kbdint(session, NULL, NULL);
+ * }
+ * return rc;
+ * }
+ * @endcode
+ *
* @see ssh_userauth_kbdint()
* @see ssh_userauth_kbdint_getnprompts
* @see ssh_userauth_kbdint_getname
@@ -310,24 +717,127 @@
* @see ssh_userauth_kbdint_getprompt
* @see ssh_userauth_kbdint_setanswer()
*
- * @subsection none "none"
- *
- * In fact this mode only serve to get the list of supported authentications, or to be authenticated
- * **without** any credental. It happens on anonymous services for an example. You can try authentication
- * with this mode by using ssh_userauth_none().
- * It also serves to get the banner message from the server, if any. You should always firstly try this method,
- * at least for getting the banner, then to enter if there is no password at all. You're advised to use
- * ssh_userauth_autopubkey instead.
- * if the account has no password (and the server is configured to let you pass), ssh_userauth_none might
- * answer SSH_AUTH_SUCCESS.
-
- * @subsection banner Issue banner
- * ssh_get_banner() retrieves the issue banner that a server may send. That banner may be receive right after a
- * call to ssh_userauth_none().
- *
- * @subsection auth_example example
- * The following code is an example of authentication using libssh. It's the content of the examples/authentication.c
- * file.
- *
- * @include authentication.c
+ *
+ * @subsection none Authenticating with "none" method
+ *
+ * The primary purpose of the "none" method is to get authenticated **without**
+ * any credential. Don't do that, use one of the other authentication methods,
+ * unless you really want to grant anonymous access.
+ *
+ * If the account has no password, and if the server is configured to let you
+ * pass, ssh_userauth_none() might answer SSH_AUTH_SUCCESS.
+ *
+ * The following example shows how to perform "none" authentication:
+ *
+ * @code
+ * int authenticate_kbdint(ssh_session session)
+ * {
+ * int rc;
+ *
+ * rc = ssh_userauth_none(session, NULL, NULL);
+ * return rc;
+ * }
+ * @endcode
+ *
+ * @subsection auth_list Getting the list of supported authentications
+ *
+ * You are not meant to choose a given authentication method, you can
+ * let the server tell you which methods are available. Once you know them,
+ * you try them one after the other.
+ *
+ * The following example shows how to get the list of available authentication
+ * methods with ssh_userauth_list() and how to use the result:
+ *
+ * @code
+ * /* Marche pas sans ssh_userauth_none(), du moins en 0.4.2 */
+ * int test_several_auth_methods(ssh_session session)
+ * {
+ * int method, rc;
+ *
+ * method = ssh_userauth_list(session, NULL);
+ *
+ * if (method & SSH_AUTH_METHOD_NONE)
+ * { // For the source code of function authenticate_none(),
+ * // refer to the corresponding example
+ * rc = authenticate_none(session);
+ * if (rc == SSH_AUTH_SUCCESS) return rc;
+ * }
+ * if (method & SSH_AUTH_METHOD_PUBLICKEY)
+ * { // For the source code of function authenticate_pubkey(),
+ * // refer to the corresponding example
+ * rc = authenticate_pubkey(session);
+ * if (rc == SSH_AUTH_SUCCESS) return rc;
+ * }
+ * if (method & SSH_AUTH_METHOD_INTERACTIVE)
+ * { // For the source code of function authenticate_kbdint(),
+ * // refer to the corresponding example
+ * rc = authenticate_kbdint(session);
+ * if (rc == SSH_AUTH_SUCCESS) return rc;
+ * }
+ * if (method & SSH_AUTH_METHOD_PASSWORD)
+ * { // For the source code of function authenticate_password(),
+ * // refer to the corresponding example
+ * rc = authenticate_password(session);
+ * if (rc == SSH_AUTH_SUCCESS) return rc;
+ * }
+ * return SSH_AUTH_ERROR;
+ * }
+ * @endcode
+ *
+ *
+ * @subsection banner
+ *
+ * The SSH server might send a banner, which you can retrieve with
+ * ssh_get_issue_banner(), then display to the user.
+ *
+ * The following example shows how to retrieve and dispose the issue banner:
+ *
+ * @code
+ * /* Marche pas sans ssh_userauth_none(), du moins en 0.4.2 */
+ * int display_banner(ssh_session session)
+ * {
+ * int rc;
+ * char *banner;
+ *
+ * rc = ssh_userauth_none(session, NULL);
+ * if (rc == SSH_AUTH_ERROR)
+ * return rc;
+ *
+ * banner = ssh_get_issue_banner(session);
+ * if (banner)
+ * {
+ * printf("%s\n", banner);
+ * free(banner);
+ * }
+ *
+ * return rc;
+ * }
+ * @endcode
+ *
+ *
+ * @page tbd Chapter 3: To be done
+ * @section opening_shell Opening a shell
+ *
+ * *** To be written ***
+ *
+ * @section remote_commands Passing remote commands
+ *
+ * *** To be written ***
+ *
+ * @section sftp_subsystem The SFTP subsystem
+ *
+ * *** To be written ***
+ *
+ * @section scp_subsystem The SCP subsystem
+ *
+ * *** To be written ***
+ *
+ * @section threads Working with threads
+ *
+ * *** To be written ***
+ *
+ * @section forwarding_connections Forwarding connections
+ *
+ * *** To be written ***
+ *
*/