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 theAddressFamily
,ListenAddress
andPort
settings). Usually the port number will behtons(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'sconnect
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, orO_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 callingcyg_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 theS_IRUSR
,S_IWUSR
,S_IXUSR
,S_IRGRP
,S_IWGRP
,S_IXGRP
,S_IROTH
,S_IWOTH
, andS_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.
2024-03-18 | eCosPro License |