Rdtfguf
Rdtfguf
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return 0;
}
The following screenshot shows ssh_command.c being compiled and run on Linux:
The preceding screenshot shows connecting to the local OpenSSH server and executing
the
ls -l command. The ssh_command code faithfully prints the output of that command
(which is a file listing for the user's home directory).
The libssh library function ssh_channel_request_exec() is useful to execute a
single
command. However, SSH also supports methods for opening a fully interactive remote
shell. Generally, a session channel is opened as shown previously. Then the libssh
library function ssh_channel_request_pty() is called to initialize a remote shell.
The libssh library provides many functions to send and receive data this way.
Please refer
to the libssh documentation for more information.
Now that you're able to execute a remote command and receive its output, it may
also be
useful to transfer files. Let's consider that next.
Downloading a file
The Secure Copy Protocol (SCP) provides a method to transfer files. It supports
both
uploading and downloading files.
libssh makes using SCP easy. This chapter's code repository contains an example,
ssh_download.c, which shows the basic method for downloading a file over SCP with
libssh.
Establishing SSH Connections with libssh Chapter 11
[ 320 ]
After the SSH session is started and the user is authenticated, ssh_download.c
prompts
the user for the remote filename using the following code:
/*ssh_download.c excerpt*/
printf("Remote file to download: ");
char filename[128];
fgets(filename, sizeof(filename), stdin);
filename[strlen(filename)-1] = 0;
A new SCP session is initialized by calling the libssh library function
ssh_scp_new(), as
shown in the following code:
/*ssh_download.c excerpt*/
ssh_scp scp = ssh_scp_new(ssh, SSH_SCP_READ, filename);
if (!scp) {
fprintf(stderr, "ssh_scp_new() failed.\n%s\n",
ssh_get_error(ssh));
return 1;
}
In the preceding code, SSH_SCP_READ is passed to ssh_scp_new(). This specifies that
we
are going to use the new SCP session for downloading files. The SSH_SCP_WRITE
option
would be used to upload files. The libssh library also provides the
SSH_SCP_RECURSIVE option to assist with uploading or downloading entire directory
trees.
After the SCP session is created successfully, ssh_scp_init() must be called to
initialize
the SCP channel. The following code shows this:
/*ssh_download.c excerpt*/
if (ssh_scp_init(scp) != SSH_OK) {
fprintf(stderr, "ssh_scp_init() failed.\n%s\n",
ssh_get_error(ssh));
return 1;
}
ssh_scp_pull_request() must be called to begin the file download. This function
returns SSH_SCP_REQUEST_NEWFILE to indicate that the remote host is going to begin
sending a new file. The following code shows this:
/*ssh_download.c excerpt*/
if (ssh_scp_pull_request(scp) != SSH_SCP_REQUEST_NEWFILE) {
Establishing SSH Connections with libssh Chapter 11
[ 321 ]
fprintf(stderr, "ssh_scp_pull_request() failed.\n%s\n",
ssh_get_error(ssh));
return 1;
}
libssh provides some methods we can use to retrieve the remote filename, file size,
and
permissions. The following code retrieves these values and prints them to the
console:
/*ssh_download.c excerpt*/
int fsize = ssh_scp_request_get_size(scp);
char *fname = strdup(ssh_scp_request_get_filename(scp));
int fpermission = ssh_scp_request_get_permissions(scp);
printf("Downloading file %s (%d bytes, permissions 0%o\n",
fname, fsize, fpermission);
free(fname);
Once the file size is known, we can allocate space to store it in memory. This is
done using
malloc() as shown in the following code:
/*ssh_download.c excerpt*/
char *buffer = malloc(fsize);
if (!buffer) {
fprintf(stderr, "malloc() failed.\n");
return 1;
}
Our program then accepts the new file request with ssh_scp_accept_request() and
downloads the file with ssh_scp_read(). The following code shows this:
/*ssh_download.c excerpt*/
ssh_scp_accept_request(scp);
if (ssh_scp_read(scp, buffer, fsize) == SSH_ERROR) {
fprintf(stderr, "ssh_scp_read() failed.\n%s\n",
ssh_get_error(ssh));
return 1;
}
Establishing SSH Connections with libssh Chapter 11
[ 322 ]
The downloaded file can be printed to the screen with a simple call to printf().
When
we're finished with the file data, it's important to free the allocated space too.
The following
code prints out the file's contents and frees the allocated memory:
/*ssh_download.c excerpt*/
printf("Received %s:\n", filename);
printf("%.*s\n", fsize, buffer);
free(buffer);
An additional call to ssh_scp_pull_request() should return SSH_SCP_REQUEST_EOF.
This indicates that we received the entire file from the remote host. The following
code
checks for the end-of-file request from the remote host:
/*ssh_download.c excerpt*/
if (ssh_scp_pull_request(scp) != SSH_SCP_REQUEST_EOF) {
fprintf(stderr, "ssh_scp_pull_request() unexpected.\n%s\n",
ssh_get_error(ssh));
return 1;
}
The preceding code is simplified a bit. The remote host could also return other
values
which aren't necessarily errors. For example, if ssh_scp_pull_request() returns
SSH_SCP_REQUEST_WARNING, then the remote host has sent a warning. This warning can
be read by calling ssh_scp_request_get_warning(), but, in any case,
ssh_scp_pull_request() should be called again.
After the file is received, ssh_scp_close() and ssh_scp_free() should be used to
free
resources as shown in the following code excerpt:
/*ssh_download.c excerpt*/
ssh_scp_close(scp);
ssh_scp_free(scp);
After your program is done with the SSH session, don't forget to call
ssh_disconnect()
and ssh_free() as well.
Establishing SSH Connections with libssh Chapter 11
[ 323 ]
The entire file-downloading example is included with this chapter's code as
ssh_download.c.
You can compile ssh_download.c with the following command on Windows using
MinGW:
gcc ssh_download.c -o ssh_download.exe -lssh
On Linux and macOS, the command to compile ssh_download.c is as follows:
gcc ssh_download.c -o ssh_download -lssh
The following screenshot shows ssh_download.c being successfully compiled and used
on Linux to download a file:
As you can see from the preceding screenshot, downloading a file using SSH and SCP
is
pretty straightforward. This can be a useful way to transfer data between computers
securely.
Establishing SSH Connections with libssh Chapter 11
[ 324 ]
Summary
This chapter provided a cursory overview of the SSH protocol and how to use it with
libssh. We learned a lot about authentication with the SSH protocol, and how the
server
and client must both authenticate for security. Once the connection was
established, we
implemented a simple program to execute a command on a remote host. We also saw how
libssh makes downloading a file using SCP very easy.
SSH provides a secure communication channel, which effectively denies eavesdroppers
the
meaning of intercepted communication.
In the next chapter, Chapter 12, Network Monitoring and Security, we continue with
the
security theme by looking at tools that can effectively eavesdrop on non-secure
communication channels.
Questions
Try these questions to test your knowledge from this chapter:
1. What is a significant downside of using Telnet?
2. Which port does SSH typically run on?
3. Why is it essential that the client authenticates the SSH server?
4. How is the server typically authenticated?
5. How is the SSH client typically authenticated?
The answers to this questions can be found in Appendix A, Answers to Questions.
Establishing SSH Connections with libssh Chapter 11
[ 325