aboutsummaryrefslogtreecommitdiff
path: root/doc/tutorial.dox
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2009-12-20 23:21:59 +0100
committerAris Adamantiadis <aris@0xbadc0de.be>2009-12-20 23:21:59 +0100
commit91f7d127ea57a2f8ed1b2aa002bbec0d1ee64424 (patch)
tree8c02cc0eee261adfb9a9fcdd923fe2d9c616fff8 /doc/tutorial.dox
parent43c1245396ac1e695b65cc0b1eb2974207460a27 (diff)
downloadlibssh-91f7d127ea57a2f8ed1b2aa002bbec0d1ee64424.tar.gz
libssh-91f7d127ea57a2f8ed1b2aa002bbec0d1ee64424.tar.xz
libssh-91f7d127ea57a2f8ed1b2aa002bbec0d1ee64424.zip
Tutorial doxyginized and updated up to auth sect.
Diffstat (limited to 'doc/tutorial.dox')
-rw-r--r--doc/tutorial.dox315
1 files changed, 290 insertions, 25 deletions
diff --git a/doc/tutorial.dox b/doc/tutorial.dox
index 700d41c4..1777bede 100644
--- a/doc/tutorial.dox
+++ b/doc/tutorial.dox
@@ -3,39 +3,45 @@
*
* @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. Lot of the protocols specifications are hidden by the ssh library API
- * (of course !) but some still needs an attention from the end-user
- * programmer. Note that libssh is still an alpha product, and the API may vary
- * from one version to another. The only guess I can make is that the API won't
- * radically change.
+ * 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 resume here :
+ * The SSH protocol was designed for some goals which I state here :
*
* - Privacy of data
- * - Security
+ * - 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
+ * 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 ie. DSA or RSA. You can choose
- * cryptographic algorithms you trust and compression algorithms if any.
+ * 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.
-
- * - The client must authenticate : the two implemented ways are password, and
+ * 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.
+ * 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
@@ -43,26 +49,285 @@
* (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 command. The virtual terminal is usable, too
- * - Invoke the sftp subsystem. (look at chapter 6)
+ * - 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 -1 for int
- * values, NULL for pointers) also sets an error message and an error code. I
- * high-lined the main steps, now that's you to follow them :)
+ * 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.
+ *
*
* @section setup Creating the session and setting options
*
- * TODO
+ * 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.
+ * @code
+ * #include <libssh/libssh.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_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.
+ * Here is a small example of how to use it:
+ * @code
+ * #include <libssh/libssh.h>
+ * int main(){
+ * int verbosity = SSH_LOG_PROTOCOL;
+ * int port = 22;
+ * ssh_session 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_LOG_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 :
+ * @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
*
- * TODO
+ * 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 <stdio.h>
+ * int main(){
+ * int ret;
+ * ssh_session 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",
+ * ssh_get_error(my_ssh_session));
+ * else
+ * 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
+ * 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
+ *
+ * @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
*
* @section auth Authentication
*
- * TODO
+ * 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 user 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 user 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().
+ *
+ * @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 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.
+ *
+ * @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.
+ * 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 :
+ * - 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 informations 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
+ * @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 "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
*/