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