diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/forwarding.dox | 63 | ||||
-rw-r--r-- | doc/guided_tour.dox | 38 | ||||
-rw-r--r-- | doc/introduction.dox | 2 | ||||
-rw-r--r-- | doc/scp.dox | 252 | ||||
-rw-r--r-- | doc/sftp.dox | 2 | ||||
-rw-r--r-- | doc/tbd.dox | 31 |
6 files changed, 349 insertions, 39 deletions
diff --git a/doc/forwarding.dox b/doc/forwarding.dox new file mode 100644 index 00000000..f6a2869e --- /dev/null +++ b/doc/forwarding.dox @@ -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 *** + +*/ diff --git a/doc/guided_tour.dox b/doc/guided_tour.dox index 3d41a3b8..5f7a1003 100644 --- a/doc/guided_tour.dox +++ b/doc/guided_tour.dox @@ -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 programmer. If you want to use those subsystems, instead of a channel, you'll usually open a "sftp session" or a "scp session". - -All the libssh functions which return an error code also set an error message. -Error codes are typically SSH_ERROR for integer values, or NULL for pointers. @subsection setup Creating the session and setting options @@ -418,12 +415,41 @@ int show_remote_processes(ssh_session session) } @endcode -That's the end of our step-by-step discovery of a SSH connection. -The next chapter describes more in depth the authentication mechanisms. - @see @ref opening_shell @see @ref remote_commands @see @ref sftp_subsystem @see @ref scp_subsystem + +@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. + + */ diff --git a/doc/introduction.dox b/doc/introduction.dox index 9026a9d1..4c51d140 100644 --- a/doc/introduction.dox +++ b/doc/introduction.dox @@ -41,6 +41,8 @@ Table of contents: @subpage scp +@subpage forwarding + @subpage tbd */ diff --git a/doc/scp.dox b/doc/scp.dox index 811b51fd..fdf589eb 100644 --- a/doc/scp.dox +++ b/doc/scp.dox @@ -2,6 +2,256 @@ @page scp Chapter 6: 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. */ diff --git a/doc/sftp.dox b/doc/sftp.dox index 6f9bcde7..7306be57 100644 --- a/doc/sftp.dox +++ b/doc/sftp.dox @@ -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. -@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, you don't handle directly the SSH channels. Instead, you open a "SFTP session". diff --git a/doc/tbd.dox b/doc/tbd.dox index 4ee5ab84..1e256fdb 100644 --- a/doc/tbd.dox +++ b/doc/tbd.dox @@ -1,40 +1,9 @@ /** @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 *** To be written *** -@section forwarding_connections Forwarding connections - -*** To be written *** - @section sshd Writing a libssh-based server *** To be written *** |