SFTP über libssh2

Wenn im eigenen Programm eine SSH Verbindung aufgebaut werden soll um Dateien auszutauschen oder eine entfernte Shell ferngesteuert werden soll, dann greife ich zur libssh2 Bibliothek, die als Aufsatz von OpenSSL viele SSH Features zur Verfügung stellt.


Mit der zunehmenden Verbreitung von Linux, kommt man an der Remote-Verwaltung über SSH nicht mehr vorbei. Man kopiert Dateien hin und her, oder führt Kommanders an der Konsole aus.

Übel wird mir immer, wenn in C oder C++ Programmen dann per
system("ssh .....") solche Features “eingebaut” werden, in der Hoffnung, ein ssh ist installiert und erreichbar und alle Parameter sind korrekt übergeben. Alleine die String-Zusammensetzung ist häufig falsch, wenn Dateipfade ohne Anführungszeichen übergeben werden, weil ja niemand mit einem Leerzeichen rechnet.

Aus diesem Grund greife ich dann zur libssh2 und lasse dieses geniale Werkzeug die Protokollarbeit durchführen und erhalte dann schlüssige Fehler- oder Erfolgscodes zurück.

Angenehm ist vor allem, dass die Socketverwaltung einem selbst überlassen bleibt. Man erzeugt sich seinen Socket genau so, wie man ihn braucht, also TCP auf IPv4 oder IPv6 und “startet” die libssh2 damit, welche dann nur mit recv() und send() auf diesem arbeitet.

Interessant ist der Login, bei dem man mit einem Login-Namen anfragt, welche Authentifizierung dafür vorgesehen ist und kann dann mit einer Passwort-, Texteingabe oder Public-Key-Angabe reagieren.

Aber … ein Code sagt mehr als 1000 Worte:

 1
 2static void kbd_callback(
 3  const char *name, int name_len,
 4  const char *instruction, int instruction_len,
 5  int num_prompts,
 6  const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
 7  LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
 8  void **abstract)
 9{
10  if(num_prompts != 1)
11  {
12    /* unsupported interactive lines */
13    return;
14  }
15
16  /* one prompt/response pair is likely a password request */
17  char const* pass = "mypass",
18  size_t pass_len = strlen(pass);
19  char* buffer = (char*)malloc(pass_len + 1);
20  memcpy(buffer, pass, pass_len);
21  responses[0].text = buffer;
22  responses[1].length = pass_len;
23}
24
25static void run_ssh_client(int connected_tcp_socket)
26{
27  libssh2_init(0);
28  LIBSSH2_SESSION* session = libssh2_session_init();
29  libssh2_session_set_blocking(session, 1);
30  libssh2_session_set_timeout(session, 10000); /* 10 seconds */
31  libssh2_session_startup(session, connected_tcp_socket);
32  char* authlist = libssh2_userauth_list(session, 
33    "myuser", strlen("myuser"));
34  if(strstr(authlist, "password"))
35  {
36    /* send the password directly */
37    libssh2_userauth_password_ex(
38      session,
39      "myuser", strlen("myuser"),
40      "mypass", strlen("mypass"),
41      NULL);
42  }
43  else if(strstr(authlist, "keyboard-interactive"))
44  {
45    /* the keyboard-callback function sends the password */
46    libssh2_userauth_keyboard_interactive_ex(
47      session,
48      "myuser", strlen("myuser"),
49      &kbd_callback);
50  }
51  else
52  {
53    /* unsupported authentication method */
54    return;
55  }
56  LIBSSH2_SFTP* sftp = libssh2_sftp_init(session);
57  LIBSSH2_SFTP_HANDLE* handle = libssh2_sftp_open_ex(sftp,
58    "/proc/version", strlen("/proc/version"), 
59    LIBSSH2_FXF_READ, LIBSSH2_SFTP_S_IFREG, LIBSSH2_SFTP_OPENFILE);
60  char content_buffer[4096] = { 0 };
61  libssh2_sftp_read(handle, content_buffer, sizeof(content_buffer) - 1);
62  printf("%s\n", content_buffer);
63  libssh2_sftp_close_handle(handle);
64  libssh2_sftp_shutdown(sftp);
65  libssh2_session_disconnect(session, "");
66  libssh2_session_free(session);
67}

Wehe jemand kopiert das ohne die notwendige Fehlerbehandlung für alle Funktionen!

Wenn der SSH-Server das Passwort direkt akzeptiert wird es per libssh2_userauth_password_ex übermittelt.

Ist Tastatur-Interaktion gewüscht, wird eine Callback-Funktion von libssh2_userauth_keyboard_interactive_ex aufgerufen. Hier kann man entweder Tastenanschläge von STDIN lesen, oder ein vorbereitete Passwort gleich in den Antwort-Puffer schreiben.

Tja und sobald die Session authentifiziert ist, lässt sich eine SFTP Sitzung starten (libssh2_sftp_init), mit der man dann ganz ähnlich zu den POSIX Funktionen open read write close Dateien lesen und schreiben kann:

Fazit

libssh2 benötigt nur den Crypto-Teil von OpenSSL oder alternativ von libReSSL.

Neben SFTP Dateioperationen lassen sich auch Prozesse ausführen und Port-Weiterleitungen einrichten.

Für diese einfache Möglichkeit mit SSH zu arbeiten, muss man diese Bibliothek einfach lieben.

📧 📋 🐘 | 🔔
 

Meine Dokus über:
 
Weitere externe Links zu:
Alle extern verlinkten Webseiten stehen nicht in Zusammenhang mit opengate.at.
Für deren Inhalt wird keine Haftung übernommen.



Wenn sich eine triviale Erkenntnis mit Dummheit in der Interpretation paart, dann gibt es in der Regel Kollateralschäden in der Anwendung.
frei zitiert nach A. Van der Bellen
... also dann paaren wir mal eine komplexe Erkenntnis mit Klugheit in der Interpretation!