This source file includes following definitions.
- sftpfs_open_socket
- sftpfs_recognize_auth_types
- sftpfs_open_connection_ssh_agent
- sftpfs_open_connection_ssh_key
- LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC
- sftpfs_open_connection_ssh_password
- sftpfs_open_connection
- sftpfs_close_connection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 #include <config.h>
28 #include <errno.h>
29
30 #include <netdb.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #ifdef HAVE_ARPA_INET_H
34 #include <arpa/inet.h>
35 #endif
36
37 #include <libssh2.h>
38 #include <libssh2_sftp.h>
39
40 #include "lib/global.h"
41
42 #include "lib/util.h"
43 #include "lib/tty/tty.h"
44 #include "lib/vfs/utilvfs.h"
45
46 #include "internal.h"
47
48
49
50
51
52
53
54
55
56 static const char *kbi_passwd = NULL;
57 static const struct vfs_s_super *kbi_super = NULL;
58
59
60
61
62
63
64
65
66
67
68
69
70 static int
71 sftpfs_open_socket (struct vfs_s_super *super, GError ** mcerror)
72 {
73 struct addrinfo hints, *res = NULL, *curr_res;
74 int my_socket = 0;
75 char port[BUF_TINY];
76 int e;
77
78 mc_return_val_if_error (mcerror, LIBSSH2_INVALID_SOCKET);
79
80 if (super->path_element->host == NULL || *super->path_element->host == '\0')
81 {
82 mc_propagate_error (mcerror, 0, "%s", _("sftp: Invalid host name."));
83 return LIBSSH2_INVALID_SOCKET;
84 }
85
86 sprintf (port, "%hu", (unsigned short) super->path_element->port);
87
88 tty_enable_interrupt_key ();
89
90 memset (&hints, 0, sizeof (hints));
91 hints.ai_family = AF_UNSPEC;
92 hints.ai_socktype = SOCK_STREAM;
93
94 #ifdef AI_ADDRCONFIG
95
96
97
98 hints.ai_flags = AI_ADDRCONFIG;
99 #endif
100
101 e = getaddrinfo (super->path_element->host, port, &hints, &res);
102
103 #ifdef AI_ADDRCONFIG
104 if (e == EAI_BADFLAGS)
105 {
106
107 hints.ai_flags = 0;
108 e = getaddrinfo (super->path_element->host, port, &hints, &res);
109 }
110 #endif
111
112 if (e != 0)
113 {
114 mc_propagate_error (mcerror, e, _("sftp: %s"), gai_strerror (e));
115 my_socket = LIBSSH2_INVALID_SOCKET;
116 goto ret;
117 }
118
119 for (curr_res = res; curr_res != NULL; curr_res = curr_res->ai_next)
120 {
121 int save_errno;
122
123 my_socket = socket (curr_res->ai_family, curr_res->ai_socktype, curr_res->ai_protocol);
124
125 if (my_socket < 0)
126 {
127 if (curr_res->ai_next != NULL)
128 continue;
129
130 vfs_print_message (_("sftp: %s"), unix_error_string (errno));
131 my_socket = LIBSSH2_INVALID_SOCKET;
132 goto ret;
133 }
134
135 vfs_print_message (_("sftp: making connection to %s"), super->path_element->host);
136
137 if (connect (my_socket, curr_res->ai_addr, curr_res->ai_addrlen) >= 0)
138 break;
139
140 save_errno = errno;
141
142 close (my_socket);
143
144 if (save_errno == EINTR && tty_got_interrupt ())
145 mc_propagate_error (mcerror, 0, "%s", _("sftp: connection interrupted by user"));
146 else if (res->ai_next == NULL)
147 mc_propagate_error (mcerror, save_errno, _("sftp: connection to server failed: %s"),
148 unix_error_string (save_errno));
149 else
150 continue;
151
152 my_socket = LIBSSH2_INVALID_SOCKET;
153 break;
154 }
155
156 ret:
157 if (res != NULL)
158 freeaddrinfo (res);
159 tty_disable_interrupt_key ();
160 return my_socket;
161 }
162
163
164
165
166
167
168
169
170
171 static gboolean
172 sftpfs_recognize_auth_types (struct vfs_s_super *super)
173 {
174 char *userauthlist;
175 sftpfs_super_t *sftpfs_super = SFTP_SUPER (super);
176
177
178
179 userauthlist = libssh2_userauth_list (sftpfs_super->session, super->path_element->user,
180 strlen (super->path_element->user));
181
182 if (userauthlist == NULL)
183 return FALSE;
184
185 if ((strstr (userauthlist, "password") != NULL
186 || strstr (userauthlist, "keyboard-interactive") != NULL)
187 && (sftpfs_super->config_auth_type & PASSWORD) != 0)
188 sftpfs_super->auth_type |= PASSWORD;
189
190 if (strstr (userauthlist, "publickey") != NULL
191 && (sftpfs_super->config_auth_type & PUBKEY) != 0)
192 sftpfs_super->auth_type |= PUBKEY;
193
194 if ((sftpfs_super->config_auth_type & AGENT) != 0)
195 sftpfs_super->auth_type |= AGENT;
196
197 return TRUE;
198 }
199
200
201
202
203
204
205
206
207
208
209 static gboolean
210 sftpfs_open_connection_ssh_agent (struct vfs_s_super *super, GError ** mcerror)
211 {
212 sftpfs_super_t *sftpfs_super = SFTP_SUPER (super);
213 struct libssh2_agent_publickey *identity, *prev_identity = NULL;
214 int rc;
215
216 mc_return_val_if_error (mcerror, FALSE);
217
218 sftpfs_super->agent = NULL;
219
220 if ((sftpfs_super->auth_type & AGENT) == 0)
221 return FALSE;
222
223
224 sftpfs_super->agent = libssh2_agent_init (sftpfs_super->session);
225 if (sftpfs_super->agent == NULL)
226 return FALSE;
227
228 if (libssh2_agent_connect (sftpfs_super->agent) != 0)
229 return FALSE;
230
231 if (libssh2_agent_list_identities (sftpfs_super->agent) != 0)
232 return FALSE;
233
234 while (TRUE)
235 {
236 rc = libssh2_agent_get_identity (sftpfs_super->agent, &identity, prev_identity);
237 if (rc == 1)
238 break;
239
240 if (rc < 0)
241 return FALSE;
242
243 if (libssh2_agent_userauth (sftpfs_super->agent, super->path_element->user, identity) == 0)
244 break;
245
246 prev_identity = identity;
247 }
248
249 return (rc == 0);
250 }
251
252
253
254
255
256
257
258
259
260
261 static gboolean
262 sftpfs_open_connection_ssh_key (struct vfs_s_super *super, GError ** mcerror)
263 {
264 sftpfs_super_t *sftpfs_super = SFTP_SUPER (super);
265 char *p, *passwd;
266 gboolean ret_value = FALSE;
267
268 mc_return_val_if_error (mcerror, FALSE);
269
270 if ((sftpfs_super->auth_type & PUBKEY) == 0)
271 return FALSE;
272
273 if (sftpfs_super->privkey == NULL)
274 return FALSE;
275
276 if (libssh2_userauth_publickey_fromfile (sftpfs_super->session, super->path_element->user,
277 sftpfs_super->pubkey, sftpfs_super->privkey,
278 super->path_element->password) == 0)
279 return TRUE;
280
281 p = g_strdup_printf (_("sftp: Enter passphrase for %s "), super->path_element->user);
282 passwd = vfs_get_password (p);
283 g_free (p);
284
285 if (passwd == NULL)
286 mc_propagate_error (mcerror, 0, "%s", _("sftp: Passphrase is empty."));
287 else
288 {
289 ret_value = (libssh2_userauth_publickey_fromfile (sftpfs_super->session,
290 super->path_element->user,
291 sftpfs_super->pubkey,
292 sftpfs_super->privkey, passwd) == 0);
293 g_free (passwd);
294 }
295
296 return ret_value;
297 }
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317 static
318 LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC (sftpfs_keyboard_interactive_helper)
319 {
320 int i;
321 size_t len;
322
323 (void) instruction;
324 (void) instruction_len;
325 (void) abstract;
326
327 if (kbi_super == NULL || kbi_passwd == NULL)
328 return;
329
330 if (strncmp (name, kbi_super->path_element->user, name_len) != 0)
331 return;
332
333
334 len = strlen (kbi_passwd);
335
336 for (i = 0; i < num_prompts; ++i)
337 if (strncmp (prompts[i].text, "Password: ", prompts[i].length) == 0)
338 {
339 responses[i].text = strdup (kbi_passwd);
340 responses[i].length = len;
341 }
342 }
343
344
345
346
347
348
349
350
351
352
353 static gboolean
354 sftpfs_open_connection_ssh_password (struct vfs_s_super *super, GError ** mcerror)
355 {
356 sftpfs_super_t *sftpfs_super = SFTP_SUPER (super);
357 char *p, *passwd;
358 gboolean ret_value = FALSE;
359 int rc;
360
361 mc_return_val_if_error (mcerror, FALSE);
362
363 if ((sftpfs_super->auth_type & PASSWORD) == 0)
364 return FALSE;
365
366 if (super->path_element->password != NULL)
367 {
368 while ((rc = libssh2_userauth_password (sftpfs_super->session, super->path_element->user,
369 super->path_element->password)) ==
370 LIBSSH2_ERROR_EAGAIN);
371 if (rc == 0)
372 return TRUE;
373
374 kbi_super = super;
375 kbi_passwd = super->path_element->password;
376
377 while ((rc =
378 libssh2_userauth_keyboard_interactive (sftpfs_super->session,
379 super->path_element->user,
380 sftpfs_keyboard_interactive_helper)) ==
381 LIBSSH2_ERROR_EAGAIN)
382 ;
383
384 kbi_super = NULL;
385 kbi_passwd = NULL;
386
387 if (rc == 0)
388 return TRUE;
389 }
390
391 p = g_strdup_printf (_("sftp: Enter password for %s "), super->path_element->user);
392 passwd = vfs_get_password (p);
393 g_free (p);
394
395 if (passwd == NULL)
396 mc_propagate_error (mcerror, 0, "%s", _("sftp: Password is empty."));
397 else
398 {
399 while ((rc = libssh2_userauth_password (sftpfs_super->session, super->path_element->user,
400 passwd)) == LIBSSH2_ERROR_EAGAIN)
401 ;
402
403 if (rc != 0)
404 {
405 kbi_super = super;
406 kbi_passwd = passwd;
407
408 while ((rc =
409 libssh2_userauth_keyboard_interactive (sftpfs_super->session,
410 super->path_element->user,
411 sftpfs_keyboard_interactive_helper)) ==
412 LIBSSH2_ERROR_EAGAIN)
413 ;
414
415 kbi_super = NULL;
416 kbi_passwd = NULL;
417 }
418
419 if (rc == 0)
420 {
421 ret_value = TRUE;
422 g_free (super->path_element->password);
423 super->path_element->password = passwd;
424 }
425 else
426 g_free (passwd);
427 }
428
429 return ret_value;
430 }
431
432
433
434
435
436
437
438
439
440
441
442
443 int
444 sftpfs_open_connection (struct vfs_s_super *super, GError ** mcerror)
445 {
446 int rc;
447 sftpfs_super_t *sftpfs_super = SFTP_SUPER (super);
448
449 mc_return_val_if_error (mcerror, -1);
450
451
452
453
454
455 sftpfs_super->socket_handle = sftpfs_open_socket (super, mcerror);
456 if (sftpfs_super->socket_handle == LIBSSH2_INVALID_SOCKET)
457 return (-1);
458
459
460 sftpfs_super->session = libssh2_session_init ();
461 if (sftpfs_super->session == NULL)
462 return (-1);
463
464
465
466
467 #if LIBSSH2_VERSION_NUM < 0x010208
468 rc = libssh2_session_startup (sftpfs_super->session, sftpfs_super->socket_handle);
469 #else
470 rc = libssh2_session_handshake (sftpfs_super->session,
471 (libssh2_socket_t) sftpfs_super->socket_handle);
472 #endif
473 if (rc != 0)
474 {
475 mc_propagate_error (mcerror, rc, "%s", _("sftp: Failure establishing SSH session"));
476 return (-1);
477 }
478
479
480
481
482
483
484 sftpfs_super->fingerprint =
485 libssh2_hostkey_hash (sftpfs_super->session, LIBSSH2_HOSTKEY_HASH_SHA1);
486
487 if (!sftpfs_recognize_auth_types (super))
488 {
489 int sftp_errno;
490
491 sftp_errno = libssh2_session_last_errno (sftpfs_super->session);
492 sftpfs_ssherror_to_gliberror (sftpfs_super, sftp_errno, mcerror);
493 return (-1);
494 }
495
496 if (!sftpfs_open_connection_ssh_agent (super, mcerror)
497 && !sftpfs_open_connection_ssh_key (super, mcerror)
498 && !sftpfs_open_connection_ssh_password (super, mcerror))
499 return (-1);
500
501 sftpfs_super->sftp_session = libssh2_sftp_init (sftpfs_super->session);
502
503 if (sftpfs_super->sftp_session == NULL)
504 return (-1);
505
506
507 libssh2_session_set_blocking (sftpfs_super->session, 1);
508
509 return 0;
510 }
511
512
513
514
515
516
517
518
519
520
521 void
522 sftpfs_close_connection (struct vfs_s_super *super, const char *shutdown_message, GError ** mcerror)
523 {
524 sftpfs_super_t *sftpfs_super = SFTP_SUPER (super);
525
526
527 (void) mcerror;
528
529 if (sftpfs_super->sftp_session != NULL)
530 {
531 libssh2_sftp_shutdown (sftpfs_super->sftp_session);
532 sftpfs_super->sftp_session = NULL;
533 }
534
535 if (sftpfs_super->agent != NULL)
536 {
537 libssh2_agent_disconnect (sftpfs_super->agent);
538 libssh2_agent_free (sftpfs_super->agent);
539 sftpfs_super->agent = NULL;
540 }
541
542 sftpfs_super->fingerprint = NULL;
543
544 if (sftpfs_super->session != NULL)
545 {
546 libssh2_session_disconnect (sftpfs_super->session, shutdown_message);
547 libssh2_session_free (sftpfs_super->session);
548 sftpfs_super->session = NULL;
549 }
550
551 if (sftpfs_super->socket_handle != LIBSSH2_INVALID_SOCKET)
552 {
553 close (sftpfs_super->socket_handle);
554 sftpfs_super->socket_handle = LIBSSH2_INVALID_SOCKET;
555 }
556 }
557
558