c65f56aefa
git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@1 7dcaeef0-15fb-0310-b436-a5af3365683c
887 строки
38 KiB
HTML
887 строки
38 KiB
HTML
<!DOCTYPE HTML SYSTEM>
|
|
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">
|
|
<head>
|
|
<title>
|
|
Libssh's Documentation
|
|
</title>
|
|
<link href="style.css" rel="stylesheet" type="text/css">
|
|
</head>
|
|
|
|
<div id="titre">
|
|
<div align="center">
|
|
LIBSSH API GUIDE <br>
|
|
Or everything you ever wanted to know about a simple and fast ssh library.
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<h2> 0 Introduction</h2>
|
|
|
|
<div class="tout">
|
|
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. <br>
|
|
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.<br>
|
|
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. <br>
|
|
The SSH protocol was designed for some goals which I resume here : <br>
|
|
-Privacy of data<br>
|
|
-Security<br>
|
|
-Authentication of the server<br>
|
|
-Authentication of the client.<br>
|
|
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:<br>
|
|
<br>
|
|
1- 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.<br>
|
|
2- 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.<br>
|
|
3- The client must authenticate : the two implemented 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.<br>
|
|
4- 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.<br>
|
|
5- With the channel you opened, you can do several things :<br>
|
|
-Open a shell. You may want to request a pseudo virtual terminal before <br>
|
|
-Execute a command. The virtual terminal is usable, too<br>
|
|
-Invoke the sftp subsystem. (look at chapter 6)<br>
|
|
-invoke your own subsystem. This is out the scope of this
|
|
document but it is easy to do.<br>
|
|
6- When everything is finished, just close the channels, and then the
|
|
connection.<br>
|
|
<br>
|
|
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 :)
|
|
<br>
|
|
</div>
|
|
<h2> 1- Setting the options </h2>
|
|
<div class="tout">
|
|
The options mechanism will change during updates of the library, but the
|
|
functions which exists now will certainly be kept.
|
|
<br><br>
|
|
The ssh system needs to know the preferences of the user, the trust into one
|
|
or another algorithm and such. More important informations have to be given
|
|
before connecting : the host name of the server, the port (if non default),
|
|
the binding address, the default username, ... <br>
|
|
The options structure is given to a ssh_connect function, then this option
|
|
structure is used again and again by the ssh implementation. you shall not
|
|
free it manually, and you shall not share it with multiple sessions.<br>
|
|
Two ways are given for setting the options : the easy one (of course !) and
|
|
the long-but-accurate one.<br><br>
|
|
</div>
|
|
<h3>a) the easy way</h3><br>
|
|
<div class="tout">
|
|
Lot of ssh options in fact come from the command line of the program... <br>
|
|
you could parse them and then use the long way for every argument, but libssh
|
|
has a mechanism to do that for you, automatically.<br>
|
|
<br>
|
|
<div class="prot">
|
|
SSH_OPTIONS *ssh_getopt(int *argcptr, char **argv);
|
|
</div>
|
|
this function will return you a new options pointer based on the arguments
|
|
you give in parameters. <br> better, they clean the argv array from used parameters
|
|
so you can use them after in your own program<br>
|
|
<div class="ex">
|
|
int main(int argc, char **argv){<br>
|
|
SSH_OPTIONS *opt;<br>
|
|
opt=ssh_getopt(&argc, argv);<br>
|
|
if(!opt){<br>
|
|
...<br>
|
|
}<br>
|
|
</div>
|
|
the function will return NULL if some problem is appearing.<br>
|
|
As a matter of portability for you own programs, the hostname isn't always<br>
|
|
the first argument from the command line, so the single arguments (not
|
|
preceded by a -something) won't be parsed.<br>
|
|
<div class="ex">
|
|
example: <br>
|
|
user@host:~$ myssh -u aris localhost <br>
|
|
-u aris will be caught, localhost will not.<br>
|
|
</div>
|
|
|
|
cfr the options_set_user() function in the next part for more informations
|
|
about it.<br>
|
|
</div>
|
|
<h3>b) the long way</h3>
|
|
<div class="tout">
|
|
<div class="prot">
|
|
SSH_OPTIONS *options_new();
|
|
</div>
|
|
This function returns an empty but initialized option structure pointer.<br>
|
|
The structure is freed by ssh_disconnect described later, so don't use the
|
|
existing function options_free() (it's an internal function).<br>
|
|
So : use it only for <b>one</b> ssh_connect(), <b>never</b> free it.<br>
|
|
<br>
|
|
<div class="prot">
|
|
SSH_OPTIONS *options_copy(SSH_OPTIONS *opt);
|
|
</div>
|
|
If you need to replicate an option object before using it, use this function.
|
|
<br><br>
|
|
|
|
The following functions are all of the following form : <br>
|
|
<div class="prot">
|
|
int options_set_something(SSH_OPTIONS *opt, something);
|
|
</div>
|
|
the something parameters are always internaly copied, so you don't have to
|
|
strdup them.<br>
|
|
some return eather 0 or -1, in which case an error message appears in the
|
|
error functions, others never fail (return void)<br>
|
|
the error codes and descriptions for these functions are recoverable throught <i>ssh_get_error(NULL);</i>
|
|
<br>
|
|
<div class="prot">
|
|
int options_set_wanted_method(SSH_OPTIONS *opt,int method, char *list);
|
|
</div>
|
|
Passing an option structure, a ssh macro for the method, and a list of allowed
|
|
parameters indicates libssh you want to use these.<br>
|
|
The macros are :<br>
|
|
KEX_ALGO<br>
|
|
KEX_HOSTKEY Server public key type expected<br>
|
|
KEX_CRYPT_C_S 2 Cryptographic algorithm client->server<br>
|
|
KEX_CRYPT_S_C 3 Cryptographic algorithm server->client<br>
|
|
KEX_MAC_C_S 4<br>
|
|
KEX_MAC_S_C 5<br>
|
|
KEX_COMP_C_S 6 Compression method for the stream ("zlib" or "none"), client to server<br>
|
|
KEX_COMP_S_C 7 Compression method for the stream ("zlib" or "none"), server to client<br>
|
|
KEX_LANG_C_S 8<br>
|
|
KEX_LANG_S_C 9<br>
|
|
<br>
|
|
Currently, only KEX_HOSTKEY and ,KEX_CRYPT_C_S,S_C, KEX_COMP_C_S and S_C work
|
|
as expected. the list is a comma separated string of prefered
|
|
algorithms/methods, in order of preference.<br>
|
|
<br>
|
|
<div class="ex">
|
|
example : this sets the ssh stream to be compressed in client->server mode only
|
|
<br>
|
|
|
|
ret = option_set_wanted_method(options,KEX_COMP_C_S,"zlib");
|
|
</div>
|
|
<div class="ex">
|
|
example: this will set the cryptographic algorithms wanted from server to
|
|
client to aes128-cbc and then aes192-cbc if the first one isn't supported by
|
|
server:<br>
|
|
ret = option_set_wanted_method(options,KEX_CRYPT_S_C,"aes128-cbc,aes192-cbc");
|
|
</div>
|
|
<div class="ex">
|
|
if you prefer getting the Dss key from a server instead of rsa, but you still
|
|
accept rsa if dss isn't available :<br>
|
|
options_set_wanted_method(options,KEX_HOSTKEY,"ssh-dss,ssh-rsa");
|
|
</div>
|
|
return value: <br>0 if the option is valid, -1 else.<br> An error is set in that case.
|
|
<br><br>
|
|
<div class="prot">
|
|
void options_set_port(SSH_OPTIONS *opt, unsigned int port);
|
|
</div>
|
|
this function sets the server port.
|
|
<div class="prot">
|
|
void options_set_host(SSH_OPTIONS *opt, const char *hostname);
|
|
</div>
|
|
this function sets the hostname of the server. It also supports
|
|
"user@hostname" syntax in which case the user options is set too.
|
|
<div class="prot">
|
|
void options_set_fd(SSH_OPTIONS *opt, int fd);
|
|
</div>
|
|
permits you to specify an opened file descriptor you've opened yourself.
|
|
<br>
|
|
It's a good way of bypassing the internal FD opening in libssh, but there are things you should take care of : <br>
|
|
-The file descriptor should be returned to libssh without nonblocking settings<br>
|
|
-If you wish to use <i>is_server_known()</i> You should also set <i>options_set_host</i>... Otherwise libssh won't have any mean of certifying the server is known or not.<br><br>
|
|
<div class="prot">
|
|
void options_set_bindaddr(SSH_OPTIONS *opt, char *bindaddr);
|
|
</div>
|
|
this function allows you to set the binding address, in case your computer has
|
|
multiple IP or interfaces. it supports both hostnames and IP's
|
|
<br><br>
|
|
<div class="prot">
|
|
void options_set_username(SSH_OPTIONS *opt,char *username);
|
|
</div>
|
|
sets username for authenticating in this session.
|
|
<br><br>
|
|
|
|
<div class="prot">
|
|
void option_set_timeout(SSH_OPTIONS *opt,long seconds, long usec);
|
|
</div>
|
|
sets the timeout for connecting to the socket. It does not include a timeout for the name resolving or handshake.
|
|
<br>
|
|
<br>
|
|
<div class="prot">
|
|
void options_set_ssh_dir(SSH_OPTIONS *opt, char *dir);
|
|
</div>
|
|
this function sets the .ssh/ directory used by libssh. You may use a %s
|
|
which will be replaced by the home directory of the user.
|
|
NEVER accept parameters others than the user's one, they may contain
|
|
format strings which are a security hole if a malicious agent gives it.
|
|
<br><br>
|
|
<div class="prot">
|
|
void options_set_known_hosts_file(SSH_OPTIONS *opt, char *dir);
|
|
</div>
|
|
same than <i>options_set_ssh_dir()</i> for known_hosts file.
|
|
<br><br>
|
|
<div class="prot">
|
|
void options_set_identity(SSH_OPTIONS *opt, char *identity);
|
|
</div>
|
|
same than upper for the identity file (they come by pair, the one asked is the file without the .pub suffix)
|
|
<br><br>
|
|
<div class="prot">
|
|
void options_set_status_callback(SSH_OPTIONS *opt, void (*callback)(void *arg, float status), void *arg);
|
|
</div>
|
|
Because more and more developpers use libssh with GUI, I've added this function to make the ssh_connect function more
|
|
interactive. This permits to set a callback of the form
|
|
<div class="prot">void function(void *userarg, float status);</div> with status going from 0 to 1 during ssh_connect. The callback won't ever be called after the connection is made.
|
|
<br><br>
|
|
</div>
|
|
<h2>
|
|
2- Connecting the ssh server
|
|
</H2>
|
|
<div class="tout">
|
|
The API provides an abstract data type, SSH_SESSION, which describes the
|
|
connection to one particular server. You can make several connections to
|
|
different servers under the same process because of this structure.
|
|
<br>
|
|
<br>
|
|
<div class="prot">
|
|
SSH_SESSION *ssh_connect(SSH_OPTIONS *options);
|
|
</div>
|
|
This function returns a handle on the newly connection. This function expects
|
|
to have a pre-set options structure.
|
|
<br>
|
|
It returns NULL in case of error, in which case you can look at error messages
|
|
for more informations.
|
|
<br><br>
|
|
<div class="prot">
|
|
void ssh_disconnect(SSH_SESSION *session);
|
|
</div>
|
|
This function sends a polite disconnect message, and does clean the session.<br>
|
|
This is the proper way of finishing a ssh connection.<br>
|
|
<br>
|
|
<div class="prot">
|
|
int ssh_get_pubkey_hash(SSH_SESSION *session, char hash[MD5_DIGEST_LEN]);
|
|
</div>
|
|
This function places the MD5 hash of the server public key into the hash array.<br>
|
|
It's IMPORTANT to verify it matches the previous known value. One server always
|
|
have the same hash. No other server/attacker can emulate it (or it'd be caught
|
|
by the public key verification procedure automatically made by libssh).
|
|
<br>
|
|
You can skip this step if you correctly handle <i>is_server_known()</i>
|
|
<br><br>
|
|
<div class="prot">
|
|
int ssh_is_server_known(SSH_SESSION *session);
|
|
</div>
|
|
|
|
Checks the user's known host file to look for a previous connection to the specified server. Return values:<br>
|
|
SSH_SERVER_KNOWN_OK : the host is known and the key has not changed<br>
|
|
SSH_SERVER_KNOWN_CHANGED : The host's key has changed. Either you are under
|
|
an active attack or the key changed. The API doesn't give any way to modify the key in known hosts yet. I Urge end developers to WARN the user about the possibility of an attack.<br>
|
|
SSH_SERVER_FOUND_OTHER: The host gave us a public key of one type, which does
|
|
not exist yet in our known host file, but there is an other type of key which is know.<br>
|
|
IE server sent a DSA key and we had a RSA key.<br>
|
|
Be carreful it's a possible attack (coder should use option_set_wanted_method() to specify
|
|
which key to use).<br>
|
|
SSH_SERVER_NOT_KNOWN: the server is unknown in known hosts. Possible reasons :
|
|
case not matching, alias, ... In any case the user MUST confirm the Md5 hash is correct.<br>
|
|
SSH_SERVER_ERROR : Some error happened while opening known host file.<br>
|
|
<br>
|
|
<div class="prot">
|
|
int ssh_write_knownhost(SSH_SESSION *session);
|
|
</div>
|
|
write the current connected host as known in the known host file. returns a negative value if something went wrong. You generaly use it when ssh_is_server_known returned SSH_SERVER_NOT_KNOWN.
|
|
<br><br>
|
|
<div class="prot">
|
|
int pubkey_get_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]);
|
|
</div>
|
|
deprecated but left for binary compatibility (will be removed in newer versions).
|
|
</div>
|
|
|
|
<h2>3- Authenticating to server</h2>
|
|
<div class="tout">
|
|
The ssh library supports the two most used authentication methods from SSH.
|
|
In every function, there is a "username" argument. If null is given instead,
|
|
the server will use the default username (which is guessed from what you gave
|
|
to options_set_user or options_set_hostname or even the local user running the code).
|
|
<br>
|
|
|
|
Authentication methods :<br>
|
|
<h3>A) Public keys</h3><br>
|
|
The public key 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).<br>
|
|
Libssh is obviously fully compatible with the openssh public and private keys.<br>
|
|
The things go this way : you scan a list of files which contain public keys.<br>
|
|
For each key, you send it to ssh server until the server acknowledges a key
|
|
(a key it knows). Then, you get the private key for this key and send a
|
|
message proving you own that private key.<br>
|
|
Here again, two ways for the public key authentication... the easy and the
|
|
complicated one.<br>
|
|
<br>
|
|
<h4> easy way:</h4>
|
|
<div class="prot">
|
|
int ssh_userauth_autopubkey(SSH_SESSION *session);
|
|
</div>
|
|
This function will try the most common places for finding the public and
|
|
private keys (your home directory) or eventualy the identity files asked by
|
|
the <i>options_set_identity()</i> function.<br>
|
|
The return values are :<br>
|
|
SSH_AUTH_ERROR : some serious error happened during authentication<br>
|
|
SSH_AUTH_DENIED : no key matched<br>
|
|
SSH_AUTH_SUCCESS : you are now authenticated<br>
|
|
SSH_AUTH_PARTIAL : some key matched but you still have to give an other mean
|
|
of authentication (like password).<br>
|
|
<br>
|
|
<h4> peanful way:</h4>
|
|
there are three steps : you get a public key, you ask the server if the key
|
|
matches a known one, if true, you get the private key and authenticate with
|
|
it.<br>
|
|
<div class="prot">
|
|
STRING *publickey_from_file(char *filename,int *_type);
|
|
</div>
|
|
will return an handle on a public key. if you give a pointer to an int,
|
|
a symbolic value will be placed there. Do it because you need it in next
|
|
step.<br><br>
|
|
<div class="prot">
|
|
int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,
|
|
int type, STRING *publickey);
|
|
</div>
|
|
this function will offer a public key to the server. SSH_AUTH_SUCCESS is
|
|
returned if the key is accepted (in which case you'll want to get the
|
|
private key), SSH_AUTH_DENIED otherwise.<br>
|
|
Still watch for SSH_AUTH_ERROR as connection problems might happen.
|
|
<br>
|
|
in case of SSH_AUTH_SUCCESS,
|
|
<br>
|
|
<div class="prot">
|
|
PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session,char *filename,
|
|
int type,char *passphrase);
|
|
</div>
|
|
will get the privatekey from the filename previously set by
|
|
publickey_from_next_file(). You can call it with a passphrase for
|
|
unlocking the key. If passphrase==NULL, the default prompt will be used.<br>
|
|
The function returns NULL if the private key wasn't opened
|
|
(ie bad passphrase or missing file).<br>
|
|
<br>
|
|
<div class="prot">
|
|
int ssh_userauth_pubkey(SSH_SESSION *session, char *username,
|
|
STRING *publickey, PRIVATE_KEY *privatekey);
|
|
</div>
|
|
Will try to authenticate using the public and private key. It shall return
|
|
SSH_AUTH_SUCCESS if you are authenticated, SSH_AUTH_ERROR, SSH_AUTH_DENIED or
|
|
SSH_AUTH_PARTIAL depending of return condition.<br>
|
|
|
|
each public key (of type STRING) must be freed with the libc "free" function.<br>
|
|
The private key must be freed with private_key_free(PRIVATE_KEY *) which
|
|
will clean the memory before (don't worry about passphrase leaking).<br>
|
|
<br>
|
|
|
|
<h3> B) Password</h3><br>
|
|
<div class="prot">
|
|
int ssh_userauth_password(SSH_SESSION *session,char *username,char *password);
|
|
</div>
|
|
Will return SSH_AUTH_SUCCESS if the password matched, one of other constants
|
|
otherwise. It's your work to ask the password and to free it in a secure
|
|
manner.<br><br>
|
|
|
|
<h3> C) Keyboard-interactive</h3><br>
|
|
<div class="prot">
|
|
int ssh_userauth_kbdint(SSH_SESSION *session, char *user, char *submethods);
|
|
</div>
|
|
This is the main keyboard-interactive function. It will return SSH_AUTH_SUCCESS,SSH_AUTH_DENIED, SSH_AUTH_PARTIAL, SSH_AUTH_ERROR depending on the result of the request.<br>
|
|
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.<br>
|
|
To begin, you call this function (you can omit user if it was set previously and omit submethods - instead you know what you do - just put them 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. Then, set the answers and call back ssh_userauth_kbdint with same arguments. It may again ask a few other questions etc. until you get an other SSH_AUTH code than SSH_AUTH_INFO.<br>
|
|
Few remarks :<br>
|
|
-Even the first call can return SSH_AUTH_DENIED or SSH_AUTH_SUCCESS.<br>
|
|
-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() once more<br>
|
|
<br>
|
|
<div class="prot">
|
|
int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session);
|
|
</div>
|
|
After you called ssh_userauth_kbdint and got SSH_AUTH_INFO, the session contains a few questions (or prompts) from the server. This function returns the number of prompts and answers.<br>
|
|
It could be zero, in which case you must act as said previously.<br>
|
|
|
|
<div class="prot">
|
|
char *ssh_userauth_kbdint_getname(SSH_SESSION *session);
|
|
</div>
|
|
this functions returns the "name" of the message block. The meaning is explained later.<br>
|
|
This function returns a pointer that stays valid until the next ssh_userauth_kbdint() call and must not be freed.<br>
|
|
|
|
<div class="prot">
|
|
char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session);
|
|
</div>
|
|
this functions returns the "instruction" of the message block. The meaning is explained later.<br>
|
|
This function returns a pointer that stays valid until the next ssh_userauth_kbdint() call and must not be freed.<br>
|
|
|
|
<div class="prot">
|
|
char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session,int i, char *echo);
|
|
</div>
|
|
This functions returns a pointer to the nth prompt. The character pointed by echo, if different from null, will contain a boolean value after the call, which means that the user prompt must be echoed or not.<br>
|
|
zero means that the echo is Off (like for a password prompt).<br>
|
|
any other value means the echo is on.<br>
|
|
This function returns a pointer that stays valid until the next ssh_userauth_kbdint() call and must not be freed.<br>
|
|
|
|
<div class="prot">
|
|
void ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i, char *a
|
|
nswer);
|
|
</div>
|
|
This function sets the ith answer. The string you give will be duplicated, and this copy will be discarded once it is no longer necessary.<br>
|
|
care must be taken so you discard the content of the original string after this function call.<br>
|
|
|
|
<h3> A little note about how to use the informations from keyboard-interactive authentication</h3>
|
|
<br>
|
|
The words from the original drafts explain everything
|
|
<div class="prot">
|
|
3.3 User Interface
|
|
|
|
Upon receiving a request message, the client SHOULD prompt the user
|
|
as follows:<br>
|
|
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.<br>
|
|
<br>
|
|
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.<br>
|
|
<br>
|
|
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.<br>
|
|
The instruction field SHOULD NOT be truncated.<br>
|
|
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.<br>
|
|
<br>
|
|
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.<br>
|
|
|
|
</div>
|
|
<br>
|
|
<h3> D) "none"</h3><br>
|
|
In fact this mode only serve to get the list of supported authentications.<br>
|
|
however, it also serves to get the banner message from the server, if any.<br>
|
|
You should firstly try this method, at least for getting the banner, then to enter if there is no password at all.<br>
|
|
<div class="prot">
|
|
int ssh_userauth_none(SSH_SESSION *session, char *username);
|
|
</div>
|
|
if the account has no password (and the server is configured to let you
|
|
pass), the function might answer SSH_AUTH_SUCCESS. That's why
|
|
ssh_auth_autopubkey already calls it for you.
|
|
<br><br>
|
|
<div class="prot">
|
|
char *ssh_get_issue_banner(SSH_SESSION *session);
|
|
</div>
|
|
if during authentication, the server has given a banner, you can get it
|
|
this way. the function returns NULL if no banner exists, and you have to
|
|
free the returned pointer.<br><br>
|
|
</div>
|
|
|
|
<h2>4- Opening a channel</h2>
|
|
<div class="tout">
|
|
Maybe you want to use the sftp subsystem : all this is done for you, you
|
|
better read at the end of the paper how to use the sftp functions.<br>
|
|
You probably want to open one or more shells, or call one or more programs.<br>
|
|
|
|
So you need a channel.<br>
|
|
<div class="prot">
|
|
CHANNEL *channel;
|
|
</div>
|
|
This is an handler to a channel object. it describes your channel.
|
|
<br>
|
|
<div class="prot">
|
|
CHANNEL *channel_open_session(SSH_SESSION *session);
|
|
</div>
|
|
This will open a channel for use into a session (which can be used for executing
|
|
a command or a shell. Not for tcp forwarding).<br>
|
|
The function returns NULL if for a reason or another the channel can't be
|
|
opened.<br>
|
|
<i>
|
|
CHANNEL *open_session_channel(...)</i> is deprecated and should not be used in future
|
|
applications.<br><br>
|
|
<div class="prot">
|
|
CHANNEL *channel_open_forward(SSH_SESSION *session, char *remotehost,
|
|
int remoteport, char *sourcehost, int localport);
|
|
</div>
|
|
Ask the server to tunnel a TCP connection. The server will connect to
|
|
remotehost:remoteport and libssh will return an handle to the channel if it is allowed.<br>
|
|
Otherwise, NULL will be returned. sourcehost and localport are generaly
|
|
used in message debugging purpose and have no effect on the result.<br>
|
|
<br>
|
|
When you've finished with your channel, you may send an EOF message and
|
|
then close it :<br>
|
|
<div class="prot">
|
|
void channel_send_eof(CHANNEL *channel);
|
|
</div>
|
|
sends an end of file into channel. It doesn't close the channel and you can still read it.<br><br>
|
|
|
|
<div class="prot">
|
|
void channel_free(CHANNEL *channel);
|
|
</div>
|
|
closes and destroy the channel.
|
|
<br>
|
|
<div class="prot">
|
|
void channel_close(CHANNEL *channel);
|
|
</div>
|
|
sends an EOF and close the channel. (if you don't know what to do, use channel_free). It doesn't free the channel.
|
|
|
|
</div>
|
|
<h2>5- The shell</h2>
|
|
<div class="tout">
|
|
<div class="prot">
|
|
int channel_request_env(CHANNEL *channel, char *name, char *value);
|
|
</div>
|
|
Ask the server to set the "name" environment variable to "value". For security
|
|
reasons, some variables won't be accepted by the server. It returns 0 otherwise.<br><br>
|
|
<div class="prot">
|
|
int channel_request_pty(CHANNEL *channel);
|
|
</div>
|
|
ask the server to allocate a pseudo terminal for the current channel.<br>
|
|
the function returns 0 on success.<br><br>
|
|
|
|
<div class="prot">
|
|
int channel_request_pty_size(CHANNEL *channel, char *terminal, int cols, int rows);
|
|
</div>
|
|
ask the server to allocate a pty. The terminal parameter is the type of pty
|
|
(vt100,xterm,...), cols and rows are the size of the new terminal (80x24 by example).<br><br>
|
|
<div class="prot">
|
|
int channel_change_pty_size(CHANNEL *channel, int cols,int rows);
|
|
</div>
|
|
changes the window size (terminal) of the current session;<br><br>
|
|
<div class="prot">
|
|
int channel_request_shell(CHANNEL *channel);
|
|
</div>
|
|
This function requests a shell. After its success, a shell is running at the other side of the channel.<br><br>
|
|
<div class="prot">
|
|
int channel_request_exec(CHANNEL *channel, char *cmd);
|
|
</div>
|
|
run a shell command without an interactive shell, ie $SHELL -c "command".<br>
|
|
returns 0 on success.<br><br>
|
|
|
|
You might ask the server to open a subsystem for you. this is done this way :
|
|
<div class="prot">
|
|
int channel_request_subsystem(CHANNEL *channel, char *subsystem);
|
|
</div>
|
|
There are some functions used to manipulate the channels :
|
|
<br><br>
|
|
<div class="prot">
|
|
int channel_write(CHANNEL *channel,void *data,int len);
|
|
</div>
|
|
writes len bytes of data into the channel. It returns the number of bytes written. The current implementation is a blocking write
|
|
of the complete data buffer, but it may vary.<br><br>
|
|
<div class="prot">
|
|
int channel_read(CHANNEL *channel, BUFFER *buffer,int bytes,int is_stderr);
|
|
</div>
|
|
It makes a blocking read on the channel, of "bytes" bytes and returns the
|
|
result into an allocated buffer you passed in. (with <i>buffer_new()</i>).<br>
|
|
it will read on stderr, if is_stderr is set.<br>
|
|
The function might read less bytes than "bytes" variable if an End of File
|
|
happened. Otherwise, the function will always block reading until "bytes"
|
|
bytes are read.<br>
|
|
with "bytes"=0, <i>channel_read()</i> will read the current state of the read buffer, but will read at least one byte (and block if nothing is available, except EOF case).<br>
|
|
|
|
You don't need to free and allocate a new buffer each time you call this function, just pass the same object each time.<br>
|
|
look at the <i>buffer_</i> functions further for the correct way of retrieving the data.<br><br>
|
|
|
|
<div class="prot">
|
|
int channel_read_nonblocking (CHANNEL *channel, char *dest, int len, int is_stderr);
|
|
</div>
|
|
Non-blocking read on channel, at most len bytes of data are read. Returns 0 if EOF or if no data available.
|
|
<br><br>
|
|
<div class="prot">
|
|
int channel_is_open(CHANNEL *channel);
|
|
</div>
|
|
returns 0 if the channel has been closed by remote host, something else otherwise.<br><br>
|
|
<div class="prot">
|
|
int channel_poll(CHANNEL *channel, int is_stderr);
|
|
</div>
|
|
This nonblocking function returns the number of bytes immediatly available for
|
|
reading on the channel and stdin/stderr.<br><br>
|
|
|
|
More interesting, if you are going to do channel multiplexing, this function
|
|
is for you :<br><br>
|
|
<div class="prot">
|
|
int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd,
|
|
fd_set *readfds, struct timeval *timeout);
|
|
</div>
|
|
channels is an array of channel pointers, finished by a NULL pointer.<br>
|
|
It can be used ever and ever, as it is never written.<br>
|
|
outchannels is an array of size at least greater or equal to "channels".<br>
|
|
It hasn't to be initialized.<br>
|
|
maxfd is the maximum file descriptor from your own filedescriptors.<br>
|
|
readfds is a pointer to a fd_set structure, like in the original
|
|
select implementation (man select).<br>
|
|
the struct timeval *timeout has the same meaning than in
|
|
select(2) (man select).<br>
|
|
|
|
There is no support for writing or special events as in <i>select(2)</i> yet.<br>
|
|
The function returns -1 if an error occured, or SSH_EINTR if select was interrupted by a syscall. This is not an error, you may restart the function.<br>
|
|
<b>note about signals:</b> libssh is not threadsafe, and most functions are not
|
|
reetrant when using the same data structures : it means you *cannot* do anything
|
|
with a channel from a ssh session passed to <i>ssh_select</i> during a signal.
|
|
<br>take a look at sample.c on how to bypass that limitation.<br>
|
|
the function works this way : it returns in the readfds the filedescriptors which have data ready for reading (the given filedescriptors have a greatest priority).<br>
|
|
Then, if no file descriptor can be read, the function looks for every
|
|
channel from the array to get a channel with data bufferized. If nothing is
|
|
available, it waits for activity on any channel/file descriptor and returns
|
|
immediatly, or waits until timeout.<br>
|
|
You will find the channels that can be read in the outchannels array (finished by NULL) and the filedescriptors in your fd_set (man FD_ISSET).<br>
|
|
this is the "heart" of your main loop.<br>
|
|
<br>
|
|
<h3>The BUFFER object.</h3>
|
|
Reading is done through the BUFFER object. here is the public interface :
|
|
<br>
|
|
<div class="prot">
|
|
BUFFER *buffer_new();
|
|
</div>
|
|
creates a buffer object.
|
|
<br><br>
|
|
<div class="prot">
|
|
void *buffer_get(BUFFER *buffer);
|
|
</div>
|
|
returns a pointer to the begining of buffer.
|
|
<br><br>
|
|
<div class="prot">
|
|
int buffer_get_len(BUFFER *buffer);
|
|
</div>
|
|
returns buffer's data size.
|
|
<br><br>
|
|
<div class="prot">
|
|
void buffer_free(BUFFER *buffer);
|
|
</div>
|
|
destoys the buffer.
|
|
<br>
|
|
<br>
|
|
How to use the buffer system when you've read something:<br>
|
|
I've seen people doing such code:<br>
|
|
<div class="prot">
|
|
char buffer[256];<br>
|
|
channel_read(channel,buf,1234,0);<br>
|
|
strcpy(buffer,buf.data);<br>
|
|
</div>
|
|
The correct way of doing this:
|
|
<div class="prot">
|
|
char buffer[256];<br>
|
|
int i;<br>
|
|
i=channel_read(channel,buf,1234,0);<br>
|
|
if(i<=0)<br>
|
|
go_out()...<br>
|
|
if(i>=256)<br>
|
|
i=255;<br>
|
|
memcpy(buffer,buffer_get(buf),i);<br>
|
|
buffer[i]=0;
|
|
</div>
|
|
Do not expect the buffer to be null-terminated. Don't access the internal structure of buffer. Check the sizes before copying.<br>
|
|
</div>
|
|
<h2>6- The SFTP subsystem</h2>
|
|
<div class="tout">
|
|
SFTP is a secure implementation of a file transfer protocol. The current
|
|
implemented version is 3. All functions aren't implemented yet but the most
|
|
important are.<br>
|
|
<br>
|
|
<h3>A) Opening the session</h3>
|
|
<div class="prot">
|
|
SFTP_SESSION *sftp_new(SSH_SESSION *session);
|
|
int sftp_init(SFTP_SESSION *sftp);
|
|
</div>
|
|
The former returns a SFTP_SESSION handle. It returns NULL if things didn't
|
|
work as expected.<br>
|
|
sftp_init makes some initialisation work. It returns 0 if things went right.
|
|
Both of them must be called.<br>
|
|
<h3>B) Opening and reading a directory</h3>
|
|
<div class="prot">
|
|
SFTP_DIR *sftp_opendir(SFTP_SESSION *session, char *path);
|
|
</div>
|
|
opens a directory for file listing. Returns NULL in error case.
|
|
<br><br>
|
|
<div class="prot">
|
|
SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *session, SFTP_DIR *dir);
|
|
</div>
|
|
This function reads one file attribute from an opened directory. It
|
|
returns NULL if the directory is EOF, or if something wrong happened.
|
|
<br><br>
|
|
<div class="prot">
|
|
int sftp_dir_eof(SFTP_DIR *dir);
|
|
</div>
|
|
When a <i>sftp_readdir()</i> returned NULL, you can use this function to
|
|
tell if an EOF occured. the function returns 0 if no EOF occured.
|
|
<br><br>
|
|
<div class="prot">
|
|
void sftp_attributes_free(SFTP_ATTRIBUTES *file);
|
|
</div>
|
|
You have to free any SFTP_ATTRIBUTE structure given by an other function
|
|
with it.<br><br>
|
|
<div class="prot">
|
|
int sftp_dir_close(SFTP_DIR *dir);
|
|
</div>
|
|
closes an opened directory. returns 0 when no error occured.
|
|
<br><br>
|
|
<h3>C) Opening, reading, writing files</h3>
|
|
<div class="prot">
|
|
SFTP_FILE *sftp_open(SFTP_SESSION *session, char *file, int access,
|
|
SFTP_ATTRIBUTES *attr);
|
|
</div>
|
|
Opens a file. The access flags are the same than the stdio flags.<br>
|
|
see open(2) for more details.<br>
|
|
attr are the wanted attributes for the new file. If you supply NULL,
|
|
default values will be used.<br>
|
|
rem: more work is going on parsing/making the attributes structure
|
|
<br><br>
|
|
<div class="prot">
|
|
int sftp_read(SFTP_FILE *file, void *dest, int len);
|
|
</div>
|
|
read on a file. Works as the fread() function. It is blocking by default but you can change the default behaviour with <i>sftp_file_set_nonblocking()</i>.
|
|
<br><br>
|
|
<div class="prot">
|
|
void sftp_file_set_nonblocking(SFTP_FILE *file);
|
|
</div>
|
|
sets the file non blocking. reads on this file won't ever block. You can't detect end of files this way.<br>
|
|
*** TODO more work going there for EOF ****
|
|
<br><br>
|
|
<div class="prot">
|
|
void sftp_file_set_blocking(SFTP_FILE *file);
|
|
</div>
|
|
restore the default setting of sftp_read.
|
|
<br><br>
|
|
<div class="prot">
|
|
int sftp_write(SFTP_FILE *file, void *source, int len);
|
|
</div>
|
|
works as fwrite() function. It is a blocking write.<br>
|
|
<br>
|
|
<div class="prot">
|
|
void sftp_seek(SFTP_FILE *file, int new_offset);
|
|
</div>
|
|
seek into the file for reading/writing at an other place.
|
|
<br><br>
|
|
<div class="prot">
|
|
unsigned long sftp_tell(SFTP_FILE *file);
|
|
</div>
|
|
returns the current offset (both writing and reading) into the opened file.
|
|
<br><br>
|
|
<div class="prot">
|
|
void sftp_rewind(SFTP_FILE *file);
|
|
</div>
|
|
same as sftp_seek(file,0);
|
|
<br><br>
|
|
<div class="prot">
|
|
int sftp_file_close(SFTP_FILE *file);
|
|
</div>
|
|
closes a file handle. returns 0 in no error case.
|
|
<br><br>
|
|
<div class="prot">
|
|
int sftp_rm(SFTP_SESSION *sftp, char *file);
|
|
</div>
|
|
deletes a file.
|
|
<br><br>
|
|
<div class="prot">
|
|
int sftp_rmdir(SFTP_SESSION *sftp, char *directory);
|
|
</div>
|
|
<br>
|
|
deletes a directory.
|
|
<br><br>
|
|
<div class="prot">
|
|
int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr);
|
|
</div>
|
|
makes a directory, with the given attributes. You can't pass NULL for attr and hope it works.
|
|
<br><br>
|
|
<div class="prot">
|
|
int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname);
|
|
</div>
|
|
changes the name of a file or directory.
|
|
<br><br>
|
|
<div class="prot">
|
|
int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr);
|
|
</div>
|
|
changes the attributes of a file or directory.
|
|
<br><br>
|
|
<div class="prot">
|
|
char *sftp_canonicalize_path(SFTP_SESSION *sftp, char *path);
|
|
</div>
|
|
gives the canonicalized form of some path. You have to
|
|
free the pointer given in return.<br>
|
|
(returns NULL if error).
|
|
<br><br>
|
|
|
|
(a function to make proper SFTP_ATTRIBUTES structures is on the way )
|
|
|
|
<h3>D) Closing the session</h3>
|
|
<div class="prot">
|
|
void sftp_free(SFTP_SESSION *sftp);
|
|
</div>
|
|
it closes the sftp channel and subsystem.
|
|
</div>
|
|
|
|
<h2>7- Handling the errors</h2>
|
|
<div class="tout">
|
|
When some function returns an error code, it's allways possible to get an
|
|
english message describing the problem. the function ssh_get_error()
|
|
returns a pointer to the static error buffer.<br>
|
|
ssh_error_code() returns the error code number. it's declared as an enum:<br>
|
|
SSH_NO_ERROR, SSH_REQUEST_DENIED, SSH_INVALID_REQUEST, SSH_CONNECTION_LOST,
|
|
SSH_FATAL, SSH_INVALID_DATA.<br><br>
|
|
SSH_REQUEST_DENIED means the ssh server refused your request but the situation is
|
|
recoverable. the others mean something happened to the connection (some
|
|
encryption problems, server problems, library bug, ...).<br>
|
|
SSH_INVALID_REQUEST means the library got some garbage from server. (But might be
|
|
recoverable).<br>
|
|
SSH_FATAL means the connection has an important problem and isn't probably
|
|
recoverable.<br>
|
|
<br>
|
|
Most of time, the error returned are SSH_FATAL, but some functions (generaly the
|
|
<i>ssh_request_*</i> ones) may fail because of server denying request. In these cases, SSH_REQUEST_DENIED is returned.<br><br>
|
|
|
|
You'll see in the prototype SSH_SESSION *session. That's because for thread
|
|
safety, error messages that can be attached to a session aren't static
|
|
anymore. So, any error that could happen during ssh_getopt(), options_* or
|
|
ssh_connect() will be retreavable giving NULL as argument.<br>
|
|
<br>
|
|
<div class="prot">
|
|
char *ssh_get_error(SSH_SESSION *session);
|
|
</div>
|
|
returns a pointer to a static message error from the given session. No
|
|
message freeing is needed.<br><br>
|
|
<div class="prot">
|
|
enum ssh_error ssh_get_error_code(SSH_SESSION *session);
|
|
</div>
|
|
returns the error code that last happened along with the message.
|
|
<br><br>
|
|
</div>
|
|
|
|
<h2>8- Final word</h2>
|
|
<div class="tout">
|
|
I made this library because nothing in the Open source or free software community was existing yet. This project is a very personnal one as it's the first "useful" thing I ever wrote.
|
|
I hope it fits your needs, but remember the experimental state of libssh : if
|
|
something doesn't work, please mail me. If something lacks, please ask for it.
|
|
If something stinks, please write a patch and send it !
|
|
</div>
|
|
|
|
</body>
|
|
</html>
|