1
0
mirror of https://github.com/libssh2/libssh2.git synced 2026-10-28 17:01:54 +03:00
Files
libssh2/example/scp.c
Viktor Szakats f784c21dec test_ssh2, examples: avoid crash on NULL fingerprint
Also bail out right away to avoid other issues down the line.

Seen in CI when Libgcrypt could not negotiate keys with modern sshd
server on Ubuntu 26.04:
```
26: 1..2
26: Failure establishing SSH session: -5
26: Fingerprint: /home/runner/tests/test_sshd.test: line 151:  8233 Segmentation fault
         (core dumped) ${LIBSSH2_TEST_EXE_RUNNER:-} "${test}"
26: not ok 1 - sshd-test_ssh2
26: libssh2_session_handshake failed (-5): Unable to exchange encryption keys
```
Ref: https://github.com/libssh2/libssh2/actions/runs/28582866680/job/84747161004?pr=2174

Ref: #2174

Closes #2179
2026-07-02 19:41:05 +02:00

198 lines
5.2 KiB
C

/* Copyright (C) The libssh2 project and its contributors.
*
* Sample showing how to do a simple SCP transfer.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "libssh2_setup.h"
#include <libssh2.h>
#ifdef _WIN32
#define write(f, b, c) _write(f, b, (unsigned int)(c))
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include <stdio.h>
static const char *pubkey = "/home/username/.ssh/id_rsa.pub";
static const char *privkey = "/home/username/.ssh/id_rsa";
static const char *username = "username";
static const char *password = "password";
static const char *scppath = "/tmp/TEST";
int main(int argc, char *argv[])
{
uint32_t hostaddr;
libssh2_socket_t sock;
int i, auth_pw = 1;
struct sockaddr_in sin;
const char *fingerprint;
int rc;
LIBSSH2_SESSION *session = NULL;
LIBSSH2_CHANNEL *channel;
libssh2_struct_stat fileinfo;
libssh2_struct_stat_size got = 0;
#ifdef _WIN32
WSADATA wsadata;
rc = WSAStartup(MAKEWORD(2, 0), &wsadata);
if(rc) {
fprintf(stderr, "WSAStartup failed with error: %d\n", rc);
return 1;
}
#endif
if(argc > 1)
hostaddr = inet_addr(argv[1]);
else
hostaddr = htonl(0x7F000001);
if(argc > 2)
username = argv[2];
if(argc > 3)
password = argv[3];
if(argc > 4)
scppath = argv[4];
rc = libssh2_init(0);
if(rc) {
fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
return 1;
}
/* Ultra basic "connect to port 22 on localhost". Your code is
* responsible for creating the socket establishing the connection
*/
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == LIBSSH2_INVALID_SOCKET) {
fprintf(stderr, "failed to create socket.\n");
goto shutdown;
}
sin.sin_family = AF_INET;
sin.sin_port = htons(22);
sin.sin_addr.s_addr = hostaddr;
if(connect(sock, (struct sockaddr *)(&sin), sizeof(struct sockaddr_in))) {
fprintf(stderr, "failed to connect.\n");
goto shutdown;
}
/* Create a session instance */
session = libssh2_session_init();
if(!session) {
fprintf(stderr, "Could not initialize SSH session.\n");
goto shutdown;
}
/* ... start it up. This trades welcome banners, exchange keys,
* and setup crypto, compression, and MAC layers
*/
rc = libssh2_session_handshake(session, sock);
if(rc) {
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
goto shutdown;
}
/* At this point we have not yet authenticated. The first thing to do
* is check the hostkey's fingerprint against our known hosts Your app
* may have it hard coded, may go to a file, may present it to the
* user, that is your call
*/
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
fprintf(stderr, "Fingerprint: ");
if(!fingerprint) {
fprintf(stderr, "(null)");
goto shutdown;
}
else
for(i = 0; i < 20; i++)
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
fprintf(stderr, "\n");
if(auth_pw) {
/* We could authenticate via password */
if(libssh2_userauth_password(session, username, password)) {
fprintf(stderr, "Authentication by password failed.\n");
goto shutdown;
}
}
else {
/* Or by public key */
if(libssh2_userauth_publickey_fromfile(session, username,
pubkey, privkey,
password)) {
fprintf(stderr, "Authentication by public key failed.\n");
goto shutdown;
}
}
/* Request a file via SCP */
channel = libssh2_scp_recv2(session, scppath, &fileinfo);
if(!channel) {
fprintf(stderr, "Unable to open a session: %d\n",
libssh2_session_last_errno(session));
goto shutdown;
}
while(got < fileinfo.st_size) {
char mem[1024];
int amount = sizeof(mem);
ssize_t nread;
if((fileinfo.st_size - got) < amount)
amount = (int)(fileinfo.st_size - got);
nread = libssh2_channel_read(channel, mem, (size_t)amount);
if(nread > 0) {
ssize_t nwritten = write(1, mem, (size_t)nread);
if(nwritten != nread)
fprintf(stderr, "write failed: %ld != %ld\n",
(long)nread, (long)nwritten);
}
else if(nread < 0) {
fprintf(stderr, "libssh2_channel_read() failed: %ld\n",
(long)nread);
break;
}
got += nread;
}
libssh2_channel_free(channel);
shutdown:
if(session) {
libssh2_session_disconnect(session, "Normal Shutdown");
libssh2_session_free(session);
}
if(sock != LIBSSH2_INVALID_SOCKET) {
shutdown(sock, 2 /* SHUT_RDWR */);
LIBSSH2_SOCKET_CLOSE(sock);
}
fprintf(stderr, "all done\n");
libssh2_exit();
#ifdef _WIN32
WSACleanup();
#endif
return 0;
}