Return to libssh2.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / vssh |
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 */