mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-07-29 13:01:13 +03:00
doc: More work on the tutorial.
This commit is contained in:
committed by
Andreas Schneider
parent
bcf4e56fe0
commit
31ad140d20
63
doc/forwarding.dox
Normal file
63
doc/forwarding.dox
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
@page forwarding Chapter 7: Forwarding connections
|
||||||
|
@section forwarding_connections Forwarding connections
|
||||||
|
|
||||||
|
Port forwarding comes in SSH protocol in two different flavours:
|
||||||
|
direct or reverse port forwarding. Direct port forwarding is also
|
||||||
|
named local port forwardind, and reverse port forwarding is also called
|
||||||
|
remote port forwarding.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@subsection forwarding_direct Direct port forwarding
|
||||||
|
|
||||||
|
Direct port forwarding is from client to server. The client opens a tunnel,
|
||||||
|
and forwards whatever data to the server. Then, the server connects to an
|
||||||
|
end point. The end point can reside on another machine or on the SSH
|
||||||
|
server itself.
|
||||||
|
|
||||||
|
Example of use of direct port forwarding:
|
||||||
|
@verbatim
|
||||||
|
Mail client application Google Mail
|
||||||
|
| ^
|
||||||
|
5555 (arbitrary) |
|
||||||
|
| 143 (IMAP2)
|
||||||
|
V |
|
||||||
|
SSH client =====> SSH server
|
||||||
|
|
||||||
|
Legend:
|
||||||
|
--P-->: port connexion through port P
|
||||||
|
=====>: SSH tunnel
|
||||||
|
@endverbatim
|
||||||
|
A mail client connects to port 5555 of a client. An encrypted tunnel is
|
||||||
|
established to the server. The server connects to port 143 of Google Mail (the
|
||||||
|
end point). Now the local mail client can retreive mail.
|
||||||
|
|
||||||
|
|
||||||
|
@subsection forwarding_reverse Reverse port forwarding
|
||||||
|
|
||||||
|
The reverse forwarding is slightly different. It goes from server to client,
|
||||||
|
even though the client has the initiative of establishing the tunnel.
|
||||||
|
Once the tunnel is established, the server will listen on a port. Whenever
|
||||||
|
a connection to this port is made, the server forwards the data to the client.
|
||||||
|
|
||||||
|
Example of use of reverse port forwarding:
|
||||||
|
@verbatim
|
||||||
|
Local mail server Mail client application
|
||||||
|
^ |
|
||||||
|
| 5555 (arbitrary)
|
||||||
|
143 (IMAP2) |
|
||||||
|
| V
|
||||||
|
SSH client <===== SSH server
|
||||||
|
|
||||||
|
Legend:
|
||||||
|
--P-->: port connexion through port P
|
||||||
|
=====>: SSH tunnel
|
||||||
|
@endverbatim
|
||||||
|
In this example, the SSH client establishes the tunnel,
|
||||||
|
but it is used to forward the connections established at
|
||||||
|
the server to the client.
|
||||||
|
|
||||||
|
*** To be written ***
|
||||||
|
|
||||||
|
*/
|
@ -36,9 +36,6 @@ A SSH session goes through the following steps:
|
|||||||
The sftp and scp subsystems use channels, but libssh hides them to
|
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,
|
the programmer. If you want to use those subsystems, instead of a channel,
|
||||||
you'll usually open a "sftp session" or a "scp session".
|
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
|
@subsection setup Creating the session and setting options
|
||||||
@ -418,12 +415,41 @@ int show_remote_processes(ssh_session session)
|
|||||||
}
|
}
|
||||||
@endcode
|
@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 opening_shell
|
||||||
@see @ref remote_commands
|
@see @ref remote_commands
|
||||||
@see @ref sftp_subsystem
|
@see @ref sftp_subsystem
|
||||||
@see @ref scp_subsystem
|
@see @ref scp_subsystem
|
||||||
|
|
||||||
|
|
||||||
|
@subsection errors Handling the errors
|
||||||
|
|
||||||
|
All the libssh functions which return an error value also set an English error message
|
||||||
|
describing the problem.
|
||||||
|
|
||||||
|
Error values are typically SSH_ERROR for integer values, or NULL for pointers.
|
||||||
|
|
||||||
|
The function ssh_get_error() returns a pointer to the static error message.
|
||||||
|
|
||||||
|
ssh_error_code() returns the error code number : SSH_NO_ERROR,
|
||||||
|
SSH_REQUEST_DENIED, SSH_INVALID_REQUEST, SSH_CONNECTION_LOST, SSH_FATAL,
|
||||||
|
or SSH_INVALID_DATA. 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, ...).
|
||||||
|
SSH_INVALID_REQUEST means the library got some garbage from server, but
|
||||||
|
might be recoverable. SSH_FATAL means the connection has an important
|
||||||
|
problem and isn't probably recoverable.
|
||||||
|
|
||||||
|
Most of time, the error returned are SSH_FATAL, but some functions
|
||||||
|
(generaly the ssh_request_xxx ones) may fail because of server denying request.
|
||||||
|
In these cases, SSH_REQUEST_DENIED is returned.
|
||||||
|
|
||||||
|
ssh_get_error() and ssh_get_error_code() take a ssh_session as a parameter.
|
||||||
|
That's for thread safety, error messages that can be attached to a session
|
||||||
|
aren't static anymore. Any error that happens during ssh_options_xxx()
|
||||||
|
or ssh_connect() (i.e., outside of any session) can be retrieved by
|
||||||
|
giving NULL as argument.
|
||||||
|
|
||||||
|
The SFTP subsystem has its own error codes, in addition to libssh ones.
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@ -41,6 +41,8 @@ Table of contents:
|
|||||||
|
|
||||||
@subpage scp
|
@subpage scp
|
||||||
|
|
||||||
|
@subpage forwarding
|
||||||
|
|
||||||
@subpage tbd
|
@subpage tbd
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
252
doc/scp.dox
252
doc/scp.dox
@ -2,6 +2,256 @@
|
|||||||
@page scp Chapter 6: The SCP subsystem
|
@page scp Chapter 6: The SCP subsystem
|
||||||
@section scp_subsystem The SCP subsystem
|
@section scp_subsystem The SCP subsystem
|
||||||
|
|
||||||
*** To be written ***
|
The SCP subsystem has far less functionnality than the SFTP subsystem.
|
||||||
|
However, if you only need to copy files from and to the remote system,
|
||||||
|
it does its job.
|
||||||
|
|
||||||
|
|
||||||
|
@subsection scp_session Opening and closing a SCP session
|
||||||
|
|
||||||
|
Like in the SFTP subsystem, you don't handle the SSH channels directly.
|
||||||
|
Instead, you open a "SCP session".
|
||||||
|
|
||||||
|
When you open your SCP session, you have to choose between read or write mode.
|
||||||
|
You can't do both in the same session. So you specify either SSH_SCP_READ or
|
||||||
|
SSH_SCP_WRITE as the second parameter of function ssh_scp_new().
|
||||||
|
|
||||||
|
Another important mode flag for opening your SCP session is SSH_SCP_RECURSIVE.
|
||||||
|
When you use SSH_SCP_RECURSIVE, you declare that you are willing to emulate
|
||||||
|
the behaviour of "scp -r" command in your program, no matter it is for
|
||||||
|
reading or for writing.
|
||||||
|
|
||||||
|
Once your session is created, you initialize it with ssh_scp_init(). When
|
||||||
|
you have finished transferring files, you terminate the SCP connection with
|
||||||
|
ssh_scp_close(). Finally, you can dispose the SCP connection with
|
||||||
|
ssh_scp_free().
|
||||||
|
|
||||||
|
The example below does the maintenance work to open a SCP connection for writing in
|
||||||
|
recursive mode:
|
||||||
|
|
||||||
|
@code
|
||||||
|
int scp_write(ssh_session session)
|
||||||
|
{
|
||||||
|
ssh_scp scp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
scp = ssh_scp_new
|
||||||
|
(session, SSH_SCP_WRITE | SSH_SCP_RECURSIVE, ".");
|
||||||
|
if (scp == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error allocating scp session: %s\n", ssh_get_error(session));
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_scp_init(scp);
|
||||||
|
if (rc != SSH_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error initializing scp session: %s\n", ssh_get_error(session));
|
||||||
|
ssh_scp_free(scp);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
ssh_scp_close(scp);
|
||||||
|
ssh_scp_free(scp);
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
The example below shows how to open a connection to read a single file:
|
||||||
|
|
||||||
|
@code
|
||||||
|
int scp_read(ssh_session session)
|
||||||
|
{
|
||||||
|
ssh_scp scp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
scp = ssh_scp_new
|
||||||
|
(session, SSH_SCP_READ, "helloworld/helloworld.txt");
|
||||||
|
if (scp == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error allocating scp session: %s\n", ssh_get_error(session));
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_scp_init(scp);
|
||||||
|
if (rc != SSH_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error initializing scp session: %s\n", ssh_get_error(session));
|
||||||
|
ssh_scp_free(scp);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
ssh_scp_close(scp);
|
||||||
|
ssh_scp_free(scp);
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
|
||||||
|
@subsection scp_write Creating files and directories
|
||||||
|
|
||||||
|
You create directories with ssh_scp_push_directory(). In recursive mode,
|
||||||
|
you are placed in this directory once it is created. If the directory
|
||||||
|
already exists and if you are in recursive mode, you simply enter that
|
||||||
|
directory.
|
||||||
|
|
||||||
|
Creating files is done in two steps. First, you prepare the writing with
|
||||||
|
ssh_scp_push_file(). Then, you write the data with ssh_scp_write().
|
||||||
|
The length of the data to write must be identical between both function calls.
|
||||||
|
There's no need to "open" nor "close" the file, this is done automatically
|
||||||
|
on the remote end. If the file already exists, it is overwritten and truncated.
|
||||||
|
|
||||||
|
The following example creates a new directory named "helloworld/", then creates
|
||||||
|
a file named "helloworld.txt" in that directory:
|
||||||
|
|
||||||
|
@code
|
||||||
|
int scp_helloworld(ssh_session session, ssh_scp scp)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
const char *helloworld = "Hello, world!\n";
|
||||||
|
int length = strlen(helloworld);
|
||||||
|
|
||||||
|
rc = ssh_scp_push_directory(scp, "helloworld", S_IRWXU);
|
||||||
|
if (rc != SSH_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Can't create remote directory: %s\n", ssh_get_error(session));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_scp_push_file
|
||||||
|
(scp, "helloworld.txt", length, S_IRUSR | S_IWUSR);
|
||||||
|
if (rc != SSH_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Can't open remote file: %s\n", ssh_get_error(session));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_scp_write(scp, helloworld, length);
|
||||||
|
if (rc != SSH_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Can't write to remote file: %s\n", ssh_get_error(session));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
|
||||||
|
@subsection scp_recursive_write Copying full directory trees to the remote server
|
||||||
|
|
||||||
|
Let's say you want to copy the following tree of files to the remote site:
|
||||||
|
|
||||||
|
@verbatim
|
||||||
|
+-- file1
|
||||||
|
+-- B --+
|
||||||
|
| +-- file2
|
||||||
|
-- A --+
|
||||||
|
| +-- file3
|
||||||
|
+-- C --+
|
||||||
|
+-- file4
|
||||||
|
@endverbatim
|
||||||
|
|
||||||
|
You would do it that way:
|
||||||
|
- open the session in recursive mode
|
||||||
|
- enter directory A
|
||||||
|
- enter its subdirectory B
|
||||||
|
- create file1 in B
|
||||||
|
- create file2 in B
|
||||||
|
- leave directory B
|
||||||
|
- enter subdirectory C
|
||||||
|
- create file3 in C
|
||||||
|
- create file4 in C
|
||||||
|
- leave directory C
|
||||||
|
- leave directory A
|
||||||
|
|
||||||
|
To leave a directory, call ssh_scp_leave_directory().
|
||||||
|
|
||||||
|
|
||||||
|
@subsection scp_read Reading files and directories
|
||||||
|
|
||||||
|
|
||||||
|
To receive files, you pull requests from the other side with ssh_scp_pull_request().
|
||||||
|
If this function returns SSH_SCP_REQUEST_NEWFILE, then you must get ready for
|
||||||
|
the reception. You can get the size of the data to receive with ssh_scp_request_get_size()
|
||||||
|
and allocate a buffer accordingly. When you are ready, you accept the request with
|
||||||
|
ssh_scp_accept_request(), then read the data with ssh_scp_read().
|
||||||
|
|
||||||
|
The following example receives a single file. The name of the file to
|
||||||
|
receive has been given earlier, when the scp session was opened:
|
||||||
|
|
||||||
|
@code
|
||||||
|
int scp_receive(ssh_session session, ssh_scp scp)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
int size, mode;
|
||||||
|
char *filename, *buffer;
|
||||||
|
|
||||||
|
rc = ssh_scp_pull_request(scp);
|
||||||
|
if (rc != SSH_SCP_REQUEST_NEWFILE)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error receiving information about file: %s\n", ssh_get_error(session));
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = ssh_scp_request_get_size(scp);
|
||||||
|
filename = strdup(ssh_scp_request_get_filename(scp));
|
||||||
|
mode = ssh_scp_request_get_permissions(scp);
|
||||||
|
printf("Receiving file %s, size %d, permisssions 0%o\n", filename, size, mode);
|
||||||
|
free(filename);
|
||||||
|
|
||||||
|
buffer = malloc(size);
|
||||||
|
if (buffer == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Memory allocation error\n");
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_scp_accept_request(scp);
|
||||||
|
rc = ssh_scp_read(scp, buffer, size);
|
||||||
|
if (rc == SSH_ERROR)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error receiving file data: %s\n", ssh_get_error(session));
|
||||||
|
free(buffer);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
printf("Done\n");
|
||||||
|
|
||||||
|
write(1, buffer, size);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
rc = ssh_scp_pull_request(scp);
|
||||||
|
if (rc != SSH_SCP_REQUEST_EOF)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Unexpected request: %s\n", ssh_get_error(session));
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
In this example, since we just requested a single file, we expect ssh_scp_request()
|
||||||
|
to return SSH_SCP_REQUEST_NEWFILE first, then SSH_SCP_REQUEST_EOF. That's quite a
|
||||||
|
naive approach; for example, the remote server might send a warning as well
|
||||||
|
(return code SSH_SCP_REQUEST_WARNING) and the example would fail. A more comprehensive
|
||||||
|
reception program would receive the requests in a loop and analyze them carefully
|
||||||
|
until SSH_SCP_REQUEST_EOF has been received.
|
||||||
|
|
||||||
|
|
||||||
|
@subsection scp_recursive_read Receiving full directory trees from the remote server
|
||||||
|
|
||||||
|
If you opened the SCP session in recursive mode, the remote end will be
|
||||||
|
telling you when to change directory.
|
||||||
|
|
||||||
|
In that case, when ssh_scp_pull_request() answers
|
||||||
|
SSH_SCP_REQUEST_NEWDIRECTORY, you should make that local directory (if
|
||||||
|
it does not exist yet) and enter it. When ssh_scp_pull_request() answers
|
||||||
|
SSH_SCP_REQUEST_ENDDIRECTORY, you should leave the current directory.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@ -29,7 +29,7 @@ The current implemented version of the SFTP protocol is version 3. All functions
|
|||||||
aren't implemented yet, but the most important are.
|
aren't implemented yet, but the most important are.
|
||||||
|
|
||||||
|
|
||||||
@subsection sftp_section Opening and closing a SFTP session
|
@subsection sftp_session Opening and closing a SFTP session
|
||||||
|
|
||||||
Unlike with remote shells and remote commands, when you use the SFTP subsystem,
|
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".
|
you don't handle directly the SSH channels. Instead, you open a "SFTP session".
|
||||||
|
31
doc/tbd.dox
31
doc/tbd.dox
@ -1,40 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
@page tbd To be done
|
@page tbd To be done
|
||||||
@section errors Handling the errors
|
|
||||||
|
|
||||||
When some function returns an error code, it's always possible to get an
|
|
||||||
english message describing the problem.
|
|
||||||
|
|
||||||
The function ssh_get_error() returns a pointer to the static error buffer.
|
|
||||||
|
|
||||||
ssh_error_code() returns the error code number : SSH_NO_ERROR,
|
|
||||||
SSH_REQUEST_DENIED, SSH_INVALID_REQUEST, SSH_CONNECTION_LOST, SSH_FATAL,
|
|
||||||
or SSH_INVALID_DATA. 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, ...).
|
|
||||||
SSH_INVALID_REQUEST means the library got some garbage from server, but
|
|
||||||
might be recoverable. SSH_FATAL means the connection has an important
|
|
||||||
problem and isn't probably recoverable.
|
|
||||||
|
|
||||||
Most of time, the error returned are SSH_FATAL, but some functions
|
|
||||||
(generaly the ssh_request_xxx ones) may fail because of server denying request.
|
|
||||||
In these cases, SSH_REQUEST_DENIED is returned.
|
|
||||||
|
|
||||||
ssh_get_error() and ssh_get_error_code() take a ssh_session as a parameter.
|
|
||||||
That's for thread safety, error messages that can be attached to a session
|
|
||||||
aren't static anymore. Any error that happens during ssh_options_xxx()
|
|
||||||
or ssh_connect() (i.e., outside of any session) can be retrieved by
|
|
||||||
giving NULL as argument.
|
|
||||||
|
|
||||||
|
|
||||||
@section threads Working with threads
|
@section threads Working with threads
|
||||||
|
|
||||||
*** To be written ***
|
*** To be written ***
|
||||||
|
|
||||||
@section forwarding_connections Forwarding connections
|
|
||||||
|
|
||||||
*** To be written ***
|
|
||||||
|
|
||||||
@section sshd Writing a libssh-based server
|
@section sshd Writing a libssh-based server
|
||||||
|
|
||||||
*** To be written ***
|
*** To be written ***
|
||||||
|
Reference in New Issue
Block a user