aboutsummaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/authentication.dox372
-rw-r--r--doc/commands.dox85
-rw-r--r--doc/guided_tour.dox428
-rw-r--r--doc/introduction.dox39
-rw-r--r--doc/sftp.dox87
-rw-r--r--doc/shell.dox360
-rw-r--r--doc/tbd.dox22
7 files changed, 1393 insertions, 0 deletions
diff --git a/doc/authentication.dox b/doc/authentication.dox
new file mode 100644
index 0000000..9628a48
--- /dev/null
+++ b/doc/authentication.dox
@@ -0,0 +1,372 @@
+@page authentication Chapter 2: A deeper insight on authentication
+@section authentication_details A deeper insight on authentication
+
+In our guided tour, we merely mentioned that the user needed to authenticate.
+We didn't explain much in detail how that was supposed to happen.
+This chapter explains better the four authentication methods: with public keys,
+with a password, with challenges and responses (keyboard-interactive), and with
+no authentication at all.
+
+If your software is supposed to connect to an arbitrary server, then you
+might need to support all authentication methods. If your software will
+connect only to a given server, then it might be enough for your software
+to support only the authentication methods used by that server. If you are
+the administrator of the server, it might be your call to choose those
+authentication methods.
+
+It is not the purpose of this document to review in detail the advantages
+and drawbacks of each authentication method. You are therefore invited
+to read the abundant documentation on this topic to fully understand the
+advantages and security risks linked to each method.
+
+
+@subsection pubkeys Authenticating with public keys
+
+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
+@see publickey_from_file
+@see publickey_from_privatekey
+@see string_free
+@see privatekey_from_file
+@see privatekey_free
+
+
+@subsection password Authenticating with 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 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 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. 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
+
+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
+@see ssh_userauth_kbdint_getinstruction
+@see ssh_userauth_kbdint_getprompt
+@see ssh_userauth_kbdint_setanswer()
+
+
+@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
+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 Getting the 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
+int display_banner(ssh_session session)
+{
+ int rc;
+ char *banner;
+
+/*
+ *** Does not work without calling ssh_userauth_none() first ***
+ *** That will be fixed ***
+*/
+ 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
+
+
diff --git a/doc/commands.dox b/doc/commands.dox
new file mode 100644
index 0000000..69286fb
--- /dev/null
+++ b/doc/commands.dox
@@ -0,0 +1,85 @@
+@page commands Chapter 4: Passing remote commands
+@section remote_commands Passing remote commands
+
+Previous chapter has shown how to open a full shell session, with an attached
+terminal or not. If you only need to execute commands on the remote end,
+you don't need all that complexity.
+
+@subsection exec_remote Executing remote commands
+
+The first steps for executing remote commands are identical to those
+for opening remote shells. You first need a SSH channel, and then
+a SSH session that uses this channel:
+
+@code
+int show_remote_files(ssh_session session)
+{
+ ssh_channel channel;
+ int rc;
+
+ 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;
+ }
+@endcode
+
+Once a session is open, you can start the remote command with
+ssh_channel_request_exec():
+
+@code
+ rc = ssh_channel_request_exec(channel, "ls -l");
+ if (rc != SSH_OK)
+ {
+ ssh_channel_close(channel);
+ ssh_channel_free(channel);
+ return rc;
+ }
+@endcode
+
+If the remote command displays data, you get them with ssh_channel_read().
+This function returns the number of bytes read. If there is no more
+data to read on the channel, this function returns 0, and you can go to next step.
+If an error has been encountered, it returns a negative value:
+
+@code
+ char buffer[256];
+ unsigned int nbytes;
+
+ 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;
+ }
+@endcode
+
+Once there are no more remote commands to execute, you can send an
+end-of-file to the channel, close it, and free the memory it used:
+
+@code
+ ssh_channel_send_eof(channel);
+ ssh_channel_close(channel);
+ ssh_channel_free(channel);
+
+ return SSH_OK;
+}
+@endcode
+
+
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
+
+
diff --git a/doc/introduction.dox b/doc/introduction.dox
new file mode 100644
index 0000000..fde9fd3
--- /dev/null
+++ b/doc/introduction.dox
@@ -0,0 +1,39 @@
+@page tutorial The Tutorial
+@section introduction Introduction
+
+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.
+
+This tutorial concentrates for its main part on the "client" side of libssh.
+To learn how to accept incoming SSH connexions (how to write a SSH server),
+you'll have to jump to the end of this document.
+
+This tutorial describes libssh version 0.5.0. This version is the development
+version and is *not* published yet. However, the examples should work with
+little changes on versions like 0.4.2 and later.
+
+
+Table of contents:
+
+@subpage guided_tour
+
+@subpage authentication
+
+@subpage shell
+
+@subpage commands
+
+@subpage sftp
+
+@subpage tbd
+
+
diff --git a/doc/sftp.dox b/doc/sftp.dox
new file mode 100644
index 0000000..72e6237
--- /dev/null
+++ b/doc/sftp.dox
@@ -0,0 +1,87 @@
+@page sftp Chapter 5: The SFTP subsystem
+@section sftp_subsystem The SFTP subsystem
+
+SFTP stands for "Secure File Transfer Protocol". It enables you to safely
+transfer files between the local and the remote computer. It reminds a lot
+of the old FTP protocol.
+
+SFTP is a rich protocol. It lets you do over the network almost everything
+that you can do with local files:
+ - send files
+ - modify only a portion of a file
+ - receive files
+ - receive only a portion of a file
+ - get file owner and group
+ - get file permissions
+ - set file owner and group
+ - set file permissions
+ - remove files
+ - rename files
+ - create a directory
+ - remove a directory
+ - retrieve the list of files in a directory
+ - get the target of a symbolic link
+ - create symbolic links
+ - get information about mounted filesystems.
+
+
+@subsection sftp_section Opening and closing a SFTP session
+
+Unlike with remote shells and remote commands, when you use the SFTP subsystem,
+you don't handle directly the SSH channels. Instead, you open a "SFTP session".
+
+The function sftp_new() creates a new SFTP session. The function sftp_init()
+initializes it. The function sftp_free() deletes it.
+
+As you see, all the SFTP-related functions start with the "sftp_" prefix
+instead of the usual "ssh_" prefix. In case of a problem, you use
+sftp_get_error() instead of ssh_get_error() to get the English error message.
+
+The example below shows how to use these functions:
+
+@code
+#include <libssh/sftp.h>
+
+int sftp_helloworld(ssh_session session)
+{
+ sftp_session sftp;
+ int rc;
+
+ sftp = sftp_new(session);
+ if (sftp == NULL)
+ {
+ fprintf(stderr, "Error allocating SFTP session: %s\n", ssh_get_error(session));
+ return SSH_ERROR;
+ }
+
+ rc = sftp_init(sftp);
+ if (rc != SSH_OK)
+ {
+ fprintf(stderr, "Error initializing SFTP session: %s.\n", sftp_get_error(sftp));
+ sftp_free(sftp);
+ return rc;
+ }
+
+ ...
+
+ sftp_free(sftp);
+ return SSH_OK;
+}
+@endcode
+
+
+@subsection sftp_mkdir Creating a directory
+
+*** To be written ***
+
+
+@subsection sftp_write Copying a file to the remote computer
+
+*** To be written ***
+
+
+@subsection sftp_read Reading a file from the remote computer
+
+*** To be written ***
+
+
diff --git a/doc/shell.dox b/doc/shell.dox
new file mode 100644
index 0000000..b5f6f62
--- /dev/null
+++ b/doc/shell.dox
@@ -0,0 +1,360 @@
+@page shell Chapter 3: Opening a remote shell
+@section opening_shell Opening a remote shell
+
+We already mentioned that a single SSH connection can be shared
+between several "channels". Channels can be used for different purposes.
+
+This chapter shows how to open one of these channels, and how to use it to
+start a command interpreter on a remote computer.
+
+
+@subsection open_channel Opening and closing a channel
+
+The ssh_channel_new() function creates a channel. It returns the channel as
+a variable of type ssh_channel.
+
+Once you have this channel, you open a SSH session that uses it with
+ssh_channel_open_session().
+
+Once you don't need the channel anymore, you can send an end-of-file
+to it with ssh_channel_close(). At this point, you can destroy the channel
+with ssh_channel_free().
+
+The code sample below achieves these tasks:
+
+@code
+int shell_session(ssh_session session)
+{
+ ssh_channel channel;
+ int rc;
+
+ 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;
+ }
+
+ ...
+
+ ssh_channel_close(channel);
+ ssh_channel_send_eof(channel);
+ ssh_channel_free(channel);
+
+ return SSH_OK;
+}
+@endcode
+
+
+@subsection interactive Interactive and non-interactive sessions
+
+A "shell" is a command interpreter. It is said to be "interactive"
+if there is a human user typing the commands, one after the
+other. The contrary, a non-interactive shell, is similar to
+the execution of commands in the background: there is no attached
+terminal.
+
+If you plan using an interactive shell, you need to create a
+pseud-terminal on the remote side. A remote terminal is usually referred
+to as a "pty", for "pseudo-teletype". The remote processes won't see the
+difference with a real text-oriented terminal.
+
+If needed, you request the pty with the function ssh_channel_request_pty().
+Then you define its dimensions (number of rows and columns)
+with ssh_channel_change_pty_size().
+
+Be your session interactive or not, the next step is to request a
+shell with ssh_channel_request_shell().
+
+@code
+int interactive_shell_session(ssh_channel channel)
+{
+ int rc;
+
+ rc = ssh_channel_request_pty(channel);
+ if (rc != SSH_OK) return rc;
+
+ rc = ssh_channel_change_pty_size(channel, 80, 24);
+ if (rc != SSH_OK) return rc;
+
+ rc = ssh_channel_request_shell(channel);
+ if (rc != SSH_OK) return rc;
+
+ ...
+
+ return rc;
+}
+@endcode
+
+
+@subsection read_data Displaying the data sent by the remote computer
+
+In your program, you will usually need to receive all the data "displayed"
+into the remote pty. You will usually analyse, log, or display this data.
+
+ssh_channel_read() and ssh_channel_read_nonblocking() are the simplest
+way to read data from a channel. If you only need to read from a single
+channel, they should be enough.
+
+The example below shows how to wait for remote data using ssh_channel_read():
+
+@code
+int interactive_shell_session(ssh_channel channel)
+{
+ int rc;
+ char buffer[256];
+ int nbytes;
+
+ rc = ssh_channel_request_pty(channel);
+ if (rc != SSH_OK) return rc;
+
+ rc = ssh_channel_change_pty_size(channel, 80, 24);
+ if (rc != SSH_OK) return rc;
+
+ rc = ssh_channel_request_shell(channel);
+ if (rc != SSH_OK) return rc;
+
+ while (ssh_channel_is_open(channel) &&
+ !ssh_channel_is_eof(channel))
+ {
+ nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
+ if (nbytes < 0)
+ return SSH_ERROR;
+
+ if (nbytes > 0)
+ write(1, buffer, nbytes);
+ }
+
+ return rc;
+}
+@endcode
+
+Unlike ssh_channel_read(), ssh_channel_read_nonblocking() never waits for
+remote data to be ready. It returns immediately.
+
+If you plan to use ssh_channel_read_nonblocking() repeatedly in a loop,
+you should use a "passive wait" function like usleep(3) in the same
+loop. Otherwise, your program will consume all the CPU time, and your
+computer might become unresponsive.
+
+
+@subsection write_data Sending user input to the remote computer
+
+User's input is sent to the remote site with ssh_channel_write().
+
+The following example shows how to combine a nonblocking read from a SSH
+channel with a nonblocking read from the keyboard. The local input is then
+sent to the remote computer:
+
+@code
+/* Under Linux, this function determines whether a key has been pressed.
+ Under Windows, it is a standard function, so you need not redefine it.
+*/
+int kbhit()
+{
+ struct timeval tv = { 0L, 0L };
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(0, &fds);
+
+ return select(1, &fds, NULL, NULL, &tv);
+}
+
+/* A very simple terminal emulator:
+ - print data received from the remote computer
+ - send keyboard input to the remote computer
+*/
+int interactive_shell_session(ssh_channel channel)
+{
+ /* Session and terminal initialization skipped */
+ ...
+
+ char buffer[256];
+ int nbytes, nwritten;
+
+ while (ssh_channel_is_open(channel) &&
+ !ssh_channel_is_eof(channel))
+ {
+ nbytes = ssh_channel_read_nonblocking(channel, buffer, sizeof(buffer), 0);
+ if (nbytes < 0) return SSH_ERROR;
+ if (nbytes > 0)
+ {
+ nwritten = write(1, buffer, nbytes);
+ if (nwritten != nbytes) return SSH_ERROR;
+
+ if (!kbhit())
+ {
+ usleep(50000L); // 0.05 second
+ continue;
+ }
+
+ nbytes = read(0, buffer, sizeof(buffer));
+ if (nbytes < 0) return SSH_ERROR;
+ if (nbytes > 0)
+ {
+ nwritten = ssh_channel_write(channel, buffer, nbytes);
+ if (nwritten != nbytes) return SSH_ERROR;
+ }
+ }
+
+ return rc;
+}
+@endcode
+
+Of course, this is a poor terminal emulator, since the echo from the keys
+pressed should not be done locally, but should be done by the remote side.
+Also, user's input should not be sent once "Enter" key is pressed, but
+immediately after each key is pressed. This can be accomplished
+by setting the local terminal to "raw" mode with the cfmakeraw(3) function.
+cfmakeraw() is a standard function under Linux, on other systems you can
+recode it with:
+
+@code
+static void cfmakeraw(struct termios *termios_p)
+{
+ termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+ termios_p->c_oflag &= ~OPOST;
+ termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+ termios_p->c_cflag &= ~(CSIZE|PARENB);
+ termios_p->c_cflag |= CS8;
+}
+@endcode
+
+If you are not using a local terminal, but some kind of graphical
+environment, the solution to this kind of "echo" problems will be different.
+
+
+@subsection select_loop A more elaborate way to get the remote data
+
+*** Warning: ssh_select() and ssh_channel_select() are not relevant anymore,
+ since libssh is about to provide an easier system for asynchronous
+ communications. This subsection should be removed then. ***
+
+ssh_channel_read() and ssh_channel_read_nonblocking() functions are simple,
+but they are not adapted when you expect data from more than one SSH channel,
+or from other file descriptors. Last example showed how getting data from
+the standard input (the keyboard) at the same time as data from the SSH
+channel was complicated. The functions ssh_select() and ssh_channel_select()
+provide a more elegant way to wait for data coming from many sources.
+
+The functions ssh_select() and ssh_channel_select() remind of the standard
+UNIX select(2) function. The idea is to wait for "something" to happen:
+incoming data to be read, outcoming data to block, or an exception to
+occur. Both these functions do a "passive wait", i.e. you can safely use
+them repeatedly in a loop, it will not consume exaggerate processor time
+and make your computer unresponsive. It is quite common to use these
+functions in your application's main loop.
+
+The difference between ssh_select() and ssh_channel_select() is that
+ssh_channel_select() is simpler, but allows you only to watch SSH channels.
+ssh_select() is more complete and enables watching regular file descriptors
+as well, in the same function call.
+
+Below is an example of a function that waits both for remote SSH data to come,
+as well as standard input from the keyboard:
+
+@code
+int interactive_shell_session(ssh_session session, ssh_channel channel)
+{
+ /* Session and terminal initialization skipped */
+ ...
+
+ char buffer[256];
+ int nbytes, nwritten;
+
+ while (ssh_channel_is_open(channel) &&
+ !ssh_channel_is_eof(channel))
+ {
+ struct timeval timeout;
+ ssh_channel in_channels[2], out_channels[2];
+ fd_set fds;
+ int maxfd;
+
+ timeout.tv_sec = 30;
+ timeout.tv_usec = 0;
+ in_channels[0] = channel;
+ in_channels[1] = NULL;
+ FD_ZERO(&fds);
+ FD_SET(0, &fds);
+ FD_SET(ssh_get_fd(session), &fds);
+ maxfd = ssh_get_fd(session) + 1;
+
+ ssh_select(in_channels, out_channels, maxfd, &fds, &timeout);
+
+ if (out_channels[0] != NULL)
+ {
+ nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
+ if (nbytes < 0) return SSH_ERROR;
+ if (nbytes > 0)
+ {
+ nwritten = write(1, buffer, nbytes);
+ if (nwritten != nbytes) return SSH_ERROR;
+ }
+ }
+
+ if (FD_ISSET(0, &fds))
+ {
+ nbytes = read(0, buffer, sizeof(buffer));
+ if (nbytes < 0) return SSH_ERROR;
+ if (nbytes > 0)
+ {
+ nwritten = ssh_channel_write(channel, buffer, nbytes);
+ if (nbytes != nwritten) return SSH_ERROR;
+ }
+ }
+ }
+
+ return rc;
+}
+@endcode
+
+
+@subsection x11 Using graphical applications on the remote side
+
+If your remote application is graphical, you can forward the X11 protocol to
+your local computer.
+
+To do that, you first declare that you accept X11 connections with
+ssh_channel_accept_x11(). Then you create the forwarding tunnel for
+the X11 protocol with ssh_channel_request_x11().
+
+The following code performs channel initialization and shell session
+opening, and handles a parallel X11 connection:
+
+@code
+int interactive_shell_session(ssh_channel channel)
+{
+ int rc;
+ ssh_channel x11channel;
+
+ rc = ssh_channel_request_pty(channel);
+ if (rc != SSH_OK) return rc;
+
+ rc = ssh_channel_change_pty_size(channel, 80, 24);
+ if (rc != SSH_OK) return rc;
+
+ rc = ssh_channel_request_x11(channel, 0, NULL, NULL, 0);
+ if (rc != SSH_OK) return rc;
+
+ rc = ssh_channel_request_shell(channel);
+ if (rc != SSH_OK) return rc;
+
+ /* Read the data sent by the remote computer here */
+ ...
+}
+@endcode
+
+Don't forget to set the $DISPLAY environment variable on the remote
+side, or the remote applications won't try using the X11 tunnel:
+
+@code
+$ export DISPLAY=:0
+$ xclock &
+@endcode
+
+
diff --git a/doc/tbd.dox b/doc/tbd.dox
new file mode 100644
index 0000000..c61b87f
--- /dev/null
+++ b/doc/tbd.dox
@@ -0,0 +1,22 @@
+@page tbd To be done
+@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 ***
+
+@section sshd Writing a libssh-based server
+
+*** To be written ***
+
+@section cpp The libssh C++ wrapper
+
+*** To be written ***
+
+