Annotation of embedaddon/curl/lib/vssh/libssh2.c, revision 1.1.1.1
1.1 misho 1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
9: *
10: * This software is licensed as described in the file COPYING, which
11: * you should have received as part of this distribution. The terms
12: * are also available at https://curl.haxx.se/docs/copyright.html.
13: *
14: * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15: * copies of the Software, and permit persons to whom the Software is
16: * furnished to do so, under the terms of the COPYING file.
17: *
18: * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19: * KIND, either express or implied.
20: *
21: ***************************************************************************/
22:
23: /* #define CURL_LIBSSH2_DEBUG */
24:
25: #include "curl_setup.h"
26:
27: #ifdef USE_LIBSSH2
28:
29: #include <limits.h>
30:
31: #include <libssh2.h>
32: #include <libssh2_sftp.h>
33:
34: #ifdef HAVE_FCNTL_H
35: #include <fcntl.h>
36: #endif
37:
38: #ifdef HAVE_NETINET_IN_H
39: #include <netinet/in.h>
40: #endif
41: #ifdef HAVE_ARPA_INET_H
42: #include <arpa/inet.h>
43: #endif
44: #ifdef HAVE_UTSNAME_H
45: #include <sys/utsname.h>
46: #endif
47: #ifdef HAVE_NETDB_H
48: #include <netdb.h>
49: #endif
50: #ifdef __VMS
51: #include <in.h>
52: #include <inet.h>
53: #endif
54:
55: #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
56: #undef in_addr_t
57: #define in_addr_t unsigned long
58: #endif
59:
60: #include <curl/curl.h>
61: #include "urldata.h"
62: #include "sendf.h"
63: #include "hostip.h"
64: #include "progress.h"
65: #include "transfer.h"
66: #include "escape.h"
67: #include "http.h" /* for HTTP proxy tunnel stuff */
68: #include "ssh.h"
69: #include "url.h"
70: #include "speedcheck.h"
71: #include "getinfo.h"
72: #include "strdup.h"
73: #include "strcase.h"
74: #include "vtls/vtls.h"
75: #include "connect.h"
76: #include "strerror.h"
77: #include "inet_ntop.h"
78: #include "parsedate.h" /* for the week day and month names */
79: #include "sockaddr.h" /* required for Curl_sockaddr_storage */
80: #include "strtoofft.h"
81: #include "multiif.h"
82: #include "select.h"
83: #include "warnless.h"
84: #include "curl_path.h"
85:
86: /* The last 3 #include files should be in this order */
87: #include "curl_printf.h"
88: #include "curl_memory.h"
89: #include "memdebug.h"
90:
91: #if LIBSSH2_VERSION_NUM >= 0x010206
92: /* libssh2_sftp_statvfs and friends were added in 1.2.6 */
93: #define HAS_STATVFS_SUPPORT 1
94: #endif
95:
96: #define sftp_libssh2_last_error(s) curlx_ultosi(libssh2_sftp_last_error(s))
97:
98: #define sftp_libssh2_realpath(s,p,t,m) \
99: libssh2_sftp_symlink_ex((s), (p), curlx_uztoui(strlen(p)), \
100: (t), (m), LIBSSH2_SFTP_REALPATH)
101:
102:
103: /* Local functions: */
104: static const char *sftp_libssh2_strerror(int err);
105: static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc);
106: static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc);
107: static LIBSSH2_FREE_FUNC(my_libssh2_free);
108:
109: static CURLcode ssh_force_knownhost_key_type(struct connectdata *conn);
110: static CURLcode ssh_connect(struct connectdata *conn, bool *done);
111: static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done);
112: static CURLcode ssh_do(struct connectdata *conn, bool *done);
113:
114: static CURLcode scp_done(struct connectdata *conn,
115: CURLcode, bool premature);
116: static CURLcode scp_doing(struct connectdata *conn,
117: bool *dophase_done);
118: static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection);
119:
120: static CURLcode sftp_done(struct connectdata *conn,
121: CURLcode, bool premature);
122: static CURLcode sftp_doing(struct connectdata *conn,
123: bool *dophase_done);
124: static CURLcode sftp_disconnect(struct connectdata *conn, bool dead);
125: static
126: CURLcode sftp_perform(struct connectdata *conn,
127: bool *connected,
128: bool *dophase_done);
129: static int ssh_getsock(struct connectdata *conn, curl_socket_t *sock);
130: static int ssh_perform_getsock(const struct connectdata *conn,
131: curl_socket_t *sock);
132: static CURLcode ssh_setup_connection(struct connectdata *conn);
133:
134: /*
135: * SCP protocol handler.
136: */
137:
138: const struct Curl_handler Curl_handler_scp = {
139: "SCP", /* scheme */
140: ssh_setup_connection, /* setup_connection */
141: ssh_do, /* do_it */
142: scp_done, /* done */
143: ZERO_NULL, /* do_more */
144: ssh_connect, /* connect_it */
145: ssh_multi_statemach, /* connecting */
146: scp_doing, /* doing */
147: ssh_getsock, /* proto_getsock */
148: ssh_getsock, /* doing_getsock */
149: ZERO_NULL, /* domore_getsock */
150: ssh_perform_getsock, /* perform_getsock */
151: scp_disconnect, /* disconnect */
152: ZERO_NULL, /* readwrite */
153: ZERO_NULL, /* connection_check */
154: PORT_SSH, /* defport */
155: CURLPROTO_SCP, /* protocol */
156: PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
157: | PROTOPT_NOURLQUERY /* flags */
158: };
159:
160:
161: /*
162: * SFTP protocol handler.
163: */
164:
165: const struct Curl_handler Curl_handler_sftp = {
166: "SFTP", /* scheme */
167: ssh_setup_connection, /* setup_connection */
168: ssh_do, /* do_it */
169: sftp_done, /* done */
170: ZERO_NULL, /* do_more */
171: ssh_connect, /* connect_it */
172: ssh_multi_statemach, /* connecting */
173: sftp_doing, /* doing */
174: ssh_getsock, /* proto_getsock */
175: ssh_getsock, /* doing_getsock */
176: ZERO_NULL, /* domore_getsock */
177: ssh_perform_getsock, /* perform_getsock */
178: sftp_disconnect, /* disconnect */
179: ZERO_NULL, /* readwrite */
180: ZERO_NULL, /* connection_check */
181: PORT_SSH, /* defport */
182: CURLPROTO_SFTP, /* protocol */
183: PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
184: | PROTOPT_NOURLQUERY /* flags */
185: };
186:
187: static void
188: kbd_callback(const char *name, int name_len, const char *instruction,
189: int instruction_len, int num_prompts,
190: const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
191: LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
192: void **abstract)
193: {
194: struct connectdata *conn = (struct connectdata *)*abstract;
195:
196: #ifdef CURL_LIBSSH2_DEBUG
197: fprintf(stderr, "name=%s\n", name);
198: fprintf(stderr, "name_len=%d\n", name_len);
199: fprintf(stderr, "instruction=%s\n", instruction);
200: fprintf(stderr, "instruction_len=%d\n", instruction_len);
201: fprintf(stderr, "num_prompts=%d\n", num_prompts);
202: #else
203: (void)name;
204: (void)name_len;
205: (void)instruction;
206: (void)instruction_len;
207: #endif /* CURL_LIBSSH2_DEBUG */
208: if(num_prompts == 1) {
209: responses[0].text = strdup(conn->passwd);
210: responses[0].length = curlx_uztoui(strlen(conn->passwd));
211: }
212: (void)prompts;
213: (void)abstract;
214: } /* kbd_callback */
215:
216: static CURLcode sftp_libssh2_error_to_CURLE(int err)
217: {
218: switch(err) {
219: case LIBSSH2_FX_OK:
220: return CURLE_OK;
221:
222: case LIBSSH2_FX_NO_SUCH_FILE:
223: case LIBSSH2_FX_NO_SUCH_PATH:
224: return CURLE_REMOTE_FILE_NOT_FOUND;
225:
226: case LIBSSH2_FX_PERMISSION_DENIED:
227: case LIBSSH2_FX_WRITE_PROTECT:
228: case LIBSSH2_FX_LOCK_CONFlICT:
229: return CURLE_REMOTE_ACCESS_DENIED;
230:
231: case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
232: case LIBSSH2_FX_QUOTA_EXCEEDED:
233: return CURLE_REMOTE_DISK_FULL;
234:
235: case LIBSSH2_FX_FILE_ALREADY_EXISTS:
236: return CURLE_REMOTE_FILE_EXISTS;
237:
238: case LIBSSH2_FX_DIR_NOT_EMPTY:
239: return CURLE_QUOTE_ERROR;
240:
241: default:
242: break;
243: }
244:
245: return CURLE_SSH;
246: }
247:
248: static CURLcode libssh2_session_error_to_CURLE(int err)
249: {
250: switch(err) {
251: /* Ordered by order of appearance in libssh2.h */
252: case LIBSSH2_ERROR_NONE:
253: return CURLE_OK;
254:
255: /* This is the error returned by libssh2_scp_recv2
256: * on unknown file */
257: case LIBSSH2_ERROR_SCP_PROTOCOL:
258: return CURLE_REMOTE_FILE_NOT_FOUND;
259:
260: case LIBSSH2_ERROR_SOCKET_NONE:
261: return CURLE_COULDNT_CONNECT;
262:
263: case LIBSSH2_ERROR_ALLOC:
264: return CURLE_OUT_OF_MEMORY;
265:
266: case LIBSSH2_ERROR_SOCKET_SEND:
267: return CURLE_SEND_ERROR;
268:
269: case LIBSSH2_ERROR_HOSTKEY_INIT:
270: case LIBSSH2_ERROR_HOSTKEY_SIGN:
271: case LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED:
272: case LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED:
273: return CURLE_PEER_FAILED_VERIFICATION;
274:
275: case LIBSSH2_ERROR_PASSWORD_EXPIRED:
276: return CURLE_LOGIN_DENIED;
277:
278: case LIBSSH2_ERROR_SOCKET_TIMEOUT:
279: case LIBSSH2_ERROR_TIMEOUT:
280: return CURLE_OPERATION_TIMEDOUT;
281:
282: case LIBSSH2_ERROR_EAGAIN:
283: return CURLE_AGAIN;
284: }
285:
286: return CURLE_SSH;
287: }
288:
289: static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc)
290: {
291: (void)abstract; /* arg not used */
292: return malloc(count);
293: }
294:
295: static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc)
296: {
297: (void)abstract; /* arg not used */
298: return realloc(ptr, count);
299: }
300:
301: static LIBSSH2_FREE_FUNC(my_libssh2_free)
302: {
303: (void)abstract; /* arg not used */
304: if(ptr) /* ssh2 agent sometimes call free with null ptr */
305: free(ptr);
306: }
307:
308: /*
309: * SSH State machine related code
310: */
311: /* This is the ONLY way to change SSH state! */
312: static void state(struct connectdata *conn, sshstate nowstate)
313: {
314: struct ssh_conn *sshc = &conn->proto.sshc;
315: #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
316: /* for debug purposes */
317: static const char * const names[] = {
318: "SSH_STOP",
319: "SSH_INIT",
320: "SSH_S_STARTUP",
321: "SSH_HOSTKEY",
322: "SSH_AUTHLIST",
323: "SSH_AUTH_PKEY_INIT",
324: "SSH_AUTH_PKEY",
325: "SSH_AUTH_PASS_INIT",
326: "SSH_AUTH_PASS",
327: "SSH_AUTH_AGENT_INIT",
328: "SSH_AUTH_AGENT_LIST",
329: "SSH_AUTH_AGENT",
330: "SSH_AUTH_HOST_INIT",
331: "SSH_AUTH_HOST",
332: "SSH_AUTH_KEY_INIT",
333: "SSH_AUTH_KEY",
334: "SSH_AUTH_GSSAPI",
335: "SSH_AUTH_DONE",
336: "SSH_SFTP_INIT",
337: "SSH_SFTP_REALPATH",
338: "SSH_SFTP_QUOTE_INIT",
339: "SSH_SFTP_POSTQUOTE_INIT",
340: "SSH_SFTP_QUOTE",
341: "SSH_SFTP_NEXT_QUOTE",
342: "SSH_SFTP_QUOTE_STAT",
343: "SSH_SFTP_QUOTE_SETSTAT",
344: "SSH_SFTP_QUOTE_SYMLINK",
345: "SSH_SFTP_QUOTE_MKDIR",
346: "SSH_SFTP_QUOTE_RENAME",
347: "SSH_SFTP_QUOTE_RMDIR",
348: "SSH_SFTP_QUOTE_UNLINK",
349: "SSH_SFTP_QUOTE_STATVFS",
350: "SSH_SFTP_GETINFO",
351: "SSH_SFTP_FILETIME",
352: "SSH_SFTP_TRANS_INIT",
353: "SSH_SFTP_UPLOAD_INIT",
354: "SSH_SFTP_CREATE_DIRS_INIT",
355: "SSH_SFTP_CREATE_DIRS",
356: "SSH_SFTP_CREATE_DIRS_MKDIR",
357: "SSH_SFTP_READDIR_INIT",
358: "SSH_SFTP_READDIR",
359: "SSH_SFTP_READDIR_LINK",
360: "SSH_SFTP_READDIR_BOTTOM",
361: "SSH_SFTP_READDIR_DONE",
362: "SSH_SFTP_DOWNLOAD_INIT",
363: "SSH_SFTP_DOWNLOAD_STAT",
364: "SSH_SFTP_CLOSE",
365: "SSH_SFTP_SHUTDOWN",
366: "SSH_SCP_TRANS_INIT",
367: "SSH_SCP_UPLOAD_INIT",
368: "SSH_SCP_DOWNLOAD_INIT",
369: "SSH_SCP_DOWNLOAD",
370: "SSH_SCP_DONE",
371: "SSH_SCP_SEND_EOF",
372: "SSH_SCP_WAIT_EOF",
373: "SSH_SCP_WAIT_CLOSE",
374: "SSH_SCP_CHANNEL_FREE",
375: "SSH_SESSION_DISCONNECT",
376: "SSH_SESSION_FREE",
377: "QUIT"
378: };
379:
380: /* a precaution to make sure the lists are in sync */
381: DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
382:
383: if(sshc->state != nowstate) {
384: infof(conn->data, "SFTP %p state change from %s to %s\n",
385: (void *)sshc, names[sshc->state], names[nowstate]);
386: }
387: #endif
388:
389: sshc->state = nowstate;
390: }
391:
392:
393: #ifdef HAVE_LIBSSH2_KNOWNHOST_API
394: static int sshkeycallback(struct Curl_easy *easy,
395: const struct curl_khkey *knownkey, /* known */
396: const struct curl_khkey *foundkey, /* found */
397: enum curl_khmatch match,
398: void *clientp)
399: {
400: (void)easy;
401: (void)knownkey;
402: (void)foundkey;
403: (void)clientp;
404:
405: /* we only allow perfect matches, and we reject everything else */
406: return (match != CURLKHMATCH_OK)?CURLKHSTAT_REJECT:CURLKHSTAT_FINE;
407: }
408: #endif
409:
410: /*
411: * Earlier libssh2 versions didn't have the ability to seek to 64bit positions
412: * with 32bit size_t.
413: */
414: #ifdef HAVE_LIBSSH2_SFTP_SEEK64
415: #define SFTP_SEEK(x,y) libssh2_sftp_seek64(x, (libssh2_uint64_t)y)
416: #else
417: #define SFTP_SEEK(x,y) libssh2_sftp_seek(x, (size_t)y)
418: #endif
419:
420: /*
421: * Earlier libssh2 versions didn't do SCP properly beyond 32bit sizes on 32bit
422: * architectures so we check of the necessary function is present.
423: */
424: #ifndef HAVE_LIBSSH2_SCP_SEND64
425: #define SCP_SEND(a,b,c,d) libssh2_scp_send_ex(a, b, (int)(c), (size_t)d, 0, 0)
426: #else
427: #define SCP_SEND(a,b,c,d) libssh2_scp_send64(a, b, (int)(c), \
428: (libssh2_uint64_t)d, 0, 0)
429: #endif
430:
431: /*
432: * libssh2 1.2.8 fixed the problem with 32bit ints used for sockets on win64.
433: */
434: #ifdef HAVE_LIBSSH2_SESSION_HANDSHAKE
435: #define libssh2_session_startup(x,y) libssh2_session_handshake(x,y)
436: #endif
437:
438: static CURLcode ssh_knownhost(struct connectdata *conn)
439: {
440: CURLcode result = CURLE_OK;
441:
442: #ifdef HAVE_LIBSSH2_KNOWNHOST_API
443: struct Curl_easy *data = conn->data;
444:
445: if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
446: /* we're asked to verify the host against a file */
447: struct ssh_conn *sshc = &conn->proto.sshc;
448: int rc;
449: int keytype;
450: size_t keylen;
451: const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
452: &keylen, &keytype);
453: int keycheck = LIBSSH2_KNOWNHOST_CHECK_FAILURE;
454: int keybit = 0;
455:
456: if(remotekey) {
457: /*
458: * A subject to figure out is what host name we need to pass in here.
459: * What host name does OpenSSH store in its file if an IDN name is
460: * used?
461: */
462: struct libssh2_knownhost *host;
463: enum curl_khmatch keymatch;
464: curl_sshkeycallback func =
465: data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback;
466: struct curl_khkey knownkey;
467: struct curl_khkey *knownkeyp = NULL;
468: struct curl_khkey foundkey;
469:
470: switch(keytype) {
471: case LIBSSH2_HOSTKEY_TYPE_RSA:
472: keybit = LIBSSH2_KNOWNHOST_KEY_SSHRSA;
473: break;
474: case LIBSSH2_HOSTKEY_TYPE_DSS:
475: keybit = LIBSSH2_KNOWNHOST_KEY_SSHDSS;
476: break;
477: #ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256
478: case LIBSSH2_HOSTKEY_TYPE_ECDSA_256:
479: keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_256;
480: break;
481: #endif
482: #ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384
483: case LIBSSH2_HOSTKEY_TYPE_ECDSA_384:
484: keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_384;
485: break;
486: #endif
487: #ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521
488: case LIBSSH2_HOSTKEY_TYPE_ECDSA_521:
489: keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_521;
490: break;
491: #endif
492: #ifdef LIBSSH2_HOSTKEY_TYPE_ED25519
493: case LIBSSH2_HOSTKEY_TYPE_ED25519:
494: keybit = LIBSSH2_KNOWNHOST_KEY_ED25519;
495: break;
496: #endif
497: default:
498: infof(data, "unsupported key type, can't check knownhosts!\n");
499: keybit = 0;
500: break;
501: }
502: if(!keybit)
503: /* no check means failure! */
504: rc = CURLKHSTAT_REJECT;
505: else {
506: #ifdef HAVE_LIBSSH2_KNOWNHOST_CHECKP
507: keycheck = libssh2_knownhost_checkp(sshc->kh,
508: conn->host.name,
509: (conn->remote_port != PORT_SSH)?
510: conn->remote_port:-1,
511: remotekey, keylen,
512: LIBSSH2_KNOWNHOST_TYPE_PLAIN|
513: LIBSSH2_KNOWNHOST_KEYENC_RAW|
514: keybit,
515: &host);
516: #else
517: keycheck = libssh2_knownhost_check(sshc->kh,
518: conn->host.name,
519: remotekey, keylen,
520: LIBSSH2_KNOWNHOST_TYPE_PLAIN|
521: LIBSSH2_KNOWNHOST_KEYENC_RAW|
522: keybit,
523: &host);
524: #endif
525:
526: infof(data, "SSH host check: %d, key: %s\n", keycheck,
527: (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
528: host->key:"<none>");
529:
530: /* setup 'knownkey' */
531: if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) {
532: knownkey.key = host->key;
533: knownkey.len = 0;
534: knownkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
535: CURLKHTYPE_RSA : CURLKHTYPE_DSS;
536: knownkeyp = &knownkey;
537: }
538:
539: /* setup 'foundkey' */
540: foundkey.key = remotekey;
541: foundkey.len = keylen;
542: foundkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
543: CURLKHTYPE_RSA : CURLKHTYPE_DSS;
544:
545: /*
546: * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the
547: * curl_khmatch enum are ever modified, we need to introduce a
548: * translation table here!
549: */
550: keymatch = (enum curl_khmatch)keycheck;
551:
552: /* Ask the callback how to behave */
553: Curl_set_in_callback(data, true);
554: rc = func(data, knownkeyp, /* from the knownhosts file */
555: &foundkey, /* from the remote host */
556: keymatch, data->set.ssh_keyfunc_userp);
557: Curl_set_in_callback(data, false);
558: }
559: }
560: else
561: /* no remotekey means failure! */
562: rc = CURLKHSTAT_REJECT;
563:
564: switch(rc) {
565: default: /* unknown return codes will equal reject */
566: /* FALLTHROUGH */
567: case CURLKHSTAT_REJECT:
568: state(conn, SSH_SESSION_FREE);
569: /* FALLTHROUGH */
570: case CURLKHSTAT_DEFER:
571: /* DEFER means bail out but keep the SSH_HOSTKEY state */
572: result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
573: break;
574: case CURLKHSTAT_FINE:
575: case CURLKHSTAT_FINE_ADD_TO_FILE:
576: /* proceed */
577: if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
578: /* the found host+key didn't match but has been told to be fine
579: anyway so we add it in memory */
580: int addrc = libssh2_knownhost_add(sshc->kh,
581: conn->host.name, NULL,
582: remotekey, keylen,
583: LIBSSH2_KNOWNHOST_TYPE_PLAIN|
584: LIBSSH2_KNOWNHOST_KEYENC_RAW|
585: keybit, NULL);
586: if(addrc)
587: infof(data, "Warning adding the known host %s failed!\n",
588: conn->host.name);
589: else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE) {
590: /* now we write the entire in-memory list of known hosts to the
591: known_hosts file */
592: int wrc =
593: libssh2_knownhost_writefile(sshc->kh,
594: data->set.str[STRING_SSH_KNOWNHOSTS],
595: LIBSSH2_KNOWNHOST_FILE_OPENSSH);
596: if(wrc) {
597: infof(data, "Warning, writing %s failed!\n",
598: data->set.str[STRING_SSH_KNOWNHOSTS]);
599: }
600: }
601: }
602: break;
603: }
604: }
605: #else /* HAVE_LIBSSH2_KNOWNHOST_API */
606: (void)conn;
607: #endif
608: return result;
609: }
610:
611: static CURLcode ssh_check_fingerprint(struct connectdata *conn)
612: {
613: struct ssh_conn *sshc = &conn->proto.sshc;
614: struct Curl_easy *data = conn->data;
615: const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
616: char md5buffer[33];
617:
618: const char *fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
619: LIBSSH2_HOSTKEY_HASH_MD5);
620:
621: if(fingerprint) {
622: /* The fingerprint points to static storage (!), don't free() it. */
623: int i;
624: for(i = 0; i < 16; i++)
625: msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
626: infof(data, "SSH MD5 fingerprint: %s\n", md5buffer);
627: }
628:
629: /* Before we authenticate we check the hostkey's MD5 fingerprint
630: * against a known fingerprint, if available.
631: */
632: if(pubkey_md5 && strlen(pubkey_md5) == 32) {
633: if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) {
634: if(fingerprint)
635: failf(data,
636: "Denied establishing ssh session: mismatch md5 fingerprint. "
637: "Remote %s is not equal to %s", md5buffer, pubkey_md5);
638: else
639: failf(data,
640: "Denied establishing ssh session: md5 fingerprint not available");
641: state(conn, SSH_SESSION_FREE);
642: sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
643: return sshc->actualcode;
644: }
645: infof(data, "MD5 checksum match!\n");
646: /* as we already matched, we skip the check for known hosts */
647: return CURLE_OK;
648: }
649: return ssh_knownhost(conn);
650: }
651:
652: /*
653: * ssh_force_knownhost_key_type() will check the known hosts file and try to
654: * force a specific public key type from the server if an entry is found.
655: */
656: static CURLcode ssh_force_knownhost_key_type(struct connectdata *conn)
657: {
658: CURLcode result = CURLE_OK;
659:
660: #ifdef HAVE_LIBSSH2_KNOWNHOST_API
661:
662: #ifdef LIBSSH2_KNOWNHOST_KEY_ED25519
663: static const char * const hostkey_method_ssh_ed25519
664: = "ssh-ed25519";
665: #endif
666: #ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521
667: static const char * const hostkey_method_ssh_ecdsa_521
668: = "ecdsa-sha2-nistp521";
669: #endif
670: #ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384
671: static const char * const hostkey_method_ssh_ecdsa_384
672: = "ecdsa-sha2-nistp384";
673: #endif
674: #ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256
675: static const char * const hostkey_method_ssh_ecdsa_256
676: = "ecdsa-sha2-nistp256";
677: #endif
678: static const char * const hostkey_method_ssh_rsa
679: = "ssh-rsa";
680: static const char * const hostkey_method_ssh_dss
681: = "ssh-dss";
682:
683: const char *hostkey_method = NULL;
684: struct ssh_conn *sshc = &conn->proto.sshc;
685: struct Curl_easy *data = conn->data;
686: struct libssh2_knownhost* store = NULL;
687: const char *kh_name_end = NULL;
688: size_t kh_name_size = 0;
689: int port = 0;
690: bool found = false;
691:
692: if(sshc->kh && !data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
693: /* lets try to find our host in the known hosts file */
694: while(!libssh2_knownhost_get(sshc->kh, &store, store)) {
695: /* For non-standard ports, the name will be enclosed in */
696: /* square brackets, followed by a colon and the port */
697: if(store) {
698: if(store->name) {
699: if(store->name[0] == '[') {
700: kh_name_end = strstr(store->name, "]:");
701: if(!kh_name_end) {
702: infof(data, "Invalid host pattern %s in %s\n",
703: store->name, data->set.str[STRING_SSH_KNOWNHOSTS]);
704: continue;
705: }
706: port = atoi(kh_name_end + 2);
707: if(kh_name_end && (port == conn->remote_port)) {
708: kh_name_size = strlen(store->name) - 1 - strlen(kh_name_end);
709: if(strncmp(store->name + 1,
710: conn->host.name, kh_name_size) == 0) {
711: found = true;
712: break;
713: }
714: }
715: }
716: else if(strcmp(store->name, conn->host.name) == 0) {
717: found = true;
718: break;
719: }
720: }
721: else {
722: found = true;
723: break;
724: }
725: }
726: }
727:
728: if(found) {
729: infof(data, "Found host %s in %s\n",
730: conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]);
731:
732: switch(store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) {
733: #ifdef LIBSSH2_KNOWNHOST_KEY_ED25519
734: case LIBSSH2_KNOWNHOST_KEY_ED25519:
735: hostkey_method = hostkey_method_ssh_ed25519;
736: break;
737: #endif
738: #ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521
739: case LIBSSH2_KNOWNHOST_KEY_ECDSA_521:
740: hostkey_method = hostkey_method_ssh_ecdsa_521;
741: break;
742: #endif
743: #ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384
744: case LIBSSH2_KNOWNHOST_KEY_ECDSA_384:
745: hostkey_method = hostkey_method_ssh_ecdsa_384;
746: break;
747: #endif
748: #ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256
749: case LIBSSH2_KNOWNHOST_KEY_ECDSA_256:
750: hostkey_method = hostkey_method_ssh_ecdsa_256;
751: break;
752: #endif
753: case LIBSSH2_KNOWNHOST_KEY_SSHRSA:
754: hostkey_method = hostkey_method_ssh_rsa;
755: break;
756: case LIBSSH2_KNOWNHOST_KEY_SSHDSS:
757: hostkey_method = hostkey_method_ssh_dss;
758: break;
759: case LIBSSH2_KNOWNHOST_KEY_RSA1:
760: failf(data, "Found host key type RSA1 which is not supported\n");
761: return CURLE_SSH;
762: default:
763: failf(data, "Unknown host key type: %i\n",
764: (store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK));
765: return CURLE_SSH;
766: }
767:
768: infof(data, "Set \"%s\" as SSH hostkey type\n", hostkey_method);
769: result = libssh2_session_error_to_CURLE(
770: libssh2_session_method_pref(
771: sshc->ssh_session, LIBSSH2_METHOD_HOSTKEY, hostkey_method));
772: }
773: else {
774: infof(data, "Did not find host %s in %s\n",
775: conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]);
776: }
777: }
778:
779: #endif /* HAVE_LIBSSH2_KNOWNHOST_API */
780:
781: return result;
782: }
783:
784: /*
785: * ssh_statemach_act() runs the SSH state machine as far as it can without
786: * blocking and without reaching the end. The data the pointer 'block' points
787: * to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
788: * meaning it wants to be called again when the socket is ready
789: */
790:
791: static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
792: {
793: CURLcode result = CURLE_OK;
794: struct Curl_easy *data = conn->data;
795: struct SSHPROTO *sftp_scp = data->req.protop;
796: struct ssh_conn *sshc = &conn->proto.sshc;
797: curl_socket_t sock = conn->sock[FIRSTSOCKET];
798: char *new_readdir_line;
799: int rc = LIBSSH2_ERROR_NONE;
800: int err;
801: int seekerr = CURL_SEEKFUNC_OK;
802: *block = 0; /* we're not blocking by default */
803:
804: do {
805:
806: switch(sshc->state) {
807: case SSH_INIT:
808: sshc->secondCreateDirs = 0;
809: sshc->nextstate = SSH_NO_STATE;
810: sshc->actualcode = CURLE_OK;
811:
812: /* Set libssh2 to non-blocking, since everything internally is
813: non-blocking */
814: libssh2_session_set_blocking(sshc->ssh_session, 0);
815:
816: result = ssh_force_knownhost_key_type(conn);
817: if(result) {
818: state(conn, SSH_SESSION_FREE);
819: break;
820: }
821:
822: state(conn, SSH_S_STARTUP);
823: /* FALLTHROUGH */
824:
825: case SSH_S_STARTUP:
826: rc = libssh2_session_startup(sshc->ssh_session, (int)sock);
827: if(rc == LIBSSH2_ERROR_EAGAIN) {
828: break;
829: }
830: if(rc) {
831: char *err_msg = NULL;
832: (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
833: failf(data, "Failure establishing ssh session: %d, %s", rc, err_msg);
834:
835: state(conn, SSH_SESSION_FREE);
836: sshc->actualcode = CURLE_FAILED_INIT;
837: break;
838: }
839:
840: state(conn, SSH_HOSTKEY);
841:
842: /* FALLTHROUGH */
843: case SSH_HOSTKEY:
844: /*
845: * Before we authenticate we should check the hostkey's fingerprint
846: * against our known hosts. How that is handled (reading from file,
847: * whatever) is up to us.
848: */
849: result = ssh_check_fingerprint(conn);
850: if(!result)
851: state(conn, SSH_AUTHLIST);
852: /* ssh_check_fingerprint sets state appropriately on error */
853: break;
854:
855: case SSH_AUTHLIST:
856: /*
857: * Figure out authentication methods
858: * NB: As soon as we have provided a username to an openssh server we
859: * must never change it later. Thus, always specify the correct username
860: * here, even though the libssh2 docs kind of indicate that it should be
861: * possible to get a 'generic' list (not user-specific) of authentication
862: * methods, presumably with a blank username. That won't work in my
863: * experience.
864: * So always specify it here.
865: */
866: sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
867: conn->user,
868: curlx_uztoui(strlen(conn->user)));
869:
870: if(!sshc->authlist) {
871: if(libssh2_userauth_authenticated(sshc->ssh_session)) {
872: sshc->authed = TRUE;
873: infof(data, "SSH user accepted with no authentication\n");
874: state(conn, SSH_AUTH_DONE);
875: break;
876: }
877: err = libssh2_session_last_errno(sshc->ssh_session);
878: if(err == LIBSSH2_ERROR_EAGAIN)
879: rc = LIBSSH2_ERROR_EAGAIN;
880: else {
881: state(conn, SSH_SESSION_FREE);
882: sshc->actualcode = libssh2_session_error_to_CURLE(err);
883: }
884: break;
885: }
886: infof(data, "SSH authentication methods available: %s\n",
887: sshc->authlist);
888:
889: state(conn, SSH_AUTH_PKEY_INIT);
890: break;
891:
892: case SSH_AUTH_PKEY_INIT:
893: /*
894: * Check the supported auth types in the order I feel is most secure
895: * with the requested type of authentication
896: */
897: sshc->authed = FALSE;
898:
899: if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
900: (strstr(sshc->authlist, "publickey") != NULL)) {
901: bool out_of_memory = FALSE;
902:
903: sshc->rsa_pub = sshc->rsa = NULL;
904:
905: if(data->set.str[STRING_SSH_PRIVATE_KEY])
906: sshc->rsa = strdup(data->set.str[STRING_SSH_PRIVATE_KEY]);
907: else {
908: /* To ponder about: should really the lib be messing about with the
909: HOME environment variable etc? */
910: char *home = curl_getenv("HOME");
911:
912: /* If no private key file is specified, try some common paths. */
913: if(home) {
914: /* Try ~/.ssh first. */
915: sshc->rsa = aprintf("%s/.ssh/id_rsa", home);
916: if(!sshc->rsa)
917: out_of_memory = TRUE;
918: else if(access(sshc->rsa, R_OK) != 0) {
919: Curl_safefree(sshc->rsa);
920: sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
921: if(!sshc->rsa)
922: out_of_memory = TRUE;
923: else if(access(sshc->rsa, R_OK) != 0) {
924: Curl_safefree(sshc->rsa);
925: }
926: }
927: free(home);
928: }
929: if(!out_of_memory && !sshc->rsa) {
930: /* Nothing found; try the current dir. */
931: sshc->rsa = strdup("id_rsa");
932: if(sshc->rsa && access(sshc->rsa, R_OK) != 0) {
933: Curl_safefree(sshc->rsa);
934: sshc->rsa = strdup("id_dsa");
935: if(sshc->rsa && access(sshc->rsa, R_OK) != 0) {
936: Curl_safefree(sshc->rsa);
937: /* Out of guesses. Set to the empty string to avoid
938: * surprising info messages. */
939: sshc->rsa = strdup("");
940: }
941: }
942: }
943: }
944:
945: /*
946: * Unless the user explicitly specifies a public key file, let
947: * libssh2 extract the public key from the private key file.
948: * This is done by simply passing sshc->rsa_pub = NULL.
949: */
950: if(data->set.str[STRING_SSH_PUBLIC_KEY]
951: /* treat empty string the same way as NULL */
952: && data->set.str[STRING_SSH_PUBLIC_KEY][0]) {
953: sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]);
954: if(!sshc->rsa_pub)
955: out_of_memory = TRUE;
956: }
957:
958: if(out_of_memory || sshc->rsa == NULL) {
959: Curl_safefree(sshc->rsa);
960: Curl_safefree(sshc->rsa_pub);
961: state(conn, SSH_SESSION_FREE);
962: sshc->actualcode = CURLE_OUT_OF_MEMORY;
963: break;
964: }
965:
966: sshc->passphrase = data->set.ssl.key_passwd;
967: if(!sshc->passphrase)
968: sshc->passphrase = "";
969:
970: if(sshc->rsa_pub)
971: infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub);
972: infof(data, "Using SSH private key file '%s'\n", sshc->rsa);
973:
974: state(conn, SSH_AUTH_PKEY);
975: }
976: else {
977: state(conn, SSH_AUTH_PASS_INIT);
978: }
979: break;
980:
981: case SSH_AUTH_PKEY:
982: /* The function below checks if the files exists, no need to stat() here.
983: */
984: rc = libssh2_userauth_publickey_fromfile_ex(sshc->ssh_session,
985: conn->user,
986: curlx_uztoui(
987: strlen(conn->user)),
988: sshc->rsa_pub,
989: sshc->rsa, sshc->passphrase);
990: if(rc == LIBSSH2_ERROR_EAGAIN) {
991: break;
992: }
993:
994: Curl_safefree(sshc->rsa_pub);
995: Curl_safefree(sshc->rsa);
996:
997: if(rc == 0) {
998: sshc->authed = TRUE;
999: infof(data, "Initialized SSH public key authentication\n");
1000: state(conn, SSH_AUTH_DONE);
1001: }
1002: else {
1003: char *err_msg = NULL;
1004: (void)libssh2_session_last_error(sshc->ssh_session,
1005: &err_msg, NULL, 0);
1006: infof(data, "SSH public key authentication failed: %s\n", err_msg);
1007: state(conn, SSH_AUTH_PASS_INIT);
1008: rc = 0; /* clear rc and continue */
1009: }
1010: break;
1011:
1012: case SSH_AUTH_PASS_INIT:
1013: if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
1014: (strstr(sshc->authlist, "password") != NULL)) {
1015: state(conn, SSH_AUTH_PASS);
1016: }
1017: else {
1018: state(conn, SSH_AUTH_HOST_INIT);
1019: rc = 0; /* clear rc and continue */
1020: }
1021: break;
1022:
1023: case SSH_AUTH_PASS:
1024: rc = libssh2_userauth_password_ex(sshc->ssh_session, conn->user,
1025: curlx_uztoui(strlen(conn->user)),
1026: conn->passwd,
1027: curlx_uztoui(strlen(conn->passwd)),
1028: NULL);
1029: if(rc == LIBSSH2_ERROR_EAGAIN) {
1030: break;
1031: }
1032: if(rc == 0) {
1033: sshc->authed = TRUE;
1034: infof(data, "Initialized password authentication\n");
1035: state(conn, SSH_AUTH_DONE);
1036: }
1037: else {
1038: state(conn, SSH_AUTH_HOST_INIT);
1039: rc = 0; /* clear rc and continue */
1040: }
1041: break;
1042:
1043: case SSH_AUTH_HOST_INIT:
1044: if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) &&
1045: (strstr(sshc->authlist, "hostbased") != NULL)) {
1046: state(conn, SSH_AUTH_HOST);
1047: }
1048: else {
1049: state(conn, SSH_AUTH_AGENT_INIT);
1050: }
1051: break;
1052:
1053: case SSH_AUTH_HOST:
1054: state(conn, SSH_AUTH_AGENT_INIT);
1055: break;
1056:
1057: case SSH_AUTH_AGENT_INIT:
1058: #ifdef HAVE_LIBSSH2_AGENT_API
1059: if((data->set.ssh_auth_types & CURLSSH_AUTH_AGENT)
1060: && (strstr(sshc->authlist, "publickey") != NULL)) {
1061:
1062: /* Connect to the ssh-agent */
1063: /* The agent could be shared by a curl thread i believe
1064: but nothing obvious as keys can be added/removed at any time */
1065: if(!sshc->ssh_agent) {
1066: sshc->ssh_agent = libssh2_agent_init(sshc->ssh_session);
1067: if(!sshc->ssh_agent) {
1068: infof(data, "Could not create agent object\n");
1069:
1070: state(conn, SSH_AUTH_KEY_INIT);
1071: break;
1072: }
1073: }
1074:
1075: rc = libssh2_agent_connect(sshc->ssh_agent);
1076: if(rc == LIBSSH2_ERROR_EAGAIN)
1077: break;
1078: if(rc < 0) {
1079: infof(data, "Failure connecting to agent\n");
1080: state(conn, SSH_AUTH_KEY_INIT);
1081: rc = 0; /* clear rc and continue */
1082: }
1083: else {
1084: state(conn, SSH_AUTH_AGENT_LIST);
1085: }
1086: }
1087: else
1088: #endif /* HAVE_LIBSSH2_AGENT_API */
1089: state(conn, SSH_AUTH_KEY_INIT);
1090: break;
1091:
1092: case SSH_AUTH_AGENT_LIST:
1093: #ifdef HAVE_LIBSSH2_AGENT_API
1094: rc = libssh2_agent_list_identities(sshc->ssh_agent);
1095:
1096: if(rc == LIBSSH2_ERROR_EAGAIN)
1097: break;
1098: if(rc < 0) {
1099: infof(data, "Failure requesting identities to agent\n");
1100: state(conn, SSH_AUTH_KEY_INIT);
1101: rc = 0; /* clear rc and continue */
1102: }
1103: else {
1104: state(conn, SSH_AUTH_AGENT);
1105: sshc->sshagent_prev_identity = NULL;
1106: }
1107: #endif
1108: break;
1109:
1110: case SSH_AUTH_AGENT:
1111: #ifdef HAVE_LIBSSH2_AGENT_API
1112: /* as prev_identity evolves only after an identity user auth finished we
1113: can safely request it again as long as EAGAIN is returned here or by
1114: libssh2_agent_userauth */
1115: rc = libssh2_agent_get_identity(sshc->ssh_agent,
1116: &sshc->sshagent_identity,
1117: sshc->sshagent_prev_identity);
1118: if(rc == LIBSSH2_ERROR_EAGAIN)
1119: break;
1120:
1121: if(rc == 0) {
1122: rc = libssh2_agent_userauth(sshc->ssh_agent, conn->user,
1123: sshc->sshagent_identity);
1124:
1125: if(rc < 0) {
1126: if(rc != LIBSSH2_ERROR_EAGAIN) {
1127: /* tried and failed? go to next identity */
1128: sshc->sshagent_prev_identity = sshc->sshagent_identity;
1129: }
1130: break;
1131: }
1132: }
1133:
1134: if(rc < 0)
1135: infof(data, "Failure requesting identities to agent\n");
1136: else if(rc == 1)
1137: infof(data, "No identity would match\n");
1138:
1139: if(rc == LIBSSH2_ERROR_NONE) {
1140: sshc->authed = TRUE;
1141: infof(data, "Agent based authentication successful\n");
1142: state(conn, SSH_AUTH_DONE);
1143: }
1144: else {
1145: state(conn, SSH_AUTH_KEY_INIT);
1146: rc = 0; /* clear rc and continue */
1147: }
1148: #endif
1149: break;
1150:
1151: case SSH_AUTH_KEY_INIT:
1152: if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
1153: && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) {
1154: state(conn, SSH_AUTH_KEY);
1155: }
1156: else {
1157: state(conn, SSH_AUTH_DONE);
1158: }
1159: break;
1160:
1161: case SSH_AUTH_KEY:
1162: /* Authentication failed. Continue with keyboard-interactive now. */
1163: rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session,
1164: conn->user,
1165: curlx_uztoui(
1166: strlen(conn->user)),
1167: &kbd_callback);
1168: if(rc == LIBSSH2_ERROR_EAGAIN) {
1169: break;
1170: }
1171: if(rc == 0) {
1172: sshc->authed = TRUE;
1173: infof(data, "Initialized keyboard interactive authentication\n");
1174: }
1175: state(conn, SSH_AUTH_DONE);
1176: break;
1177:
1178: case SSH_AUTH_DONE:
1179: if(!sshc->authed) {
1180: failf(data, "Authentication failure");
1181: state(conn, SSH_SESSION_FREE);
1182: sshc->actualcode = CURLE_LOGIN_DENIED;
1183: break;
1184: }
1185:
1186: /*
1187: * At this point we have an authenticated ssh session.
1188: */
1189: infof(data, "Authentication complete\n");
1190:
1191: Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */
1192:
1193: conn->sockfd = sock;
1194: conn->writesockfd = CURL_SOCKET_BAD;
1195:
1196: if(conn->handler->protocol == CURLPROTO_SFTP) {
1197: state(conn, SSH_SFTP_INIT);
1198: break;
1199: }
1200: infof(data, "SSH CONNECT phase done\n");
1201: state(conn, SSH_STOP);
1202: break;
1203:
1204: case SSH_SFTP_INIT:
1205: /*
1206: * Start the libssh2 sftp session
1207: */
1208: sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session);
1209: if(!sshc->sftp_session) {
1210: char *err_msg = NULL;
1211: if(libssh2_session_last_errno(sshc->ssh_session) ==
1212: LIBSSH2_ERROR_EAGAIN) {
1213: rc = LIBSSH2_ERROR_EAGAIN;
1214: break;
1215: }
1216:
1217: (void)libssh2_session_last_error(sshc->ssh_session,
1218: &err_msg, NULL, 0);
1219: failf(data, "Failure initializing sftp session: %s", err_msg);
1220: state(conn, SSH_SESSION_FREE);
1221: sshc->actualcode = CURLE_FAILED_INIT;
1222: break;
1223: }
1224: state(conn, SSH_SFTP_REALPATH);
1225: break;
1226:
1227: case SSH_SFTP_REALPATH:
1228: {
1229: char tempHome[PATH_MAX];
1230:
1231: /*
1232: * Get the "home" directory
1233: */
1234: rc = sftp_libssh2_realpath(sshc->sftp_session, ".",
1235: tempHome, PATH_MAX-1);
1236: if(rc == LIBSSH2_ERROR_EAGAIN) {
1237: break;
1238: }
1239: if(rc > 0) {
1240: /* It seems that this string is not always NULL terminated */
1241: tempHome[rc] = '\0';
1242: sshc->homedir = strdup(tempHome);
1243: if(!sshc->homedir) {
1244: state(conn, SSH_SFTP_CLOSE);
1245: sshc->actualcode = CURLE_OUT_OF_MEMORY;
1246: break;
1247: }
1248: conn->data->state.most_recent_ftp_entrypath = sshc->homedir;
1249: }
1250: else {
1251: /* Return the error type */
1252: err = sftp_libssh2_last_error(sshc->sftp_session);
1253: if(err)
1254: result = sftp_libssh2_error_to_CURLE(err);
1255: else
1256: /* in this case, the error wasn't in the SFTP level but for example
1257: a time-out or similar */
1258: result = CURLE_SSH;
1259: sshc->actualcode = result;
1260: DEBUGF(infof(data, "error = %d makes libcurl = %d\n",
1261: err, (int)result));
1262: state(conn, SSH_STOP);
1263: break;
1264: }
1265: }
1266: /* This is the last step in the SFTP connect phase. Do note that while
1267: we get the homedir here, we get the "workingpath" in the DO action
1268: since the homedir will remain the same between request but the
1269: working path will not. */
1270: DEBUGF(infof(data, "SSH CONNECT phase done\n"));
1271: state(conn, SSH_STOP);
1272: break;
1273:
1274: case SSH_SFTP_QUOTE_INIT:
1275:
1276: result = Curl_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
1277: if(result) {
1278: sshc->actualcode = result;
1279: state(conn, SSH_STOP);
1280: break;
1281: }
1282:
1283: if(data->set.quote) {
1284: infof(data, "Sending quote commands\n");
1285: sshc->quote_item = data->set.quote;
1286: state(conn, SSH_SFTP_QUOTE);
1287: }
1288: else {
1289: state(conn, SSH_SFTP_GETINFO);
1290: }
1291: break;
1292:
1293: case SSH_SFTP_POSTQUOTE_INIT:
1294: if(data->set.postquote) {
1295: infof(data, "Sending quote commands\n");
1296: sshc->quote_item = data->set.postquote;
1297: state(conn, SSH_SFTP_QUOTE);
1298: }
1299: else {
1300: state(conn, SSH_STOP);
1301: }
1302: break;
1303:
1304: case SSH_SFTP_QUOTE:
1305: /* Send any quote commands */
1306: {
1307: const char *cp;
1308:
1309: /*
1310: * Support some of the "FTP" commands
1311: *
1312: * 'sshc->quote_item' is already verified to be non-NULL before it
1313: * switched to this state.
1314: */
1315: char *cmd = sshc->quote_item->data;
1316: sshc->acceptfail = FALSE;
1317:
1318: /* if a command starts with an asterisk, which a legal SFTP command never
1319: can, the command will be allowed to fail without it causing any
1320: aborts or cancels etc. It will cause libcurl to act as if the command
1321: is successful, whatever the server reponds. */
1322:
1323: if(cmd[0] == '*') {
1324: cmd++;
1325: sshc->acceptfail = TRUE;
1326: }
1327:
1328: if(strcasecompare("pwd", cmd)) {
1329: /* output debug output if that is requested */
1330: char *tmp = aprintf("257 \"%s\" is current directory.\n",
1331: sftp_scp->path);
1332: if(!tmp) {
1333: result = CURLE_OUT_OF_MEMORY;
1334: state(conn, SSH_SFTP_CLOSE);
1335: sshc->nextstate = SSH_NO_STATE;
1336: break;
1337: }
1338: if(data->set.verbose) {
1339: Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4);
1340: Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
1341: }
1342: /* this sends an FTP-like "header" to the header callback so that the
1343: current directory can be read very similar to how it is read when
1344: using ordinary FTP. */
1345: result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
1346: free(tmp);
1347: if(result) {
1348: state(conn, SSH_SFTP_CLOSE);
1349: sshc->nextstate = SSH_NO_STATE;
1350: sshc->actualcode = result;
1351: }
1352: else
1353: state(conn, SSH_SFTP_NEXT_QUOTE);
1354: break;
1355: }
1356: {
1357: /*
1358: * the arguments following the command must be separated from the
1359: * command with a space so we can check for it unconditionally
1360: */
1361: cp = strchr(cmd, ' ');
1362: if(cp == NULL) {
1363: failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
1364: state(conn, SSH_SFTP_CLOSE);
1365: sshc->nextstate = SSH_NO_STATE;
1366: sshc->actualcode = CURLE_QUOTE_ERROR;
1367: break;
1368: }
1369:
1370: /*
1371: * also, every command takes at least one argument so we get that
1372: * first argument right now
1373: */
1374: result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
1375: if(result) {
1376: if(result == CURLE_OUT_OF_MEMORY)
1377: failf(data, "Out of memory");
1378: else
1379: failf(data, "Syntax error: Bad first parameter");
1380: state(conn, SSH_SFTP_CLOSE);
1381: sshc->nextstate = SSH_NO_STATE;
1382: sshc->actualcode = result;
1383: break;
1384: }
1385:
1386: /*
1387: * SFTP is a binary protocol, so we don't send text commands
1388: * to the server. Instead, we scan for commands used by
1389: * OpenSSH's sftp program and call the appropriate libssh2
1390: * functions.
1391: */
1392: if(strncasecompare(cmd, "chgrp ", 6) ||
1393: strncasecompare(cmd, "chmod ", 6) ||
1394: strncasecompare(cmd, "chown ", 6) ) {
1395: /* attribute change */
1396:
1397: /* sshc->quote_path1 contains the mode to set */
1398: /* get the destination */
1399: result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
1400: if(result) {
1401: if(result == CURLE_OUT_OF_MEMORY)
1402: failf(data, "Out of memory");
1403: else
1404: failf(data, "Syntax error in chgrp/chmod/chown: "
1405: "Bad second parameter");
1406: Curl_safefree(sshc->quote_path1);
1407: state(conn, SSH_SFTP_CLOSE);
1408: sshc->nextstate = SSH_NO_STATE;
1409: sshc->actualcode = result;
1410: break;
1411: }
1412: memset(&sshc->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
1413: state(conn, SSH_SFTP_QUOTE_STAT);
1414: break;
1415: }
1416: if(strncasecompare(cmd, "ln ", 3) ||
1417: strncasecompare(cmd, "symlink ", 8)) {
1418: /* symbolic linking */
1419: /* sshc->quote_path1 is the source */
1420: /* get the destination */
1421: result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
1422: if(result) {
1423: if(result == CURLE_OUT_OF_MEMORY)
1424: failf(data, "Out of memory");
1425: else
1426: failf(data,
1427: "Syntax error in ln/symlink: Bad second parameter");
1428: Curl_safefree(sshc->quote_path1);
1429: state(conn, SSH_SFTP_CLOSE);
1430: sshc->nextstate = SSH_NO_STATE;
1431: sshc->actualcode = result;
1432: break;
1433: }
1434: state(conn, SSH_SFTP_QUOTE_SYMLINK);
1435: break;
1436: }
1437: else if(strncasecompare(cmd, "mkdir ", 6)) {
1438: /* create dir */
1439: state(conn, SSH_SFTP_QUOTE_MKDIR);
1440: break;
1441: }
1442: else if(strncasecompare(cmd, "rename ", 7)) {
1443: /* rename file */
1444: /* first param is the source path */
1445: /* second param is the dest. path */
1446: result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
1447: if(result) {
1448: if(result == CURLE_OUT_OF_MEMORY)
1449: failf(data, "Out of memory");
1450: else
1451: failf(data, "Syntax error in rename: Bad second parameter");
1452: Curl_safefree(sshc->quote_path1);
1453: state(conn, SSH_SFTP_CLOSE);
1454: sshc->nextstate = SSH_NO_STATE;
1455: sshc->actualcode = result;
1456: break;
1457: }
1458: state(conn, SSH_SFTP_QUOTE_RENAME);
1459: break;
1460: }
1461: else if(strncasecompare(cmd, "rmdir ", 6)) {
1462: /* delete dir */
1463: state(conn, SSH_SFTP_QUOTE_RMDIR);
1464: break;
1465: }
1466: else if(strncasecompare(cmd, "rm ", 3)) {
1467: state(conn, SSH_SFTP_QUOTE_UNLINK);
1468: break;
1469: }
1470: #ifdef HAS_STATVFS_SUPPORT
1471: else if(strncasecompare(cmd, "statvfs ", 8)) {
1472: state(conn, SSH_SFTP_QUOTE_STATVFS);
1473: break;
1474: }
1475: #endif
1476:
1477: failf(data, "Unknown SFTP command");
1478: Curl_safefree(sshc->quote_path1);
1479: Curl_safefree(sshc->quote_path2);
1480: state(conn, SSH_SFTP_CLOSE);
1481: sshc->nextstate = SSH_NO_STATE;
1482: sshc->actualcode = CURLE_QUOTE_ERROR;
1483: break;
1484: }
1485: }
1486: break;
1487:
1488: case SSH_SFTP_NEXT_QUOTE:
1489: Curl_safefree(sshc->quote_path1);
1490: Curl_safefree(sshc->quote_path2);
1491:
1492: sshc->quote_item = sshc->quote_item->next;
1493:
1494: if(sshc->quote_item) {
1495: state(conn, SSH_SFTP_QUOTE);
1496: }
1497: else {
1498: if(sshc->nextstate != SSH_NO_STATE) {
1499: state(conn, sshc->nextstate);
1500: sshc->nextstate = SSH_NO_STATE;
1501: }
1502: else {
1503: state(conn, SSH_SFTP_GETINFO);
1504: }
1505: }
1506: break;
1507:
1508: case SSH_SFTP_QUOTE_STAT:
1509: {
1510: char *cmd = sshc->quote_item->data;
1511: sshc->acceptfail = FALSE;
1512:
1513: /* if a command starts with an asterisk, which a legal SFTP command never
1514: can, the command will be allowed to fail without it causing any
1515: aborts or cancels etc. It will cause libcurl to act as if the command
1516: is successful, whatever the server reponds. */
1517:
1518: if(cmd[0] == '*') {
1519: cmd++;
1520: sshc->acceptfail = TRUE;
1521: }
1522:
1523: if(!strncasecompare(cmd, "chmod", 5)) {
1524: /* Since chown and chgrp only set owner OR group but libssh2 wants to
1525: * set them both at once, we need to obtain the current ownership
1526: * first. This takes an extra protocol round trip.
1527: */
1528: rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
1529: curlx_uztoui(strlen(sshc->quote_path2)),
1530: LIBSSH2_SFTP_STAT,
1531: &sshc->quote_attrs);
1532: if(rc == LIBSSH2_ERROR_EAGAIN) {
1533: break;
1534: }
1535: if(rc != 0 && !sshc->acceptfail) { /* get those attributes */
1536: err = sftp_libssh2_last_error(sshc->sftp_session);
1537: Curl_safefree(sshc->quote_path1);
1538: Curl_safefree(sshc->quote_path2);
1539: failf(data, "Attempt to get SFTP stats failed: %s",
1540: sftp_libssh2_strerror(err));
1541: state(conn, SSH_SFTP_CLOSE);
1542: sshc->nextstate = SSH_NO_STATE;
1543: sshc->actualcode = CURLE_QUOTE_ERROR;
1544: break;
1545: }
1546: }
1547:
1548: /* Now set the new attributes... */
1549: if(strncasecompare(cmd, "chgrp", 5)) {
1550: sshc->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10);
1551: sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
1552: if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
1553: !sshc->acceptfail) {
1554: Curl_safefree(sshc->quote_path1);
1555: Curl_safefree(sshc->quote_path2);
1556: failf(data, "Syntax error: chgrp gid not a number");
1557: state(conn, SSH_SFTP_CLOSE);
1558: sshc->nextstate = SSH_NO_STATE;
1559: sshc->actualcode = CURLE_QUOTE_ERROR;
1560: break;
1561: }
1562: }
1563: else if(strncasecompare(cmd, "chmod", 5)) {
1564: sshc->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8);
1565: sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
1566: /* permissions are octal */
1567: if(sshc->quote_attrs.permissions == 0 &&
1568: !ISDIGIT(sshc->quote_path1[0])) {
1569: Curl_safefree(sshc->quote_path1);
1570: Curl_safefree(sshc->quote_path2);
1571: failf(data, "Syntax error: chmod permissions not a number");
1572: state(conn, SSH_SFTP_CLOSE);
1573: sshc->nextstate = SSH_NO_STATE;
1574: sshc->actualcode = CURLE_QUOTE_ERROR;
1575: break;
1576: }
1577: }
1578: else if(strncasecompare(cmd, "chown", 5)) {
1579: sshc->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10);
1580: sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
1581: if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
1582: !sshc->acceptfail) {
1583: Curl_safefree(sshc->quote_path1);
1584: Curl_safefree(sshc->quote_path2);
1585: failf(data, "Syntax error: chown uid not a number");
1586: state(conn, SSH_SFTP_CLOSE);
1587: sshc->nextstate = SSH_NO_STATE;
1588: sshc->actualcode = CURLE_QUOTE_ERROR;
1589: break;
1590: }
1591: }
1592:
1593: /* Now send the completed structure... */
1594: state(conn, SSH_SFTP_QUOTE_SETSTAT);
1595: break;
1596: }
1597:
1598: case SSH_SFTP_QUOTE_SETSTAT:
1599: rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
1600: curlx_uztoui(strlen(sshc->quote_path2)),
1601: LIBSSH2_SFTP_SETSTAT,
1602: &sshc->quote_attrs);
1603: if(rc == LIBSSH2_ERROR_EAGAIN) {
1604: break;
1605: }
1606: if(rc != 0 && !sshc->acceptfail) {
1607: err = sftp_libssh2_last_error(sshc->sftp_session);
1608: Curl_safefree(sshc->quote_path1);
1609: Curl_safefree(sshc->quote_path2);
1610: failf(data, "Attempt to set SFTP stats failed: %s",
1611: sftp_libssh2_strerror(err));
1612: state(conn, SSH_SFTP_CLOSE);
1613: sshc->nextstate = SSH_NO_STATE;
1614: sshc->actualcode = CURLE_QUOTE_ERROR;
1615: break;
1616: }
1617: state(conn, SSH_SFTP_NEXT_QUOTE);
1618: break;
1619:
1620: case SSH_SFTP_QUOTE_SYMLINK:
1621: rc = libssh2_sftp_symlink_ex(sshc->sftp_session, sshc->quote_path1,
1622: curlx_uztoui(strlen(sshc->quote_path1)),
1623: sshc->quote_path2,
1624: curlx_uztoui(strlen(sshc->quote_path2)),
1625: LIBSSH2_SFTP_SYMLINK);
1626: if(rc == LIBSSH2_ERROR_EAGAIN) {
1627: break;
1628: }
1629: if(rc != 0 && !sshc->acceptfail) {
1630: err = sftp_libssh2_last_error(sshc->sftp_session);
1631: Curl_safefree(sshc->quote_path1);
1632: Curl_safefree(sshc->quote_path2);
1633: failf(data, "symlink command failed: %s",
1634: sftp_libssh2_strerror(err));
1635: state(conn, SSH_SFTP_CLOSE);
1636: sshc->nextstate = SSH_NO_STATE;
1637: sshc->actualcode = CURLE_QUOTE_ERROR;
1638: break;
1639: }
1640: state(conn, SSH_SFTP_NEXT_QUOTE);
1641: break;
1642:
1643: case SSH_SFTP_QUOTE_MKDIR:
1644: rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshc->quote_path1,
1645: curlx_uztoui(strlen(sshc->quote_path1)),
1646: data->set.new_directory_perms);
1647: if(rc == LIBSSH2_ERROR_EAGAIN) {
1648: break;
1649: }
1650: if(rc != 0 && !sshc->acceptfail) {
1651: err = sftp_libssh2_last_error(sshc->sftp_session);
1652: Curl_safefree(sshc->quote_path1);
1653: failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err));
1654: state(conn, SSH_SFTP_CLOSE);
1655: sshc->nextstate = SSH_NO_STATE;
1656: sshc->actualcode = CURLE_QUOTE_ERROR;
1657: break;
1658: }
1659: state(conn, SSH_SFTP_NEXT_QUOTE);
1660: break;
1661:
1662: case SSH_SFTP_QUOTE_RENAME:
1663: rc = libssh2_sftp_rename_ex(sshc->sftp_session, sshc->quote_path1,
1664: curlx_uztoui(strlen(sshc->quote_path1)),
1665: sshc->quote_path2,
1666: curlx_uztoui(strlen(sshc->quote_path2)),
1667: LIBSSH2_SFTP_RENAME_OVERWRITE |
1668: LIBSSH2_SFTP_RENAME_ATOMIC |
1669: LIBSSH2_SFTP_RENAME_NATIVE);
1670:
1671: if(rc == LIBSSH2_ERROR_EAGAIN) {
1672: break;
1673: }
1674: if(rc != 0 && !sshc->acceptfail) {
1675: err = sftp_libssh2_last_error(sshc->sftp_session);
1676: Curl_safefree(sshc->quote_path1);
1677: Curl_safefree(sshc->quote_path2);
1678: failf(data, "rename command failed: %s", sftp_libssh2_strerror(err));
1679: state(conn, SSH_SFTP_CLOSE);
1680: sshc->nextstate = SSH_NO_STATE;
1681: sshc->actualcode = CURLE_QUOTE_ERROR;
1682: break;
1683: }
1684: state(conn, SSH_SFTP_NEXT_QUOTE);
1685: break;
1686:
1687: case SSH_SFTP_QUOTE_RMDIR:
1688: rc = libssh2_sftp_rmdir_ex(sshc->sftp_session, sshc->quote_path1,
1689: curlx_uztoui(strlen(sshc->quote_path1)));
1690: if(rc == LIBSSH2_ERROR_EAGAIN) {
1691: break;
1692: }
1693: if(rc != 0 && !sshc->acceptfail) {
1694: err = sftp_libssh2_last_error(sshc->sftp_session);
1695: Curl_safefree(sshc->quote_path1);
1696: failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err));
1697: state(conn, SSH_SFTP_CLOSE);
1698: sshc->nextstate = SSH_NO_STATE;
1699: sshc->actualcode = CURLE_QUOTE_ERROR;
1700: break;
1701: }
1702: state(conn, SSH_SFTP_NEXT_QUOTE);
1703: break;
1704:
1705: case SSH_SFTP_QUOTE_UNLINK:
1706: rc = libssh2_sftp_unlink_ex(sshc->sftp_session, sshc->quote_path1,
1707: curlx_uztoui(strlen(sshc->quote_path1)));
1708: if(rc == LIBSSH2_ERROR_EAGAIN) {
1709: break;
1710: }
1711: if(rc != 0 && !sshc->acceptfail) {
1712: err = sftp_libssh2_last_error(sshc->sftp_session);
1713: Curl_safefree(sshc->quote_path1);
1714: failf(data, "rm command failed: %s", sftp_libssh2_strerror(err));
1715: state(conn, SSH_SFTP_CLOSE);
1716: sshc->nextstate = SSH_NO_STATE;
1717: sshc->actualcode = CURLE_QUOTE_ERROR;
1718: break;
1719: }
1720: state(conn, SSH_SFTP_NEXT_QUOTE);
1721: break;
1722:
1723: #ifdef HAS_STATVFS_SUPPORT
1724: case SSH_SFTP_QUOTE_STATVFS:
1725: {
1726: LIBSSH2_SFTP_STATVFS statvfs;
1727: rc = libssh2_sftp_statvfs(sshc->sftp_session, sshc->quote_path1,
1728: curlx_uztoui(strlen(sshc->quote_path1)),
1729: &statvfs);
1730:
1731: if(rc == LIBSSH2_ERROR_EAGAIN) {
1732: break;
1733: }
1734: if(rc != 0 && !sshc->acceptfail) {
1735: err = sftp_libssh2_last_error(sshc->sftp_session);
1736: Curl_safefree(sshc->quote_path1);
1737: failf(data, "statvfs command failed: %s", sftp_libssh2_strerror(err));
1738: state(conn, SSH_SFTP_CLOSE);
1739: sshc->nextstate = SSH_NO_STATE;
1740: sshc->actualcode = CURLE_QUOTE_ERROR;
1741: break;
1742: }
1743: else if(rc == 0) {
1744: char *tmp = aprintf("statvfs:\n"
1745: "f_bsize: %llu\n" "f_frsize: %llu\n"
1746: "f_blocks: %llu\n" "f_bfree: %llu\n"
1747: "f_bavail: %llu\n" "f_files: %llu\n"
1748: "f_ffree: %llu\n" "f_favail: %llu\n"
1749: "f_fsid: %llu\n" "f_flag: %llu\n"
1750: "f_namemax: %llu\n",
1751: statvfs.f_bsize, statvfs.f_frsize,
1752: statvfs.f_blocks, statvfs.f_bfree,
1753: statvfs.f_bavail, statvfs.f_files,
1754: statvfs.f_ffree, statvfs.f_favail,
1755: statvfs.f_fsid, statvfs.f_flag,
1756: statvfs.f_namemax);
1757: if(!tmp) {
1758: result = CURLE_OUT_OF_MEMORY;
1759: state(conn, SSH_SFTP_CLOSE);
1760: sshc->nextstate = SSH_NO_STATE;
1761: break;
1762: }
1763:
1764: result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
1765: free(tmp);
1766: if(result) {
1767: state(conn, SSH_SFTP_CLOSE);
1768: sshc->nextstate = SSH_NO_STATE;
1769: sshc->actualcode = result;
1770: }
1771: }
1772: state(conn, SSH_SFTP_NEXT_QUOTE);
1773: break;
1774: }
1775: #endif
1776: case SSH_SFTP_GETINFO:
1777: {
1778: if(data->set.get_filetime) {
1779: state(conn, SSH_SFTP_FILETIME);
1780: }
1781: else {
1782: state(conn, SSH_SFTP_TRANS_INIT);
1783: }
1784: break;
1785: }
1786:
1787: case SSH_SFTP_FILETIME:
1788: {
1789: LIBSSH2_SFTP_ATTRIBUTES attrs;
1790:
1791: rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path,
1792: curlx_uztoui(strlen(sftp_scp->path)),
1793: LIBSSH2_SFTP_STAT, &attrs);
1794: if(rc == LIBSSH2_ERROR_EAGAIN) {
1795: break;
1796: }
1797: if(rc == 0) {
1798: data->info.filetime = attrs.mtime;
1799: }
1800:
1801: state(conn, SSH_SFTP_TRANS_INIT);
1802: break;
1803: }
1804:
1805: case SSH_SFTP_TRANS_INIT:
1806: if(data->set.upload)
1807: state(conn, SSH_SFTP_UPLOAD_INIT);
1808: else {
1809: if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
1810: state(conn, SSH_SFTP_READDIR_INIT);
1811: else
1812: state(conn, SSH_SFTP_DOWNLOAD_INIT);
1813: }
1814: break;
1815:
1816: case SSH_SFTP_UPLOAD_INIT:
1817: {
1818: unsigned long flags;
1819: /*
1820: * NOTE!!! libssh2 requires that the destination path is a full path
1821: * that includes the destination file and name OR ends in a "/"
1822: * If this is not done the destination file will be named the
1823: * same name as the last directory in the path.
1824: */
1825:
1826: if(data->state.resume_from != 0) {
1827: LIBSSH2_SFTP_ATTRIBUTES attrs;
1828: if(data->state.resume_from < 0) {
1829: rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path,
1830: curlx_uztoui(strlen(sftp_scp->path)),
1831: LIBSSH2_SFTP_STAT, &attrs);
1832: if(rc == LIBSSH2_ERROR_EAGAIN) {
1833: break;
1834: }
1835: if(rc) {
1836: data->state.resume_from = 0;
1837: }
1838: else {
1839: curl_off_t size = attrs.filesize;
1840: if(size < 0) {
1841: failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
1842: return CURLE_BAD_DOWNLOAD_RESUME;
1843: }
1844: data->state.resume_from = attrs.filesize;
1845: }
1846: }
1847: }
1848:
1849: if(data->set.ftp_append)
1850: /* Try to open for append, but create if nonexisting */
1851: flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND;
1852: else if(data->state.resume_from > 0)
1853: /* If we have restart position then open for append */
1854: flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND;
1855: else
1856: /* Clear file before writing (normal behaviour) */
1857: flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
1858:
1859: sshc->sftp_handle =
1860: libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path,
1861: curlx_uztoui(strlen(sftp_scp->path)),
1862: flags, data->set.new_file_perms,
1863: LIBSSH2_SFTP_OPENFILE);
1864:
1865: if(!sshc->sftp_handle) {
1866: rc = libssh2_session_last_errno(sshc->ssh_session);
1867:
1868: if(LIBSSH2_ERROR_EAGAIN == rc)
1869: break;
1870:
1871: if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc)
1872: /* only when there was an SFTP protocol error can we extract
1873: the sftp error! */
1874: err = sftp_libssh2_last_error(sshc->sftp_session);
1875: else
1876: err = -1; /* not an sftp error at all */
1877:
1878: if(sshc->secondCreateDirs) {
1879: state(conn, SSH_SFTP_CLOSE);
1880: sshc->actualcode = err>= LIBSSH2_FX_OK?
1881: sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
1882: failf(data, "Creating the dir/file failed: %s",
1883: sftp_libssh2_strerror(err));
1884: break;
1885: }
1886: if(((err == LIBSSH2_FX_NO_SUCH_FILE) ||
1887: (err == LIBSSH2_FX_FAILURE) ||
1888: (err == LIBSSH2_FX_NO_SUCH_PATH)) &&
1889: (data->set.ftp_create_missing_dirs &&
1890: (strlen(sftp_scp->path) > 1))) {
1891: /* try to create the path remotely */
1892: rc = 0; /* clear rc and continue */
1893: sshc->secondCreateDirs = 1;
1894: state(conn, SSH_SFTP_CREATE_DIRS_INIT);
1895: break;
1896: }
1897: state(conn, SSH_SFTP_CLOSE);
1898: sshc->actualcode = err>= LIBSSH2_FX_OK?
1899: sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
1900: if(!sshc->actualcode) {
1901: /* Sometimes, for some reason libssh2_sftp_last_error() returns
1902: zero even though libssh2_sftp_open() failed previously! We need
1903: to work around that! */
1904: sshc->actualcode = CURLE_SSH;
1905: err = -1;
1906: }
1907: failf(data, "Upload failed: %s (%d/%d)",
1908: err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error",
1909: err, rc);
1910: break;
1911: }
1912:
1913: /* If we have a restart point then we need to seek to the correct
1914: position. */
1915: if(data->state.resume_from > 0) {
1916: /* Let's read off the proper amount of bytes from the input. */
1917: if(conn->seek_func) {
1918: Curl_set_in_callback(data, true);
1919: seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1920: SEEK_SET);
1921: Curl_set_in_callback(data, false);
1922: }
1923:
1924: if(seekerr != CURL_SEEKFUNC_OK) {
1925: curl_off_t passed = 0;
1926:
1927: if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1928: failf(data, "Could not seek stream");
1929: return CURLE_FTP_COULDNT_USE_REST;
1930: }
1931: /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1932: do {
1933: size_t readthisamountnow =
1934: (data->state.resume_from - passed > data->set.buffer_size) ?
1935: (size_t)data->set.buffer_size :
1936: curlx_sotouz(data->state.resume_from - passed);
1937:
1938: size_t actuallyread;
1939: Curl_set_in_callback(data, true);
1940: actuallyread = data->state.fread_func(data->state.buffer, 1,
1941: readthisamountnow,
1942: data->state.in);
1943: Curl_set_in_callback(data, false);
1944:
1945: passed += actuallyread;
1946: if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1947: /* this checks for greater-than only to make sure that the
1948: CURL_READFUNC_ABORT return code still aborts */
1949: failf(data, "Failed to read data");
1950: return CURLE_FTP_COULDNT_USE_REST;
1951: }
1952: } while(passed < data->state.resume_from);
1953: }
1954:
1955: /* now, decrease the size of the read */
1956: if(data->state.infilesize > 0) {
1957: data->state.infilesize -= data->state.resume_from;
1958: data->req.size = data->state.infilesize;
1959: Curl_pgrsSetUploadSize(data, data->state.infilesize);
1960: }
1961:
1962: SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
1963: }
1964: if(data->state.infilesize > 0) {
1965: data->req.size = data->state.infilesize;
1966: Curl_pgrsSetUploadSize(data, data->state.infilesize);
1967: }
1968: /* upload data */
1969: Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
1970:
1971: /* not set by Curl_setup_transfer to preserve keepon bits */
1972: conn->sockfd = conn->writesockfd;
1973:
1974: if(result) {
1975: state(conn, SSH_SFTP_CLOSE);
1976: sshc->actualcode = result;
1977: }
1978: else {
1979: /* store this original bitmask setup to use later on if we can't
1980: figure out a "real" bitmask */
1981: sshc->orig_waitfor = data->req.keepon;
1982:
1983: /* we want to use the _sending_ function even when the socket turns
1984: out readable as the underlying libssh2 sftp send function will deal
1985: with both accordingly */
1986: conn->cselect_bits = CURL_CSELECT_OUT;
1987:
1988: /* since we don't really wait for anything at this point, we want the
1989: state machine to move on as soon as possible so we set a very short
1990: timeout here */
1991: Curl_expire(data, 0, EXPIRE_RUN_NOW);
1992:
1993: state(conn, SSH_STOP);
1994: }
1995: break;
1996: }
1997:
1998: case SSH_SFTP_CREATE_DIRS_INIT:
1999: if(strlen(sftp_scp->path) > 1) {
2000: sshc->slash_pos = sftp_scp->path + 1; /* ignore the leading '/' */
2001: state(conn, SSH_SFTP_CREATE_DIRS);
2002: }
2003: else {
2004: state(conn, SSH_SFTP_UPLOAD_INIT);
2005: }
2006: break;
2007:
2008: case SSH_SFTP_CREATE_DIRS:
2009: sshc->slash_pos = strchr(sshc->slash_pos, '/');
2010: if(sshc->slash_pos) {
2011: *sshc->slash_pos = 0;
2012:
2013: infof(data, "Creating directory '%s'\n", sftp_scp->path);
2014: state(conn, SSH_SFTP_CREATE_DIRS_MKDIR);
2015: break;
2016: }
2017: state(conn, SSH_SFTP_UPLOAD_INIT);
2018: break;
2019:
2020: case SSH_SFTP_CREATE_DIRS_MKDIR:
2021: /* 'mode' - parameter is preliminary - default to 0644 */
2022: rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sftp_scp->path,
2023: curlx_uztoui(strlen(sftp_scp->path)),
2024: data->set.new_directory_perms);
2025: if(rc == LIBSSH2_ERROR_EAGAIN) {
2026: break;
2027: }
2028: *sshc->slash_pos = '/';
2029: ++sshc->slash_pos;
2030: if(rc < 0) {
2031: /*
2032: * Abort if failure wasn't that the dir already exists or the
2033: * permission was denied (creation might succeed further down the
2034: * path) - retry on unspecific FAILURE also
2035: */
2036: err = sftp_libssh2_last_error(sshc->sftp_session);
2037: if((err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
2038: (err != LIBSSH2_FX_FAILURE) &&
2039: (err != LIBSSH2_FX_PERMISSION_DENIED)) {
2040: result = sftp_libssh2_error_to_CURLE(err);
2041: state(conn, SSH_SFTP_CLOSE);
2042: sshc->actualcode = result?result:CURLE_SSH;
2043: break;
2044: }
2045: rc = 0; /* clear rc and continue */
2046: }
2047: state(conn, SSH_SFTP_CREATE_DIRS);
2048: break;
2049:
2050: case SSH_SFTP_READDIR_INIT:
2051: Curl_pgrsSetDownloadSize(data, -1);
2052: if(data->set.opt_no_body) {
2053: state(conn, SSH_STOP);
2054: break;
2055: }
2056:
2057: /*
2058: * This is a directory that we are trying to get, so produce a directory
2059: * listing
2060: */
2061: sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session,
2062: sftp_scp->path,
2063: curlx_uztoui(
2064: strlen(sftp_scp->path)),
2065: 0, 0, LIBSSH2_SFTP_OPENDIR);
2066: if(!sshc->sftp_handle) {
2067: if(libssh2_session_last_errno(sshc->ssh_session) ==
2068: LIBSSH2_ERROR_EAGAIN) {
2069: rc = LIBSSH2_ERROR_EAGAIN;
2070: break;
2071: }
2072: err = sftp_libssh2_last_error(sshc->sftp_session);
2073: failf(data, "Could not open directory for reading: %s",
2074: sftp_libssh2_strerror(err));
2075: state(conn, SSH_SFTP_CLOSE);
2076: result = sftp_libssh2_error_to_CURLE(err);
2077: sshc->actualcode = result?result:CURLE_SSH;
2078: break;
2079: }
2080: sshc->readdir_filename = malloc(PATH_MAX + 1);
2081: if(!sshc->readdir_filename) {
2082: state(conn, SSH_SFTP_CLOSE);
2083: sshc->actualcode = CURLE_OUT_OF_MEMORY;
2084: break;
2085: }
2086: sshc->readdir_longentry = malloc(PATH_MAX + 1);
2087: if(!sshc->readdir_longentry) {
2088: Curl_safefree(sshc->readdir_filename);
2089: state(conn, SSH_SFTP_CLOSE);
2090: sshc->actualcode = CURLE_OUT_OF_MEMORY;
2091: break;
2092: }
2093: state(conn, SSH_SFTP_READDIR);
2094: break;
2095:
2096: case SSH_SFTP_READDIR:
2097: rc = libssh2_sftp_readdir_ex(sshc->sftp_handle,
2098: sshc->readdir_filename,
2099: PATH_MAX,
2100: sshc->readdir_longentry,
2101: PATH_MAX,
2102: &sshc->readdir_attrs);
2103: if(rc == LIBSSH2_ERROR_EAGAIN) {
2104: break;
2105: }
2106: if(rc > 0) {
2107: sshc->readdir_len = (size_t) rc;
2108: sshc->readdir_filename[sshc->readdir_len] = '\0';
2109:
2110: if(data->set.ftp_list_only) {
2111: char *tmpLine;
2112:
2113: tmpLine = aprintf("%s\n", sshc->readdir_filename);
2114: if(tmpLine == NULL) {
2115: state(conn, SSH_SFTP_CLOSE);
2116: sshc->actualcode = CURLE_OUT_OF_MEMORY;
2117: break;
2118: }
2119: result = Curl_client_write(conn, CLIENTWRITE_BODY,
2120: tmpLine, sshc->readdir_len + 1);
2121: free(tmpLine);
2122:
2123: if(result) {
2124: state(conn, SSH_STOP);
2125: break;
2126: }
2127: /* since this counts what we send to the client, we include the
2128: newline in this counter */
2129: data->req.bytecount += sshc->readdir_len + 1;
2130:
2131: /* output debug output if that is requested */
2132: if(data->set.verbose) {
2133: Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_filename,
2134: sshc->readdir_len);
2135: }
2136: }
2137: else {
2138: sshc->readdir_currLen = strlen(sshc->readdir_longentry);
2139: sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
2140: sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
2141: if(!sshc->readdir_line) {
2142: Curl_safefree(sshc->readdir_filename);
2143: Curl_safefree(sshc->readdir_longentry);
2144: state(conn, SSH_SFTP_CLOSE);
2145: sshc->actualcode = CURLE_OUT_OF_MEMORY;
2146: break;
2147: }
2148:
2149: memcpy(sshc->readdir_line, sshc->readdir_longentry,
2150: sshc->readdir_currLen);
2151: if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
2152: ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
2153: LIBSSH2_SFTP_S_IFLNK)) {
2154: sshc->readdir_linkPath = malloc(PATH_MAX + 1);
2155: if(sshc->readdir_linkPath == NULL) {
2156: Curl_safefree(sshc->readdir_filename);
2157: Curl_safefree(sshc->readdir_longentry);
2158: state(conn, SSH_SFTP_CLOSE);
2159: sshc->actualcode = CURLE_OUT_OF_MEMORY;
2160: break;
2161: }
2162:
2163: msnprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path,
2164: sshc->readdir_filename);
2165: state(conn, SSH_SFTP_READDIR_LINK);
2166: break;
2167: }
2168: state(conn, SSH_SFTP_READDIR_BOTTOM);
2169: break;
2170: }
2171: }
2172: else if(rc == 0) {
2173: Curl_safefree(sshc->readdir_filename);
2174: Curl_safefree(sshc->readdir_longentry);
2175: state(conn, SSH_SFTP_READDIR_DONE);
2176: break;
2177: }
2178: else if(rc < 0) {
2179: err = sftp_libssh2_last_error(sshc->sftp_session);
2180: result = sftp_libssh2_error_to_CURLE(err);
2181: sshc->actualcode = result?result:CURLE_SSH;
2182: failf(data, "Could not open remote file for reading: %s :: %d",
2183: sftp_libssh2_strerror(err),
2184: libssh2_session_last_errno(sshc->ssh_session));
2185: Curl_safefree(sshc->readdir_filename);
2186: Curl_safefree(sshc->readdir_longentry);
2187: state(conn, SSH_SFTP_CLOSE);
2188: break;
2189: }
2190: break;
2191:
2192: case SSH_SFTP_READDIR_LINK:
2193: rc =
2194: libssh2_sftp_symlink_ex(sshc->sftp_session,
2195: sshc->readdir_linkPath,
2196: curlx_uztoui(strlen(sshc->readdir_linkPath)),
2197: sshc->readdir_filename,
2198: PATH_MAX, LIBSSH2_SFTP_READLINK);
2199: if(rc == LIBSSH2_ERROR_EAGAIN) {
2200: break;
2201: }
2202: sshc->readdir_len = (size_t) rc;
2203: Curl_safefree(sshc->readdir_linkPath);
2204:
2205: /* get room for the filename and extra output */
2206: sshc->readdir_totalLen += 4 + sshc->readdir_len;
2207: new_readdir_line = Curl_saferealloc(sshc->readdir_line,
2208: sshc->readdir_totalLen);
2209: if(!new_readdir_line) {
2210: sshc->readdir_line = NULL;
2211: Curl_safefree(sshc->readdir_filename);
2212: Curl_safefree(sshc->readdir_longentry);
2213: state(conn, SSH_SFTP_CLOSE);
2214: sshc->actualcode = CURLE_OUT_OF_MEMORY;
2215: break;
2216: }
2217: sshc->readdir_line = new_readdir_line;
2218:
2219: sshc->readdir_currLen += msnprintf(sshc->readdir_line +
2220: sshc->readdir_currLen,
2221: sshc->readdir_totalLen -
2222: sshc->readdir_currLen,
2223: " -> %s",
2224: sshc->readdir_filename);
2225:
2226: state(conn, SSH_SFTP_READDIR_BOTTOM);
2227: break;
2228:
2229: case SSH_SFTP_READDIR_BOTTOM:
2230: sshc->readdir_currLen += msnprintf(sshc->readdir_line +
2231: sshc->readdir_currLen,
2232: sshc->readdir_totalLen -
2233: sshc->readdir_currLen, "\n");
2234: result = Curl_client_write(conn, CLIENTWRITE_BODY,
2235: sshc->readdir_line,
2236: sshc->readdir_currLen);
2237:
2238: if(!result) {
2239:
2240: /* output debug output if that is requested */
2241: if(data->set.verbose) {
2242: Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
2243: sshc->readdir_currLen);
2244: }
2245: data->req.bytecount += sshc->readdir_currLen;
2246: }
2247: Curl_safefree(sshc->readdir_line);
2248: if(result) {
2249: state(conn, SSH_STOP);
2250: }
2251: else
2252: state(conn, SSH_SFTP_READDIR);
2253: break;
2254:
2255: case SSH_SFTP_READDIR_DONE:
2256: if(libssh2_sftp_closedir(sshc->sftp_handle) ==
2257: LIBSSH2_ERROR_EAGAIN) {
2258: rc = LIBSSH2_ERROR_EAGAIN;
2259: break;
2260: }
2261: sshc->sftp_handle = NULL;
2262: Curl_safefree(sshc->readdir_filename);
2263: Curl_safefree(sshc->readdir_longentry);
2264:
2265: /* no data to transfer */
2266: Curl_setup_transfer(data, -1, -1, FALSE, -1);
2267: state(conn, SSH_STOP);
2268: break;
2269:
2270: case SSH_SFTP_DOWNLOAD_INIT:
2271: /*
2272: * Work on getting the specified file
2273: */
2274: sshc->sftp_handle =
2275: libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path,
2276: curlx_uztoui(strlen(sftp_scp->path)),
2277: LIBSSH2_FXF_READ, data->set.new_file_perms,
2278: LIBSSH2_SFTP_OPENFILE);
2279: if(!sshc->sftp_handle) {
2280: if(libssh2_session_last_errno(sshc->ssh_session) ==
2281: LIBSSH2_ERROR_EAGAIN) {
2282: rc = LIBSSH2_ERROR_EAGAIN;
2283: break;
2284: }
2285: err = sftp_libssh2_last_error(sshc->sftp_session);
2286: failf(data, "Could not open remote file for reading: %s",
2287: sftp_libssh2_strerror(err));
2288: state(conn, SSH_SFTP_CLOSE);
2289: result = sftp_libssh2_error_to_CURLE(err);
2290: sshc->actualcode = result?result:CURLE_SSH;
2291: break;
2292: }
2293: state(conn, SSH_SFTP_DOWNLOAD_STAT);
2294: break;
2295:
2296: case SSH_SFTP_DOWNLOAD_STAT:
2297: {
2298: LIBSSH2_SFTP_ATTRIBUTES attrs;
2299:
2300: rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path,
2301: curlx_uztoui(strlen(sftp_scp->path)),
2302: LIBSSH2_SFTP_STAT, &attrs);
2303: if(rc == LIBSSH2_ERROR_EAGAIN) {
2304: break;
2305: }
2306: if(rc ||
2307: !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) ||
2308: (attrs.filesize == 0)) {
2309: /*
2310: * libssh2_sftp_open() didn't return an error, so maybe the server
2311: * just doesn't support stat()
2312: * OR the server doesn't return a file size with a stat()
2313: * OR file size is 0
2314: */
2315: data->req.size = -1;
2316: data->req.maxdownload = -1;
2317: Curl_pgrsSetDownloadSize(data, -1);
2318: }
2319: else {
2320: curl_off_t size = attrs.filesize;
2321:
2322: if(size < 0) {
2323: failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
2324: return CURLE_BAD_DOWNLOAD_RESUME;
2325: }
2326: if(conn->data->state.use_range) {
2327: curl_off_t from, to;
2328: char *ptr;
2329: char *ptr2;
2330: CURLofft to_t;
2331: CURLofft from_t;
2332:
2333: from_t = curlx_strtoofft(conn->data->state.range, &ptr, 0, &from);
2334: if(from_t == CURL_OFFT_FLOW)
2335: return CURLE_RANGE_ERROR;
2336: while(*ptr && (ISSPACE(*ptr) || (*ptr == '-')))
2337: ptr++;
2338: to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
2339: if(to_t == CURL_OFFT_FLOW)
2340: return CURLE_RANGE_ERROR;
2341: if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
2342: || (to >= size)) {
2343: to = size - 1;
2344: }
2345: if(from_t) {
2346: /* from is relative to end of file */
2347: from = size - to;
2348: to = size - 1;
2349: }
2350: if(from > size) {
2351: failf(data, "Offset (%"
2352: CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
2353: CURL_FORMAT_CURL_OFF_T ")", from, attrs.filesize);
2354: return CURLE_BAD_DOWNLOAD_RESUME;
2355: }
2356: if(from > to) {
2357: from = to;
2358: size = 0;
2359: }
2360: else {
2361: size = to - from + 1;
2362: }
2363:
2364: SFTP_SEEK(conn->proto.sshc.sftp_handle, from);
2365: }
2366: data->req.size = size;
2367: data->req.maxdownload = size;
2368: Curl_pgrsSetDownloadSize(data, size);
2369: }
2370:
2371: /* We can resume if we can seek to the resume position */
2372: if(data->state.resume_from) {
2373: if(data->state.resume_from < 0) {
2374: /* We're supposed to download the last abs(from) bytes */
2375: if((curl_off_t)attrs.filesize < -data->state.resume_from) {
2376: failf(data, "Offset (%"
2377: CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
2378: CURL_FORMAT_CURL_OFF_T ")",
2379: data->state.resume_from, attrs.filesize);
2380: return CURLE_BAD_DOWNLOAD_RESUME;
2381: }
2382: /* download from where? */
2383: data->state.resume_from += attrs.filesize;
2384: }
2385: else {
2386: if((curl_off_t)attrs.filesize < data->state.resume_from) {
2387: failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2388: ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2389: data->state.resume_from, attrs.filesize);
2390: return CURLE_BAD_DOWNLOAD_RESUME;
2391: }
2392: }
2393: /* Now store the number of bytes we are expected to download */
2394: data->req.size = attrs.filesize - data->state.resume_from;
2395: data->req.maxdownload = attrs.filesize - data->state.resume_from;
2396: Curl_pgrsSetDownloadSize(data,
2397: attrs.filesize - data->state.resume_from);
2398: SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
2399: }
2400: }
2401:
2402: /* Setup the actual download */
2403: if(data->req.size == 0) {
2404: /* no data to transfer */
2405: Curl_setup_transfer(data, -1, -1, FALSE, -1);
2406: infof(data, "File already completely downloaded\n");
2407: state(conn, SSH_STOP);
2408: break;
2409: }
2410: Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
2411:
2412: /* not set by Curl_setup_transfer to preserve keepon bits */
2413: conn->writesockfd = conn->sockfd;
2414:
2415: /* we want to use the _receiving_ function even when the socket turns
2416: out writableable as the underlying libssh2 recv function will deal
2417: with both accordingly */
2418: conn->cselect_bits = CURL_CSELECT_IN;
2419:
2420: if(result) {
2421: /* this should never occur; the close state should be entered
2422: at the time the error occurs */
2423: state(conn, SSH_SFTP_CLOSE);
2424: sshc->actualcode = result;
2425: }
2426: else {
2427: state(conn, SSH_STOP);
2428: }
2429: break;
2430:
2431: case SSH_SFTP_CLOSE:
2432: if(sshc->sftp_handle) {
2433: rc = libssh2_sftp_close(sshc->sftp_handle);
2434: if(rc == LIBSSH2_ERROR_EAGAIN) {
2435: break;
2436: }
2437: if(rc < 0) {
2438: char *err_msg = NULL;
2439: (void)libssh2_session_last_error(sshc->ssh_session,
2440: &err_msg, NULL, 0);
2441: infof(data, "Failed to close libssh2 file: %d %s\n", rc, err_msg);
2442: }
2443: sshc->sftp_handle = NULL;
2444: }
2445:
2446: Curl_safefree(sftp_scp->path);
2447:
2448: DEBUGF(infof(data, "SFTP DONE done\n"));
2449:
2450: /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
2451: After nextstate is executed, the control should come back to
2452: SSH_SFTP_CLOSE to pass the correct result back */
2453: if(sshc->nextstate != SSH_NO_STATE &&
2454: sshc->nextstate != SSH_SFTP_CLOSE) {
2455: state(conn, sshc->nextstate);
2456: sshc->nextstate = SSH_SFTP_CLOSE;
2457: }
2458: else {
2459: state(conn, SSH_STOP);
2460: result = sshc->actualcode;
2461: }
2462: break;
2463:
2464: case SSH_SFTP_SHUTDOWN:
2465: /* during times we get here due to a broken transfer and then the
2466: sftp_handle might not have been taken down so make sure that is done
2467: before we proceed */
2468:
2469: if(sshc->sftp_handle) {
2470: rc = libssh2_sftp_close(sshc->sftp_handle);
2471: if(rc == LIBSSH2_ERROR_EAGAIN) {
2472: break;
2473: }
2474: if(rc < 0) {
2475: char *err_msg = NULL;
2476: (void)libssh2_session_last_error(sshc->ssh_session, &err_msg,
2477: NULL, 0);
2478: infof(data, "Failed to close libssh2 file: %d %s\n", rc, err_msg);
2479: }
2480: sshc->sftp_handle = NULL;
2481: }
2482: if(sshc->sftp_session) {
2483: rc = libssh2_sftp_shutdown(sshc->sftp_session);
2484: if(rc == LIBSSH2_ERROR_EAGAIN) {
2485: break;
2486: }
2487: if(rc < 0) {
2488: infof(data, "Failed to stop libssh2 sftp subsystem\n");
2489: }
2490: sshc->sftp_session = NULL;
2491: }
2492:
2493: Curl_safefree(sshc->homedir);
2494: conn->data->state.most_recent_ftp_entrypath = NULL;
2495:
2496: state(conn, SSH_SESSION_DISCONNECT);
2497: break;
2498:
2499: case SSH_SCP_TRANS_INIT:
2500: result = Curl_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
2501: if(result) {
2502: sshc->actualcode = result;
2503: state(conn, SSH_STOP);
2504: break;
2505: }
2506:
2507: if(data->set.upload) {
2508: if(data->state.infilesize < 0) {
2509: failf(data, "SCP requires a known file size for upload");
2510: sshc->actualcode = CURLE_UPLOAD_FAILED;
2511: state(conn, SSH_SCP_CHANNEL_FREE);
2512: break;
2513: }
2514: state(conn, SSH_SCP_UPLOAD_INIT);
2515: }
2516: else {
2517: state(conn, SSH_SCP_DOWNLOAD_INIT);
2518: }
2519: break;
2520:
2521: case SSH_SCP_UPLOAD_INIT:
2522: /*
2523: * libssh2 requires that the destination path is a full path that
2524: * includes the destination file and name OR ends in a "/" . If this is
2525: * not done the destination file will be named the same name as the last
2526: * directory in the path.
2527: */
2528: sshc->ssh_channel =
2529: SCP_SEND(sshc->ssh_session, sftp_scp->path, data->set.new_file_perms,
2530: data->state.infilesize);
2531: if(!sshc->ssh_channel) {
2532: int ssh_err;
2533: char *err_msg = NULL;
2534:
2535: if(libssh2_session_last_errno(sshc->ssh_session) ==
2536: LIBSSH2_ERROR_EAGAIN) {
2537: rc = LIBSSH2_ERROR_EAGAIN;
2538: break;
2539: }
2540:
2541: ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
2542: &err_msg, NULL, 0));
2543: failf(conn->data, "%s", err_msg);
2544: state(conn, SSH_SCP_CHANNEL_FREE);
2545: sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
2546: /* Map generic errors to upload failed */
2547: if(sshc->actualcode == CURLE_SSH ||
2548: sshc->actualcode == CURLE_REMOTE_FILE_NOT_FOUND)
2549: sshc->actualcode = CURLE_UPLOAD_FAILED;
2550: break;
2551: }
2552:
2553: /* upload data */
2554: Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET);
2555:
2556: /* not set by Curl_setup_transfer to preserve keepon bits */
2557: conn->sockfd = conn->writesockfd;
2558:
2559: if(result) {
2560: state(conn, SSH_SCP_CHANNEL_FREE);
2561: sshc->actualcode = result;
2562: }
2563: else {
2564: /* store this original bitmask setup to use later on if we can't
2565: figure out a "real" bitmask */
2566: sshc->orig_waitfor = data->req.keepon;
2567:
2568: /* we want to use the _sending_ function even when the socket turns
2569: out readable as the underlying libssh2 scp send function will deal
2570: with both accordingly */
2571: conn->cselect_bits = CURL_CSELECT_OUT;
2572:
2573: state(conn, SSH_STOP);
2574: }
2575: break;
2576:
2577: case SSH_SCP_DOWNLOAD_INIT:
2578: {
2579: curl_off_t bytecount;
2580:
2581: /*
2582: * We must check the remote file; if it is a directory no values will
2583: * be set in sb
2584: */
2585:
2586: /*
2587: * If support for >2GB files exists, use it.
2588: */
2589:
2590: /* get a fresh new channel from the ssh layer */
2591: #if LIBSSH2_VERSION_NUM < 0x010700
2592: struct stat sb;
2593: memset(&sb, 0, sizeof(struct stat));
2594: sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session,
2595: sftp_scp->path, &sb);
2596: #else
2597: libssh2_struct_stat sb;
2598: memset(&sb, 0, sizeof(libssh2_struct_stat));
2599: sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session,
2600: sftp_scp->path, &sb);
2601: #endif
2602:
2603: if(!sshc->ssh_channel) {
2604: int ssh_err;
2605: char *err_msg = NULL;
2606:
2607: if(libssh2_session_last_errno(sshc->ssh_session) ==
2608: LIBSSH2_ERROR_EAGAIN) {
2609: rc = LIBSSH2_ERROR_EAGAIN;
2610: break;
2611: }
2612:
2613:
2614: ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
2615: &err_msg, NULL, 0));
2616: failf(conn->data, "%s", err_msg);
2617: state(conn, SSH_SCP_CHANNEL_FREE);
2618: sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
2619: break;
2620: }
2621:
2622: /* download data */
2623: bytecount = (curl_off_t)sb.st_size;
2624: data->req.maxdownload = (curl_off_t)sb.st_size;
2625: Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
2626:
2627: /* not set by Curl_setup_transfer to preserve keepon bits */
2628: conn->writesockfd = conn->sockfd;
2629:
2630: /* we want to use the _receiving_ function even when the socket turns
2631: out writableable as the underlying libssh2 recv function will deal
2632: with both accordingly */
2633: conn->cselect_bits = CURL_CSELECT_IN;
2634:
2635: if(result) {
2636: state(conn, SSH_SCP_CHANNEL_FREE);
2637: sshc->actualcode = result;
2638: }
2639: else
2640: state(conn, SSH_STOP);
2641: }
2642: break;
2643:
2644: case SSH_SCP_DONE:
2645: if(data->set.upload)
2646: state(conn, SSH_SCP_SEND_EOF);
2647: else
2648: state(conn, SSH_SCP_CHANNEL_FREE);
2649: break;
2650:
2651: case SSH_SCP_SEND_EOF:
2652: if(sshc->ssh_channel) {
2653: rc = libssh2_channel_send_eof(sshc->ssh_channel);
2654: if(rc == LIBSSH2_ERROR_EAGAIN) {
2655: break;
2656: }
2657: if(rc) {
2658: char *err_msg = NULL;
2659: (void)libssh2_session_last_error(sshc->ssh_session,
2660: &err_msg, NULL, 0);
2661: infof(data, "Failed to send libssh2 channel EOF: %d %s\n",
2662: rc, err_msg);
2663: }
2664: }
2665: state(conn, SSH_SCP_WAIT_EOF);
2666: break;
2667:
2668: case SSH_SCP_WAIT_EOF:
2669: if(sshc->ssh_channel) {
2670: rc = libssh2_channel_wait_eof(sshc->ssh_channel);
2671: if(rc == LIBSSH2_ERROR_EAGAIN) {
2672: break;
2673: }
2674: if(rc) {
2675: char *err_msg = NULL;
2676: (void)libssh2_session_last_error(sshc->ssh_session,
2677: &err_msg, NULL, 0);
2678: infof(data, "Failed to get channel EOF: %d %s\n", rc, err_msg);
2679: }
2680: }
2681: state(conn, SSH_SCP_WAIT_CLOSE);
2682: break;
2683:
2684: case SSH_SCP_WAIT_CLOSE:
2685: if(sshc->ssh_channel) {
2686: rc = libssh2_channel_wait_closed(sshc->ssh_channel);
2687: if(rc == LIBSSH2_ERROR_EAGAIN) {
2688: break;
2689: }
2690: if(rc) {
2691: char *err_msg = NULL;
2692: (void)libssh2_session_last_error(sshc->ssh_session,
2693: &err_msg, NULL, 0);
2694: infof(data, "Channel failed to close: %d %s\n", rc, err_msg);
2695: }
2696: }
2697: state(conn, SSH_SCP_CHANNEL_FREE);
2698: break;
2699:
2700: case SSH_SCP_CHANNEL_FREE:
2701: if(sshc->ssh_channel) {
2702: rc = libssh2_channel_free(sshc->ssh_channel);
2703: if(rc == LIBSSH2_ERROR_EAGAIN) {
2704: break;
2705: }
2706: if(rc < 0) {
2707: char *err_msg = NULL;
2708: (void)libssh2_session_last_error(sshc->ssh_session,
2709: &err_msg, NULL, 0);
2710: infof(data, "Failed to free libssh2 scp subsystem: %d %s\n",
2711: rc, err_msg);
2712: }
2713: sshc->ssh_channel = NULL;
2714: }
2715: DEBUGF(infof(data, "SCP DONE phase complete\n"));
2716: #if 0 /* PREV */
2717: state(conn, SSH_SESSION_DISCONNECT);
2718: #endif
2719: state(conn, SSH_STOP);
2720: result = sshc->actualcode;
2721: break;
2722:
2723: case SSH_SESSION_DISCONNECT:
2724: /* during weird times when we've been prematurely aborted, the channel
2725: is still alive when we reach this state and we MUST kill the channel
2726: properly first */
2727: if(sshc->ssh_channel) {
2728: rc = libssh2_channel_free(sshc->ssh_channel);
2729: if(rc == LIBSSH2_ERROR_EAGAIN) {
2730: break;
2731: }
2732: if(rc < 0) {
2733: char *err_msg = NULL;
2734: (void)libssh2_session_last_error(sshc->ssh_session,
2735: &err_msg, NULL, 0);
2736: infof(data, "Failed to free libssh2 scp subsystem: %d %s\n",
2737: rc, err_msg);
2738: }
2739: sshc->ssh_channel = NULL;
2740: }
2741:
2742: if(sshc->ssh_session) {
2743: rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown");
2744: if(rc == LIBSSH2_ERROR_EAGAIN) {
2745: break;
2746: }
2747: if(rc < 0) {
2748: char *err_msg = NULL;
2749: (void)libssh2_session_last_error(sshc->ssh_session,
2750: &err_msg, NULL, 0);
2751: infof(data, "Failed to disconnect libssh2 session: %d %s\n",
2752: rc, err_msg);
2753: }
2754: }
2755:
2756: Curl_safefree(sshc->homedir);
2757: conn->data->state.most_recent_ftp_entrypath = NULL;
2758:
2759: state(conn, SSH_SESSION_FREE);
2760: break;
2761:
2762: case SSH_SESSION_FREE:
2763: #ifdef HAVE_LIBSSH2_KNOWNHOST_API
2764: if(sshc->kh) {
2765: libssh2_knownhost_free(sshc->kh);
2766: sshc->kh = NULL;
2767: }
2768: #endif
2769:
2770: #ifdef HAVE_LIBSSH2_AGENT_API
2771: if(sshc->ssh_agent) {
2772: rc = libssh2_agent_disconnect(sshc->ssh_agent);
2773: if(rc == LIBSSH2_ERROR_EAGAIN) {
2774: break;
2775: }
2776: if(rc < 0) {
2777: char *err_msg = NULL;
2778: (void)libssh2_session_last_error(sshc->ssh_session,
2779: &err_msg, NULL, 0);
2780: infof(data, "Failed to disconnect from libssh2 agent: %d %s\n",
2781: rc, err_msg);
2782: }
2783: libssh2_agent_free(sshc->ssh_agent);
2784: sshc->ssh_agent = NULL;
2785:
2786: /* NB: there is no need to free identities, they are part of internal
2787: agent stuff */
2788: sshc->sshagent_identity = NULL;
2789: sshc->sshagent_prev_identity = NULL;
2790: }
2791: #endif
2792:
2793: if(sshc->ssh_session) {
2794: rc = libssh2_session_free(sshc->ssh_session);
2795: if(rc == LIBSSH2_ERROR_EAGAIN) {
2796: break;
2797: }
2798: if(rc < 0) {
2799: char *err_msg = NULL;
2800: (void)libssh2_session_last_error(sshc->ssh_session,
2801: &err_msg, NULL, 0);
2802: infof(data, "Failed to free libssh2 session: %d %s\n", rc, err_msg);
2803: }
2804: sshc->ssh_session = NULL;
2805: }
2806:
2807: /* worst-case scenario cleanup */
2808:
2809: DEBUGASSERT(sshc->ssh_session == NULL);
2810: DEBUGASSERT(sshc->ssh_channel == NULL);
2811: DEBUGASSERT(sshc->sftp_session == NULL);
2812: DEBUGASSERT(sshc->sftp_handle == NULL);
2813: #ifdef HAVE_LIBSSH2_KNOWNHOST_API
2814: DEBUGASSERT(sshc->kh == NULL);
2815: #endif
2816: #ifdef HAVE_LIBSSH2_AGENT_API
2817: DEBUGASSERT(sshc->ssh_agent == NULL);
2818: #endif
2819:
2820: Curl_safefree(sshc->rsa_pub);
2821: Curl_safefree(sshc->rsa);
2822:
2823: Curl_safefree(sshc->quote_path1);
2824: Curl_safefree(sshc->quote_path2);
2825:
2826: Curl_safefree(sshc->homedir);
2827:
2828: Curl_safefree(sshc->readdir_filename);
2829: Curl_safefree(sshc->readdir_longentry);
2830: Curl_safefree(sshc->readdir_line);
2831: Curl_safefree(sshc->readdir_linkPath);
2832:
2833: /* the code we are about to return */
2834: result = sshc->actualcode;
2835:
2836: memset(sshc, 0, sizeof(struct ssh_conn));
2837:
2838: connclose(conn, "SSH session free");
2839: sshc->state = SSH_SESSION_FREE; /* current */
2840: sshc->nextstate = SSH_NO_STATE;
2841: state(conn, SSH_STOP);
2842: break;
2843:
2844: case SSH_QUIT:
2845: /* fallthrough, just stop! */
2846: default:
2847: /* internal error */
2848: sshc->nextstate = SSH_NO_STATE;
2849: state(conn, SSH_STOP);
2850: break;
2851: }
2852:
2853: } while(!rc && (sshc->state != SSH_STOP));
2854:
2855: if(rc == LIBSSH2_ERROR_EAGAIN) {
2856: /* we would block, we need to wait for the socket to be ready (in the
2857: right direction too)! */
2858: *block = TRUE;
2859: }
2860:
2861: return result;
2862: }
2863:
2864: /* called by the multi interface to figure out what socket(s) to wait for and
2865: for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
2866: static int ssh_perform_getsock(const struct connectdata *conn,
2867: curl_socket_t *sock)
2868: {
2869: #ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
2870: int bitmap = GETSOCK_BLANK;
2871:
2872: sock[0] = conn->sock[FIRSTSOCKET];
2873:
2874: if(conn->waitfor & KEEP_RECV)
2875: bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
2876:
2877: if(conn->waitfor & KEEP_SEND)
2878: bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
2879:
2880: return bitmap;
2881: #else
2882: /* if we don't know the direction we can use the generic *_getsock()
2883: function even for the protocol_connect and doing states */
2884: return Curl_single_getsock(conn, sock);
2885: #endif
2886: }
2887:
2888: /* Generic function called by the multi interface to figure out what socket(s)
2889: to wait for and for what actions during the DOING and PROTOCONNECT states*/
2890: static int ssh_getsock(struct connectdata *conn,
2891: curl_socket_t *sock)
2892: {
2893: #ifndef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
2894: (void)conn;
2895: (void)sock;
2896: /* if we don't know any direction we can just play along as we used to and
2897: not provide any sensible info */
2898: return GETSOCK_BLANK;
2899: #else
2900: /* if we know the direction we can use the generic *_getsock() function even
2901: for the protocol_connect and doing states */
2902: return ssh_perform_getsock(conn, sock);
2903: #endif
2904: }
2905:
2906: #ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
2907: /*
2908: * When one of the libssh2 functions has returned LIBSSH2_ERROR_EAGAIN this
2909: * function is used to figure out in what direction and stores this info so
2910: * that the multi interface can take advantage of it. Make sure to call this
2911: * function in all cases so that when it _doesn't_ return EAGAIN we can
2912: * restore the default wait bits.
2913: */
2914: static void ssh_block2waitfor(struct connectdata *conn, bool block)
2915: {
2916: struct ssh_conn *sshc = &conn->proto.sshc;
2917: int dir = 0;
2918: if(block) {
2919: dir = libssh2_session_block_directions(sshc->ssh_session);
2920: if(dir) {
2921: /* translate the libssh2 define bits into our own bit defines */
2922: conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) |
2923: ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0);
2924: }
2925: }
2926: if(!dir)
2927: /* It didn't block or libssh2 didn't reveal in which direction, put back
2928: the original set */
2929: conn->waitfor = sshc->orig_waitfor;
2930: }
2931: #else
2932: /* no libssh2 directional support so we simply don't know */
2933: #define ssh_block2waitfor(x,y) Curl_nop_stmt
2934: #endif
2935:
2936: /* called repeatedly until done from multi.c */
2937: static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done)
2938: {
2939: struct ssh_conn *sshc = &conn->proto.sshc;
2940: CURLcode result = CURLE_OK;
2941: bool block; /* we store the status and use that to provide a ssh_getsock()
2942: implementation */
2943: do {
2944: result = ssh_statemach_act(conn, &block);
2945: *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
2946: /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
2947: try again */
2948: } while(!result && !*done && !block);
2949: ssh_block2waitfor(conn, block);
2950:
2951: return result;
2952: }
2953:
2954: static CURLcode ssh_block_statemach(struct connectdata *conn,
2955: bool disconnect)
2956: {
2957: struct ssh_conn *sshc = &conn->proto.sshc;
2958: CURLcode result = CURLE_OK;
2959: struct Curl_easy *data = conn->data;
2960:
2961: while((sshc->state != SSH_STOP) && !result) {
2962: bool block;
2963: timediff_t left = 1000;
2964: struct curltime now = Curl_now();
2965:
2966: result = ssh_statemach_act(conn, &block);
2967: if(result)
2968: break;
2969:
2970: if(!disconnect) {
2971: if(Curl_pgrsUpdate(conn))
2972: return CURLE_ABORTED_BY_CALLBACK;
2973:
2974: result = Curl_speedcheck(data, now);
2975: if(result)
2976: break;
2977:
2978: left = Curl_timeleft(data, NULL, FALSE);
2979: if(left < 0) {
2980: failf(data, "Operation timed out");
2981: return CURLE_OPERATION_TIMEDOUT;
2982: }
2983: }
2984:
2985: #ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
2986: if(block) {
2987: int dir = libssh2_session_block_directions(sshc->ssh_session);
2988: curl_socket_t sock = conn->sock[FIRSTSOCKET];
2989: curl_socket_t fd_read = CURL_SOCKET_BAD;
2990: curl_socket_t fd_write = CURL_SOCKET_BAD;
2991: if(LIBSSH2_SESSION_BLOCK_INBOUND & dir)
2992: fd_read = sock;
2993: if(LIBSSH2_SESSION_BLOCK_OUTBOUND & dir)
2994: fd_write = sock;
2995: /* wait for the socket to become ready */
2996: (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write,
2997: left>1000?1000:(time_t)left);
2998: }
2999: #endif
3000:
3001: }
3002:
3003: return result;
3004: }
3005:
3006: /*
3007: * SSH setup and connection
3008: */
3009: static CURLcode ssh_setup_connection(struct connectdata *conn)
3010: {
3011: struct SSHPROTO *ssh;
3012:
3013: conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
3014: if(!ssh)
3015: return CURLE_OUT_OF_MEMORY;
3016:
3017: return CURLE_OK;
3018: }
3019:
3020: static Curl_recv scp_recv, sftp_recv;
3021: static Curl_send scp_send, sftp_send;
3022:
3023: /*
3024: * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
3025: * do protocol-specific actions at connect-time.
3026: */
3027: static CURLcode ssh_connect(struct connectdata *conn, bool *done)
3028: {
3029: #ifdef CURL_LIBSSH2_DEBUG
3030: curl_socket_t sock;
3031: #endif
3032: struct ssh_conn *ssh;
3033: CURLcode result;
3034: struct Curl_easy *data = conn->data;
3035:
3036: /* initialize per-handle data if not already */
3037: if(!data->req.protop)
3038: ssh_setup_connection(conn);
3039:
3040: /* We default to persistent connections. We set this already in this connect
3041: function to make the re-use checks properly be able to check this bit. */
3042: connkeep(conn, "SSH default");
3043:
3044: if(conn->handler->protocol & CURLPROTO_SCP) {
3045: conn->recv[FIRSTSOCKET] = scp_recv;
3046: conn->send[FIRSTSOCKET] = scp_send;
3047: }
3048: else {
3049: conn->recv[FIRSTSOCKET] = sftp_recv;
3050: conn->send[FIRSTSOCKET] = sftp_send;
3051: }
3052: ssh = &conn->proto.sshc;
3053:
3054: #ifdef CURL_LIBSSH2_DEBUG
3055: if(conn->user) {
3056: infof(data, "User: %s\n", conn->user);
3057: }
3058: if(conn->passwd) {
3059: infof(data, "Password: %s\n", conn->passwd);
3060: }
3061: sock = conn->sock[FIRSTSOCKET];
3062: #endif /* CURL_LIBSSH2_DEBUG */
3063:
3064: ssh->ssh_session = libssh2_session_init_ex(my_libssh2_malloc,
3065: my_libssh2_free,
3066: my_libssh2_realloc, conn);
3067: if(ssh->ssh_session == NULL) {
3068: failf(data, "Failure initialising ssh session");
3069: return CURLE_FAILED_INIT;
3070: }
3071:
3072: if(data->set.ssh_compression) {
3073: #if LIBSSH2_VERSION_NUM >= 0x010208
3074: if(libssh2_session_flag(ssh->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0)
3075: #endif
3076: infof(data, "Failed to enable compression for ssh session\n");
3077: }
3078:
3079: #ifdef HAVE_LIBSSH2_KNOWNHOST_API
3080: if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
3081: int rc;
3082: ssh->kh = libssh2_knownhost_init(ssh->ssh_session);
3083: if(!ssh->kh) {
3084: libssh2_session_free(ssh->ssh_session);
3085: return CURLE_FAILED_INIT;
3086: }
3087:
3088: /* read all known hosts from there */
3089: rc = libssh2_knownhost_readfile(ssh->kh,
3090: data->set.str[STRING_SSH_KNOWNHOSTS],
3091: LIBSSH2_KNOWNHOST_FILE_OPENSSH);
3092: if(rc < 0)
3093: infof(data, "Failed to read known hosts from %s\n",
3094: data->set.str[STRING_SSH_KNOWNHOSTS]);
3095: }
3096: #endif /* HAVE_LIBSSH2_KNOWNHOST_API */
3097:
3098: #ifdef CURL_LIBSSH2_DEBUG
3099: libssh2_trace(ssh->ssh_session, ~0);
3100: infof(data, "SSH socket: %d\n", (int)sock);
3101: #endif /* CURL_LIBSSH2_DEBUG */
3102:
3103: state(conn, SSH_INIT);
3104:
3105: result = ssh_multi_statemach(conn, done);
3106:
3107: return result;
3108: }
3109:
3110: /*
3111: ***********************************************************************
3112: *
3113: * scp_perform()
3114: *
3115: * This is the actual DO function for SCP. Get a file according to
3116: * the options previously setup.
3117: */
3118:
3119: static
3120: CURLcode scp_perform(struct connectdata *conn,
3121: bool *connected,
3122: bool *dophase_done)
3123: {
3124: CURLcode result = CURLE_OK;
3125:
3126: DEBUGF(infof(conn->data, "DO phase starts\n"));
3127:
3128: *dophase_done = FALSE; /* not done yet */
3129:
3130: /* start the first command in the DO phase */
3131: state(conn, SSH_SCP_TRANS_INIT);
3132:
3133: /* run the state-machine */
3134: result = ssh_multi_statemach(conn, dophase_done);
3135:
3136: *connected = conn->bits.tcpconnect[FIRSTSOCKET];
3137:
3138: if(*dophase_done) {
3139: DEBUGF(infof(conn->data, "DO phase is complete\n"));
3140: }
3141:
3142: return result;
3143: }
3144:
3145: /* called from multi.c while DOing */
3146: static CURLcode scp_doing(struct connectdata *conn,
3147: bool *dophase_done)
3148: {
3149: CURLcode result;
3150: result = ssh_multi_statemach(conn, dophase_done);
3151:
3152: if(*dophase_done) {
3153: DEBUGF(infof(conn->data, "DO phase is complete\n"));
3154: }
3155: return result;
3156: }
3157:
3158: /*
3159: * The DO function is generic for both protocols. There was previously two
3160: * separate ones but this way means less duplicated code.
3161: */
3162:
3163: static CURLcode ssh_do(struct connectdata *conn, bool *done)
3164: {
3165: CURLcode result;
3166: bool connected = 0;
3167: struct Curl_easy *data = conn->data;
3168: struct ssh_conn *sshc = &conn->proto.sshc;
3169:
3170: *done = FALSE; /* default to false */
3171:
3172: data->req.size = -1; /* make sure this is unknown at this point */
3173:
3174: sshc->actualcode = CURLE_OK; /* reset error code */
3175: sshc->secondCreateDirs = 0; /* reset the create dir attempt state
3176: variable */
3177:
3178: Curl_pgrsSetUploadCounter(data, 0);
3179: Curl_pgrsSetDownloadCounter(data, 0);
3180: Curl_pgrsSetUploadSize(data, -1);
3181: Curl_pgrsSetDownloadSize(data, -1);
3182:
3183: if(conn->handler->protocol & CURLPROTO_SCP)
3184: result = scp_perform(conn, &connected, done);
3185: else
3186: result = sftp_perform(conn, &connected, done);
3187:
3188: return result;
3189: }
3190:
3191: /* BLOCKING, but the function is using the state machine so the only reason
3192: this is still blocking is that the multi interface code has no support for
3193: disconnecting operations that takes a while */
3194: static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection)
3195: {
3196: CURLcode result = CURLE_OK;
3197: struct ssh_conn *ssh = &conn->proto.sshc;
3198: (void) dead_connection;
3199:
3200: if(ssh->ssh_session) {
3201: /* only if there's a session still around to use! */
3202:
3203: state(conn, SSH_SESSION_DISCONNECT);
3204:
3205: result = ssh_block_statemach(conn, TRUE);
3206: }
3207:
3208: return result;
3209: }
3210:
3211: /* generic done function for both SCP and SFTP called from their specific
3212: done functions */
3213: static CURLcode ssh_done(struct connectdata *conn, CURLcode status)
3214: {
3215: CURLcode result = CURLE_OK;
3216: struct SSHPROTO *sftp_scp = conn->data->req.protop;
3217:
3218: if(!status) {
3219: /* run the state-machine */
3220: result = ssh_block_statemach(conn, FALSE);
3221: }
3222: else
3223: result = status;
3224:
3225: if(sftp_scp)
3226: Curl_safefree(sftp_scp->path);
3227: if(Curl_pgrsDone(conn))
3228: return CURLE_ABORTED_BY_CALLBACK;
3229:
3230: conn->data->req.keepon = 0; /* clear all bits */
3231: return result;
3232: }
3233:
3234:
3235: static CURLcode scp_done(struct connectdata *conn, CURLcode status,
3236: bool premature)
3237: {
3238: (void)premature; /* not used */
3239:
3240: if(!status)
3241: state(conn, SSH_SCP_DONE);
3242:
3243: return ssh_done(conn, status);
3244:
3245: }
3246:
3247: static ssize_t scp_send(struct connectdata *conn, int sockindex,
3248: const void *mem, size_t len, CURLcode *err)
3249: {
3250: ssize_t nwrite;
3251: (void)sockindex; /* we only support SCP on the fixed known primary socket */
3252:
3253: /* libssh2_channel_write() returns int! */
3254: nwrite = (ssize_t)
3255: libssh2_channel_write(conn->proto.sshc.ssh_channel, mem, len);
3256:
3257: ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
3258:
3259: if(nwrite == LIBSSH2_ERROR_EAGAIN) {
3260: *err = CURLE_AGAIN;
3261: nwrite = 0;
3262: }
3263: else if(nwrite < LIBSSH2_ERROR_NONE) {
3264: *err = libssh2_session_error_to_CURLE((int)nwrite);
3265: nwrite = -1;
3266: }
3267:
3268: return nwrite;
3269: }
3270:
3271: static ssize_t scp_recv(struct connectdata *conn, int sockindex,
3272: char *mem, size_t len, CURLcode *err)
3273: {
3274: ssize_t nread;
3275: (void)sockindex; /* we only support SCP on the fixed known primary socket */
3276:
3277: /* libssh2_channel_read() returns int */
3278: nread = (ssize_t)
3279: libssh2_channel_read(conn->proto.sshc.ssh_channel, mem, len);
3280:
3281: ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
3282: if(nread == LIBSSH2_ERROR_EAGAIN) {
3283: *err = CURLE_AGAIN;
3284: nread = -1;
3285: }
3286:
3287: return nread;
3288: }
3289:
3290: /*
3291: * =============== SFTP ===============
3292: */
3293:
3294: /*
3295: ***********************************************************************
3296: *
3297: * sftp_perform()
3298: *
3299: * This is the actual DO function for SFTP. Get a file/directory according to
3300: * the options previously setup.
3301: */
3302:
3303: static
3304: CURLcode sftp_perform(struct connectdata *conn,
3305: bool *connected,
3306: bool *dophase_done)
3307: {
3308: CURLcode result = CURLE_OK;
3309:
3310: DEBUGF(infof(conn->data, "DO phase starts\n"));
3311:
3312: *dophase_done = FALSE; /* not done yet */
3313:
3314: /* start the first command in the DO phase */
3315: state(conn, SSH_SFTP_QUOTE_INIT);
3316:
3317: /* run the state-machine */
3318: result = ssh_multi_statemach(conn, dophase_done);
3319:
3320: *connected = conn->bits.tcpconnect[FIRSTSOCKET];
3321:
3322: if(*dophase_done) {
3323: DEBUGF(infof(conn->data, "DO phase is complete\n"));
3324: }
3325:
3326: return result;
3327: }
3328:
3329: /* called from multi.c while DOing */
3330: static CURLcode sftp_doing(struct connectdata *conn,
3331: bool *dophase_done)
3332: {
3333: CURLcode result = ssh_multi_statemach(conn, dophase_done);
3334:
3335: if(*dophase_done) {
3336: DEBUGF(infof(conn->data, "DO phase is complete\n"));
3337: }
3338: return result;
3339: }
3340:
3341: /* BLOCKING, but the function is using the state machine so the only reason
3342: this is still blocking is that the multi interface code has no support for
3343: disconnecting operations that takes a while */
3344: static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection)
3345: {
3346: CURLcode result = CURLE_OK;
3347: (void) dead_connection;
3348:
3349: DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));
3350:
3351: if(conn->proto.sshc.ssh_session) {
3352: /* only if there's a session still around to use! */
3353: state(conn, SSH_SFTP_SHUTDOWN);
3354: result = ssh_block_statemach(conn, TRUE);
3355: }
3356:
3357: DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
3358:
3359: return result;
3360:
3361: }
3362:
3363: static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
3364: bool premature)
3365: {
3366: struct ssh_conn *sshc = &conn->proto.sshc;
3367:
3368: if(!status) {
3369: /* Post quote commands are executed after the SFTP_CLOSE state to avoid
3370: errors that could happen due to open file handles during POSTQUOTE
3371: operation */
3372: if(!premature && conn->data->set.postquote && !conn->bits.retry)
3373: sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
3374: state(conn, SSH_SFTP_CLOSE);
3375: }
3376: return ssh_done(conn, status);
3377: }
3378:
3379: /* return number of sent bytes */
3380: static ssize_t sftp_send(struct connectdata *conn, int sockindex,
3381: const void *mem, size_t len, CURLcode *err)
3382: {
3383: ssize_t nwrite; /* libssh2_sftp_write() used to return size_t in 0.14
3384: but is changed to ssize_t in 0.15. These days we don't
3385: support libssh2 0.15*/
3386: (void)sockindex;
3387:
3388: nwrite = libssh2_sftp_write(conn->proto.sshc.sftp_handle, mem, len);
3389:
3390: ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
3391:
3392: if(nwrite == LIBSSH2_ERROR_EAGAIN) {
3393: *err = CURLE_AGAIN;
3394: nwrite = 0;
3395: }
3396: else if(nwrite < LIBSSH2_ERROR_NONE) {
3397: *err = libssh2_session_error_to_CURLE((int)nwrite);
3398: nwrite = -1;
3399: }
3400:
3401: return nwrite;
3402: }
3403:
3404: /*
3405: * Return number of received (decrypted) bytes
3406: * or <0 on error
3407: */
3408: static ssize_t sftp_recv(struct connectdata *conn, int sockindex,
3409: char *mem, size_t len, CURLcode *err)
3410: {
3411: ssize_t nread;
3412: (void)sockindex;
3413:
3414: nread = libssh2_sftp_read(conn->proto.sshc.sftp_handle, mem, len);
3415:
3416: ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
3417:
3418: if(nread == LIBSSH2_ERROR_EAGAIN) {
3419: *err = CURLE_AGAIN;
3420: nread = -1;
3421:
3422: }
3423: else if(nread < 0) {
3424: *err = libssh2_session_error_to_CURLE((int)nread);
3425: }
3426: return nread;
3427: }
3428:
3429: static const char *sftp_libssh2_strerror(int err)
3430: {
3431: switch(err) {
3432: case LIBSSH2_FX_NO_SUCH_FILE:
3433: return "No such file or directory";
3434:
3435: case LIBSSH2_FX_PERMISSION_DENIED:
3436: return "Permission denied";
3437:
3438: case LIBSSH2_FX_FAILURE:
3439: return "Operation failed";
3440:
3441: case LIBSSH2_FX_BAD_MESSAGE:
3442: return "Bad message from SFTP server";
3443:
3444: case LIBSSH2_FX_NO_CONNECTION:
3445: return "Not connected to SFTP server";
3446:
3447: case LIBSSH2_FX_CONNECTION_LOST:
3448: return "Connection to SFTP server lost";
3449:
3450: case LIBSSH2_FX_OP_UNSUPPORTED:
3451: return "Operation not supported by SFTP server";
3452:
3453: case LIBSSH2_FX_INVALID_HANDLE:
3454: return "Invalid handle";
3455:
3456: case LIBSSH2_FX_NO_SUCH_PATH:
3457: return "No such file or directory";
3458:
3459: case LIBSSH2_FX_FILE_ALREADY_EXISTS:
3460: return "File already exists";
3461:
3462: case LIBSSH2_FX_WRITE_PROTECT:
3463: return "File is write protected";
3464:
3465: case LIBSSH2_FX_NO_MEDIA:
3466: return "No media";
3467:
3468: case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
3469: return "Disk full";
3470:
3471: case LIBSSH2_FX_QUOTA_EXCEEDED:
3472: return "User quota exceeded";
3473:
3474: case LIBSSH2_FX_UNKNOWN_PRINCIPLE:
3475: return "Unknown principle";
3476:
3477: case LIBSSH2_FX_LOCK_CONFlICT:
3478: return "File lock conflict";
3479:
3480: case LIBSSH2_FX_DIR_NOT_EMPTY:
3481: return "Directory not empty";
3482:
3483: case LIBSSH2_FX_NOT_A_DIRECTORY:
3484: return "Not a directory";
3485:
3486: case LIBSSH2_FX_INVALID_FILENAME:
3487: return "Invalid filename";
3488:
3489: case LIBSSH2_FX_LINK_LOOP:
3490: return "Link points to itself";
3491: }
3492: return "Unknown error in libssh2";
3493: }
3494:
3495: CURLcode Curl_ssh_init(void)
3496: {
3497: #ifdef HAVE_LIBSSH2_INIT
3498: if(libssh2_init(0)) {
3499: DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n"));
3500: return CURLE_FAILED_INIT;
3501: }
3502: #endif
3503: return CURLE_OK;
3504: }
3505:
3506: void Curl_ssh_cleanup(void)
3507: {
3508: #ifdef HAVE_LIBSSH2_EXIT
3509: (void)libssh2_exit();
3510: #endif
3511: }
3512:
3513: size_t Curl_ssh_version(char *buffer, size_t buflen)
3514: {
3515: return msnprintf(buffer, buflen, "libssh2/%s", LIBSSH2_VERSION);
3516: }
3517:
3518: #endif /* USE_LIBSSH2 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>