File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / vssh / libssh.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>