diff options
author | Aris Adamantiadis <aris@0xbadc0de.be> | 2009-12-20 23:21:59 +0100 |
---|---|---|
committer | Aris Adamantiadis <aris@0xbadc0de.be> | 2009-12-20 23:21:59 +0100 |
commit | 91f7d127ea57a2f8ed1b2aa002bbec0d1ee64424 (patch) | |
tree | 8c02cc0eee261adfb9a9fcdd923fe2d9c616fff8 /doc/tutorial.dox | |
parent | 43c1245396ac1e695b65cc0b1eb2974207460a27 (diff) | |
download | libssh-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.dox | 315 |
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 */ |