Annotation of embedaddon/curl/lib/vssh/libssh.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>