Name

Dropbear — scp client support

Synopsis

#include <dropbear.h>
      

int cyg_dropbear_scp_open(cyg_dropbear_scp_handle* handle, const struct sockaddr_storage* addr, const cyg_dropbear_authenticate* auth, const char* path, int flags, size_t* len, mode_t mode);

ssize_t cyg_dropbear_scp_write(cyg_dropbear_scp_handle* handle, const void* buf, size_t len);

ssize_t cyg_dropbear_scp_read(cyg_dropbear_scp_handle* handle, void* buf, size_t len);

void cyg_dropbear_scp_close(cyg_dropbear_scp_handle* handle);

Description

The scp client support allows eCos applications to read and write files on a remote server over a secure channel. It is implemented as a thin layer over the generic client-side support and the same caveats regarding security implications etc. are applicable. The package comes with a testcase tests/scptest1.c which can serve as example code.

API

The scp API consists of just four functions. cyg_dropbear_scp_open is used to establish a secure connection to a remote ssh server, run the scp command on that server to handle the remote file I/O. and perform some initial protocol operations. The data can then be transferred using repeated calls to cyg_dropbear_scp_read and cyg_dropbear_scp_write. Finally cyg_dropbear_scp_close can be used to shut down the connection. All calls make use of a handle structure to hold per-connection state:

typedef struct cyg_dropbear_scp_handle {
    cyg_dropbear_cli_handle     db_cli_handle;
    …
} cyg_dropbear_scp_handle;

The main field of interest is db_cli_handle.db_error which will contain a suitable error message if a connect operation fails. Typical code to write to a remote file would look like this:

<global sockaddr_storage structure containing a suitable address>

<global cyg_dropbear_authenticate structure appropriately filled in>

void
write_remote_file(char* buf, int len)
{
    cyg_dropbear_scp_handle  handle;
    int                      xfrd;

    if (!cyg_dropbear_scp_open(&handle, <addr>, <auth>,
                               "/tmp/out", O_WRONLY, &len,
                               S_IRUSR | S_IWUSR)) {
        <report handle.db_cli_handle.db_error to the user>
        return
    }

    for (xfrd = 0; xfrd < len; ) {
        <use cyg_dropbear_scp_write to send a chunk to the remote server>
    }

    cyg_dropbear_scp_close(&handle);
}

The code for reading a remote file is very similar:

void
read_remote_file(char* buf, int maxlen)
{
    cyg_dropbear_scp_handle handle;
    int len;

    if (!cyg_dropbear_scp_open(&handle, <addr>, <auth>,
                               "/tmp/in", O_RDONLY, &len, 0)) {
        <report handle.db_cli_handle.db_error to the user>
        return
    }
    if (len > maxlen) {
        <decide what to do>
    }

    for (xfrd = 0; xfrd < len; ) {
        <use cyg_dropbear_scp_read to read a chunk from the remote server>
    }

    cyg_dropbear_scp_close(&handle);
}

Connecting

The function cyg_dropbear_scp_open is used to establish a secure connection to a remote server and to open a file on that remote system. It takes seven arguments:

handle
A pointer to a cyg_dropbear_scp_handle structure. This will be filled in and managed by the dropbear code, and should only be read by the eCos application. The structure must remain valid for the duration of the scp operation, until after the call to cyg_dropbear_scp_close.
addr
The full address of the ssh server on the remote machine. Typically this will actually be a sockaddr_in or sockaddr_in6 structure (assuming CYGPKG_NET_INET6 is enabled). The ssh server must be accessible via this address irrespective of any firewall filtering, tcpwrapper settings (/etc/hosts.allow and /etc/hosts.deny, if enabled), and ssh server settings (/etc/ssh/sshd_config, especially the AddressFamily, ListenAddress and Port settings). Usually the port number will be htons(22) but it is possible to connect to an alternative ssh server listening on a different port, if desired. The dropbear code does not examine the contents of the address, it simply passes the address on to the TCP/IP stack's connect function.
auth
This structure holds all the authentication information and is discussed in detail in the documentation for the Ssh client support.
path
The full path of a file on the remote system.
flags
This should be O_RDONLY to read a file on the remote system, or O_WRONLY to write a file.
len
The scp protocol requires that the total amount of data to be transferred is known at the start of the transfer. len should be a pointer to an ssize_t variable. For a write operation the application should initialize that variable with the total transfer size before calling cyg_dropbear_scp_open. For a read operation the dropbear code will set that variable to the file size, thus letting the application know how much data it should read.
mode
This field is only relevant when writing a file, and is used to set the access mask for the file on the remote system as per e.g. the Linux chmod system call. It will be some combination of the S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, and S_IXOTH constants defined in the <sys/stat.h> header file. Note that the application should use the eCos values for these constants and the dropbear code will automatically translate them to the Linux equivalents. Also note that the settings are subject to the account's umask value on the remote server.

The cyg_dropbear_scp_open function will attempt to make a secure connection to the remote server, start the scp on that server, and perform the initial protocol operations. If it returns successfully then the application can proceed with the data transfers using cyg_dropbear_scp_write or cyg_dropbear_scp_read. If it fails for any reason then an error message will be written to the db_cli_handle.db_error field of the handle. Due to the complexity of the operation and the implementation's need for a background worker thread that runs the bulk of the dropbear code, the value in errno may not give an accurate indication of the error(s) that occurred.

Transferring Data

Once an scp connection has been established the application can transfer data using cyg_dropbear_scp_write if the remote file was opened with O_WRONLY, or cyg_dropbear_scp_read if O_RDONLY was used. In addition to transferring the data these functions catch certain error conditions and manage the scp protocol, so their use is preferable to any attempt to read or write the data directly over sockets.

cyg_dropbear_scp_read will return the amount of data actually read during this call, which may be less than the amount requested because of buffering effects. Typically this function will be called in a loop until all required data has been transferred. A return value of 0 indicates an end-of-file condition, usually because the transfer is complete but possibly because the connection has been broken. A return value of -1 indicates some unexpected and indeterminate error condition.

cyg_dropbear_scp_write will return the amount of data actually written during this call. Usually this will be the amount requested, but may be less because of buffering effects. Typically this function will be called in a loop until all required data has been transferred. For large transfers it may be desirable to split the transfer into a number of smaller chunks, effectively spreading the cpu cycle and buffering costs over a longer period of time. A return value of 0 or -1 indicates an unexpected and indeterminate error condition.

Closing a Connection

At the end of a transfer cyg_dropbear_scp_close should be used to shut down the connection. The handle structure will no longer be needed after this call returns.

Normally the application should transfer exactly the amount of data requested. For a write this is the size specified during the open call. For a read this is the size filled in by the dropbear code during the open call. It is possible to call cyg_dropbear_scp_close before the transfer has completed. For a read this is harmless. For a write, some or all of the data transferred so far may be discarded by the remote scp command, and the exact behaviour is unpredictable.

Configuration

There are no configuration options specific to the client-side scp support. However this support is built on top of the generic ssh client-side API so all configuration options relevant to that also affect scp operations.

Testing

The dropbear package comes with a testcase tests/scptest1.c. However this testcase is not built by default. It will only be built if the configuration enables the building of the generic client-side testcase tests/clitest1.c, and will use the same configuration options to identify the remote server and to provide the authentication information.