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