1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 2017 - 2019 Red Hat, Inc.
9 *
10 * Authors: Nikos Mavrogiannopoulos, Tomas Mraz, Stanislav Zidek,
11 * Robert Kolcun, Andreas Schneider
12 *
13 * This software is licensed as described in the file COPYING, which
14 * you should have received as part of this distribution. The terms
15 * are also available at https://curl.haxx.se/docs/copyright.html.
16 *
17 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
18 * copies of the Software, and permit persons to whom the Software is
19 * furnished to do so, under the terms of the COPYING file.
20 *
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
23 *
24 ***************************************************************************/
25
26#include "curl_setup.h"
27
28#ifdef USE_LIBSSH
29
30#include <limits.h>
31
32#include <libssh/libssh.h>
33#include <libssh/sftp.h>
34
35#ifdef HAVE_FCNTL_H
36#include <fcntl.h>
37#endif
38
39#ifdef HAVE_NETINET_IN_H
40#include <netinet/in.h>
41#endif
42#ifdef HAVE_ARPA_INET_H
43#include <arpa/inet.h>
44#endif
45#ifdef HAVE_UTSNAME_H
46#include <sys/utsname.h>
47#endif
48#ifdef HAVE_NETDB_H
49#include <netdb.h>
50#endif
51#ifdef __VMS
52#include <in.h>
53#include <inet.h>
54#endif
55
56#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
57#undef in_addr_t
58#define in_addr_t unsigned long
59#endif
60
61#include <curl/curl.h>
62#include "urldata.h"
63#include "sendf.h"
64#include "hostip.h"
65#include "progress.h"
66#include "transfer.h"
67#include "escape.h"
68#include "http.h" /* for HTTP proxy tunnel stuff */
69#include "ssh.h"
70#include "url.h"
71#include "speedcheck.h"
72#include "getinfo.h"
73#include "strdup.h"
74#include "strcase.h"
75#include "vtls/vtls.h"
76#include "connect.h"
77#include "strerror.h"
78#include "inet_ntop.h"
79#include "parsedate.h" /* for the week day and month names */
80#include "sockaddr.h" /* required for Curl_sockaddr_storage */
81#include "strtoofft.h"
82#include "multiif.h"
83#include "select.h"
84#include "warnless.h"
85
86/* for permission and open flags */
87#include <sys/types.h>
88#include <sys/stat.h>
89#include <unistd.h>
90#include <fcntl.h>
91
92/* The last 3 #include files should be in this order */
93#include "curl_printf.h"
94#include "curl_memory.h"
95#include "memdebug.h"
96#include "curl_path.h"
97
98/* A recent macro provided by libssh. Or make our own. */
99#ifndef SSH_STRING_FREE_CHAR
100#define SSH_STRING_FREE_CHAR(x) \
101 do { if((x) != NULL) { ssh_string_free_char(x); x = NULL; } } while(0)
102#endif
103
104/* Local functions: */
105static CURLcode myssh_connect(struct connectdata *conn, bool *done);
106static CURLcode myssh_multi_statemach(struct connectdata *conn,
107 bool *done);
108static CURLcode myssh_do_it(struct connectdata *conn, bool *done);
109
110static CURLcode scp_done(struct connectdata *conn,
111 CURLcode, bool premature);
112static CURLcode scp_doing(struct connectdata *conn, bool *dophase_done);
113static CURLcode scp_disconnect(struct connectdata *conn,
114 bool dead_connection);
115
116static CURLcode sftp_done(struct connectdata *conn,
117 CURLcode, bool premature);
118static CURLcode sftp_doing(struct connectdata *conn,
119 bool *dophase_done);
120static CURLcode sftp_disconnect(struct connectdata *conn, bool dead);
121static
122CURLcode sftp_perform(struct connectdata *conn,
123 bool *connected,
124 bool *dophase_done);
125
126static void sftp_quote(struct connectdata *conn);
127static void sftp_quote_stat(struct connectdata *conn);
128static int myssh_getsock(struct connectdata *conn, curl_socket_t *sock);
129static int myssh_perform_getsock(const struct connectdata *conn,
130 curl_socket_t *sock);
131
132static CURLcode myssh_setup_connection(struct connectdata *conn);
133
134/*
135 * SCP protocol handler.
136 */
137
138const struct Curl_handler Curl_handler_scp = {
139 "SCP", /* scheme */
140 myssh_setup_connection, /* setup_connection */
141 myssh_do_it, /* do_it */
142 scp_done, /* done */
143 ZERO_NULL, /* do_more */
144 myssh_connect, /* connect_it */
145 myssh_multi_statemach, /* connecting */
146 scp_doing, /* doing */
147 myssh_getsock, /* proto_getsock */
148 myssh_getsock, /* doing_getsock */
149 ZERO_NULL, /* domore_getsock */
150 myssh_perform_getsock, /* perform_getsock */
151 scp_disconnect, /* disconnect */
152 ZERO_NULL, /* readwrite */
153 ZERO_NULL, /* connection_check */
154 PORT_SSH, /* defport */
155 CURLPROTO_SCP, /* protocol */
156 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
157};
158
159/*
160 * SFTP protocol handler.
161 */
162
163const struct Curl_handler Curl_handler_sftp = {
164 "SFTP", /* scheme */
165 myssh_setup_connection, /* setup_connection */
166 myssh_do_it, /* do_it */
167 sftp_done, /* done */
168 ZERO_NULL, /* do_more */
169 myssh_connect, /* connect_it */
170 myssh_multi_statemach, /* connecting */
171 sftp_doing, /* doing */
172 myssh_getsock, /* proto_getsock */
173 myssh_getsock, /* doing_getsock */
174 ZERO_NULL, /* domore_getsock */
175 myssh_perform_getsock, /* perform_getsock */
176 sftp_disconnect, /* disconnect */
177 ZERO_NULL, /* readwrite */
178 ZERO_NULL, /* connection_check */
179 PORT_SSH, /* defport */
180 CURLPROTO_SFTP, /* protocol */
181 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
182 | PROTOPT_NOURLQUERY /* flags */
183};
184
185static CURLcode sftp_error_to_CURLE(int err)
186{
187 switch(err) {
188 case SSH_FX_OK:
189 return CURLE_OK;
190
191 case SSH_FX_NO_SUCH_FILE:
192 case SSH_FX_NO_SUCH_PATH:
193 return CURLE_REMOTE_FILE_NOT_FOUND;
194
195 case SSH_FX_PERMISSION_DENIED:
196 case SSH_FX_WRITE_PROTECT:
197 return CURLE_REMOTE_ACCESS_DENIED;
198
199 case SSH_FX_FILE_ALREADY_EXISTS:
200 return CURLE_REMOTE_FILE_EXISTS;
201
202 default:
203 break;
204 }
205
206 return CURLE_SSH;
207}
208
209#ifndef DEBUGBUILD
210#define state(x,y) mystate(x,y)
211#else
212#define state(x,y) mystate(x,y, __LINE__)
213#endif
214
215/*
216 * SSH State machine related code
217 */
218/* This is the ONLY way to change SSH state! */
219static void mystate(struct connectdata *conn, sshstate nowstate
220#ifdef DEBUGBUILD
221 , int lineno
222#endif
223 )
224{
225 struct ssh_conn *sshc = &conn->proto.sshc;
226#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
227 /* for debug purposes */
228 static const char *const names[] = {
229 "SSH_STOP",
230 "SSH_INIT",
231 "SSH_S_STARTUP",
232 "SSH_HOSTKEY",
233 "SSH_AUTHLIST",
234 "SSH_AUTH_PKEY_INIT",
235 "SSH_AUTH_PKEY",
236 "SSH_AUTH_PASS_INIT",
237 "SSH_AUTH_PASS",
238 "SSH_AUTH_AGENT_INIT",
239 "SSH_AUTH_AGENT_LIST",
240 "SSH_AUTH_AGENT",
241 "SSH_AUTH_HOST_INIT",
242 "SSH_AUTH_HOST",
243 "SSH_AUTH_KEY_INIT",
244 "SSH_AUTH_KEY",
245 "SSH_AUTH_GSSAPI",
246 "SSH_AUTH_DONE",
247 "SSH_SFTP_INIT",
248 "SSH_SFTP_REALPATH",
249 "SSH_SFTP_QUOTE_INIT",
250 "SSH_SFTP_POSTQUOTE_INIT",
251 "SSH_SFTP_QUOTE",
252 "SSH_SFTP_NEXT_QUOTE",
253 "SSH_SFTP_QUOTE_STAT",
254 "SSH_SFTP_QUOTE_SETSTAT",
255 "SSH_SFTP_QUOTE_SYMLINK",
256 "SSH_SFTP_QUOTE_MKDIR",
257 "SSH_SFTP_QUOTE_RENAME",
258 "SSH_SFTP_QUOTE_RMDIR",
259 "SSH_SFTP_QUOTE_UNLINK",
260 "SSH_SFTP_QUOTE_STATVFS",
261 "SSH_SFTP_GETINFO",
262 "SSH_SFTP_FILETIME",
263 "SSH_SFTP_TRANS_INIT",
264 "SSH_SFTP_UPLOAD_INIT",
265 "SSH_SFTP_CREATE_DIRS_INIT",
266 "SSH_SFTP_CREATE_DIRS",
267 "SSH_SFTP_CREATE_DIRS_MKDIR",
268 "SSH_SFTP_READDIR_INIT",
269 "SSH_SFTP_READDIR",
270 "SSH_SFTP_READDIR_LINK",
271 "SSH_SFTP_READDIR_BOTTOM",
272 "SSH_SFTP_READDIR_DONE",
273 "SSH_SFTP_DOWNLOAD_INIT",
274 "SSH_SFTP_DOWNLOAD_STAT",
275 "SSH_SFTP_CLOSE",
276 "SSH_SFTP_SHUTDOWN",
277 "SSH_SCP_TRANS_INIT",
278 "SSH_SCP_UPLOAD_INIT",
279 "SSH_SCP_DOWNLOAD_INIT",
280 "SSH_SCP_DOWNLOAD",
281 "SSH_SCP_DONE",
282 "SSH_SCP_SEND_EOF",
283 "SSH_SCP_WAIT_EOF",
284 "SSH_SCP_WAIT_CLOSE",
285 "SSH_SCP_CHANNEL_FREE",
286 "SSH_SESSION_DISCONNECT",
287 "SSH_SESSION_FREE",
288 "QUIT"
289 };
290
291
292 if(sshc->state != nowstate) {
293 infof(conn->data, "SSH %p state change from %s to %s (line %d)\n",
294 (void *) sshc, names[sshc->state], names[nowstate],
295 lineno);
296 }
297#endif
298
299 sshc->state = nowstate;
300}
301
302/* Multiple options:
303 * 1. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] is set with an MD5
304 * hash (90s style auth, not sure we should have it here)
305 * 2. data->set.ssh_keyfunc callback is set. Then we do trust on first
306 * use. We even save on knownhosts if CURLKHSTAT_FINE_ADD_TO_FILE
307 * is returned by it.
308 * 3. none of the above. We only accept if it is present on known hosts.
309 *
310 * Returns SSH_OK or SSH_ERROR.
311 */
312static int myssh_is_known(struct connectdata *conn)
313{
314 int rc;
315 struct Curl_easy *data = conn->data;
316 struct ssh_conn *sshc = &conn->proto.sshc;
317 ssh_key pubkey;
318 size_t hlen;
319 unsigned char *hash = NULL;
320 char *base64 = NULL;
321 int vstate;
322 enum curl_khmatch keymatch;
323 struct curl_khkey foundkey;
324 curl_sshkeycallback func =
325 data->set.ssh_keyfunc;
326
327 rc = ssh_get_publickey(sshc->ssh_session, &pubkey);
328 if(rc != SSH_OK)
329 return rc;
330
331 if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
332 rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5,
333 &hash, &hlen);
334 if(rc != SSH_OK)
335 goto cleanup;
336
337 if(hlen != strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) ||
338 memcmp(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5], hash, hlen)) {
339 rc = SSH_ERROR;
340 goto cleanup;
341 }
342
343 rc = SSH_OK;
344 goto cleanup;
345 }
346
347 if(data->set.ssl.primary.verifyhost != TRUE) {
348 rc = SSH_OK;
349 goto cleanup;
350 }
351
352 vstate = ssh_is_server_known(sshc->ssh_session);
353 switch(vstate) {
354 case SSH_SERVER_KNOWN_OK:
355 keymatch = CURLKHMATCH_OK;
356 break;
357 case SSH_SERVER_FILE_NOT_FOUND:
358 /* fallthrough */
359 case SSH_SERVER_NOT_KNOWN:
360 keymatch = CURLKHMATCH_MISSING;
361 break;
362 default:
363 keymatch = CURLKHMATCH_MISMATCH;
364 break;
365 }
366
367 if(func) { /* use callback to determine action */
368 rc = ssh_pki_export_pubkey_base64(pubkey, &base64);
369 if(rc != SSH_OK)
370 goto cleanup;
371
372 foundkey.key = base64;
373 foundkey.len = strlen(base64);
374
375 switch(ssh_key_type(pubkey)) {
376 case SSH_KEYTYPE_RSA:
377 foundkey.keytype = CURLKHTYPE_RSA;
378 break;
379 case SSH_KEYTYPE_RSA1:
380 foundkey.keytype = CURLKHTYPE_RSA1;
381 break;
382 case SSH_KEYTYPE_ECDSA:
383 foundkey.keytype = CURLKHTYPE_ECDSA;
384 break;
385#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,7,0)
386 case SSH_KEYTYPE_ED25519:
387 foundkey.keytype = CURLKHTYPE_ED25519;
388 break;
389#endif
390 case SSH_KEYTYPE_DSS:
391 foundkey.keytype = CURLKHTYPE_DSS;
392 break;
393 default:
394 rc = SSH_ERROR;
395 goto cleanup;
396 }
397
398 /* we don't have anything equivalent to knownkey. Always NULL */
399 Curl_set_in_callback(data, true);
400 rc = func(data, NULL, &foundkey, /* from the remote host */
401 keymatch, data->set.ssh_keyfunc_userp);
402 Curl_set_in_callback(data, false);
403
404 switch(rc) {
405 case CURLKHSTAT_FINE_ADD_TO_FILE:
406 rc = ssh_write_knownhost(sshc->ssh_session);
407 if(rc != SSH_OK) {
408 goto cleanup;
409 }
410 break;
411 case CURLKHSTAT_FINE:
412 break;
413 default: /* REJECT/DEFER */
414 rc = SSH_ERROR;
415 goto cleanup;
416 }
417 }
418 else {
419 if(keymatch != CURLKHMATCH_OK) {
420 rc = SSH_ERROR;
421 goto cleanup;
422 }
423 }
424 rc = SSH_OK;
425
426cleanup:
427 if(hash)
428 ssh_clean_pubkey_hash(&hash);
429 ssh_key_free(pubkey);
430 return rc;
431}
432
433#define MOVE_TO_ERROR_STATE(_r) { \
434 state(conn, SSH_SESSION_DISCONNECT); \
435 sshc->actualcode = _r; \
436 rc = SSH_ERROR; \
437 break; \
438}
439
440#define MOVE_TO_SFTP_CLOSE_STATE() { \
441 state(conn, SSH_SFTP_CLOSE); \
442 sshc->actualcode = sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \
443 rc = SSH_ERROR; \
444 break; \
445}
446
447#define MOVE_TO_LAST_AUTH \
448 if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \
449 rc = SSH_OK; \
450 state(conn, SSH_AUTH_PASS_INIT); \
451 break; \
452 } \
453 else { \
454 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); \
455 }
456
457#define MOVE_TO_TERTIARY_AUTH \
458 if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \
459 rc = SSH_OK; \
460 state(conn, SSH_AUTH_KEY_INIT); \
461 break; \
462 } \
463 else { \
464 MOVE_TO_LAST_AUTH; \
465 }
466
467#define MOVE_TO_SECONDARY_AUTH \
468 if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \
469 rc = SSH_OK; \
470 state(conn, SSH_AUTH_GSSAPI); \
471 break; \
472 } \
473 else { \
474 MOVE_TO_TERTIARY_AUTH; \
475 }
476
477static
478int myssh_auth_interactive(struct connectdata *conn)
479{
480 int rc;
481 struct ssh_conn *sshc = &conn->proto.sshc;
482 int nprompts;
483
484restart:
485 switch(sshc->kbd_state) {
486 case 0:
487 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
488 if(rc == SSH_AUTH_AGAIN)
489 return SSH_AGAIN;
490
491 if(rc != SSH_AUTH_INFO)
492 return SSH_ERROR;
493
494 nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
495 if(nprompts != 1)
496 return SSH_ERROR;
497
498 rc = ssh_userauth_kbdint_setanswer(sshc->ssh_session, 0, conn->passwd);
499 if(rc < 0)
500 return SSH_ERROR;
501
502 /* FALLTHROUGH */
503 case 1:
504 sshc->kbd_state = 1;
505
506 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
507 if(rc == SSH_AUTH_AGAIN)
508 return SSH_AGAIN;
509 else if(rc == SSH_AUTH_SUCCESS)
510 rc = SSH_OK;
511 else if(rc == SSH_AUTH_INFO) {
512 nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
513 if(nprompts != 0)
514 return SSH_ERROR;
515
516 sshc->kbd_state = 2;
517 goto restart;
518 }
519 else
520 rc = SSH_ERROR;
521 break;
522 case 2:
523 sshc->kbd_state = 2;
524
525 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
526 if(rc == SSH_AUTH_AGAIN)
527 return SSH_AGAIN;
528 else if(rc == SSH_AUTH_SUCCESS)
529 rc = SSH_OK;
530 else
531 rc = SSH_ERROR;
532
533 break;
534 default:
535 return SSH_ERROR;
536 }
537
538 sshc->kbd_state = 0;
539 return rc;
540}
541
542/*
543 * ssh_statemach_act() runs the SSH state machine as far as it can without
544 * blocking and without reaching the end. The data the pointer 'block' points
545 * to will be set to TRUE if the libssh function returns SSH_AGAIN
546 * meaning it wants to be called again when the socket is ready
547 */
548static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
549{
550 CURLcode result = CURLE_OK;
551 struct Curl_easy *data = conn->data;
552 struct SSHPROTO *protop = data->req.protop;
553 struct ssh_conn *sshc = &conn->proto.sshc;
554 curl_socket_t sock = conn->sock[FIRSTSOCKET];
555 int rc = SSH_NO_ERROR, err;
556 char *new_readdir_line;
557 int seekerr = CURL_SEEKFUNC_OK;
558 const char *err_msg;
559 *block = 0; /* we're not blocking by default */
560
561 do {
562
563 switch(sshc->state) {
564 case SSH_INIT:
565 sshc->secondCreateDirs = 0;
566 sshc->nextstate = SSH_NO_STATE;
567 sshc->actualcode = CURLE_OK;
568
569#if 0
570 ssh_set_log_level(SSH_LOG_PROTOCOL);
571#endif
572
573 /* Set libssh to non-blocking, since everything internally is
574 non-blocking */
575 ssh_set_blocking(sshc->ssh_session, 0);
576
577 state(conn, SSH_S_STARTUP);
578 /* FALLTHROUGH */
579
580 case SSH_S_STARTUP:
581 rc = ssh_connect(sshc->ssh_session);
582 if(rc == SSH_AGAIN)
583 break;
584
585 if(rc != SSH_OK) {
586 failf(data, "Failure establishing ssh session");
587 MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT);
588 }
589
590 state(conn, SSH_HOSTKEY);
591
592 /* FALLTHROUGH */
593 case SSH_HOSTKEY:
594
595 rc = myssh_is_known(conn);
596 if(rc != SSH_OK) {
597 MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION);
598 }
599
600 state(conn, SSH_AUTHLIST);
601 /* FALLTHROUGH */
602 case SSH_AUTHLIST:{
603 sshc->authed = FALSE;
604
605 rc = ssh_userauth_none(sshc->ssh_session, NULL);
606 if(rc == SSH_AUTH_AGAIN) {
607 rc = SSH_AGAIN;
608 break;
609 }
610
611 if(rc == SSH_AUTH_SUCCESS) {
612 sshc->authed = TRUE;
613 infof(data, "Authenticated with none\n");
614 state(conn, SSH_AUTH_DONE);
615 break;
616 }
617 else if(rc == SSH_AUTH_ERROR) {
618 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
619 }
620
621 sshc->auth_methods = ssh_userauth_list(sshc->ssh_session, NULL);
622 if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
623 state(conn, SSH_AUTH_PKEY_INIT);
624 infof(data, "Authentication using SSH public key file\n");
625 }
626 else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
627 state(conn, SSH_AUTH_GSSAPI);
628 }
629 else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
630 state(conn, SSH_AUTH_KEY_INIT);
631 }
632 else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
633 state(conn, SSH_AUTH_PASS_INIT);
634 }
635 else { /* unsupported authentication method */
636 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
637 }
638
639 break;
640 }
641 case SSH_AUTH_PKEY_INIT:
642 if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) {
643 MOVE_TO_SECONDARY_AUTH;
644 }
645
646 /* Two choices, (1) private key was given on CMD,
647 * (2) use the "default" keys. */
648 if(data->set.str[STRING_SSH_PRIVATE_KEY]) {
649 if(sshc->pubkey && !data->set.ssl.key_passwd) {
650 rc = ssh_userauth_try_publickey(sshc->ssh_session, NULL,
651 sshc->pubkey);
652 if(rc == SSH_AUTH_AGAIN) {
653 rc = SSH_AGAIN;
654 break;
655 }
656
657 if(rc != SSH_OK) {
658 MOVE_TO_SECONDARY_AUTH;
659 }
660 }
661
662 rc = ssh_pki_import_privkey_file(data->
663 set.str[STRING_SSH_PRIVATE_KEY],
664 data->set.ssl.key_passwd, NULL,
665 NULL, &sshc->privkey);
666 if(rc != SSH_OK) {
667 failf(data, "Could not load private key file %s",
668 data->set.str[STRING_SSH_PRIVATE_KEY]);
669 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
670 break;
671 }
672
673 state(conn, SSH_AUTH_PKEY);
674 break;
675
676 }
677 else {
678 rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL,
679 data->set.ssl.key_passwd);
680 if(rc == SSH_AUTH_AGAIN) {
681 rc = SSH_AGAIN;
682 break;
683 }
684 if(rc == SSH_AUTH_SUCCESS) {
685 rc = SSH_OK;
686 sshc->authed = TRUE;
687 infof(data, "Completed public key authentication\n");
688 state(conn, SSH_AUTH_DONE);
689 break;
690 }
691
692 MOVE_TO_SECONDARY_AUTH;
693 }
694 break;
695 case SSH_AUTH_PKEY:
696 rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey);
697 if(rc == SSH_AUTH_AGAIN) {
698 rc = SSH_AGAIN;
699 break;
700 }
701
702 if(rc == SSH_AUTH_SUCCESS) {
703 sshc->authed = TRUE;
704 infof(data, "Completed public key authentication\n");
705 state(conn, SSH_AUTH_DONE);
706 break;
707 }
708 else {
709 infof(data, "Failed public key authentication (rc: %d)\n", rc);
710 MOVE_TO_SECONDARY_AUTH;
711 }
712 break;
713
714 case SSH_AUTH_GSSAPI:
715 if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI)) {
716 MOVE_TO_TERTIARY_AUTH;
717 }
718
719 rc = ssh_userauth_gssapi(sshc->ssh_session);
720 if(rc == SSH_AUTH_AGAIN) {
721 rc = SSH_AGAIN;
722 break;
723 }
724
725 if(rc == SSH_AUTH_SUCCESS) {
726 rc = SSH_OK;
727 sshc->authed = TRUE;
728 infof(data, "Completed gssapi authentication\n");
729 state(conn, SSH_AUTH_DONE);
730 break;
731 }
732
733 MOVE_TO_TERTIARY_AUTH;
734 break;
735
736 case SSH_AUTH_KEY_INIT:
737 if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) {
738 state(conn, SSH_AUTH_KEY);
739 }
740 else {
741 MOVE_TO_LAST_AUTH;
742 }
743 break;
744
745 case SSH_AUTH_KEY:
746
747 /* Authentication failed. Continue with keyboard-interactive now. */
748 rc = myssh_auth_interactive(conn);
749 if(rc == SSH_AGAIN) {
750 break;
751 }
752 if(rc == SSH_OK) {
753 sshc->authed = TRUE;
754 infof(data, "completed keyboard interactive authentication\n");
755 }
756 state(conn, SSH_AUTH_DONE);
757 break;
758
759 case SSH_AUTH_PASS_INIT:
760 if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD)) {
761 /* Host key authentication is intentionally not implemented */
762 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
763 }
764 state(conn, SSH_AUTH_PASS);
765 /* FALLTHROUGH */
766
767 case SSH_AUTH_PASS:
768 rc = ssh_userauth_password(sshc->ssh_session, NULL, conn->passwd);
769 if(rc == SSH_AUTH_AGAIN) {
770 rc = SSH_AGAIN;
771 break;
772 }
773
774 if(rc == SSH_AUTH_SUCCESS) {
775 sshc->authed = TRUE;
776 infof(data, "Completed password authentication\n");
777 state(conn, SSH_AUTH_DONE);
778 }
779 else {
780 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
781 }
782 break;
783
784 case SSH_AUTH_DONE:
785 if(!sshc->authed) {
786 failf(data, "Authentication failure");
787 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
788 break;
789 }
790
791 /*
792 * At this point we have an authenticated ssh session.
793 */
794 infof(data, "Authentication complete\n");
795
796 Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */
797
798 conn->sockfd = sock;
799 conn->writesockfd = CURL_SOCKET_BAD;
800
801 if(conn->handler->protocol == CURLPROTO_SFTP) {
802 state(conn, SSH_SFTP_INIT);
803 break;
804 }
805 infof(data, "SSH CONNECT phase done\n");
806 state(conn, SSH_STOP);
807 break;
808
809 case SSH_SFTP_INIT:
810 ssh_set_blocking(sshc->ssh_session, 1);
811
812 sshc->sftp_session = sftp_new(sshc->ssh_session);
813 if(!sshc->sftp_session) {
814 failf(data, "Failure initializing sftp session: %s",
815 ssh_get_error(sshc->ssh_session));
816 MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
817 break;
818 }
819
820 rc = sftp_init(sshc->sftp_session);
821 if(rc != SSH_OK) {
822 rc = sftp_get_error(sshc->sftp_session);
823 failf(data, "Failure initializing sftp session: %s",
824 ssh_get_error(sshc->ssh_session));
825 MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(rc));
826 break;
827 }
828 state(conn, SSH_SFTP_REALPATH);
829 /* FALLTHROUGH */
830 case SSH_SFTP_REALPATH:
831 /*
832 * Get the "home" directory
833 */
834 sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, ".");
835 if(sshc->homedir == NULL) {
836 MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
837 }
838 conn->data->state.most_recent_ftp_entrypath = sshc->homedir;
839
840 /* This is the last step in the SFTP connect phase. Do note that while
841 we get the homedir here, we get the "workingpath" in the DO action
842 since the homedir will remain the same between request but the
843 working path will not. */
844 DEBUGF(infof(data, "SSH CONNECT phase done\n"));
845 state(conn, SSH_STOP);
846 break;
847
848 case SSH_SFTP_QUOTE_INIT:
849
850 result = Curl_getworkingpath(conn, sshc->homedir, &protop->path);
851 if(result) {
852 sshc->actualcode = result;
853 state(conn, SSH_STOP);
854 break;
855 }
856
857 if(data->set.quote) {
858 infof(data, "Sending quote commands\n");
859 sshc->quote_item = data->set.quote;
860 state(conn, SSH_SFTP_QUOTE);
861 }
862 else {
863 state(conn, SSH_SFTP_GETINFO);
864 }
865 break;
866
867 case SSH_SFTP_POSTQUOTE_INIT:
868 if(data->set.postquote) {
869 infof(data, "Sending quote commands\n");
870 sshc->quote_item = data->set.postquote;
871 state(conn, SSH_SFTP_QUOTE);
872 }
873 else {
874 state(conn, SSH_STOP);
875 }
876 break;
877
878 case SSH_SFTP_QUOTE:
879 /* Send any quote commands */
880 sftp_quote(conn);
881 break;
882
883 case SSH_SFTP_NEXT_QUOTE:
884 Curl_safefree(sshc->quote_path1);
885 Curl_safefree(sshc->quote_path2);
886
887 sshc->quote_item = sshc->quote_item->next;
888
889 if(sshc->quote_item) {
890 state(conn, SSH_SFTP_QUOTE);
891 }
892 else {
893 if(sshc->nextstate != SSH_NO_STATE) {
894 state(conn, sshc->nextstate);
895 sshc->nextstate = SSH_NO_STATE;
896 }
897 else {
898 state(conn, SSH_SFTP_GETINFO);
899 }
900 }
901 break;
902
903 case SSH_SFTP_QUOTE_STAT:
904 sftp_quote_stat(conn);
905 break;
906
907 case SSH_SFTP_QUOTE_SETSTAT:
908 rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2,
909 sshc->quote_attrs);
910 if(rc != 0 && !sshc->acceptfail) {
911 Curl_safefree(sshc->quote_path1);
912 Curl_safefree(sshc->quote_path2);
913 failf(data, "Attempt to set SFTP stats failed: %s",
914 ssh_get_error(sshc->ssh_session));
915 state(conn, SSH_SFTP_CLOSE);
916 sshc->nextstate = SSH_NO_STATE;
917 sshc->actualcode = CURLE_QUOTE_ERROR;
918 /* sshc->actualcode = sftp_error_to_CURLE(err);
919 * we do not send the actual error; we return
920 * the error the libssh2 backend is returning */
921 break;
922 }
923 state(conn, SSH_SFTP_NEXT_QUOTE);
924 break;
925
926 case SSH_SFTP_QUOTE_SYMLINK:
927 rc = sftp_symlink(sshc->sftp_session, sshc->quote_path2,
928 sshc->quote_path1);
929 if(rc != 0 && !sshc->acceptfail) {
930 Curl_safefree(sshc->quote_path1);
931 Curl_safefree(sshc->quote_path2);
932 failf(data, "symlink command failed: %s",
933 ssh_get_error(sshc->ssh_session));
934 state(conn, SSH_SFTP_CLOSE);
935 sshc->nextstate = SSH_NO_STATE;
936 sshc->actualcode = CURLE_QUOTE_ERROR;
937 break;
938 }
939 state(conn, SSH_SFTP_NEXT_QUOTE);
940 break;
941
942 case SSH_SFTP_QUOTE_MKDIR:
943 rc = sftp_mkdir(sshc->sftp_session, sshc->quote_path1,
944 (mode_t)data->set.new_directory_perms);
945 if(rc != 0 && !sshc->acceptfail) {
946 Curl_safefree(sshc->quote_path1);
947 failf(data, "mkdir command failed: %s",
948 ssh_get_error(sshc->ssh_session));
949 state(conn, SSH_SFTP_CLOSE);
950 sshc->nextstate = SSH_NO_STATE;
951 sshc->actualcode = CURLE_QUOTE_ERROR;
952 break;
953 }
954 state(conn, SSH_SFTP_NEXT_QUOTE);
955 break;
956
957 case SSH_SFTP_QUOTE_RENAME:
958 rc = sftp_rename(sshc->sftp_session, sshc->quote_path1,
959 sshc->quote_path2);
960 if(rc != 0 && !sshc->acceptfail) {
961 Curl_safefree(sshc->quote_path1);
962 Curl_safefree(sshc->quote_path2);
963 failf(data, "rename command failed: %s",
964 ssh_get_error(sshc->ssh_session));
965 state(conn, SSH_SFTP_CLOSE);
966 sshc->nextstate = SSH_NO_STATE;
967 sshc->actualcode = CURLE_QUOTE_ERROR;
968 break;
969 }
970 state(conn, SSH_SFTP_NEXT_QUOTE);
971 break;
972
973 case SSH_SFTP_QUOTE_RMDIR:
974 rc = sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
975 if(rc != 0 && !sshc->acceptfail) {
976 Curl_safefree(sshc->quote_path1);
977 failf(data, "rmdir command failed: %s",
978 ssh_get_error(sshc->ssh_session));
979 state(conn, SSH_SFTP_CLOSE);
980 sshc->nextstate = SSH_NO_STATE;
981 sshc->actualcode = CURLE_QUOTE_ERROR;
982 break;
983 }
984 state(conn, SSH_SFTP_NEXT_QUOTE);
985 break;
986
987 case SSH_SFTP_QUOTE_UNLINK:
988 rc = sftp_unlink(sshc->sftp_session, sshc->quote_path1);
989 if(rc != 0 && !sshc->acceptfail) {
990 Curl_safefree(sshc->quote_path1);
991 failf(data, "rm command failed: %s",
992 ssh_get_error(sshc->ssh_session));
993 state(conn, SSH_SFTP_CLOSE);
994 sshc->nextstate = SSH_NO_STATE;
995 sshc->actualcode = CURLE_QUOTE_ERROR;
996 break;
997 }
998 state(conn, SSH_SFTP_NEXT_QUOTE);
999 break;
1000
1001 case SSH_SFTP_QUOTE_STATVFS:
1002 {
1003 sftp_statvfs_t statvfs;
1004
1005 statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1);
1006 if(!statvfs && !sshc->acceptfail) {
1007 Curl_safefree(sshc->quote_path1);
1008 failf(data, "statvfs command failed: %s",
1009 ssh_get_error(sshc->ssh_session));
1010 state(conn, SSH_SFTP_CLOSE);
1011 sshc->nextstate = SSH_NO_STATE;
1012 sshc->actualcode = CURLE_QUOTE_ERROR;
1013 break;
1014 }
1015 else if(statvfs) {
1016 char *tmp = aprintf("statvfs:\n"
1017 "f_bsize: %llu\n" "f_frsize: %llu\n"
1018 "f_blocks: %llu\n" "f_bfree: %llu\n"
1019 "f_bavail: %llu\n" "f_files: %llu\n"
1020 "f_ffree: %llu\n" "f_favail: %llu\n"
1021 "f_fsid: %llu\n" "f_flag: %llu\n"
1022 "f_namemax: %llu\n",
1023 statvfs->f_bsize, statvfs->f_frsize,
1024 statvfs->f_blocks, statvfs->f_bfree,
1025 statvfs->f_bavail, statvfs->f_files,
1026 statvfs->f_ffree, statvfs->f_favail,
1027 statvfs->f_fsid, statvfs->f_flag,
1028 statvfs->f_namemax);
1029 sftp_statvfs_free(statvfs);
1030
1031 if(!tmp) {
1032 result = CURLE_OUT_OF_MEMORY;
1033 state(conn, SSH_SFTP_CLOSE);
1034 sshc->nextstate = SSH_NO_STATE;
1035 break;
1036 }
1037
1038 result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
1039 free(tmp);
1040 if(result) {
1041 state(conn, SSH_SFTP_CLOSE);
1042 sshc->nextstate = SSH_NO_STATE;
1043 sshc->actualcode = result;
1044 }
1045 }
1046 state(conn, SSH_SFTP_NEXT_QUOTE);
1047 break;
1048 }
1049
1050 case SSH_SFTP_GETINFO:
1051 if(data->set.get_filetime) {
1052 state(conn, SSH_SFTP_FILETIME);
1053 }
1054 else {
1055 state(conn, SSH_SFTP_TRANS_INIT);
1056 }
1057 break;
1058
1059 case SSH_SFTP_FILETIME:
1060 {
1061 sftp_attributes attrs;
1062
1063 attrs = sftp_stat(sshc->sftp_session, protop->path);
1064 if(attrs != 0) {
1065 data->info.filetime = attrs->mtime;
1066 sftp_attributes_free(attrs);
1067 }
1068
1069 state(conn, SSH_SFTP_TRANS_INIT);
1070 break;
1071 }
1072
1073 case SSH_SFTP_TRANS_INIT:
1074 if(data->set.upload)
1075 state(conn, SSH_SFTP_UPLOAD_INIT);
1076 else {
1077 if(protop->path[strlen(protop->path)-1] == '/')
1078 state(conn, SSH_SFTP_READDIR_INIT);
1079 else
1080 state(conn, SSH_SFTP_DOWNLOAD_INIT);
1081 }
1082 break;
1083
1084 case SSH_SFTP_UPLOAD_INIT:
1085 {
1086 int flags;
1087
1088 if(data->state.resume_from != 0) {
1089 sftp_attributes attrs;
1090
1091 if(data->state.resume_from < 0) {
1092 attrs = sftp_stat(sshc->sftp_session, protop->path);
1093 if(attrs != 0) {
1094 curl_off_t size = attrs->size;
1095 if(size < 0) {
1096 failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
1097 MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
1098 }
1099 data->state.resume_from = attrs->size;
1100
1101 sftp_attributes_free(attrs);
1102 }
1103 else {
1104 data->state.resume_from = 0;
1105 }
1106 }
1107 }
1108
1109 if(data->set.ftp_append)
1110 /* Try to open for append, but create if nonexisting */
1111 flags = O_WRONLY|O_CREAT|O_APPEND;
1112 else if(data->state.resume_from > 0)
1113 /* If we have restart position then open for append */
1114 flags = O_WRONLY|O_APPEND;
1115 else
1116 /* Clear file before writing (normal behaviour) */
1117 flags = O_WRONLY|O_CREAT|O_TRUNC;
1118
1119 if(sshc->sftp_file)
1120 sftp_close(sshc->sftp_file);
1121 sshc->sftp_file =
1122 sftp_open(sshc->sftp_session, protop->path,
1123 flags, (mode_t)data->set.new_file_perms);
1124 if(!sshc->sftp_file) {
1125 err = sftp_get_error(sshc->sftp_session);
1126
1127 if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE ||
1128 err == SSH_FX_NO_SUCH_PATH)) &&
1129 (data->set.ftp_create_missing_dirs &&
1130 (strlen(protop->path) > 1))) {
1131 /* try to create the path remotely */
1132 rc = 0;
1133 sshc->secondCreateDirs = 1;
1134 state(conn, SSH_SFTP_CREATE_DIRS_INIT);
1135 break;
1136 }
1137 else {
1138 MOVE_TO_SFTP_CLOSE_STATE();
1139 }
1140 }
1141
1142 /* If we have a restart point then we need to seek to the correct
1143 position. */
1144 if(data->state.resume_from > 0) {
1145 /* Let's read off the proper amount of bytes from the input. */
1146 if(conn->seek_func) {
1147 Curl_set_in_callback(data, true);
1148 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1149 SEEK_SET);
1150 Curl_set_in_callback(data, false);
1151 }
1152
1153 if(seekerr != CURL_SEEKFUNC_OK) {
1154 curl_off_t passed = 0;
1155
1156 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1157 failf(data, "Could not seek stream");
1158 return CURLE_FTP_COULDNT_USE_REST;
1159 }
1160 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1161 do {
1162 size_t readthisamountnow =
1163 (data->state.resume_from - passed > data->set.buffer_size) ?
1164 (size_t)data->set.buffer_size :
1165 curlx_sotouz(data->state.resume_from - passed);
1166
1167 size_t actuallyread =
1168 data->state.fread_func(data->state.buffer, 1,
1169 readthisamountnow, data->state.in);
1170
1171 passed += actuallyread;
1172 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1173 /* this checks for greater-than only to make sure that the
1174 CURL_READFUNC_ABORT return code still aborts */
1175 failf(data, "Failed to read data");
1176 MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
1177 }
1178 } while(passed < data->state.resume_from);
1179 }
1180
1181 /* now, decrease the size of the read */
1182 if(data->state.infilesize > 0) {
1183 data->state.infilesize -= data->state.resume_from;
1184 data->req.size = data->state.infilesize;
1185 Curl_pgrsSetUploadSize(data, data->state.infilesize);
1186 }
1187
1188 rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1189 if(rc != 0) {
1190 MOVE_TO_SFTP_CLOSE_STATE();
1191 }
1192 }
1193 if(data->state.infilesize > 0) {
1194 data->req.size = data->state.infilesize;
1195 Curl_pgrsSetUploadSize(data, data->state.infilesize);
1196 }
1197 /* upload data */
1198 Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
1199
1200 /* not set by Curl_setup_transfer to preserve keepon bits */
1201 conn->sockfd = conn->writesockfd;
1202
1203 /* store this original bitmask setup to use later on if we can't
1204 figure out a "real" bitmask */
1205 sshc->orig_waitfor = data->req.keepon;
1206
1207 /* we want to use the _sending_ function even when the socket turns
1208 out readable as the underlying libssh sftp send function will deal
1209 with both accordingly */
1210 conn->cselect_bits = CURL_CSELECT_OUT;
1211
1212 /* since we don't really wait for anything at this point, we want the
1213 state machine to move on as soon as possible so we set a very short
1214 timeout here */
1215 Curl_expire(data, 0, EXPIRE_RUN_NOW);
1216
1217 state(conn, SSH_STOP);
1218 break;
1219 }
1220
1221 case SSH_SFTP_CREATE_DIRS_INIT:
1222 if(strlen(protop->path) > 1) {
1223 sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */
1224 state(conn, SSH_SFTP_CREATE_DIRS);
1225 }
1226 else {
1227 state(conn, SSH_SFTP_UPLOAD_INIT);
1228 }
1229 break;
1230
1231 case SSH_SFTP_CREATE_DIRS:
1232 sshc->slash_pos = strchr(sshc->slash_pos, '/');
1233 if(sshc->slash_pos) {
1234 *sshc->slash_pos = 0;
1235
1236 infof(data, "Creating directory '%s'\n", protop->path);
1237 state(conn, SSH_SFTP_CREATE_DIRS_MKDIR);
1238 break;
1239 }
1240 state(conn, SSH_SFTP_UPLOAD_INIT);
1241 break;
1242
1243 case SSH_SFTP_CREATE_DIRS_MKDIR:
1244 /* 'mode' - parameter is preliminary - default to 0644 */
1245 rc = sftp_mkdir(sshc->sftp_session, protop->path,
1246 (mode_t)data->set.new_directory_perms);
1247 *sshc->slash_pos = '/';
1248 ++sshc->slash_pos;
1249 if(rc < 0) {
1250 /*
1251 * Abort if failure wasn't that the dir already exists or the
1252 * permission was denied (creation might succeed further down the
1253 * path) - retry on unspecific FAILURE also
1254 */
1255 err = sftp_get_error(sshc->sftp_session);
1256 if((err != SSH_FX_FILE_ALREADY_EXISTS) &&
1257 (err != SSH_FX_FAILURE) &&
1258 (err != SSH_FX_PERMISSION_DENIED)) {
1259 MOVE_TO_SFTP_CLOSE_STATE();
1260 }
1261 rc = 0; /* clear rc and continue */
1262 }
1263 state(conn, SSH_SFTP_CREATE_DIRS);
1264 break;
1265
1266 case SSH_SFTP_READDIR_INIT:
1267 Curl_pgrsSetDownloadSize(data, -1);
1268 if(data->set.opt_no_body) {
1269 state(conn, SSH_STOP);
1270 break;
1271 }
1272
1273 /*
1274 * This is a directory that we are trying to get, so produce a directory
1275 * listing
1276 */
1277 sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
1278 protop->path);
1279 if(!sshc->sftp_dir) {
1280 failf(data, "Could not open directory for reading: %s",
1281 ssh_get_error(sshc->ssh_session));
1282 MOVE_TO_SFTP_CLOSE_STATE();
1283 }
1284 state(conn, SSH_SFTP_READDIR);
1285 break;
1286
1287 case SSH_SFTP_READDIR:
1288
1289 if(sshc->readdir_attrs)
1290 sftp_attributes_free(sshc->readdir_attrs);
1291
1292 sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir);
1293 if(sshc->readdir_attrs) {
1294 sshc->readdir_filename = sshc->readdir_attrs->name;
1295 sshc->readdir_longentry = sshc->readdir_attrs->longname;
1296 sshc->readdir_len = strlen(sshc->readdir_filename);
1297
1298 if(data->set.ftp_list_only) {
1299 char *tmpLine;
1300
1301 tmpLine = aprintf("%s\n", sshc->readdir_filename);
1302 if(tmpLine == NULL) {
1303 state(conn, SSH_SFTP_CLOSE);
1304 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1305 break;
1306 }
1307 result = Curl_client_write(conn, CLIENTWRITE_BODY,
1308 tmpLine, sshc->readdir_len + 1);
1309 free(tmpLine);
1310
1311 if(result) {
1312 state(conn, SSH_STOP);
1313 break;
1314 }
1315 /* since this counts what we send to the client, we include the
1316 newline in this counter */
1317 data->req.bytecount += sshc->readdir_len + 1;
1318
1319 /* output debug output if that is requested */
1320 if(data->set.verbose) {
1321 Curl_debug(data, CURLINFO_DATA_OUT,
1322 (char *)sshc->readdir_filename,
1323 sshc->readdir_len);
1324 }
1325 }
1326 else {
1327 sshc->readdir_currLen = strlen(sshc->readdir_longentry);
1328 sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
1329 sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
1330 if(!sshc->readdir_line) {
1331 state(conn, SSH_SFTP_CLOSE);
1332 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1333 break;
1334 }
1335
1336 memcpy(sshc->readdir_line, sshc->readdir_longentry,
1337 sshc->readdir_currLen);
1338 if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
1339 ((sshc->readdir_attrs->permissions & S_IFMT) ==
1340 S_IFLNK)) {
1341 sshc->readdir_linkPath = malloc(PATH_MAX + 1);
1342 if(sshc->readdir_linkPath == NULL) {
1343 state(conn, SSH_SFTP_CLOSE);
1344 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1345 break;
1346 }
1347
1348 msnprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", protop->path,
1349 sshc->readdir_filename);
1350
1351 state(conn, SSH_SFTP_READDIR_LINK);
1352 break;
1353 }
1354 state(conn, SSH_SFTP_READDIR_BOTTOM);
1355 break;
1356 }
1357 }
1358 else if(sftp_dir_eof(sshc->sftp_dir)) {
1359 state(conn, SSH_SFTP_READDIR_DONE);
1360 break;
1361 }
1362 else {
1363 failf(data, "Could not open remote file for reading: %s",
1364 ssh_get_error(sshc->ssh_session));
1365 MOVE_TO_SFTP_CLOSE_STATE();
1366 break;
1367 }
1368 break;
1369
1370 case SSH_SFTP_READDIR_LINK:
1371 if(sshc->readdir_link_attrs)
1372 sftp_attributes_free(sshc->readdir_link_attrs);
1373
1374 sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session,
1375 sshc->readdir_linkPath);
1376 if(sshc->readdir_link_attrs == 0) {
1377 failf(data, "Could not read symlink for reading: %s",
1378 ssh_get_error(sshc->ssh_session));
1379 MOVE_TO_SFTP_CLOSE_STATE();
1380 }
1381
1382 if(sshc->readdir_link_attrs->name == NULL) {
1383 sshc->readdir_tmp = sftp_readlink(sshc->sftp_session,
1384 sshc->readdir_linkPath);
1385 if(sshc->readdir_filename == NULL)
1386 sshc->readdir_len = 0;
1387 else
1388 sshc->readdir_len = strlen(sshc->readdir_tmp);
1389 sshc->readdir_longentry = NULL;
1390 sshc->readdir_filename = sshc->readdir_tmp;
1391 }
1392 else {
1393 sshc->readdir_len = strlen(sshc->readdir_link_attrs->name);
1394 sshc->readdir_filename = sshc->readdir_link_attrs->name;
1395 sshc->readdir_longentry = sshc->readdir_link_attrs->longname;
1396 }
1397
1398 Curl_safefree(sshc->readdir_linkPath);
1399
1400 /* get room for the filename and extra output */
1401 sshc->readdir_totalLen += 4 + sshc->readdir_len;
1402 new_readdir_line = Curl_saferealloc(sshc->readdir_line,
1403 sshc->readdir_totalLen);
1404 if(!new_readdir_line) {
1405 sshc->readdir_line = NULL;
1406 state(conn, SSH_SFTP_CLOSE);
1407 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1408 break;
1409 }
1410 sshc->readdir_line = new_readdir_line;
1411
1412 sshc->readdir_currLen += msnprintf(sshc->readdir_line +
1413 sshc->readdir_currLen,
1414 sshc->readdir_totalLen -
1415 sshc->readdir_currLen,
1416 " -> %s",
1417 sshc->readdir_filename);
1418
1419 sftp_attributes_free(sshc->readdir_link_attrs);
1420 sshc->readdir_link_attrs = NULL;
1421 sshc->readdir_filename = NULL;
1422 sshc->readdir_longentry = NULL;
1423
1424 state(conn, SSH_SFTP_READDIR_BOTTOM);
1425 /* FALLTHROUGH */
1426 case SSH_SFTP_READDIR_BOTTOM:
1427 sshc->readdir_currLen += msnprintf(sshc->readdir_line +
1428 sshc->readdir_currLen,
1429 sshc->readdir_totalLen -
1430 sshc->readdir_currLen, "\n");
1431 result = Curl_client_write(conn, CLIENTWRITE_BODY,
1432 sshc->readdir_line,
1433 sshc->readdir_currLen);
1434
1435 if(!result) {
1436
1437 /* output debug output if that is requested */
1438 if(data->set.verbose) {
1439 Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
1440 sshc->readdir_currLen);
1441 }
1442 data->req.bytecount += sshc->readdir_currLen;
1443 }
1444 Curl_safefree(sshc->readdir_line);
1445 ssh_string_free_char(sshc->readdir_tmp);
1446 sshc->readdir_tmp = NULL;
1447
1448 if(result) {
1449 state(conn, SSH_STOP);
1450 }
1451 else
1452 state(conn, SSH_SFTP_READDIR);
1453 break;
1454
1455 case SSH_SFTP_READDIR_DONE:
1456 sftp_closedir(sshc->sftp_dir);
1457 sshc->sftp_dir = NULL;
1458
1459 /* no data to transfer */
1460 Curl_setup_transfer(data, -1, -1, FALSE, -1);
1461 state(conn, SSH_STOP);
1462 break;
1463
1464 case SSH_SFTP_DOWNLOAD_INIT:
1465 /*
1466 * Work on getting the specified file
1467 */
1468 if(sshc->sftp_file)
1469 sftp_close(sshc->sftp_file);
1470
1471 sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path,
1472 O_RDONLY, (mode_t)data->set.new_file_perms);
1473 if(!sshc->sftp_file) {
1474 failf(data, "Could not open remote file for reading: %s",
1475 ssh_get_error(sshc->ssh_session));
1476
1477 MOVE_TO_SFTP_CLOSE_STATE();
1478 }
1479
1480 state(conn, SSH_SFTP_DOWNLOAD_STAT);
1481 break;
1482
1483 case SSH_SFTP_DOWNLOAD_STAT:
1484 {
1485 sftp_attributes attrs;
1486 curl_off_t size;
1487
1488 attrs = sftp_fstat(sshc->sftp_file);
1489 if(!attrs ||
1490 !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
1491 (attrs->size == 0)) {
1492 /*
1493 * sftp_fstat didn't return an error, so maybe the server
1494 * just doesn't support stat()
1495 * OR the server doesn't return a file size with a stat()
1496 * OR file size is 0
1497 */
1498 data->req.size = -1;
1499 data->req.maxdownload = -1;
1500 Curl_pgrsSetDownloadSize(data, -1);
1501 size = 0;
1502 }
1503 else {
1504 size = attrs->size;
1505
1506 sftp_attributes_free(attrs);
1507
1508 if(size < 0) {
1509 failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
1510 return CURLE_BAD_DOWNLOAD_RESUME;
1511 }
1512 if(conn->data->state.use_range) {
1513 curl_off_t from, to;
1514 char *ptr;
1515 char *ptr2;
1516 CURLofft to_t;
1517 CURLofft from_t;
1518
1519 from_t = curlx_strtoofft(conn->data->state.range, &ptr, 0, &from);
1520 if(from_t == CURL_OFFT_FLOW) {
1521 return CURLE_RANGE_ERROR;
1522 }
1523 while(*ptr && (ISSPACE(*ptr) || (*ptr == '-')))
1524 ptr++;
1525 to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
1526 if(to_t == CURL_OFFT_FLOW) {
1527 return CURLE_RANGE_ERROR;
1528 }
1529 if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
1530 || (to >= size)) {
1531 to = size - 1;
1532 }
1533 if(from_t) {
1534 /* from is relative to end of file */
1535 from = size - to;
1536 to = size - 1;
1537 }
1538 if(from > size) {
1539 failf(data, "Offset (%"
1540 CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
1541 CURL_FORMAT_CURL_OFF_T ")", from, size);
1542 return CURLE_BAD_DOWNLOAD_RESUME;
1543 }
1544 if(from > to) {
1545 from = to;
1546 size = 0;
1547 }
1548 else {
1549 size = to - from + 1;
1550 }
1551
1552 rc = sftp_seek64(sshc->sftp_file, from);
1553 if(rc != 0) {
1554 MOVE_TO_SFTP_CLOSE_STATE();
1555 }
1556 }
1557 data->req.size = size;
1558 data->req.maxdownload = size;
1559 Curl_pgrsSetDownloadSize(data, size);
1560 }
1561
1562 /* We can resume if we can seek to the resume position */
1563 if(data->state.resume_from) {
1564 if(data->state.resume_from < 0) {
1565 /* We're supposed to download the last abs(from) bytes */
1566 if((curl_off_t)size < -data->state.resume_from) {
1567 failf(data, "Offset (%"
1568 CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
1569 CURL_FORMAT_CURL_OFF_T ")",
1570 data->state.resume_from, size);
1571 return CURLE_BAD_DOWNLOAD_RESUME;
1572 }
1573 /* download from where? */
1574 data->state.resume_from += size;
1575 }
1576 else {
1577 if((curl_off_t)size < data->state.resume_from) {
1578 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
1579 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
1580 data->state.resume_from, size);
1581 return CURLE_BAD_DOWNLOAD_RESUME;
1582 }
1583 }
1584 /* Does a completed file need to be seeked and started or closed ? */
1585 /* Now store the number of bytes we are expected to download */
1586 data->req.size = size - data->state.resume_from;
1587 data->req.maxdownload = size - data->state.resume_from;
1588 Curl_pgrsSetDownloadSize(data,
1589 size - data->state.resume_from);
1590
1591 rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1592 if(rc != 0) {
1593 MOVE_TO_SFTP_CLOSE_STATE();
1594 }
1595 }
1596 }
1597
1598 /* Setup the actual download */
1599 if(data->req.size == 0) {
1600 /* no data to transfer */
1601 Curl_setup_transfer(data, -1, -1, FALSE, -1);
1602 infof(data, "File already completely downloaded\n");
1603 state(conn, SSH_STOP);
1604 break;
1605 }
1606 Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
1607
1608 /* not set by Curl_setup_transfer to preserve keepon bits */
1609 conn->writesockfd = conn->sockfd;
1610
1611 /* we want to use the _receiving_ function even when the socket turns
1612 out writableable as the underlying libssh recv function will deal
1613 with both accordingly */
1614 conn->cselect_bits = CURL_CSELECT_IN;
1615
1616 if(result) {
1617 /* this should never occur; the close state should be entered
1618 at the time the error occurs */
1619 state(conn, SSH_SFTP_CLOSE);
1620 sshc->actualcode = result;
1621 }
1622 else {
1623 sshc->sftp_recv_state = 0;
1624 state(conn, SSH_STOP);
1625 }
1626 break;
1627
1628 case SSH_SFTP_CLOSE:
1629 if(sshc->sftp_file) {
1630 sftp_close(sshc->sftp_file);
1631 sshc->sftp_file = NULL;
1632 }
1633 Curl_safefree(protop->path);
1634
1635 DEBUGF(infof(data, "SFTP DONE done\n"));
1636
1637 /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
1638 After nextstate is executed, the control should come back to
1639 SSH_SFTP_CLOSE to pass the correct result back */
1640 if(sshc->nextstate != SSH_NO_STATE &&
1641 sshc->nextstate != SSH_SFTP_CLOSE) {
1642 state(conn, sshc->nextstate);
1643 sshc->nextstate = SSH_SFTP_CLOSE;
1644 }
1645 else {
1646 state(conn, SSH_STOP);
1647 result = sshc->actualcode;
1648 }
1649 break;
1650
1651 case SSH_SFTP_SHUTDOWN:
1652 /* during times we get here due to a broken transfer and then the
1653 sftp_handle might not have been taken down so make sure that is done
1654 before we proceed */
1655
1656 if(sshc->sftp_file) {
1657 sftp_close(sshc->sftp_file);
1658 sshc->sftp_file = NULL;
1659 }
1660
1661 if(sshc->sftp_session) {
1662 sftp_free(sshc->sftp_session);
1663 sshc->sftp_session = NULL;
1664 }
1665
1666 SSH_STRING_FREE_CHAR(sshc->homedir);
1667 conn->data->state.most_recent_ftp_entrypath = NULL;
1668
1669 state(conn, SSH_SESSION_DISCONNECT);
1670 break;
1671
1672
1673 case SSH_SCP_TRANS_INIT:
1674 result = Curl_getworkingpath(conn, sshc->homedir, &protop->path);
1675 if(result) {
1676 sshc->actualcode = result;
1677 state(conn, SSH_STOP);
1678 break;
1679 }
1680
1681 /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */
1682 ssh_set_blocking(sshc->ssh_session, 1);
1683
1684 if(data->set.upload) {
1685 if(data->state.infilesize < 0) {
1686 failf(data, "SCP requires a known file size for upload");
1687 sshc->actualcode = CURLE_UPLOAD_FAILED;
1688 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1689 }
1690
1691 sshc->scp_session =
1692 ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path);
1693 state(conn, SSH_SCP_UPLOAD_INIT);
1694 }
1695 else {
1696 sshc->scp_session =
1697 ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path);
1698 state(conn, SSH_SCP_DOWNLOAD_INIT);
1699 }
1700
1701 if(!sshc->scp_session) {
1702 err_msg = ssh_get_error(sshc->ssh_session);
1703 failf(conn->data, "%s", err_msg);
1704 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1705 }
1706
1707 break;
1708
1709 case SSH_SCP_UPLOAD_INIT:
1710
1711 rc = ssh_scp_init(sshc->scp_session);
1712 if(rc != SSH_OK) {
1713 err_msg = ssh_get_error(sshc->ssh_session);
1714 failf(conn->data, "%s", err_msg);
1715 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1716 }
1717
1718 rc = ssh_scp_push_file(sshc->scp_session, protop->path,
1719 data->state.infilesize,
1720 (int)data->set.new_file_perms);
1721 if(rc != SSH_OK) {
1722 err_msg = ssh_get_error(sshc->ssh_session);
1723 failf(conn->data, "%s", err_msg);
1724 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1725 }
1726
1727 /* upload data */
1728 Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET);
1729
1730 /* not set by Curl_setup_transfer to preserve keepon bits */
1731 conn->sockfd = conn->writesockfd;
1732
1733 /* store this original bitmask setup to use later on if we can't
1734 figure out a "real" bitmask */
1735 sshc->orig_waitfor = data->req.keepon;
1736
1737 /* we want to use the _sending_ function even when the socket turns
1738 out readable as the underlying libssh scp send function will deal
1739 with both accordingly */
1740 conn->cselect_bits = CURL_CSELECT_OUT;
1741
1742 state(conn, SSH_STOP);
1743
1744 break;
1745
1746 case SSH_SCP_DOWNLOAD_INIT:
1747
1748 rc = ssh_scp_init(sshc->scp_session);
1749 if(rc != SSH_OK) {
1750 err_msg = ssh_get_error(sshc->ssh_session);
1751 failf(conn->data, "%s", err_msg);
1752 MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
1753 }
1754 state(conn, SSH_SCP_DOWNLOAD);
1755 /* FALLTHROUGH */
1756
1757 case SSH_SCP_DOWNLOAD:{
1758 curl_off_t bytecount;
1759
1760 rc = ssh_scp_pull_request(sshc->scp_session);
1761 if(rc != SSH_SCP_REQUEST_NEWFILE) {
1762 err_msg = ssh_get_error(sshc->ssh_session);
1763 failf(conn->data, "%s", err_msg);
1764 MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND);
1765 break;
1766 }
1767
1768 /* download data */
1769 bytecount = ssh_scp_request_get_size(sshc->scp_session);
1770 data->req.maxdownload = (curl_off_t) bytecount;
1771 Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
1772
1773 /* not set by Curl_setup_transfer to preserve keepon bits */
1774 conn->writesockfd = conn->sockfd;
1775
1776 /* we want to use the _receiving_ function even when the socket turns
1777 out writableable as the underlying libssh recv function will deal
1778 with both accordingly */
1779 conn->cselect_bits = CURL_CSELECT_IN;
1780
1781 state(conn, SSH_STOP);
1782 break;
1783 }
1784 case SSH_SCP_DONE:
1785 if(data->set.upload)
1786 state(conn, SSH_SCP_SEND_EOF);
1787 else
1788 state(conn, SSH_SCP_CHANNEL_FREE);
1789 break;
1790
1791 case SSH_SCP_SEND_EOF:
1792 if(sshc->scp_session) {
1793 rc = ssh_scp_close(sshc->scp_session);
1794 if(rc == SSH_AGAIN) {
1795 /* Currently the ssh_scp_close handles waiting for EOF in
1796 * blocking way.
1797 */
1798 break;
1799 }
1800 if(rc != SSH_OK) {
1801 infof(data, "Failed to close libssh scp channel: %s\n",
1802 ssh_get_error(sshc->ssh_session));
1803 }
1804 }
1805
1806 state(conn, SSH_SCP_CHANNEL_FREE);
1807 break;
1808
1809 case SSH_SCP_CHANNEL_FREE:
1810 if(sshc->scp_session) {
1811 ssh_scp_free(sshc->scp_session);
1812 sshc->scp_session = NULL;
1813 }
1814 DEBUGF(infof(data, "SCP DONE phase complete\n"));
1815
1816 ssh_set_blocking(sshc->ssh_session, 0);
1817
1818 state(conn, SSH_SESSION_DISCONNECT);
1819 /* FALLTHROUGH */
1820
1821 case SSH_SESSION_DISCONNECT:
1822 /* during weird times when we've been prematurely aborted, the channel
1823 is still alive when we reach this state and we MUST kill the channel
1824 properly first */
1825 if(sshc->scp_session) {
1826 ssh_scp_free(sshc->scp_session);
1827 sshc->scp_session = NULL;
1828 }
1829
1830 ssh_disconnect(sshc->ssh_session);
1831
1832 SSH_STRING_FREE_CHAR(sshc->homedir);
1833 conn->data->state.most_recent_ftp_entrypath = NULL;
1834
1835 state(conn, SSH_SESSION_FREE);
1836 /* FALLTHROUGH */
1837 case SSH_SESSION_FREE:
1838 if(sshc->ssh_session) {
1839 ssh_free(sshc->ssh_session);
1840 sshc->ssh_session = NULL;
1841 }
1842
1843 /* worst-case scenario cleanup */
1844
1845 DEBUGASSERT(sshc->ssh_session == NULL);
1846 DEBUGASSERT(sshc->scp_session == NULL);
1847
1848 if(sshc->readdir_tmp) {
1849 ssh_string_free_char(sshc->readdir_tmp);
1850 sshc->readdir_tmp = NULL;
1851 }
1852
1853 if(sshc->quote_attrs)
1854 sftp_attributes_free(sshc->quote_attrs);
1855
1856 if(sshc->readdir_attrs)
1857 sftp_attributes_free(sshc->readdir_attrs);
1858
1859 if(sshc->readdir_link_attrs)
1860 sftp_attributes_free(sshc->readdir_link_attrs);
1861
1862 if(sshc->privkey)
1863 ssh_key_free(sshc->privkey);
1864 if(sshc->pubkey)
1865 ssh_key_free(sshc->pubkey);
1866
1867 Curl_safefree(sshc->rsa_pub);
1868 Curl_safefree(sshc->rsa);
1869 Curl_safefree(sshc->quote_path1);
1870 Curl_safefree(sshc->quote_path2);
1871 Curl_safefree(sshc->readdir_line);
1872 Curl_safefree(sshc->readdir_linkPath);
1873 SSH_STRING_FREE_CHAR(sshc->homedir);
1874
1875 /* the code we are about to return */
1876 result = sshc->actualcode;
1877
1878 memset(sshc, 0, sizeof(struct ssh_conn));
1879
1880 connclose(conn, "SSH session free");
1881 sshc->state = SSH_SESSION_FREE; /* current */
1882 sshc->nextstate = SSH_NO_STATE;
1883 state(conn, SSH_STOP);
1884 break;
1885
1886 case SSH_QUIT:
1887 /* fallthrough, just stop! */
1888 default:
1889 /* internal error */
1890 sshc->nextstate = SSH_NO_STATE;
1891 state(conn, SSH_STOP);
1892 break;
1893
1894 }
1895 } while(!rc && (sshc->state != SSH_STOP));
1896
1897
1898 if(rc == SSH_AGAIN) {
1899 /* we would block, we need to wait for the socket to be ready (in the
1900 right direction too)! */
1901 *block = TRUE;
1902 }
1903
1904 return result;
1905}
1906
1907
1908/* called by the multi interface to figure out what socket(s) to wait for and
1909 for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
1910static int myssh_perform_getsock(const struct connectdata *conn,
1911 curl_socket_t *sock)
1912{
1913 int bitmap = GETSOCK_BLANK;
1914 sock[0] = conn->sock[FIRSTSOCKET];
1915
1916 if(conn->waitfor & KEEP_RECV)
1917 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
1918
1919 if(conn->waitfor & KEEP_SEND)
1920 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
1921
1922 return bitmap;
1923}
1924
1925/* Generic function called by the multi interface to figure out what socket(s)
1926 to wait for and for what actions during the DOING and PROTOCONNECT states*/
1927static int myssh_getsock(struct connectdata *conn,
1928 curl_socket_t *sock)
1929{
1930 /* if we know the direction we can use the generic *_getsock() function even
1931 for the protocol_connect and doing states */
1932 return myssh_perform_getsock(conn, sock);
1933}
1934
1935static void myssh_block2waitfor(struct connectdata *conn, bool block)
1936{
1937 struct ssh_conn *sshc = &conn->proto.sshc;
1938
1939 /* If it didn't block, or nothing was returned by ssh_get_poll_flags
1940 * have the original set */
1941 conn->waitfor = sshc->orig_waitfor;
1942
1943 if(block) {
1944 int dir = ssh_get_poll_flags(sshc->ssh_session);
1945 if(dir & SSH_READ_PENDING) {
1946 /* translate the libssh define bits into our own bit defines */
1947 conn->waitfor = KEEP_RECV;
1948 }
1949 else if(dir & SSH_WRITE_PENDING) {
1950 conn->waitfor = KEEP_SEND;
1951 }
1952 }
1953}
1954
1955/* called repeatedly until done from multi.c */
1956static CURLcode myssh_multi_statemach(struct connectdata *conn,
1957 bool *done)
1958{
1959 struct ssh_conn *sshc = &conn->proto.sshc;
1960 bool block; /* we store the status and use that to provide a ssh_getsock()
1961 implementation */
1962 CURLcode result = myssh_statemach_act(conn, &block);
1963
1964 *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
1965 myssh_block2waitfor(conn, block);
1966
1967 return result;
1968}
1969
1970static CURLcode myssh_block_statemach(struct connectdata *conn,
1971 bool disconnect)
1972{
1973 struct ssh_conn *sshc = &conn->proto.sshc;
1974 CURLcode result = CURLE_OK;
1975 struct Curl_easy *data = conn->data;
1976
1977 while((sshc->state != SSH_STOP) && !result) {
1978 bool block;
1979 timediff_t left = 1000;
1980 struct curltime now = Curl_now();
1981
1982 result = myssh_statemach_act(conn, &block);
1983 if(result)
1984 break;
1985
1986 if(!disconnect) {
1987 if(Curl_pgrsUpdate(conn))
1988 return CURLE_ABORTED_BY_CALLBACK;
1989
1990 result = Curl_speedcheck(data, now);
1991 if(result)
1992 break;
1993
1994 left = Curl_timeleft(data, NULL, FALSE);
1995 if(left < 0) {
1996 failf(data, "Operation timed out");
1997 return CURLE_OPERATION_TIMEDOUT;
1998 }
1999 }
2000
2001 if(block) {
2002 curl_socket_t fd_read = conn->sock[FIRSTSOCKET];
2003 /* wait for the socket to become ready */
2004 (void) Curl_socket_check(fd_read, CURL_SOCKET_BAD,
2005 CURL_SOCKET_BAD, left > 1000 ? 1000 : left);
2006 }
2007
2008 }
2009
2010 return result;
2011}
2012
2013/*
2014 * SSH setup connection
2015 */
2016static CURLcode myssh_setup_connection(struct connectdata *conn)
2017{
2018 struct SSHPROTO *ssh;
2019
2020 conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
2021 if(!ssh)
2022 return CURLE_OUT_OF_MEMORY;
2023
2024 return CURLE_OK;
2025}
2026
2027static Curl_recv scp_recv, sftp_recv;
2028static Curl_send scp_send, sftp_send;
2029
2030/*
2031 * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
2032 * do protocol-specific actions at connect-time.
2033 */
2034static CURLcode myssh_connect(struct connectdata *conn, bool *done)
2035{
2036 struct ssh_conn *ssh;
2037 CURLcode result;
2038 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2039 struct Curl_easy *data = conn->data;
2040
2041 /* initialize per-handle data if not already */
2042 if(!data->req.protop)
2043 myssh_setup_connection(conn);
2044
2045 /* We default to persistent connections. We set this already in this connect
2046 function to make the re-use checks properly be able to check this bit. */
2047 connkeep(conn, "SSH default");
2048
2049 if(conn->handler->protocol & CURLPROTO_SCP) {
2050 conn->recv[FIRSTSOCKET] = scp_recv;
2051 conn->send[FIRSTSOCKET] = scp_send;
2052 }
2053 else {
2054 conn->recv[FIRSTSOCKET] = sftp_recv;
2055 conn->send[FIRSTSOCKET] = sftp_send;
2056 }
2057
2058 ssh = &conn->proto.sshc;
2059
2060 ssh->ssh_session = ssh_new();
2061 if(ssh->ssh_session == NULL) {
2062 failf(data, "Failure initialising ssh session");
2063 return CURLE_FAILED_INIT;
2064 }
2065
2066 ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
2067
2068 if(conn->user) {
2069 infof(data, "User: %s\n", conn->user);
2070 ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
2071 }
2072
2073 if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
2074 infof(data, "Known hosts: %s\n", data->set.str[STRING_SSH_KNOWNHOSTS]);
2075 ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
2076 data->set.str[STRING_SSH_KNOWNHOSTS]);
2077 }
2078
2079 ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
2080 if(conn->remote_port)
2081 ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT,
2082 &conn->remote_port);
2083
2084 if(data->set.ssh_compression) {
2085 ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION,
2086 "zlib,zlib@openssh.com,none");
2087 }
2088
2089 ssh->privkey = NULL;
2090 ssh->pubkey = NULL;
2091
2092 if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
2093 int rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
2094 &ssh->pubkey);
2095 if(rc != SSH_OK) {
2096 failf(data, "Could not load public key file");
2097 /* ignore */
2098 }
2099 }
2100
2101 /* we do not verify here, we do it at the state machine,
2102 * after connection */
2103
2104 state(conn, SSH_INIT);
2105
2106 result = myssh_multi_statemach(conn, done);
2107
2108 return result;
2109}
2110
2111/* called from multi.c while DOing */
2112static CURLcode scp_doing(struct connectdata *conn, bool *dophase_done)
2113{
2114 CURLcode result;
2115
2116 result = myssh_multi_statemach(conn, dophase_done);
2117
2118 if(*dophase_done) {
2119 DEBUGF(infof(conn->data, "DO phase is complete\n"));
2120 }
2121 return result;
2122}
2123
2124/*
2125 ***********************************************************************
2126 *
2127 * scp_perform()
2128 *
2129 * This is the actual DO function for SCP. Get a file according to
2130 * the options previously setup.
2131 */
2132
2133static
2134CURLcode scp_perform(struct connectdata *conn,
2135 bool *connected, bool *dophase_done)
2136{
2137 CURLcode result = CURLE_OK;
2138
2139 DEBUGF(infof(conn->data, "DO phase starts\n"));
2140
2141 *dophase_done = FALSE; /* not done yet */
2142
2143 /* start the first command in the DO phase */
2144 state(conn, SSH_SCP_TRANS_INIT);
2145
2146 result = myssh_multi_statemach(conn, dophase_done);
2147
2148 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
2149
2150 if(*dophase_done) {
2151 DEBUGF(infof(conn->data, "DO phase is complete\n"));
2152 }
2153
2154 return result;
2155}
2156
2157static CURLcode myssh_do_it(struct connectdata *conn, bool *done)
2158{
2159 CURLcode result;
2160 bool connected = 0;
2161 struct Curl_easy *data = conn->data;
2162 struct ssh_conn *sshc = &conn->proto.sshc;
2163
2164 *done = FALSE; /* default to false */
2165
2166 data->req.size = -1; /* make sure this is unknown at this point */
2167
2168 sshc->actualcode = CURLE_OK; /* reset error code */
2169 sshc->secondCreateDirs = 0; /* reset the create dir attempt state
2170 variable */
2171
2172 Curl_pgrsSetUploadCounter(data, 0);
2173 Curl_pgrsSetDownloadCounter(data, 0);
2174 Curl_pgrsSetUploadSize(data, -1);
2175 Curl_pgrsSetDownloadSize(data, -1);
2176
2177 if(conn->handler->protocol & CURLPROTO_SCP)
2178 result = scp_perform(conn, &connected, done);
2179 else
2180 result = sftp_perform(conn, &connected, done);
2181
2182 return result;
2183}
2184
2185/* BLOCKING, but the function is using the state machine so the only reason
2186 this is still blocking is that the multi interface code has no support for
2187 disconnecting operations that takes a while */
2188static CURLcode scp_disconnect(struct connectdata *conn,
2189 bool dead_connection)
2190{
2191 CURLcode result = CURLE_OK;
2192 struct ssh_conn *ssh = &conn->proto.sshc;
2193 (void) dead_connection;
2194
2195 if(ssh->ssh_session) {
2196 /* only if there's a session still around to use! */
2197
2198 state(conn, SSH_SESSION_DISCONNECT);
2199
2200 result = myssh_block_statemach(conn, TRUE);
2201 }
2202
2203 return result;
2204}
2205
2206/* generic done function for both SCP and SFTP called from their specific
2207 done functions */
2208static CURLcode myssh_done(struct connectdata *conn, CURLcode status)
2209{
2210 CURLcode result = CURLE_OK;
2211 struct SSHPROTO *protop = conn->data->req.protop;
2212
2213 if(!status) {
2214 /* run the state-machine */
2215 result = myssh_block_statemach(conn, FALSE);
2216 }
2217 else
2218 result = status;
2219
2220 if(protop)
2221 Curl_safefree(protop->path);
2222 if(Curl_pgrsDone(conn))
2223 return CURLE_ABORTED_BY_CALLBACK;
2224
2225 conn->data->req.keepon = 0; /* clear all bits */
2226 return result;
2227}
2228
2229
2230static CURLcode scp_done(struct connectdata *conn, CURLcode status,
2231 bool premature)
2232{
2233 (void) premature; /* not used */
2234
2235 if(!status)
2236 state(conn, SSH_SCP_DONE);
2237
2238 return myssh_done(conn, status);
2239
2240}
2241
2242static ssize_t scp_send(struct connectdata *conn, int sockindex,
2243 const void *mem, size_t len, CURLcode *err)
2244{
2245 int rc;
2246 (void) sockindex; /* we only support SCP on the fixed known primary socket */
2247 (void) err;
2248
2249 rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
2250
2251#if 0
2252 /* The following code is misleading, mostly added as wishful thinking
2253 * that libssh at some point will implement non-blocking ssh_scp_write/read.
2254 * Currently rc can only be number of bytes read or SSH_ERROR. */
2255 myssh_block2waitfor(conn, (rc == SSH_AGAIN) ? TRUE : FALSE);
2256
2257 if(rc == SSH_AGAIN) {
2258 *err = CURLE_AGAIN;
2259 return 0;
2260 }
2261 else
2262#endif
2263 if(rc != SSH_OK) {
2264 *err = CURLE_SSH;
2265 return -1;
2266 }
2267
2268 return len;
2269}
2270
2271static ssize_t scp_recv(struct connectdata *conn, int sockindex,
2272 char *mem, size_t len, CURLcode *err)
2273{
2274 ssize_t nread;
2275 (void) err;
2276 (void) sockindex; /* we only support SCP on the fixed known primary socket */
2277
2278 /* libssh returns int */
2279 nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
2280
2281#if 0
2282 /* The following code is misleading, mostly added as wishful thinking
2283 * that libssh at some point will implement non-blocking ssh_scp_write/read.
2284 * Currently rc can only be SSH_OK or SSH_ERROR. */
2285
2286 myssh_block2waitfor(conn, (nread == SSH_AGAIN) ? TRUE : FALSE);
2287 if(nread == SSH_AGAIN) {
2288 *err = CURLE_AGAIN;
2289 nread = -1;
2290 }
2291#endif
2292
2293 return nread;
2294}
2295
2296/*
2297 * =============== SFTP ===============
2298 */
2299
2300/*
2301 ***********************************************************************
2302 *
2303 * sftp_perform()
2304 *
2305 * This is the actual DO function for SFTP. Get a file/directory according to
2306 * the options previously setup.
2307 */
2308
2309static
2310CURLcode sftp_perform(struct connectdata *conn,
2311 bool *connected,
2312 bool *dophase_done)
2313{
2314 CURLcode result = CURLE_OK;
2315
2316 DEBUGF(infof(conn->data, "DO phase starts\n"));
2317
2318 *dophase_done = FALSE; /* not done yet */
2319
2320 /* start the first command in the DO phase */
2321 state(conn, SSH_SFTP_QUOTE_INIT);
2322
2323 /* run the state-machine */
2324 result = myssh_multi_statemach(conn, dophase_done);
2325
2326 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
2327
2328 if(*dophase_done) {
2329 DEBUGF(infof(conn->data, "DO phase is complete\n"));
2330 }
2331
2332 return result;
2333}
2334
2335/* called from multi.c while DOing */
2336static CURLcode sftp_doing(struct connectdata *conn,
2337 bool *dophase_done)
2338{
2339 CURLcode result = myssh_multi_statemach(conn, dophase_done);
2340 if(*dophase_done) {
2341 DEBUGF(infof(conn->data, "DO phase is complete\n"));
2342 }
2343 return result;
2344}
2345
2346/* BLOCKING, but the function is using the state machine so the only reason
2347 this is still blocking is that the multi interface code has no support for
2348 disconnecting operations that takes a while */
2349static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection)
2350{
2351 CURLcode result = CURLE_OK;
2352 (void) dead_connection;
2353
2354 DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));
2355
2356 if(conn->proto.sshc.ssh_session) {
2357 /* only if there's a session still around to use! */
2358 state(conn, SSH_SFTP_SHUTDOWN);
2359 result = myssh_block_statemach(conn, TRUE);
2360 }
2361
2362 DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
2363
2364 return result;
2365
2366}
2367
2368static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
2369 bool premature)
2370{
2371 struct ssh_conn *sshc = &conn->proto.sshc;
2372
2373 if(!status) {
2374 /* Post quote commands are executed after the SFTP_CLOSE state to avoid
2375 errors that could happen due to open file handles during POSTQUOTE
2376 operation */
2377 if(!premature && conn->data->set.postquote && !conn->bits.retry)
2378 sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
2379 state(conn, SSH_SFTP_CLOSE);
2380 }
2381 return myssh_done(conn, status);
2382}
2383
2384/* return number of sent bytes */
2385static ssize_t sftp_send(struct connectdata *conn, int sockindex,
2386 const void *mem, size_t len, CURLcode *err)
2387{
2388 ssize_t nwrite;
2389 (void)sockindex;
2390
2391 nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
2392
2393 myssh_block2waitfor(conn, FALSE);
2394
2395#if 0 /* not returned by libssh on write */
2396 if(nwrite == SSH_AGAIN) {
2397 *err = CURLE_AGAIN;
2398 nwrite = 0;
2399 }
2400 else
2401#endif
2402 if(nwrite < 0) {
2403 *err = CURLE_SSH;
2404 nwrite = -1;
2405 }
2406
2407 return nwrite;
2408}
2409
2410/*
2411 * Return number of received (decrypted) bytes
2412 * or <0 on error
2413 */
2414static ssize_t sftp_recv(struct connectdata *conn, int sockindex,
2415 char *mem, size_t len, CURLcode *err)
2416{
2417 ssize_t nread;
2418 (void)sockindex;
2419
2420 DEBUGASSERT(len < CURL_MAX_READ_SIZE);
2421
2422 switch(conn->proto.sshc.sftp_recv_state) {
2423 case 0:
2424 conn->proto.sshc.sftp_file_index =
2425 sftp_async_read_begin(conn->proto.sshc.sftp_file,
2426 (uint32_t)len);
2427 if(conn->proto.sshc.sftp_file_index < 0) {
2428 *err = CURLE_RECV_ERROR;
2429 return -1;
2430 }
2431
2432 /* FALLTHROUGH */
2433 case 1:
2434 conn->proto.sshc.sftp_recv_state = 1;
2435
2436 nread = sftp_async_read(conn->proto.sshc.sftp_file,
2437 mem, (uint32_t)len,
2438 conn->proto.sshc.sftp_file_index);
2439
2440 myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE);
2441
2442 if(nread == SSH_AGAIN) {
2443 *err = CURLE_AGAIN;
2444 return -1;
2445 }
2446 else if(nread < 0) {
2447 *err = CURLE_RECV_ERROR;
2448 return -1;
2449 }
2450
2451 conn->proto.sshc.sftp_recv_state = 0;
2452 return nread;
2453
2454 default:
2455 /* we never reach here */
2456 return -1;
2457 }
2458}
2459
2460static void sftp_quote(struct connectdata *conn)
2461{
2462 const char *cp;
2463 struct Curl_easy *data = conn->data;
2464 struct SSHPROTO *protop = data->req.protop;
2465 struct ssh_conn *sshc = &conn->proto.sshc;
2466 CURLcode result;
2467
2468 /*
2469 * Support some of the "FTP" commands
2470 */
2471 char *cmd = sshc->quote_item->data;
2472 sshc->acceptfail = FALSE;
2473
2474 /* if a command starts with an asterisk, which a legal SFTP command never
2475 can, the command will be allowed to fail without it causing any
2476 aborts or cancels etc. It will cause libcurl to act as if the command
2477 is successful, whatever the server reponds. */
2478
2479 if(cmd[0] == '*') {
2480 cmd++;
2481 sshc->acceptfail = TRUE;
2482 }
2483
2484 if(strcasecompare("pwd", cmd)) {
2485 /* output debug output if that is requested */
2486 char *tmp = aprintf("257 \"%s\" is current directory.\n",
2487 protop->path);
2488 if(!tmp) {
2489 sshc->actualcode = CURLE_OUT_OF_MEMORY;
2490 state(conn, SSH_SFTP_CLOSE);
2491 sshc->nextstate = SSH_NO_STATE;
2492 return;
2493 }
2494 if(data->set.verbose) {
2495 Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
2496 Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
2497 }
2498 /* this sends an FTP-like "header" to the header callback so that the
2499 current directory can be read very similar to how it is read when
2500 using ordinary FTP. */
2501 result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
2502 free(tmp);
2503 if(result) {
2504 state(conn, SSH_SFTP_CLOSE);
2505 sshc->nextstate = SSH_NO_STATE;
2506 sshc->actualcode = result;
2507 }
2508 else
2509 state(conn, SSH_SFTP_NEXT_QUOTE);
2510 return;
2511 }
2512
2513 /*
2514 * the arguments following the command must be separated from the
2515 * command with a space so we can check for it unconditionally
2516 */
2517 cp = strchr(cmd, ' ');
2518 if(cp == NULL) {
2519 failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
2520 state(conn, SSH_SFTP_CLOSE);
2521 sshc->nextstate = SSH_NO_STATE;
2522 sshc->actualcode = CURLE_QUOTE_ERROR;
2523 return;
2524 }
2525
2526 /*
2527 * also, every command takes at least one argument so we get that
2528 * first argument right now
2529 */
2530 result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
2531 if(result) {
2532 if(result == CURLE_OUT_OF_MEMORY)
2533 failf(data, "Out of memory");
2534 else
2535 failf(data, "Syntax error: Bad first parameter");
2536 state(conn, SSH_SFTP_CLOSE);
2537 sshc->nextstate = SSH_NO_STATE;
2538 sshc->actualcode = result;
2539 return;
2540 }
2541
2542 /*
2543 * SFTP is a binary protocol, so we don't send text commands
2544 * to the server. Instead, we scan for commands used by
2545 * OpenSSH's sftp program and call the appropriate libssh
2546 * functions.
2547 */
2548 if(strncasecompare(cmd, "chgrp ", 6) ||
2549 strncasecompare(cmd, "chmod ", 6) ||
2550 strncasecompare(cmd, "chown ", 6)) {
2551 /* attribute change */
2552
2553 /* sshc->quote_path1 contains the mode to set */
2554 /* get the destination */
2555 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2556 if(result) {
2557 if(result == CURLE_OUT_OF_MEMORY)
2558 failf(data, "Out of memory");
2559 else
2560 failf(data, "Syntax error in chgrp/chmod/chown: "
2561 "Bad second parameter");
2562 Curl_safefree(sshc->quote_path1);
2563 state(conn, SSH_SFTP_CLOSE);
2564 sshc->nextstate = SSH_NO_STATE;
2565 sshc->actualcode = result;
2566 return;
2567 }
2568 sshc->quote_attrs = NULL;
2569 state(conn, SSH_SFTP_QUOTE_STAT);
2570 return;
2571 }
2572 if(strncasecompare(cmd, "ln ", 3) ||
2573 strncasecompare(cmd, "symlink ", 8)) {
2574 /* symbolic linking */
2575 /* sshc->quote_path1 is the source */
2576 /* get the destination */
2577 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2578 if(result) {
2579 if(result == CURLE_OUT_OF_MEMORY)
2580 failf(data, "Out of memory");
2581 else
2582 failf(data, "Syntax error in ln/symlink: Bad second parameter");
2583 Curl_safefree(sshc->quote_path1);
2584 state(conn, SSH_SFTP_CLOSE);
2585 sshc->nextstate = SSH_NO_STATE;
2586 sshc->actualcode = result;
2587 return;
2588 }
2589 state(conn, SSH_SFTP_QUOTE_SYMLINK);
2590 return;
2591 }
2592 else if(strncasecompare(cmd, "mkdir ", 6)) {
2593 /* create dir */
2594 state(conn, SSH_SFTP_QUOTE_MKDIR);
2595 return;
2596 }
2597 else if(strncasecompare(cmd, "rename ", 7)) {
2598 /* rename file */
2599 /* first param is the source path */
2600 /* second param is the dest. path */
2601 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2602 if(result) {
2603 if(result == CURLE_OUT_OF_MEMORY)
2604 failf(data, "Out of memory");
2605 else
2606 failf(data, "Syntax error in rename: Bad second parameter");
2607 Curl_safefree(sshc->quote_path1);
2608 state(conn, SSH_SFTP_CLOSE);
2609 sshc->nextstate = SSH_NO_STATE;
2610 sshc->actualcode = result;
2611 return;
2612 }
2613 state(conn, SSH_SFTP_QUOTE_RENAME);
2614 return;
2615 }
2616 else if(strncasecompare(cmd, "rmdir ", 6)) {
2617 /* delete dir */
2618 state(conn, SSH_SFTP_QUOTE_RMDIR);
2619 return;
2620 }
2621 else if(strncasecompare(cmd, "rm ", 3)) {
2622 state(conn, SSH_SFTP_QUOTE_UNLINK);
2623 return;
2624 }
2625#ifdef HAS_STATVFS_SUPPORT
2626 else if(strncasecompare(cmd, "statvfs ", 8)) {
2627 state(conn, SSH_SFTP_QUOTE_STATVFS);
2628 return;
2629 }
2630#endif
2631
2632 failf(data, "Unknown SFTP command");
2633 Curl_safefree(sshc->quote_path1);
2634 Curl_safefree(sshc->quote_path2);
2635 state(conn, SSH_SFTP_CLOSE);
2636 sshc->nextstate = SSH_NO_STATE;
2637 sshc->actualcode = CURLE_QUOTE_ERROR;
2638}
2639
2640static void sftp_quote_stat(struct connectdata *conn)
2641{
2642 struct Curl_easy *data = conn->data;
2643 struct ssh_conn *sshc = &conn->proto.sshc;
2644 char *cmd = sshc->quote_item->data;
2645 sshc->acceptfail = FALSE;
2646
2647 /* if a command starts with an asterisk, which a legal SFTP command never
2648 can, the command will be allowed to fail without it causing any
2649 aborts or cancels etc. It will cause libcurl to act as if the command
2650 is successful, whatever the server reponds. */
2651
2652 if(cmd[0] == '*') {
2653 cmd++;
2654 sshc->acceptfail = TRUE;
2655 }
2656
2657 /* We read the file attributes, store them in sshc->quote_attrs
2658 * and modify them accordingly to command. Then we switch to
2659 * QUOTE_SETSTAT state to write new ones.
2660 */
2661
2662 if(sshc->quote_attrs)
2663 sftp_attributes_free(sshc->quote_attrs);
2664 sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
2665 if(sshc->quote_attrs == NULL) {
2666 Curl_safefree(sshc->quote_path1);
2667 Curl_safefree(sshc->quote_path2);
2668 failf(data, "Attempt to get SFTP stats failed: %d",
2669 sftp_get_error(sshc->sftp_session));
2670 state(conn, SSH_SFTP_CLOSE);
2671 sshc->nextstate = SSH_NO_STATE;
2672 sshc->actualcode = CURLE_QUOTE_ERROR;
2673 return;
2674 }
2675
2676 /* Now set the new attributes... */
2677 if(strncasecompare(cmd, "chgrp", 5)) {
2678 sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2679 if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2680 !sshc->acceptfail) {
2681 Curl_safefree(sshc->quote_path1);
2682 Curl_safefree(sshc->quote_path2);
2683 failf(data, "Syntax error: chgrp gid not a number");
2684 state(conn, SSH_SFTP_CLOSE);
2685 sshc->nextstate = SSH_NO_STATE;
2686 sshc->actualcode = CURLE_QUOTE_ERROR;
2687 return;
2688 }
2689 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2690 }
2691 else if(strncasecompare(cmd, "chmod", 5)) {
2692 mode_t perms;
2693 perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
2694 /* permissions are octal */
2695 if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
2696 Curl_safefree(sshc->quote_path1);
2697 Curl_safefree(sshc->quote_path2);
2698 failf(data, "Syntax error: chmod permissions not a number");
2699 state(conn, SSH_SFTP_CLOSE);
2700 sshc->nextstate = SSH_NO_STATE;
2701 sshc->actualcode = CURLE_QUOTE_ERROR;
2702 return;
2703 }
2704 sshc->quote_attrs->permissions = perms;
2705 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
2706 }
2707 else if(strncasecompare(cmd, "chown", 5)) {
2708 sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2709 if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2710 !sshc->acceptfail) {
2711 Curl_safefree(sshc->quote_path1);
2712 Curl_safefree(sshc->quote_path2);
2713 failf(data, "Syntax error: chown uid not a number");
2714 state(conn, SSH_SFTP_CLOSE);
2715 sshc->nextstate = SSH_NO_STATE;
2716 sshc->actualcode = CURLE_QUOTE_ERROR;
2717 return;
2718 }
2719 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2720 }
2721
2722 /* Now send the completed structure... */
2723 state(conn, SSH_SFTP_QUOTE_SETSTAT);
2724 return;
2725}
2726
2727CURLcode Curl_ssh_init(void)
2728{
2729 if(ssh_init()) {
2730 DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
2731 return CURLE_FAILED_INIT;
2732 }
2733 return CURLE_OK;
2734}
2735
2736void Curl_ssh_cleanup(void)
2737{
2738 (void)ssh_finalize();
2739}
2740
2741size_t Curl_ssh_version(char *buffer, size_t buflen)
2742{
2743 return msnprintf(buffer, buflen, "libssh/%s", CURL_LIBSSH_VERSION);
2744}
2745
2746#endif /* USE_LIBSSH */
2747