00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "setup.h"
00025
00026 #ifndef CURL_DISABLE_FTP
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include <stdlib.h>
00030 #include <stdarg.h>
00031 #include <ctype.h>
00032
00033 #ifdef HAVE_UNISTD_H
00034 #include <unistd.h>
00035 #endif
00036
00037 #ifndef WIN32
00038 #ifdef HAVE_SYS_SOCKET_H
00039 #include <sys/socket.h>
00040 #endif
00041 #ifdef HAVE_NETINET_IN_H
00042 #include <netinet/in.h>
00043 #endif
00044 #ifdef HAVE_ARPA_INET_H
00045 #include <arpa/inet.h>
00046 #endif
00047 #ifdef HAVE_UTSNAME_H
00048 #include <sys/utsname.h>
00049 #endif
00050 #ifdef HAVE_NETDB_H
00051 #include <netdb.h>
00052 #endif
00053 #ifdef VMS
00054 #include <in.h>
00055 #include <inet.h>
00056 #endif
00057 #endif
00058
00059 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
00060 #undef in_addr_t
00061 #define in_addr_t unsigned long
00062 #endif
00063
00064 #include <curl/curl.h>
00065 #include "urldata.h"
00066 #include "sendf.h"
00067 #include "easyif.h"
00068
00069 #include "if2ip.h"
00070 #include "hostip.h"
00071 #include "progress.h"
00072 #include "transfer.h"
00073 #include "escape.h"
00074 #include "http.h"
00075 #include "socks.h"
00076 #include "ftp.h"
00077
00078 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
00079 #include "krb4.h"
00080 #endif
00081
00082 #include "strtoofft.h"
00083 #include "strequal.h"
00084 #include "sslgen.h"
00085 #include "connect.h"
00086 #include "strerror.h"
00087 #include "memory.h"
00088 #include "inet_ntop.h"
00089 #include "select.h"
00090 #include "parsedate.h"
00091 #include "sockaddr.h"
00092 #include "multiif.h"
00093
00094 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
00095 #include "inet_ntoa_r.h"
00096 #endif
00097
00098 #define _MPRINTF_REPLACE
00099 #include <curl/mprintf.h>
00100
00101
00102 #ifdef CURLDEBUG
00103 #include "memdebug.h"
00104 #endif
00105
00106 #ifdef HAVE_NI_WITHSCOPEID
00107 #define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID
00108 #else
00109 #define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV
00110 #endif
00111
00112 #ifdef CURL_DISABLE_VERBOSE_STRINGS
00113 #define ftp_pasv_verbose(a,b,c,d) do { } while (0)
00114 #endif
00115
00116
00117 static CURLcode ftp_sendquote(struct connectdata *conn,
00118 struct curl_slist *quote);
00119 static CURLcode ftp_quit(struct connectdata *conn);
00120 static CURLcode ftp_parse_url_path(struct connectdata *conn);
00121 static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
00122 #ifndef CURL_DISABLE_VERBOSE_STRINGS
00123 static void ftp_pasv_verbose(struct connectdata *conn,
00124 Curl_addrinfo *ai,
00125 char *newhost,
00126 int port);
00127 #endif
00128 static CURLcode ftp_state_post_rest(struct connectdata *conn);
00129 static CURLcode ftp_state_post_cwd(struct connectdata *conn);
00130 static CURLcode ftp_state_quote(struct connectdata *conn,
00131 bool init, ftpstate instate);
00132 static CURLcode ftp_nb_type(struct connectdata *conn,
00133 bool ascii, ftpstate state);
00134 static int ftp_need_type(struct connectdata *conn,
00135 bool ascii);
00136
00137
00138 #define FTPSENDF(x,y,z) if ((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
00139 return result
00140 #define NBFTPSENDF(x,y,z) if ((result = Curl_nbftpsendf(x,y,z)) != CURLE_OK) \
00141 return result
00142
00143 static void freedirs(struct connectdata *conn)
00144 {
00145 struct ftp_conn *ftpc = &conn->proto.ftpc;
00146 struct FTP *ftp = conn->data->reqdata.proto.ftp;
00147
00148 int i;
00149 if(ftpc->dirs) {
00150 for (i=0; i < ftpc->dirdepth; i++){
00151 if(ftpc->dirs[i]) {
00152 free(ftpc->dirs[i]);
00153 ftpc->dirs[i]=NULL;
00154 }
00155 }
00156 free(ftpc->dirs);
00157 ftpc->dirs = NULL;
00158 }
00159 if(ftp->file) {
00160 free(ftp->file);
00161 ftp->file = NULL;
00162 }
00163 }
00164
00165
00166
00167
00168
00169
00170
00171 static bool isBadFtpString(const char *string)
00172 {
00173 return (bool)((NULL != strchr(string, '\r')) || (NULL != strchr(string, '\n')));
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185 static CURLcode AllowServerConnect(struct connectdata *conn)
00186 {
00187 long timeout_ms;
00188 struct SessionHandle *data = conn->data;
00189 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
00190 int timeout_set = 0;
00191
00192
00193
00194 if (data->set.timeout > 0)
00195 timeout_set += 1;
00196 if (data->set.connecttimeout > 0)
00197 timeout_set += 2;
00198
00199 switch (timeout_set) {
00200 case 1:
00201 timeout_ms = data->set.timeout;
00202 break;
00203 case 2:
00204 timeout_ms = data->set.connecttimeout;
00205 break;
00206 case 3:
00207 if (data->set.timeout < data->set.connecttimeout)
00208 timeout_ms = data->set.timeout;
00209 else
00210 timeout_ms = data->set.connecttimeout;
00211 break;
00212 default:
00213 timeout_ms = 60000;
00214 break;
00215 }
00216
00217 if (timeout_set > 0) {
00218
00219 timeout_ms -= Curl_tvdiff(Curl_tvnow(), conn->now);
00220 if(timeout_ms < 0) {
00221 failf(data, "Timed out before server could connect to us");
00222 return CURLE_OPERATION_TIMEDOUT;
00223 }
00224 }
00225
00226 switch (Curl_socket_ready(sock, CURL_SOCKET_BAD, (int)timeout_ms)) {
00227 case -1:
00228
00229 failf(data, "Error while waiting for server connect");
00230 return CURLE_FTP_PORT_FAILED;
00231 case 0:
00232
00233 failf(data, "Timeout while waiting for server connect");
00234 return CURLE_FTP_PORT_FAILED;
00235 default:
00236
00237 {
00238 curl_socket_t s = CURL_SOCKET_BAD;
00239 #ifdef ENABLE_IPV6
00240 struct Curl_sockaddr_storage add;
00241 #else
00242 struct sockaddr_in add;
00243 #endif
00244 socklen_t size = (socklen_t) sizeof(add);
00245
00246 if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
00247 size = sizeof(add);
00248
00249 s=accept(sock, (struct sockaddr *) &add, &size);
00250 }
00251 sclose(sock);
00252
00253 if (CURL_SOCKET_BAD == s) {
00254
00255 failf(data, "Error accept()ing server connect");
00256 return CURLE_FTP_PORT_FAILED;
00257 }
00258 infof(data, "Connection accepted from server\n");
00259
00260 conn->sock[SECONDARYSOCKET] = s;
00261 Curl_nonblock(s, TRUE);
00262 }
00263 break;
00264 }
00265
00266 return CURLE_OK;
00267 }
00268
00269
00270 static void ftp_respinit(struct connectdata *conn)
00271 {
00272 struct ftp_conn *ftpc = &conn->proto.ftpc;
00273 ftpc->nread_resp = 0;
00274 ftpc->linestart_resp = conn->data->state.buffer;
00275 }
00276
00277
00278 #define lastline(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
00279 ISDIGIT(line[2]) && (' ' == line[3]))
00280
00281 static CURLcode ftp_readresp(curl_socket_t sockfd,
00282 struct connectdata *conn,
00283 int *ftpcode,
00284 size_t *size)
00285 {
00286 int perline;
00287 bool keepon=TRUE;
00288 ssize_t gotbytes;
00289 char *ptr;
00290 struct SessionHandle *data = conn->data;
00291 char *buf = data->state.buffer;
00292 CURLcode result = CURLE_OK;
00293 struct ftp_conn *ftpc = &conn->proto.ftpc;
00294 int code = 0;
00295
00296 *ftpcode = 0;
00297
00298 ptr=buf + ftpc->nread_resp;
00299
00300 perline= (int)(ptr-ftpc->linestart_resp);
00301
00302 keepon=TRUE;
00303
00304 while((ftpc->nread_resp<BUFSIZE) && (keepon && !result)) {
00305
00306 if(ftpc->cache) {
00307
00308
00309
00310
00311
00312
00313
00314
00315 memcpy(ptr, ftpc->cache, (int)ftpc->cache_size);
00316 gotbytes = (int)ftpc->cache_size;
00317 free(ftpc->cache);
00318 ftpc->cache = NULL;
00319 ftpc->cache_size = 0;
00320 }
00321 else {
00322 int res;
00323 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
00324 enum protection_level prot = conn->data_prot;
00325
00326 conn->data_prot = 0;
00327 #endif
00328 res = Curl_read(conn, sockfd, ptr, BUFSIZE-ftpc->nread_resp,
00329 &gotbytes);
00330 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
00331 conn->data_prot = prot;
00332 #endif
00333 if(res < 0)
00334
00335 return CURLE_OK;
00336
00337 #ifdef CURL_DOES_CONVERSIONS
00338 if((res == CURLE_OK) && (gotbytes > 0)) {
00339
00340 result = res = Curl_convert_from_network(data, ptr, gotbytes);
00341
00342 }
00343 #endif
00344
00345 if(CURLE_OK != res)
00346 keepon = FALSE;
00347 }
00348
00349 if(!keepon)
00350 ;
00351 else if(gotbytes <= 0) {
00352 keepon = FALSE;
00353 result = CURLE_RECV_ERROR;
00354 failf(data, "FTP response reading failed");
00355 }
00356 else {
00357
00358
00359
00360 int i;
00361
00362 data->reqdata.keep.headerbytecount += gotbytes;
00363
00364 ftpc->nread_resp += gotbytes;
00365 for(i = 0; i < gotbytes; ptr++, i++) {
00366 perline++;
00367 if(*ptr=='\n') {
00368
00369
00370
00371
00372 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
00373 if(!conn->sec_complete)
00374 #endif
00375 if(data->set.verbose)
00376 Curl_debug(data, CURLINFO_HEADER_IN,
00377 ftpc->linestart_resp, (size_t)perline, conn);
00378
00379
00380
00381
00382
00383
00384 result = Curl_client_write(conn, CLIENTWRITE_HEADER,
00385 ftpc->linestart_resp, perline);
00386 if(result)
00387 return result;
00388
00389 if(perline>3 && lastline(ftpc->linestart_resp)) {
00390
00391
00392
00393 char *meow;
00394 int n;
00395 for(meow=ftpc->linestart_resp, n=0; meow<ptr; meow++, n++)
00396 buf[n] = *meow;
00397 *meow=0;
00398 keepon=FALSE;
00399 ftpc->linestart_resp = ptr+1;
00400 i++;
00401
00402 *size = ftpc->nread_resp;
00403 ftpc->nread_resp = 0;
00404 break;
00405 }
00406 perline=0;
00407 ftpc->linestart_resp = ptr+1;
00408 }
00409 }
00410 if(!keepon && (i != gotbytes)) {
00411
00412
00413
00414
00415 ftpc->cache_size = gotbytes - i;
00416 ftpc->cache = (char *)malloc((int)ftpc->cache_size);
00417 if(ftpc->cache)
00418 memcpy(ftpc->cache, ftpc->linestart_resp, (int)ftpc->cache_size);
00419 else
00420 return CURLE_OUT_OF_MEMORY;
00421 }
00422 }
00423
00424 }
00425
00426 if(!result)
00427 code = atoi(buf);
00428
00429 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
00430
00431
00432 switch(code) {
00433 case 631:
00434 code = Curl_sec_read_msg(conn, buf, prot_safe);
00435 break;
00436 case 632:
00437 code = Curl_sec_read_msg(conn, buf, prot_private);
00438 break;
00439 case 633:
00440 code = Curl_sec_read_msg(conn, buf, prot_confidential);
00441 break;
00442 default:
00443
00444 break;
00445 }
00446 #endif
00447
00448 *ftpcode=code;
00449
00450
00451 conn->data->info.httpcode=code;
00452
00453 return result;
00454 }
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464 CURLcode Curl_GetFTPResponse(ssize_t *nreadp,
00465 struct connectdata *conn,
00466 int *ftpcode)
00467 {
00468
00469
00470
00471
00472
00473
00474
00475 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
00476 int perline;
00477 bool keepon=TRUE;
00478 ssize_t gotbytes;
00479 char *ptr;
00480 long timeout;
00481 long interval_ms;
00482 struct SessionHandle *data = conn->data;
00483 char *line_start;
00484 int code=0;
00485 char *buf = data->state.buffer;
00486 CURLcode result = CURLE_OK;
00487 struct ftp_conn *ftpc = &conn->proto.ftpc;
00488 struct timeval now = Curl_tvnow();
00489
00490 if (ftpcode)
00491 *ftpcode = 0;
00492
00493 ptr=buf;
00494 line_start = buf;
00495
00496 *nreadp=0;
00497 perline=0;
00498 keepon=TRUE;
00499
00500 while((*nreadp<BUFSIZE) && (keepon && !result)) {
00501
00502 if(data->set.ftp_response_timeout )
00503
00504
00505
00506
00507
00508 timeout = data->set.ftp_response_timeout -
00509 Curl_tvdiff(Curl_tvnow(), now);
00510 else if(data->set.timeout)
00511
00512 timeout = data->set.timeout -
00513 Curl_tvdiff(Curl_tvnow(), conn->now);
00514 else
00515
00516
00517 timeout = ftpc->response_time -
00518 Curl_tvdiff(Curl_tvnow(), now);
00519
00520 if(timeout <=0 ) {
00521 failf(data, "FTP response timeout");
00522 return CURLE_OPERATION_TIMEDOUT;
00523 }
00524
00525 if(!ftpc->cache) {
00526 interval_ms = 1 * 1000;
00527 if(timeout < interval_ms)
00528 interval_ms = timeout;
00529
00530 switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, (int)interval_ms)) {
00531 case -1:
00532 result = CURLE_RECV_ERROR;
00533 failf(data, "FTP response aborted due to select/poll error: %d",
00534 SOCKERRNO);
00535 break;
00536 case 0:
00537 if(Curl_pgrsUpdate(conn))
00538 return CURLE_ABORTED_BY_CALLBACK;
00539 continue;
00540
00541 default:
00542 break;
00543 }
00544 }
00545 if(CURLE_OK == result) {
00546
00547
00548
00549
00550
00551 if(ftpc->cache) {
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561 memcpy(ptr, ftpc->cache, (int)ftpc->cache_size);
00562 gotbytes = (int)ftpc->cache_size;
00563 free(ftpc->cache);
00564 ftpc->cache = NULL;
00565 ftpc->cache_size = 0;
00566 }
00567 else {
00568 int res;
00569 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
00570 enum protection_level prot = conn->data_prot;
00571
00572 conn->data_prot = 0;
00573 #endif
00574 res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp,
00575 &gotbytes);
00576 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
00577 conn->data_prot = prot;
00578 #endif
00579 if(res < 0)
00580
00581 continue;
00582
00583 #ifdef CURL_DOES_CONVERSIONS
00584 if((res == CURLE_OK) && (gotbytes > 0)) {
00585
00586 result = res = Curl_convert_from_network(data, ptr, gotbytes);
00587
00588 }
00589 #endif
00590
00591 if(CURLE_OK != res)
00592 keepon = FALSE;
00593 }
00594
00595 if(!keepon)
00596 ;
00597 else if(gotbytes <= 0) {
00598 keepon = FALSE;
00599 result = CURLE_RECV_ERROR;
00600 failf(data, "FTP response reading failed");
00601 }
00602 else {
00603
00604
00605
00606 int i;
00607
00608 data->reqdata.keep.headerbytecount += gotbytes;
00609
00610 *nreadp += gotbytes;
00611 for(i = 0; i < gotbytes; ptr++, i++) {
00612 perline++;
00613 if(*ptr=='\n') {
00614
00615
00616
00617
00618 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
00619 if(!conn->sec_complete)
00620 #endif
00621 if(data->set.verbose)
00622 Curl_debug(data, CURLINFO_HEADER_IN,
00623 line_start, (size_t)perline, conn);
00624
00625
00626
00627
00628
00629
00630 result = Curl_client_write(conn, CLIENTWRITE_HEADER,
00631 line_start, perline);
00632 if(result)
00633 return result;
00634
00635 if(perline>3 && lastline(line_start)) {
00636
00637
00638
00639 char *meow;
00640 int n;
00641 for(meow=line_start, n=0; meow<ptr; meow++, n++)
00642 buf[n] = *meow;
00643 *meow=0;
00644 keepon=FALSE;
00645 line_start = ptr+1;
00646 i++;
00647 break;
00648 }
00649 perline=0;
00650 line_start = ptr+1;
00651 }
00652 }
00653 if(!keepon && (i != gotbytes)) {
00654
00655
00656
00657
00658
00659
00660 ftpc->cache_size = gotbytes - i;
00661 ftpc->cache = (char *)malloc((int)ftpc->cache_size);
00662 if(ftpc->cache)
00663 memcpy(ftpc->cache, line_start, (int)ftpc->cache_size);
00664 else
00665 return CURLE_OUT_OF_MEMORY;
00666 }
00667 }
00668 }
00669 }
00670
00671 if(!result)
00672 code = atoi(buf);
00673
00674 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
00675
00676
00677 switch(code) {
00678 case 631:
00679 code = Curl_sec_read_msg(conn, buf, prot_safe);
00680 break;
00681 case 632:
00682 code = Curl_sec_read_msg(conn, buf, prot_private);
00683 break;
00684 case 633:
00685 code = Curl_sec_read_msg(conn, buf, prot_confidential);
00686 break;
00687 default:
00688
00689 break;
00690 }
00691 #endif
00692
00693 if(ftpcode)
00694 *ftpcode=code;
00695
00696
00697 conn->data->info.httpcode=code;
00698
00699 return result;
00700 }
00701
00702
00703 static void state(struct connectdata *conn,
00704 ftpstate state)
00705 {
00706 #if defined(CURLDEBUG) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
00707
00708 const char *names[]={
00709 "STOP",
00710 "WAIT220",
00711 "AUTH",
00712 "USER",
00713 "PASS",
00714 "ACCT",
00715 "PBSZ",
00716 "PROT",
00717 "CCC",
00718 "PWD",
00719 "QUOTE",
00720 "RETR_PREQUOTE",
00721 "STOR_PREQUOTE",
00722 "POSTQUOTE",
00723 "CWD",
00724 "MKD",
00725 "MDTM",
00726 "TYPE",
00727 "LIST_TYPE",
00728 "RETR_TYPE",
00729 "STOR_TYPE",
00730 "SIZE",
00731 "RETR_SIZE",
00732 "STOR_SIZE",
00733 "REST",
00734 "RETR_REST",
00735 "PORT",
00736 "PASV",
00737 "LIST",
00738 "RETR",
00739 "STOR",
00740 "QUIT"
00741 };
00742 #endif
00743 struct ftp_conn *ftpc = &conn->proto.ftpc;
00744 #if defined(CURLDEBUG) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
00745 if(ftpc->state != state)
00746 infof(conn->data, "FTP %p state change from %s to %s\n",
00747 ftpc, names[ftpc->state], names[state]);
00748 #endif
00749 ftpc->state = state;
00750 }
00751
00752 static CURLcode ftp_state_user(struct connectdata *conn)
00753 {
00754 CURLcode result;
00755 struct FTP *ftp = conn->data->reqdata.proto.ftp;
00756
00757 NBFTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
00758
00759 state(conn, FTP_USER);
00760 conn->data->state.ftp_trying_alternative = FALSE;
00761
00762 return CURLE_OK;
00763 }
00764
00765 static CURLcode ftp_state_pwd(struct connectdata *conn)
00766 {
00767 CURLcode result;
00768
00769
00770 NBFTPSENDF(conn, "PWD", NULL);
00771 state(conn, FTP_PWD);
00772
00773 return CURLE_OK;
00774 }
00775
00776
00777 int Curl_ftp_getsock(struct connectdata *conn,
00778 curl_socket_t *socks,
00779 int numsocks)
00780 {
00781 struct ftp_conn *ftpc = &conn->proto.ftpc;
00782
00783 if(!numsocks)
00784 return GETSOCK_BLANK;
00785
00786 socks[0] = conn->sock[FIRSTSOCKET];
00787
00788 if(ftpc->sendleft) {
00789
00790 return GETSOCK_WRITESOCK(0);
00791 }
00792
00793
00794 return GETSOCK_READSOCK(0);
00795 }
00796
00797
00798
00799
00800
00801
00802
00803 static CURLcode ftp_state_cwd(struct connectdata *conn)
00804 {
00805 CURLcode result = CURLE_OK;
00806 struct ftp_conn *ftpc = &conn->proto.ftpc;
00807
00808 if(ftpc->cwddone)
00809
00810 result = ftp_state_post_cwd(conn);
00811 else {
00812 ftpc->count2 = 0;
00813 if (conn->bits.reuse && ftpc->entrypath) {
00814
00815
00816
00817 ftpc->count1 = 0;
00818
00819 NBFTPSENDF(conn, "CWD %s", ftpc->entrypath);
00820 state(conn, FTP_CWD);
00821 }
00822 else {
00823 if(ftpc->dirdepth) {
00824 ftpc->count1 = 1;
00825
00826
00827 NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
00828 state(conn, FTP_CWD);
00829 }
00830 else {
00831
00832 result = ftp_state_post_cwd(conn);
00833 }
00834 }
00835 }
00836 return result;
00837 }
00838
00839 typedef enum {
00840 EPRT,
00841 PORT,
00842 DONE
00843 } ftpport;
00844
00845 static CURLcode ftp_state_use_port(struct connectdata *conn,
00846 ftpport fcmd)
00847
00848 {
00849 CURLcode result = CURLE_OK;
00850 struct ftp_conn *ftpc = &conn->proto.ftpc;
00851 struct SessionHandle *data=conn->data;
00852 curl_socket_t portsock= CURL_SOCKET_BAD;
00853 char myhost[256] = "";
00854
00855 #ifdef ENABLE_IPV6
00856
00857
00858
00859 struct Curl_sockaddr_storage ss;
00860 struct addrinfo *res, *ai;
00861 socklen_t sslen;
00862 char hbuf[NI_MAXHOST];
00863 struct sockaddr *sa=(struct sockaddr *)&ss;
00864 char tmp[1024];
00865 const char *mode[] = { "EPRT", "PORT", NULL };
00866 int rc;
00867 int error;
00868 char *host=NULL;
00869 struct Curl_dns_entry *h=NULL;
00870 unsigned short port = 0;
00871
00872
00873
00874 if(data->set.ftpport && (strlen(data->set.ftpport) > 1)) {
00875
00876 if(!Curl_if2ip(data->set.ftpport, hbuf, sizeof(hbuf)))
00877
00878 host = data->set.ftpport;
00879 else
00880 host = hbuf;
00881 }
00882
00883 if(!host) {
00884
00885
00886
00887 sslen = sizeof(ss);
00888 if (getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen)) {
00889 failf(data, "getsockname() failed: %s",
00890 Curl_strerror(conn, SOCKERRNO) );
00891 return CURLE_FTP_PORT_FAILED;
00892 }
00893
00894 if (sslen > (socklen_t)sizeof(ss))
00895 sslen = sizeof(ss);
00896 rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL,
00897 0, NIFLAGS);
00898 if(rc) {
00899 failf(data, "getnameinfo() returned %d \n", rc);
00900 return CURLE_FTP_PORT_FAILED;
00901 }
00902 host = hbuf;
00903 }
00904
00905 rc = Curl_resolv(conn, host, 0, &h);
00906 if(rc == CURLRESOLV_PENDING)
00907 rc = Curl_wait_for_resolv(conn, &h);
00908 if(h) {
00909 res = h->addr;
00910
00911
00912 Curl_resolv_unlock(data, h);
00913 }
00914 else
00915 res = NULL;
00916
00917
00918
00919
00920 portsock = CURL_SOCKET_BAD;
00921 error = 0;
00922 for (ai = res; ai; ai = ai->ai_next) {
00923
00924
00925
00926 if (ai->ai_socktype == 0)
00927 ai->ai_socktype = conn->socktype;
00928
00929 portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
00930 if (portsock == CURL_SOCKET_BAD) {
00931 error = SOCKERRNO;
00932 continue;
00933 }
00934 break;
00935 }
00936 if(!ai) {
00937 failf(data, "socket failure: %s", Curl_strerror(conn, error));
00938 return CURLE_FTP_PORT_FAILED;
00939 }
00940
00941
00942
00943
00944 if (bind(portsock, ai->ai_addr, ai->ai_addrlen)) {
00945
00946
00947 sslen = sizeof(ss);
00948 if (getsockname(conn->sock[FIRSTSOCKET],
00949 (struct sockaddr *)sa, &sslen)) {
00950 failf(data, "getsockname() failed: %s",
00951 Curl_strerror(conn, SOCKERRNO) );
00952 sclose(portsock);
00953 return CURLE_FTP_PORT_FAILED;
00954 }
00955
00956
00957 if(((struct sockaddr *)sa)->sa_family == AF_INET)
00958 ((struct sockaddr_in *)sa)->sin_port=0;
00959 else
00960 ((struct sockaddr_in6 *)sa)->sin6_port =0;
00961
00962 if (sslen > (socklen_t)sizeof(ss))
00963 sslen = sizeof(ss);
00964
00965 if(bind(portsock, (struct sockaddr *)sa, sslen)) {
00966 failf(data, "bind failed: %s", Curl_strerror(conn, SOCKERRNO));
00967 sclose(portsock);
00968 return CURLE_FTP_PORT_FAILED;
00969 }
00970 }
00971
00972
00973
00974 sslen = sizeof(ss);
00975 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
00976 failf(data, "getsockname() failed: %s",
00977 Curl_strerror(conn, SOCKERRNO) );
00978 sclose(portsock);
00979 return CURLE_FTP_PORT_FAILED;
00980 }
00981
00982
00983
00984 if (listen(portsock, 1)) {
00985 failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
00986 sclose(portsock);
00987 return CURLE_FTP_PORT_FAILED;
00988 }
00989
00990
00991
00992
00993
00994 Curl_printable_address(ai, myhost, sizeof(myhost));
00995
00996 #ifdef PF_INET6
00997 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
00998
00999
01000 conn->bits.ftp_use_eprt = TRUE;
01001 #endif
01002
01003 for (; fcmd != DONE; fcmd++) {
01004
01005 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
01006
01007 continue;
01008
01009 switch (sa->sa_family) {
01010 case AF_INET:
01011 port = ntohs(((struct sockaddr_in *)sa)->sin_port);
01012 break;
01013 case AF_INET6:
01014 port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
01015 break;
01016 default:
01017 break;
01018 }
01019
01020 if (EPRT == fcmd) {
01021
01022
01023
01024
01025
01026
01027
01028
01029 result = Curl_nbftpsendf(conn, "%s |%d|%s|%d|", mode[fcmd],
01030 ai->ai_family == AF_INET?1:2,
01031 myhost, port);
01032 if(result)
01033 return result;
01034 break;
01035 }
01036 else if (PORT == fcmd) {
01037 char *source = myhost;
01038 char *dest = tmp;
01039
01040 if ((PORT == fcmd) && ai->ai_family != AF_INET)
01041 continue;
01042
01043
01044 while(source && *source) {
01045 if(*source == '.')
01046 *dest=',';
01047 else
01048 *dest = *source;
01049 dest++;
01050 source++;
01051 }
01052 *dest = 0;
01053 snprintf(dest, 20, ",%d,%d", port>>8, port&0xff);
01054
01055 result = Curl_nbftpsendf(conn, "%s %s", mode[fcmd], tmp);
01056 if(result)
01057 return result;
01058 break;
01059 }
01060 }
01061
01062
01063 ftpc->count1 = fcmd;
01064
01065
01066
01067
01068 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
01069 sclose(conn->sock[SECONDARYSOCKET]);
01070 conn->sock[SECONDARYSOCKET] = portsock;
01071
01072 #else
01073
01074
01075
01076 struct sockaddr_in sa;
01077 unsigned short porttouse;
01078 bool sa_filled_in = FALSE;
01079 Curl_addrinfo *addr = NULL;
01080 unsigned short ip[4];
01081 bool freeaddr = TRUE;
01082 socklen_t sslen = sizeof(sa);
01083
01084 (void)fcmd;
01085 if(data->set.ftpport) {
01086 in_addr_t in;
01087
01088
01089 in=inet_addr(data->set.ftpport);
01090
01091 if(in != CURL_INADDR_NONE)
01092
01093 addr = Curl_ip2addr(in, data->set.ftpport, 0);
01094 else {
01095 if(Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
01096
01097 in=inet_addr(myhost);
01098 addr = Curl_ip2addr(in, myhost, 0);
01099 }
01100 else if(strlen(data->set.ftpport)> 1) {
01101
01102 struct Curl_dns_entry *h=NULL;
01103 int rc = Curl_resolv(conn, data->set.ftpport, 0, &h);
01104 if(rc == CURLRESOLV_PENDING)
01105
01106 rc = Curl_wait_for_resolv(conn, &h);
01107 if(h) {
01108 addr = h->addr;
01109
01110
01111 Curl_resolv_unlock(data, h);
01112
01113 freeaddr = FALSE;
01114
01115 }
01116 else {
01117 infof(data, "Failed to resolve host name %s\n", data->set.ftpport);
01118 }
01119 }
01120 }
01121 }
01122
01123 if(!addr) {
01124
01125
01126 if (getsockname(conn->sock[FIRSTSOCKET],
01127 (struct sockaddr *)&sa, &sslen)) {
01128 failf(data, "getsockname() failed: %s",
01129 Curl_strerror(conn, SOCKERRNO) );
01130 return CURLE_FTP_PORT_FAILED;
01131 }
01132 if (sslen > (socklen_t)sizeof(sa))
01133 sslen = sizeof(sa);
01134
01135 sa_filled_in = TRUE;
01136 }
01137
01138 if (addr || sa_filled_in) {
01139 portsock = socket(AF_INET, SOCK_STREAM, 0);
01140 if(CURL_SOCKET_BAD != portsock) {
01141
01142
01143
01144
01145 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
01146 sclose(conn->sock[SECONDARYSOCKET]);
01147 conn->sock[SECONDARYSOCKET] = portsock;
01148
01149 if(!sa_filled_in) {
01150 memcpy(&sa, addr->ai_addr, sslen);
01151 sa.sin_addr.s_addr = INADDR_ANY;
01152 }
01153
01154 sa.sin_port = 0;
01155 sslen = sizeof(sa);
01156
01157 if(bind(portsock, (struct sockaddr *)&sa, sslen) == 0) {
01158
01159 struct sockaddr_in add;
01160 socklen_t socksize = sizeof(add);
01161
01162 if(getsockname(portsock, (struct sockaddr *) &add,
01163 &socksize)) {
01164 failf(data, "getsockname() failed: %s",
01165 Curl_strerror(conn, SOCKERRNO) );
01166 return CURLE_FTP_PORT_FAILED;
01167 }
01168 porttouse = ntohs(add.sin_port);
01169
01170 if ( listen(portsock, 1) < 0 ) {
01171 failf(data, "listen(2) failed on socket");
01172 return CURLE_FTP_PORT_FAILED;
01173 }
01174 }
01175 else {
01176 failf(data, "bind(2) failed on socket");
01177 return CURLE_FTP_PORT_FAILED;
01178 }
01179 }
01180 else {
01181 failf(data, "socket(2) failed (%s)");
01182 return CURLE_FTP_PORT_FAILED;
01183 }
01184 }
01185 else {
01186 failf(data, "couldn't find IP address to use");
01187 return CURLE_FTP_PORT_FAILED;
01188 }
01189
01190 if(sa_filled_in)
01191 Curl_inet_ntop(AF_INET, &((struct sockaddr_in *)&sa)->sin_addr,
01192 myhost, sizeof(myhost));
01193 else
01194 Curl_printable_address(addr, myhost, sizeof(myhost));
01195
01196 if(4 == sscanf(myhost, "%hu.%hu.%hu.%hu",
01197 &ip[0], &ip[1], &ip[2], &ip[3])) {
01198
01199 infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n",
01200 ip[0], ip[1], ip[2], ip[3], porttouse);
01201
01202 result=Curl_nbftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d",
01203 ip[0], ip[1], ip[2], ip[3],
01204 porttouse >> 8, porttouse & 255);
01205 if(result)
01206 return result;
01207 }
01208 else
01209 return CURLE_FTP_PORT_FAILED;
01210
01211 if(freeaddr)
01212 Curl_freeaddrinfo(addr);
01213
01214 ftpc->count1 = PORT;
01215
01216 #endif
01217
01218
01219
01220
01221
01222
01223
01224
01225 conn->bits.tcpconnect = TRUE;
01226
01227 state(conn, FTP_PORT);
01228 return result;
01229 }
01230
01231 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
01232 {
01233 struct ftp_conn *ftpc = &conn->proto.ftpc;
01234 CURLcode result = CURLE_OK;
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249 const char *mode[] = { "EPSV", "PASV", NULL };
01250 int modeoff;
01251
01252 #ifdef PF_INET6
01253 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
01254
01255
01256 conn->bits.ftp_use_epsv = TRUE;
01257 #endif
01258
01259 modeoff = conn->bits.ftp_use_epsv?0:1;
01260
01261 result = Curl_nbftpsendf(conn, "%s", mode[modeoff]);
01262 if(result)
01263 return result;
01264
01265 ftpc->count1 = modeoff;
01266 state(conn, FTP_PASV);
01267 infof(conn->data, "Connect data stream passively\n");
01268
01269 return result;
01270 }
01271
01272
01273
01274
01275 static CURLcode ftp_state_post_rest(struct connectdata *conn)
01276 {
01277 CURLcode result = CURLE_OK;
01278 struct FTP *ftp = conn->data->reqdata.proto.ftp;
01279 struct SessionHandle *data = conn->data;
01280
01281 if(ftp->no_transfer) {
01282
01283
01284
01285 state(conn, FTP_RETR_PREQUOTE);
01286 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
01287 }
01288 else if(data->set.ftp_use_port) {
01289
01290 result = ftp_state_use_port(conn, EPRT);
01291 }
01292 else {
01293
01294 result = ftp_state_use_pasv(conn);
01295 }
01296 return result;
01297 }
01298
01299 static CURLcode ftp_state_post_size(struct connectdata *conn)
01300 {
01301 CURLcode result = CURLE_OK;
01302 struct FTP *ftp = conn->data->reqdata.proto.ftp;
01303
01304 if(ftp->no_transfer) {
01305
01306
01307
01308
01309 NBFTPSENDF(conn, "REST %d", 0);
01310
01311 state(conn, FTP_REST);
01312 }
01313 else
01314 result = ftp_state_post_rest(conn);
01315
01316 return result;
01317 }
01318
01319 static CURLcode ftp_state_post_type(struct connectdata *conn)
01320 {
01321 CURLcode result = CURLE_OK;
01322 struct FTP *ftp = conn->data->reqdata.proto.ftp;
01323
01324 if(ftp->no_transfer) {
01325
01326
01327
01328 NBFTPSENDF(conn, "SIZE %s", ftp->file);
01329
01330 state(conn, FTP_SIZE);
01331 }
01332 else
01333 result = ftp_state_post_size(conn);
01334
01335 return result;
01336 }
01337
01338 static CURLcode ftp_state_post_listtype(struct connectdata *conn)
01339 {
01340 CURLcode result = CURLE_OK;
01341 struct SessionHandle *data = conn->data;
01342
01343
01344
01345
01346
01347
01348 NBFTPSENDF(conn, "%s",
01349 data->set.customrequest?data->set.customrequest:
01350 (data->set.ftp_list_only?"NLST":"LIST"));
01351
01352 state(conn, FTP_LIST);
01353
01354 return result;
01355 }
01356
01357 static CURLcode ftp_state_post_retrtype(struct connectdata *conn)
01358 {
01359 CURLcode result = CURLE_OK;
01360
01361
01362
01363 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
01364
01365 return result;
01366 }
01367
01368 static CURLcode ftp_state_post_stortype(struct connectdata *conn)
01369 {
01370 CURLcode result = CURLE_OK;
01371
01372
01373
01374 result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
01375
01376 return result;
01377 }
01378
01379 static CURLcode ftp_state_post_mdtm(struct connectdata *conn)
01380 {
01381 CURLcode result = CURLE_OK;
01382 struct FTP *ftp = conn->data->reqdata.proto.ftp;
01383 struct SessionHandle *data = conn->data;
01384
01385
01386
01387
01388 if(conn->bits.no_body && data->set.include_header && ftp->file &&
01389 ftp_need_type(conn, data->set.prefer_ascii)) {
01390
01391
01392
01393
01394 ftp->no_transfer = TRUE;
01395
01396
01397
01398 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
01399 if (result)
01400 return result;
01401 }
01402 else
01403 result = ftp_state_post_type(conn);
01404
01405 return result;
01406 }
01407
01408
01409
01410 static CURLcode ftp_state_post_cwd(struct connectdata *conn)
01411 {
01412 CURLcode result = CURLE_OK;
01413 struct FTP *ftp = conn->data->reqdata.proto.ftp;
01414 struct SessionHandle *data = conn->data;
01415
01416
01417 if((data->set.get_filetime || data->set.timecondition) && ftp->file) {
01418
01419
01420
01421 NBFTPSENDF(conn, "MDTM %s", ftp->file);
01422
01423 state(conn, FTP_MDTM);
01424 }
01425 else
01426 result = ftp_state_post_mdtm(conn);
01427
01428 return result;
01429 }
01430
01431
01432
01433 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
01434 bool sizechecked)
01435 {
01436 CURLcode result = CURLE_OK;
01437 struct FTP *ftp = conn->data->reqdata.proto.ftp;
01438 struct SessionHandle *data = conn->data;
01439 curl_off_t passed=0;
01440
01441 if((data->reqdata.resume_from && !sizechecked) ||
01442 ((data->reqdata.resume_from > 0) && sizechecked)) {
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454
01455
01456 if(data->reqdata.resume_from < 0 ) {
01457
01458 NBFTPSENDF(conn, "SIZE %s", ftp->file);
01459 state(conn, FTP_STOR_SIZE);
01460 return result;
01461 }
01462
01463
01464 data->set.ftp_append = TRUE;
01465
01466
01467
01468
01469
01470
01471
01472 do {
01473 curl_off_t readthisamountnow = (data->reqdata.resume_from - passed);
01474 curl_off_t actuallyread;
01475
01476 if(readthisamountnow > BUFSIZE)
01477 readthisamountnow = BUFSIZE;
01478
01479 actuallyread = (curl_off_t)
01480 conn->fread(data->state.buffer, 1, (size_t)readthisamountnow,
01481 conn->fread_in);
01482
01483 passed += actuallyread;
01484 if(actuallyread != readthisamountnow) {
01485 failf(data, "Could only read %" FORMAT_OFF_T
01486 " bytes from the input", passed);
01487 return CURLE_FTP_COULDNT_USE_REST;
01488 }
01489 } while(passed != data->reqdata.resume_from);
01490
01491
01492 if(data->set.infilesize>0) {
01493 data->set.infilesize -= data->reqdata.resume_from;
01494
01495 if(data->set.infilesize <= 0) {
01496 infof(data, "File already completely uploaded\n");
01497
01498
01499 result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
01500
01501
01502
01503 ftp->no_transfer = TRUE;
01504
01505 state(conn, FTP_STOP);
01506 return CURLE_OK;
01507 }
01508 }
01509
01510 }
01511
01512 NBFTPSENDF(conn, data->set.ftp_append?"APPE %s":"STOR %s",
01513 ftp->file);
01514
01515 state(conn, FTP_STOR);
01516
01517 return result;
01518 }
01519
01520 static CURLcode ftp_state_quote(struct connectdata *conn,
01521 bool init,
01522 ftpstate instate)
01523 {
01524 CURLcode result = CURLE_OK;
01525 struct SessionHandle *data = conn->data;
01526 struct FTP *ftp = data->reqdata.proto.ftp;
01527 struct ftp_conn *ftpc = &conn->proto.ftpc;
01528 bool quote=FALSE;
01529 struct curl_slist *item;
01530
01531 switch(instate) {
01532 case FTP_QUOTE:
01533 default:
01534 item = data->set.quote;
01535 break;
01536 case FTP_RETR_PREQUOTE:
01537 case FTP_STOR_PREQUOTE:
01538 item = data->set.prequote;
01539 break;
01540 case FTP_POSTQUOTE:
01541 item = data->set.postquote;
01542 break;
01543 }
01544
01545 if(init)
01546 ftpc->count1 = 0;
01547 else
01548 ftpc->count1++;
01549
01550 if(item) {
01551 int i = 0;
01552
01553
01554 while((i< ftpc->count1) && item) {
01555 item = item->next;
01556 i++;
01557 }
01558 if(item) {
01559 NBFTPSENDF(conn, "%s", item->data);
01560 state(conn, instate);
01561 quote = TRUE;
01562 }
01563 }
01564
01565 if(!quote) {
01566
01567 switch(instate) {
01568 case FTP_QUOTE:
01569 default:
01570 result = ftp_state_cwd(conn);
01571 break;
01572 case FTP_RETR_PREQUOTE:
01573 if (ftp->no_transfer)
01574 state(conn, FTP_STOP);
01575 else {
01576 NBFTPSENDF(conn, "SIZE %s", ftp->file);
01577 state(conn, FTP_RETR_SIZE);
01578 }
01579 break;
01580 case FTP_STOR_PREQUOTE:
01581 result = ftp_state_ul_setup(conn, FALSE);
01582 break;
01583 case FTP_POSTQUOTE:
01584 break;
01585 }
01586 }
01587
01588 return result;
01589 }
01590
01591 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
01592 int ftpcode)
01593 {
01594 struct ftp_conn *ftpc = &conn->proto.ftpc;
01595 CURLcode result;
01596 struct SessionHandle *data=conn->data;
01597 Curl_addrinfo *conninfo;
01598 struct Curl_dns_entry *addr=NULL;
01599 int rc;
01600 unsigned short connectport;
01601 unsigned short newport=0;
01602 bool connected;
01603
01604
01605
01606 #define NEWHOST_BUFSIZE 48
01607 char newhost[NEWHOST_BUFSIZE];
01608 char *str=&data->state.buffer[4];
01609
01610 if((ftpc->count1 == 0) &&
01611 (ftpcode == 229)) {
01612
01613 char *ptr = strchr(str, '(');
01614 if(ptr) {
01615 unsigned int num;
01616 char separator[4];
01617 ptr++;
01618 if(5 == sscanf(ptr, "%c%c%c%u%c",
01619 &separator[0],
01620 &separator[1],
01621 &separator[2],
01622 &num,
01623 &separator[3])) {
01624 const char sep1 = separator[0];
01625 int i;
01626
01627
01628
01629 for(i=1; i<4; i++) {
01630 if(separator[i] != sep1) {
01631 ptr=NULL;
01632 break;
01633 }
01634 }
01635 if(ptr) {
01636 newport = (unsigned short)(num & 0xffff);
01637
01638 if (conn->bits.tunnel_proxy ||
01639 data->set.proxytype == CURLPROXY_SOCKS5 ||
01640 data->set.proxytype == CURLPROXY_SOCKS4)
01641
01642
01643 snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
01644 else
01645
01646 snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
01647 }
01648 }
01649 else
01650 ptr=NULL;
01651 }
01652 if(!ptr) {
01653 failf(data, "Weirdly formatted EPSV reply");
01654 return CURLE_FTP_WEIRD_PASV_REPLY;
01655 }
01656 }
01657 else if((ftpc->count1 == 1) &&
01658 (ftpcode == 227)) {
01659
01660 int ip[4];
01661 int port[2];
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672 while(*str) {
01673 if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
01674 &ip[0], &ip[1], &ip[2], &ip[3],
01675 &port[0], &port[1]))
01676 break;
01677 str++;
01678 }
01679
01680 if(!*str) {
01681 failf(data, "Couldn't interpret the 227-response");
01682 return CURLE_FTP_WEIRD_227_FORMAT;
01683 }
01684
01685
01686 if(data->set.ftp_skip_ip) {
01687
01688
01689 infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
01690 ip[0], ip[1], ip[2], ip[3],
01691 conn->ip_addr_str);
01692 if (conn->bits.tunnel_proxy ||
01693 data->set.proxytype == CURLPROXY_SOCKS5 ||
01694 data->set.proxytype == CURLPROXY_SOCKS4)
01695
01696
01697 snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
01698 else
01699 snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str);
01700 }
01701 else
01702 snprintf(newhost, sizeof(newhost),
01703 "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
01704 newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
01705 }
01706 else if(ftpc->count1 == 0) {
01707
01708
01709
01710 conn->bits.ftp_use_epsv = FALSE;
01711 infof(data, "disabling EPSV usage\n");
01712
01713 NBFTPSENDF(conn, "PASV", NULL);
01714 ftpc->count1++;
01715
01716 return result;
01717 }
01718 else {
01719 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
01720 return CURLE_FTP_WEIRD_PASV_REPLY;
01721 }
01722
01723 if(data->set.proxy && *data->set.proxy) {
01724
01725
01726
01727
01728
01729
01730
01731 rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
01732 if(rc == CURLRESOLV_PENDING)
01733
01734 rc = Curl_wait_for_resolv(conn, &addr);
01735
01736 connectport =
01737 (unsigned short)conn->port;
01738
01739 }
01740 else {
01741
01742 rc = Curl_resolv(conn, newhost, newport, &addr);
01743 if(rc == CURLRESOLV_PENDING)
01744
01745 rc = Curl_wait_for_resolv(conn, &addr);
01746
01747 if(!addr) {
01748 failf(data, "Can't resolve new host %s:%d", newhost, newport);
01749 return CURLE_FTP_CANT_GET_HOST;
01750 }
01751 connectport = newport;
01752 }
01753
01754 result = Curl_connecthost(conn,
01755 addr,
01756 &conn->sock[SECONDARYSOCKET],
01757 &conninfo,
01758 &connected);
01759
01760 Curl_resolv_unlock(data, addr);
01761
01762 if (result && ftpc->count1 == 0 && ftpcode == 229) {
01763 infof(data, "got positive EPSV response, but can't connect. "
01764 "Disabling EPSV\n");
01765
01766 conn->bits.ftp_use_epsv = FALSE;
01767 data->state.errorbuf = FALSE;
01768 NBFTPSENDF(conn, "PASV", NULL);
01769 ftpc->count1++;
01770
01771 return result;
01772 }
01773
01774 if(result)
01775 return result;
01776
01777 conn->bits.tcpconnect = connected;
01778
01779
01780
01781
01782
01783
01784
01785 if(data->set.verbose)
01786
01787 ftp_pasv_verbose(conn, conninfo, newhost, connectport);
01788
01789 switch(data->set.proxytype) {
01790 case CURLPROXY_SOCKS5:
01791 result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport,
01792 SECONDARYSOCKET, conn);
01793 break;
01794 case CURLPROXY_HTTP:
01795
01796 break;
01797 case CURLPROXY_SOCKS4:
01798 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
01799 SECONDARYSOCKET, conn);
01800 break;
01801 default:
01802 failf(data, "unknown proxytype option given");
01803 result = CURLE_COULDNT_CONNECT;
01804 break;
01805 }
01806 #ifndef CURL_DISABLE_HTTP
01807 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820 struct HTTP http_proxy;
01821 struct FTP *ftp_save = data->reqdata.proto.ftp;
01822 memset(&http_proxy, 0, sizeof(http_proxy));
01823 data->reqdata.proto.http = &http_proxy;
01824
01825 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
01826
01827 data->reqdata.proto.ftp = ftp_save;
01828
01829 if(CURLE_OK != result)
01830 return result;
01831 }
01832 #endif
01833
01834 state(conn, FTP_STOP);
01835
01836 return result;
01837 }
01838
01839 static CURLcode ftp_state_port_resp(struct connectdata *conn,
01840 int ftpcode)
01841 {
01842 struct SessionHandle *data = conn->data;
01843 struct ftp_conn *ftpc = &conn->proto.ftpc;
01844 ftpport fcmd = (ftpport)ftpc->count1;
01845 CURLcode result = CURLE_OK;
01846
01847 if(ftpcode != 200) {
01848
01849
01850 if (EPRT == fcmd) {
01851 infof(data, "disabling EPRT usage\n");
01852 conn->bits.ftp_use_eprt = FALSE;
01853 }
01854 fcmd++;
01855
01856 if(fcmd == DONE) {
01857 failf(data, "Failed to do PORT");
01858 result = CURLE_FTP_PORT_FAILED;
01859 }
01860 else
01861
01862 result = ftp_state_use_port(conn, fcmd);
01863 }
01864 else {
01865 infof(data, "Connect data stream actively\n");
01866 state(conn, FTP_STOP);
01867 }
01868
01869 return result;
01870 }
01871
01872 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
01873 int ftpcode)
01874 {
01875 CURLcode result = CURLE_OK;
01876 struct SessionHandle *data=conn->data;
01877 struct FTP *ftp = data->reqdata.proto.ftp;
01878
01879 switch(ftpcode) {
01880 case 213:
01881 {
01882
01883
01884 int year, month, day, hour, minute, second;
01885 char *buf = data->state.buffer;
01886 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
01887 &year, &month, &day, &hour, &minute, &second)) {
01888
01889 time_t secs=time(NULL);
01890
01891 snprintf(buf, sizeof(conn->data->state.buffer),
01892 "%04d%02d%02d %02d:%02d:%02d GMT",
01893 year, month, day, hour, minute, second);
01894
01895 data->info.filetime = (long)curl_getdate(buf, &secs);
01896 }
01897
01898
01899
01900
01901 if(conn->bits.no_body &&
01902 data->set.include_header &&
01903 ftp->file &&
01904 data->set.get_filetime &&
01905 (data->info.filetime>=0) ) {
01906 struct tm *tm;
01907 time_t clock = (time_t)data->info.filetime;
01908 #ifdef HAVE_GMTIME_R
01909 struct tm buffer;
01910 tm = (struct tm *)gmtime_r(&clock, &buffer);
01911 #else
01912 tm = gmtime(&clock);
01913 #endif
01914
01915 snprintf(buf, BUFSIZE-1,
01916 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
01917 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
01918 tm->tm_mday,
01919 Curl_month[tm->tm_mon],
01920 tm->tm_year + 1900,
01921 tm->tm_hour,
01922 tm->tm_min,
01923 tm->tm_sec);
01924 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
01925 if(result)
01926 return result;
01927 }
01928 }
01929 break;
01930 default:
01931 infof(data, "unsupported MDTM reply format\n");
01932 break;
01933 case 550:
01934 failf(data, "Given file does not exist");
01935 result = CURLE_FTP_COULDNT_RETR_FILE;
01936 break;
01937 }
01938
01939 if(data->set.timecondition) {
01940 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
01941 switch(data->set.timecondition) {
01942 case CURL_TIMECOND_IFMODSINCE:
01943 default:
01944 if(data->info.filetime <= data->set.timevalue) {
01945 infof(data, "The requested document is not new enough\n");
01946 ftp->no_transfer = TRUE;
01947 state(conn, FTP_STOP);
01948 return CURLE_OK;
01949 }
01950 break;
01951 case CURL_TIMECOND_IFUNMODSINCE:
01952 if(data->info.filetime > data->set.timevalue) {
01953 infof(data, "The requested document is not old enough\n");
01954 ftp->no_transfer = TRUE;
01955 state(conn, FTP_STOP);
01956 return CURLE_OK;
01957 }
01958 break;
01959 }
01960 }
01961 else {
01962 infof(data, "Skipping time comparison\n");
01963 }
01964 }
01965
01966 if(!result)
01967 result = ftp_state_post_mdtm(conn);
01968
01969 return result;
01970 }
01971
01972 static CURLcode ftp_state_type_resp(struct connectdata *conn,
01973 int ftpcode,
01974 ftpstate instate)
01975 {
01976 CURLcode result = CURLE_OK;
01977 struct SessionHandle *data=conn->data;
01978
01979 if(ftpcode/100 != 2) {
01980
01981
01982
01983 failf(data, "Couldn't set desired mode");
01984 return CURLE_FTP_COULDNT_SET_BINARY;
01985 }
01986 if(ftpcode != 200)
01987 infof(data, "Got a %03d response code instead of the assumed 200\n",
01988 ftpcode);
01989
01990 if(instate == FTP_TYPE)
01991 result = ftp_state_post_type(conn);
01992 else if(instate == FTP_LIST_TYPE)
01993 result = ftp_state_post_listtype(conn);
01994 else if(instate == FTP_RETR_TYPE)
01995 result = ftp_state_post_retrtype(conn);
01996 else if(instate == FTP_STOR_TYPE)
01997 result = ftp_state_post_stortype(conn);
01998
01999 return result;
02000 }
02001
02002 static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
02003 curl_off_t filesize)
02004 {
02005 CURLcode result = CURLE_OK;
02006 struct SessionHandle *data=conn->data;
02007 struct FTP *ftp = data->reqdata.proto.ftp;
02008
02009 if (data->set.max_filesize && (filesize > data->set.max_filesize)) {
02010 failf(data, "Maximum file size exceeded");
02011 return CURLE_FILESIZE_EXCEEDED;
02012 }
02013 ftp->downloadsize = filesize;
02014
02015 if(data->reqdata.resume_from) {
02016
02017
02018 if(filesize == -1) {
02019 infof(data, "ftp server doesn't support SIZE\n");
02020
02021
02022
02023
02024 }
02025 else {
02026
02027
02028 if(data->reqdata.resume_from< 0) {
02029
02030 if(filesize < -data->reqdata.resume_from) {
02031 failf(data, "Offset (%" FORMAT_OFF_T
02032 ") was beyond file size (%" FORMAT_OFF_T ")",
02033 data->reqdata.resume_from, filesize);
02034 return CURLE_BAD_DOWNLOAD_RESUME;
02035 }
02036
02037 ftp->downloadsize = -data->reqdata.resume_from;
02038
02039 data->reqdata.resume_from = filesize - ftp->downloadsize;
02040 }
02041 else {
02042 if(filesize < data->reqdata.resume_from) {
02043 failf(data, "Offset (%" FORMAT_OFF_T
02044 ") was beyond file size (%" FORMAT_OFF_T ")",
02045 data->reqdata.resume_from, filesize);
02046 return CURLE_BAD_DOWNLOAD_RESUME;
02047 }
02048
02049 ftp->downloadsize = filesize-data->reqdata.resume_from;
02050 }
02051 }
02052
02053 if(ftp->downloadsize == 0) {
02054
02055 result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
02056 infof(data, "File already completely downloaded\n");
02057
02058
02059
02060 ftp->no_transfer = TRUE;
02061 state(conn, FTP_STOP);
02062 return CURLE_OK;
02063 }
02064
02065
02066 infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
02067 "\n", data->reqdata.resume_from);
02068
02069 NBFTPSENDF(conn, "REST %" FORMAT_OFF_T, data->reqdata.resume_from);
02070
02071 state(conn, FTP_RETR_REST);
02072
02073 }
02074 else {
02075
02076 NBFTPSENDF(conn, "RETR %s", ftp->file);
02077 state(conn, FTP_RETR);
02078 }
02079
02080 return result;
02081 }
02082
02083 static CURLcode ftp_state_size_resp(struct connectdata *conn,
02084 int ftpcode,
02085 ftpstate instate)
02086 {
02087 CURLcode result = CURLE_OK;
02088 struct SessionHandle *data=conn->data;
02089 curl_off_t filesize;
02090 char *buf = data->state.buffer;
02091
02092
02093 filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
02094
02095 if(instate == FTP_SIZE) {
02096 if(-1 != filesize) {
02097 snprintf(buf, sizeof(data->state.buffer),
02098 "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
02099 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
02100 if(result)
02101 return result;
02102 }
02103 result = ftp_state_post_size(conn);
02104 }
02105 else if(instate == FTP_RETR_SIZE)
02106 result = ftp_state_post_retr_size(conn, filesize);
02107 else if(instate == FTP_STOR_SIZE) {
02108 data->reqdata.resume_from = filesize;
02109 result = ftp_state_ul_setup(conn, TRUE);
02110 }
02111
02112 return result;
02113 }
02114
02115 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
02116 int ftpcode,
02117 ftpstate instate)
02118 {
02119 CURLcode result = CURLE_OK;
02120 struct FTP *ftp = conn->data->reqdata.proto.ftp;
02121
02122 switch(instate) {
02123 case FTP_REST:
02124 default:
02125 if (ftpcode == 350) {
02126 result = Curl_client_write(conn, CLIENTWRITE_BOTH,
02127 (char *)"Accept-ranges: bytes\r\n", 0);
02128 if(result)
02129 return result;
02130 }
02131
02132 result = ftp_state_post_rest(conn);
02133 break;
02134
02135 case FTP_RETR_REST:
02136 if (ftpcode != 350) {
02137 failf(conn->data, "Couldn't use REST");
02138 result = CURLE_FTP_COULDNT_USE_REST;
02139 }
02140 else {
02141 NBFTPSENDF(conn, "RETR %s", ftp->file);
02142 state(conn, FTP_RETR);
02143 }
02144 break;
02145 }
02146
02147 return result;
02148 }
02149
02150 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
02151 int ftpcode)
02152 {
02153 CURLcode result = CURLE_OK;
02154 struct SessionHandle *data = conn->data;
02155 struct FTP *ftp = data->reqdata.proto.ftp;
02156
02157 if(ftpcode>=400) {
02158 failf(data, "Failed FTP upload: %0d", ftpcode);
02159
02160 return CURLE_FTP_COULDNT_STOR_FILE;
02161 }
02162
02163 if(data->set.ftp_use_port) {
02164
02165
02166 result = AllowServerConnect(conn);
02167 if( result )
02168 return result;
02169 }
02170
02171 if(conn->ssl[SECONDARYSOCKET].use) {
02172
02173
02174 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
02175
02176 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
02177 if(result)
02178 return result;
02179 }
02180
02181 *(ftp->bytecountp)=0;
02182
02183
02184
02185
02186 Curl_pgrsSetUploadSize(data, data->set.infilesize);
02187
02188 result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL,
02189 SECONDARYSOCKET, ftp->bytecountp);
02190 state(conn, FTP_STOP);
02191
02192 return result;
02193 }
02194
02195
02196 static CURLcode ftp_state_get_resp(struct connectdata *conn,
02197 int ftpcode,
02198 ftpstate instate)
02199 {
02200 CURLcode result = CURLE_OK;
02201 struct SessionHandle *data = conn->data;
02202 struct FTP *ftp = data->reqdata.proto.ftp;
02203 char *buf = data->state.buffer;
02204
02205 if((ftpcode == 150) || (ftpcode == 125)) {
02206
02207
02208
02209
02210
02211
02212
02213
02214
02215
02216
02217
02218
02219
02220
02221
02222
02223
02224 curl_off_t size=-1;
02225
02226
02227
02228
02229
02230
02231
02232
02233
02234
02235
02236 if((instate != FTP_LIST) &&
02237 !data->set.prefer_ascii &&
02238 (ftp->downloadsize < 1)) {
02239
02240
02241
02242
02243
02244
02245
02246 char *bytes;
02247 bytes=strstr(buf, " bytes");
02248 if(bytes--) {
02249 long in=(long)(bytes-buf);
02250
02251 while(--in) {
02252
02253 if('(' == *bytes)
02254 break;
02255
02256 if(!ISDIGIT(*bytes)) {
02257 bytes=NULL;
02258 break;
02259 }
02260
02261 bytes--;
02262 }
02263
02264 if(bytes++) {
02265
02266 size = curlx_strtoofft(bytes, NULL, 0);
02267 }
02268 }
02269 }
02270 else if(ftp->downloadsize > -1)
02271 size = ftp->downloadsize;
02272
02273 if(data->set.ftp_use_port) {
02274
02275 result = AllowServerConnect(conn);
02276 if( result )
02277 return result;
02278 }
02279
02280 if(conn->ssl[SECONDARYSOCKET].use) {
02281
02282
02283 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
02284 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
02285 if(result)
02286 return result;
02287 }
02288
02289 if(size > data->reqdata.maxdownload && data->reqdata.maxdownload > 0)
02290 size = data->reqdata.size = data->reqdata.maxdownload;
02291
02292 infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->reqdata.maxdownload);
02293
02294 if(instate != FTP_LIST)
02295 infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
02296
02297
02298 result=Curl_setup_transfer(conn, SECONDARYSOCKET, size, FALSE,
02299 ftp->bytecountp,
02300 -1, NULL);
02301 if(result)
02302 return result;
02303
02304 state(conn, FTP_STOP);
02305 }
02306 else {
02307 if((instate == FTP_LIST) && (ftpcode == 450)) {
02308
02309 ftp->no_transfer = TRUE;
02310 state(conn, FTP_STOP);
02311 }
02312 else {
02313 failf(data, "RETR response: %03d", ftpcode);
02314 return CURLE_FTP_COULDNT_RETR_FILE;
02315 }
02316 }
02317
02318 return result;
02319 }
02320
02321
02322 static CURLcode ftp_state_loggedin(struct connectdata *conn)
02323 {
02324 CURLcode result = CURLE_OK;
02325
02326 #ifdef HAVE_KRB4
02327 if(conn->data->set.krb) {
02328
02329
02330
02331 if(conn->passwd && *conn->passwd) {
02332
02333 result = Curl_krb_kauth(conn);
02334 if(result)
02335 return result;
02336 }
02337 }
02338 #endif
02339 if(conn->ssl[FIRSTSOCKET].use) {
02340
02341
02342
02343
02344
02345
02346
02347
02348
02349
02350
02351
02352
02353
02354 NBFTPSENDF(conn, "PBSZ %d", 0);
02355 state(conn, FTP_PBSZ);
02356 }
02357 else {
02358 result = ftp_state_pwd(conn);
02359 }
02360 return result;
02361 }
02362
02363
02364 static CURLcode ftp_state_user_resp(struct connectdata *conn,
02365 int ftpcode,
02366 ftpstate instate)
02367 {
02368 CURLcode result = CURLE_OK;
02369 struct SessionHandle *data = conn->data;
02370 struct FTP *ftp = data->reqdata.proto.ftp;
02371 struct ftp_conn *ftpc = &conn->proto.ftpc;
02372 (void)instate;
02373
02374
02375 if((ftpcode == 331 || ftpcode/100 == 2) && (ftpc->state == FTP_USER)) {
02376
02377
02378 NBFTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:"");
02379 state(conn, FTP_PASS);
02380 }
02381 else if(ftpcode/100 == 2) {
02382
02383
02384 result = ftp_state_loggedin(conn);
02385 }
02386 else if(ftpcode == 332) {
02387 if(data->set.ftp_account) {
02388 NBFTPSENDF(conn, "ACCT %s", data->set.ftp_account);
02389 state(conn, FTP_ACCT);
02390 }
02391 else {
02392 failf(data, "ACCT requested but none available");
02393 result = CURLE_LOGIN_DENIED;
02394 }
02395 }
02396 else {
02397
02398
02399
02400
02401
02402 if (conn->data->set.ftp_alternative_to_user &&
02403 !conn->data->state.ftp_trying_alternative) {
02404
02405 NBFTPSENDF(conn, "%s", conn->data->set.ftp_alternative_to_user);
02406 conn->data->state.ftp_trying_alternative = TRUE;
02407 state(conn, FTP_USER);
02408 result = CURLE_OK;
02409 }
02410 else {
02411 failf(data, "Access denied: %03d", ftpcode);
02412 result = CURLE_LOGIN_DENIED;
02413 }
02414 }
02415 return result;
02416 }
02417
02418
02419 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
02420 int ftpcode)
02421 {
02422 CURLcode result = CURLE_OK;
02423 struct SessionHandle *data = conn->data;
02424 if(ftpcode != 230) {
02425 failf(data, "ACCT rejected by server: %03d", ftpcode);
02426 result = CURLE_FTP_WEIRD_PASS_REPLY;
02427 }
02428 else
02429 result = ftp_state_loggedin(conn);
02430
02431 return result;
02432 }
02433
02434
02435 static CURLcode ftp_statemach_act(struct connectdata *conn)
02436 {
02437 CURLcode result;
02438 curl_socket_t sock = conn->sock[FIRSTSOCKET];
02439 struct SessionHandle *data=conn->data;
02440 int ftpcode;
02441 struct ftp_conn *ftpc = &conn->proto.ftpc;
02442 static const char * const ftpauth[] = {
02443 "SSL", "TLS"
02444 };
02445 size_t nread = 0;
02446
02447 if(ftpc->sendleft) {
02448
02449 ssize_t written;
02450 result = Curl_write(conn, sock, ftpc->sendthis + ftpc->sendsize -
02451 ftpc->sendleft, ftpc->sendleft, &written);
02452 if(result)
02453 return result;
02454
02455 if(written != (ssize_t)ftpc->sendleft) {
02456
02457 ftpc->sendleft -= written;
02458 }
02459 else {
02460 free(ftpc->sendthis);
02461 ftpc->sendthis=NULL;
02462 ftpc->sendleft = ftpc->sendsize = 0;
02463 ftpc->response = Curl_tvnow();
02464 }
02465 return CURLE_OK;
02466 }
02467
02468
02469 result = ftp_readresp(sock, conn, &ftpcode, &nread);
02470 if(result)
02471 return result;
02472
02473 if(ftpcode) {
02474
02475 switch(ftpc->state) {
02476 case FTP_WAIT220:
02477 if(ftpcode != 220) {
02478 failf(data, "This doesn't seem like a nice ftp-server response");
02479 return CURLE_FTP_WEIRD_SERVER_REPLY;
02480 }
02481
02482
02483 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
02484 if(data->set.krb) {
02485
02486
02487
02488 Curl_sec_request_prot(conn, "private");
02489
02490
02491 Curl_sec_request_prot(conn, data->set.krb_level);
02492
02493 if(Curl_sec_login(conn) != 0)
02494 infof(data, "Logging in with password in cleartext!\n");
02495 else
02496 infof(data, "Authentication successful\n");
02497 }
02498 #endif
02499
02500 if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
02501
02502
02503
02504 ftpc->count3=0;
02505 switch(data->set.ftpsslauth) {
02506 case CURLFTPAUTH_DEFAULT:
02507 case CURLFTPAUTH_SSL:
02508 ftpc->count2 = 1;
02509 ftpc->count1 = 0;
02510 break;
02511 case CURLFTPAUTH_TLS:
02512 ftpc->count2 = -1;
02513 ftpc->count1 = 1;
02514 break;
02515 default:
02516 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d\n",
02517 data->set.ftpsslauth);
02518 return CURLE_FAILED_INIT;
02519 }
02520 NBFTPSENDF(conn, "AUTH %s", ftpauth[ftpc->count1]);
02521 state(conn, FTP_AUTH);
02522 }
02523 else {
02524 result = ftp_state_user(conn);
02525 if(result)
02526 return result;
02527 }
02528
02529 break;
02530
02531 case FTP_AUTH:
02532
02533
02534
02535
02536
02537
02538
02539
02540
02541 if((ftpcode == 234) || (ftpcode == 334)) {
02542
02543 result = Curl_ssl_connect(conn, FIRSTSOCKET);
02544 if(CURLE_OK == result) {
02545 conn->protocol |= PROT_FTPS;
02546 conn->ssl[SECONDARYSOCKET].use = FALSE;
02547 result = ftp_state_user(conn);
02548 }
02549 }
02550 else if(ftpc->count3 < 1) {
02551 ftpc->count3++;
02552 ftpc->count1 += ftpc->count2;
02553 result = Curl_nbftpsendf(conn, "AUTH %s", ftpauth[ftpc->count1]);
02554
02555 }
02556 else {
02557 if(data->set.ftp_ssl > CURLFTPSSL_TRY)
02558
02559 result = CURLE_FTP_SSL_FAILED;
02560 else
02561
02562 result = ftp_state_user(conn);
02563 }
02564
02565 if(result)
02566 return result;
02567 break;
02568
02569 case FTP_USER:
02570 case FTP_PASS:
02571 result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
02572 break;
02573
02574 case FTP_ACCT:
02575 result = ftp_state_acct_resp(conn, ftpcode);
02576 break;
02577
02578 case FTP_PBSZ:
02579
02580
02581
02582
02583
02584
02585
02586
02587 if(!conn->ssl[SECONDARYSOCKET].use) {
02588 NBFTPSENDF(conn, "PROT %c",
02589 data->set.ftp_ssl == CURLFTPSSL_CONTROL ? 'C' : 'P');
02590 state(conn, FTP_PROT);
02591 }
02592 else {
02593 result = ftp_state_pwd(conn);
02594 if(result)
02595 return result;
02596 }
02597
02598 break;
02599
02600 case FTP_PROT:
02601 if(ftpcode/100 == 2)
02602
02603 conn->ssl[SECONDARYSOCKET].use =
02604 (bool)(data->set.ftp_ssl != CURLFTPSSL_CONTROL);
02605
02606
02607 else if(data->set.ftp_ssl> CURLFTPSSL_CONTROL)
02608
02609 return CURLE_FTP_SSL_FAILED;
02610
02611 if(data->set.ftp_ccc) {
02612
02613
02614 NBFTPSENDF(conn, "CCC", NULL);
02615 state(conn, FTP_CCC);
02616 }
02617 else {
02618 result = ftp_state_pwd(conn);
02619 if(result)
02620 return result;
02621 }
02622 break;
02623
02624 case FTP_CCC:
02625 if (ftpcode < 500) {
02626
02627 result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
02628
02629 if(result) {
02630 failf(conn->data, "Failed to clear the command channel (CCC)");
02631 return result;
02632 }
02633 }
02634
02635
02636 result = ftp_state_pwd(conn);
02637 if(result)
02638 return result;
02639 break;
02640
02641 case FTP_PWD:
02642 if(ftpcode == 257) {
02643 char *dir = (char *)malloc(nread+1);
02644 char *store=dir;
02645 char *ptr=&data->state.buffer[4];
02646
02647 if(!dir)
02648 return CURLE_OUT_OF_MEMORY;
02649
02650
02651
02652
02653
02654
02655
02656
02657
02658 if('\"' == *ptr) {
02659
02660 ptr++;
02661 while(ptr && *ptr) {
02662 if('\"' == *ptr) {
02663 if('\"' == ptr[1]) {
02664
02665 *store = ptr[1];
02666 ptr++;
02667 }
02668 else {
02669
02670 *store = '\0';
02671 break;
02672 }
02673 }
02674 else
02675 *store = *ptr;
02676 store++;
02677 ptr++;
02678 }
02679 ftpc->entrypath =dir;
02680 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
02681
02682 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
02683 }
02684 else {
02685
02686 free(dir);
02687 infof(data, "Failed to figure out path\n");
02688 }
02689 }
02690 state(conn, FTP_STOP);
02691 DEBUGF(infof(data, "protocol connect phase DONE\n"));
02692 break;
02693
02694 case FTP_QUOTE:
02695 case FTP_POSTQUOTE:
02696 case FTP_RETR_PREQUOTE:
02697 case FTP_STOR_PREQUOTE:
02698 if(ftpcode >= 400) {
02699 failf(conn->data, "QUOT command failed with %03d", ftpcode);
02700 return CURLE_FTP_QUOTE_ERROR;
02701 }
02702 result = ftp_state_quote(conn, FALSE, ftpc->state);
02703 if(result)
02704 return result;
02705
02706 break;
02707
02708 case FTP_CWD:
02709 if(ftpcode/100 != 2) {
02710
02711 if(conn->data->set.ftp_create_missing_dirs &&
02712 ftpc->count1 && !ftpc->count2) {
02713
02714 ftpc->count2++;
02715 NBFTPSENDF(conn, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
02716 state(conn, FTP_MKD);
02717 }
02718 else {
02719
02720 failf(data, "Server denied you to change to the given directory");
02721 ftpc->cwdfail = TRUE;
02722
02723 return CURLE_FTP_ACCESS_DENIED;
02724 }
02725 }
02726 else {
02727
02728 ftpc->count2=0;
02729 if(++ftpc->count1 <= ftpc->dirdepth) {
02730
02731 NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
02732 }
02733 else {
02734 result = ftp_state_post_cwd(conn);
02735 if(result)
02736 return result;
02737 }
02738 }
02739 break;
02740
02741 case FTP_MKD:
02742 if(ftpcode/100 != 2) {
02743
02744 failf(data, "Failed to MKD dir: %03d", ftpcode);
02745 return CURLE_FTP_ACCESS_DENIED;
02746 }
02747 state(conn, FTP_CWD);
02748
02749 NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
02750 break;
02751
02752 case FTP_MDTM:
02753 result = ftp_state_mdtm_resp(conn, ftpcode);
02754 break;
02755
02756 case FTP_TYPE:
02757 case FTP_LIST_TYPE:
02758 case FTP_RETR_TYPE:
02759 case FTP_STOR_TYPE:
02760 result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
02761 break;
02762
02763 case FTP_SIZE:
02764 case FTP_RETR_SIZE:
02765 case FTP_STOR_SIZE:
02766 result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
02767 break;
02768
02769 case FTP_REST:
02770 case FTP_RETR_REST:
02771 result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
02772 break;
02773
02774 case FTP_PASV:
02775 result = ftp_state_pasv_resp(conn, ftpcode);
02776 break;
02777
02778 case FTP_PORT:
02779 result = ftp_state_port_resp(conn, ftpcode);
02780 break;
02781
02782 case FTP_LIST:
02783 case FTP_RETR:
02784 result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
02785 break;
02786
02787 case FTP_STOR:
02788 result = ftp_state_stor_resp(conn, ftpcode);
02789 break;
02790
02791 case FTP_QUIT:
02792
02793 default:
02794
02795 state(conn, FTP_STOP);
02796 break;
02797 }
02798 }
02799
02800 return result;
02801 }
02802
02803
02804
02805 static long ftp_state_timeout(struct connectdata *conn)
02806 {
02807 struct SessionHandle *data=conn->data;
02808 struct ftp_conn *ftpc = &conn->proto.ftpc;
02809 long timeout_ms=360000;
02810
02811 if(data->set.ftp_response_timeout )
02812
02813
02814
02815
02816 timeout_ms = data->set.ftp_response_timeout -
02817 Curl_tvdiff(Curl_tvnow(), ftpc->response);
02818 else if(data->set.timeout)
02819
02820 timeout_ms = data->set.timeout -
02821 Curl_tvdiff(Curl_tvnow(), conn->now);
02822 else
02823
02824
02825 timeout_ms = ftpc->response_time -
02826 Curl_tvdiff(Curl_tvnow(), ftpc->response);
02827
02828 return timeout_ms;
02829 }
02830
02831
02832
02833 CURLcode Curl_ftp_multi_statemach(struct connectdata *conn,
02834 bool *done)
02835 {
02836 curl_socket_t sock = conn->sock[FIRSTSOCKET];
02837 int rc;
02838 struct SessionHandle *data=conn->data;
02839 struct ftp_conn *ftpc = &conn->proto.ftpc;
02840 CURLcode result = CURLE_OK;
02841 long timeout_ms = ftp_state_timeout(conn);
02842
02843 *done = FALSE;
02844
02845 if(timeout_ms <= 0) {
02846 failf(data, "FTP response timeout");
02847 return CURLE_OPERATION_TIMEDOUT;
02848 }
02849
02850 rc = Curl_socket_ready(ftpc->sendleft?CURL_SOCKET_BAD:sock,
02851 ftpc->sendleft?sock:CURL_SOCKET_BAD,
02852 0);
02853
02854 if(rc == -1) {
02855 failf(data, "select/poll error");
02856 return CURLE_OUT_OF_MEMORY;
02857 }
02858 else if(rc != 0) {
02859 result = ftp_statemach_act(conn);
02860 *done = (bool)(ftpc->state == FTP_STOP);
02861 }
02862
02863
02864 return result;
02865 }
02866
02867 static CURLcode ftp_easy_statemach(struct connectdata *conn)
02868 {
02869 curl_socket_t sock = conn->sock[FIRSTSOCKET];
02870 int rc;
02871 struct SessionHandle *data=conn->data;
02872 struct ftp_conn *ftpc = &conn->proto.ftpc;
02873 CURLcode result = CURLE_OK;
02874
02875 while(ftpc->state != FTP_STOP) {
02876 long timeout_ms = ftp_state_timeout(conn);
02877
02878 if(timeout_ms <=0 ) {
02879 failf(data, "FTP response timeout");
02880 return CURLE_OPERATION_TIMEDOUT;
02881 }
02882
02883 rc = Curl_socket_ready(ftpc->sendleft?CURL_SOCKET_BAD:sock,
02884 ftpc->sendleft?sock:CURL_SOCKET_BAD,
02885 (int)timeout_ms);
02886
02887 if(rc == -1) {
02888 failf(data, "select/poll error");
02889 return CURLE_OUT_OF_MEMORY;
02890 }
02891 else if(rc == 0) {
02892 result = CURLE_OPERATION_TIMEDOUT;
02893 break;
02894 }
02895 else {
02896 result = ftp_statemach_act(conn);
02897 if(result)
02898 break;
02899 }
02900 }
02901
02902 return result;
02903 }
02904
02905
02906
02907
02908
02909 static CURLcode ftp_init(struct connectdata *conn)
02910 {
02911 struct SessionHandle *data = conn->data;
02912 struct FTP *ftp;
02913 if(data->reqdata.proto.ftp)
02914 return CURLE_OK;
02915
02916 ftp = (struct FTP *)calloc(sizeof(struct FTP), 1);
02917 if(!ftp)
02918 return CURLE_OUT_OF_MEMORY;
02919
02920 data->reqdata.proto.ftp = ftp;
02921
02922
02923 ftp->bytecountp = &data->reqdata.keep.bytecount;
02924
02925
02926 ftp->user = conn->user;
02927 ftp->passwd = conn->passwd;
02928 if (isBadFtpString(ftp->user) || isBadFtpString(ftp->passwd))
02929 return CURLE_URL_MALFORMAT;
02930
02931 return CURLE_OK;
02932 }
02933
02934
02935
02936
02937
02938
02939
02940
02941
02942 CURLcode Curl_ftp_connect(struct connectdata *conn,
02943 bool *done)
02944 {
02945 CURLcode result;
02946 #ifndef CURL_DISABLE_HTTP
02947
02948 struct HTTP http_proxy;
02949 struct FTP *ftp_save;
02950 #endif
02951 struct ftp_conn *ftpc = &conn->proto.ftpc;
02952 struct SessionHandle *data=conn->data;
02953
02954 *done = FALSE;
02955
02956 if (data->reqdata.proto.ftp) {
02957 Curl_ftp_disconnect(conn);
02958 free(data->reqdata.proto.ftp);
02959 data->reqdata.proto.ftp = NULL;
02960 }
02961
02962 result = ftp_init(conn);
02963 if(result)
02964 return result;
02965
02966
02967 conn->bits.close = FALSE;
02968
02969 ftpc->response_time = 3600000;
02970
02971 #ifndef CURL_DISABLE_HTTP
02972 if (conn->bits.tunnel_proxy && conn->bits.httpproxy) {
02973
02974
02975
02976
02977
02978
02979
02980
02981
02982 ftp_save = data->reqdata.proto.ftp;
02983 memset(&http_proxy, 0, sizeof(http_proxy));
02984 data->reqdata.proto.http = &http_proxy;
02985
02986 result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
02987 conn->host.name, conn->remote_port);
02988
02989 data->reqdata.proto.ftp = ftp_save;
02990
02991 if(CURLE_OK != result)
02992 return result;
02993 }
02994 #endif
02995
02996 if(conn->protocol & PROT_FTPS) {
02997
02998
02999
03000 result = Curl_ssl_connect(conn, FIRSTSOCKET);
03001 if(result)
03002 return result;
03003 }
03004
03005
03006
03007 ftp_respinit(conn);
03008 state(conn, FTP_WAIT220);
03009 ftpc->response = Curl_tvnow();
03010
03011 if(data->state.used_interface == Curl_if_multi)
03012 result = Curl_ftp_multi_statemach(conn, done);
03013 else {
03014 result = ftp_easy_statemach(conn);
03015 if(!result)
03016 *done = TRUE;
03017 }
03018
03019 return result;
03020 }
03021
03022
03023
03024
03025
03026
03027
03028
03029
03030
03031 CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status, bool premature)
03032 {
03033 struct SessionHandle *data = conn->data;
03034 struct FTP *ftp = data->reqdata.proto.ftp;
03035 struct ftp_conn *ftpc = &conn->proto.ftpc;
03036 ssize_t nread;
03037 int ftpcode;
03038 CURLcode result=CURLE_OK;
03039 bool was_ctl_valid = ftpc->ctl_valid;
03040 char *path;
03041 char *path_to_use = data->reqdata.path;
03042 struct Curl_transfer_keeper *k = &data->reqdata.keep;
03043
03044 if(!ftp)
03045
03046
03047
03048
03049
03050 return CURLE_OK;
03051
03052 switch(status) {
03053 case CURLE_BAD_DOWNLOAD_RESUME:
03054 case CURLE_FTP_WEIRD_PASV_REPLY:
03055 case CURLE_FTP_PORT_FAILED:
03056 case CURLE_FTP_COULDNT_SET_BINARY:
03057 case CURLE_FTP_COULDNT_RETR_FILE:
03058 case CURLE_FTP_COULDNT_STOR_FILE:
03059 case CURLE_FTP_ACCESS_DENIED:
03060 case CURLE_FILESIZE_EXCEEDED:
03061
03062
03063 case CURLE_OK:
03064 if (!premature) {
03065 ftpc->ctl_valid = was_ctl_valid;
03066 break;
03067 }
03068
03069
03070 default:
03071
03072 ftpc->ctl_valid = FALSE;
03073 ftpc->cwdfail = TRUE;
03074
03075 conn->bits.close = TRUE;
03076 break;
03077 }
03078
03079
03080 if(ftpc->prevpath)
03081 free(ftpc->prevpath);
03082
03083
03084 path = curl_easy_unescape(data, path_to_use, 0, NULL);
03085 if(!path) {
03086
03087
03088 ftpc->prevpath = NULL;
03089
03090 } else {
03091 size_t flen = ftp->file?strlen(ftp->file):0;
03092 size_t dlen = strlen(path)-flen;
03093 if(dlen && !ftpc->cwdfail) {
03094 ftpc->prevpath = path;
03095 if(flen)
03096
03097 ftpc->prevpath[dlen]=0;
03098 infof(data, "Remembering we are in dir %s\n", ftpc->prevpath);
03099 }
03100 else {
03101 ftpc->prevpath = NULL;
03102 free(path);
03103 }
03104 }
03105
03106 freedirs(conn);
03107
03108 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
03109 Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
03110 #endif
03111
03112
03113
03114 #ifdef _WIN32_WCE
03115 shutdown(conn->sock[SECONDARYSOCKET],2);
03116 #endif
03117
03118 sclose(conn->sock[SECONDARYSOCKET]);
03119
03120 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
03121
03122 if(!ftp->no_transfer && !status && !premature) {
03123
03124
03125
03126
03127
03128
03129 long old_time = ftpc->response_time;
03130
03131 ftpc->response_time = 60000;
03132
03133 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
03134
03135 ftpc->response_time = old_time;
03136
03137 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
03138 failf(data, "control connection looks dead");
03139 ftpc->ctl_valid = FALSE;
03140 return result;
03141 }
03142
03143 if(result)
03144 return result;
03145
03146 if(!ftpc->dont_check) {
03147
03148 if((ftpcode != 226) && (ftpcode != 250)) {
03149 failf(data, "server did not report OK, got %d", ftpcode);
03150 result = CURLE_PARTIAL_FILE;
03151 }
03152 }
03153 }
03154
03155 if(result || premature)
03156
03157
03158 ;
03159 else if(data->set.upload) {
03160 if((-1 != data->set.infilesize) &&
03161 (data->set.infilesize != *ftp->bytecountp) &&
03162 !data->set.crlf &&
03163 !ftp->no_transfer) {
03164 failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
03165 " out of %" FORMAT_OFF_T " bytes)",
03166 *ftp->bytecountp, data->set.infilesize);
03167 result = CURLE_PARTIAL_FILE;
03168 }
03169 }
03170 else {
03171 if((-1 != k->size) && (k->size != *ftp->bytecountp) &&
03172 #ifdef CURL_DO_LINEEND_CONV
03173
03174
03175
03176
03177 ((k->size + data->state.crlf_conversions) != *ftp->bytecountp) &&
03178 #endif
03179 (k->maxdownload != *ftp->bytecountp)) {
03180 failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
03181 *ftp->bytecountp);
03182 result = CURLE_PARTIAL_FILE;
03183 }
03184 else if(!ftpc->dont_check &&
03185 !*ftp->bytecountp &&
03186 (k->size>0)) {
03187 failf(data, "No data was received!");
03188 result = CURLE_FTP_COULDNT_RETR_FILE;
03189 }
03190 }
03191
03192
03193 ftp->no_transfer = FALSE;
03194 ftpc->dont_check = FALSE;
03195
03196
03197 if(!status && !result && !premature && data->set.postquote)
03198 result = ftp_sendquote(conn, data->set.postquote);
03199
03200 return result;
03201 }
03202
03203
03204
03205
03206
03207
03208
03209
03210
03211 static
03212 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
03213 {
03214 struct curl_slist *item;
03215 ssize_t nread;
03216 int ftpcode;
03217 CURLcode result;
03218
03219 item = quote;
03220 while (item) {
03221 if (item->data) {
03222 FTPSENDF(conn, "%s", item->data);
03223
03224 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
03225 if (result)
03226 return result;
03227
03228 if (ftpcode >= 400) {
03229 failf(conn->data, "QUOT string not accepted: %s", item->data);
03230 return CURLE_FTP_QUOTE_ERROR;
03231 }
03232 }
03233
03234 item = item->next;
03235 }
03236
03237 return CURLE_OK;
03238 }
03239
03240
03241
03242
03243
03244
03245
03246 static int ftp_need_type(struct connectdata *conn,
03247 bool ascii_wanted)
03248 {
03249 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
03250 }
03251
03252
03253
03254
03255
03256
03257
03258
03259
03260 static CURLcode ftp_nb_type(struct connectdata *conn,
03261 bool ascii, ftpstate newstate)
03262 {
03263 struct ftp_conn *ftpc = &conn->proto.ftpc;
03264 CURLcode result;
03265 int want = ascii?'A':'I';
03266
03267 if (ftpc->transfertype == want) {
03268 state(conn, newstate);
03269 return ftp_state_type_resp(conn, 200, newstate);
03270 }
03271
03272 NBFTPSENDF(conn, "TYPE %c", want);
03273 state(conn, newstate);
03274
03275
03276 ftpc->transfertype = (char)want;
03277 return CURLE_OK;
03278 }
03279
03280
03281
03282
03283
03284
03285
03286
03287
03288
03289 #ifndef CURL_DISABLE_VERBOSE_STRINGS
03290 static void
03291 ftp_pasv_verbose(struct connectdata *conn,
03292 Curl_addrinfo *ai,
03293 char *newhost,
03294 int port)
03295 {
03296 char buf[256];
03297 Curl_printable_address(ai, buf, sizeof(buf));
03298 infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
03299 }
03300 #endif
03301
03302
03303
03304
03305
03306
03307 static CURLcode ftp_range(struct connectdata *conn)
03308 {
03309 curl_off_t from, to;
03310 curl_off_t totalsize=-1;
03311 char *ptr;
03312 char *ptr2;
03313 struct SessionHandle *data = conn->data;
03314 struct ftp_conn *ftpc = &conn->proto.ftpc;
03315
03316 if(data->reqdata.use_range && data->reqdata.range) {
03317 from=curlx_strtoofft(data->reqdata.range, &ptr, 0);
03318 while(ptr && *ptr && (ISSPACE(*ptr) || (*ptr=='-')))
03319 ptr++;
03320 to=curlx_strtoofft(ptr, &ptr2, 0);
03321 if(ptr == ptr2) {
03322
03323 to=-1;
03324 }
03325 if((-1 == to) && (from>=0)) {
03326
03327 data->reqdata.resume_from = from;
03328 DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n",
03329 from));
03330 }
03331 else if(from < 0) {
03332
03333 totalsize = -from;
03334 data->reqdata.maxdownload = -from;
03335 data->reqdata.resume_from = from;
03336 DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n",
03337 totalsize));
03338 }
03339 else {
03340
03341 totalsize = to-from;
03342 data->reqdata.maxdownload = totalsize+1;
03343 data->reqdata.resume_from = from;
03344 DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
03345 " getting %" FORMAT_OFF_T " bytes\n",
03346 from, data->reqdata.maxdownload));
03347 }
03348 DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T
03349 " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
03350 from, to, data->reqdata.maxdownload));
03351 ftpc->dont_check = TRUE;
03352 }
03353 else
03354 data->reqdata.maxdownload = -1;
03355 return CURLE_OK;
03356 }
03357
03358
03359
03360
03361
03362
03363
03364
03365
03366 CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
03367 {
03368 struct SessionHandle *data=conn->data;
03369 CURLcode result = CURLE_OK;
03370
03371
03372 struct FTP *ftp = data->reqdata.proto.ftp;
03373
03374 DEBUGF(infof(data, "DO-MORE phase starts\n"));
03375
03376 if(!ftp->no_transfer) {
03377
03378
03379 if(data->set.upload) {
03380 result = ftp_nb_type(conn, data->set.prefer_ascii,
03381 FTP_STOR_TYPE);
03382 if (result)
03383 return result;
03384 }
03385 else {
03386
03387 ftp->downloadsize = -1;
03388
03389 result = ftp_range(conn);
03390 if(result)
03391 ;
03392 else if((data->set.ftp_list_only) || !ftp->file) {
03393
03394
03395
03396 result = ftp_nb_type(conn, 1, FTP_LIST_TYPE);
03397 if (result)
03398 return result;
03399 }
03400 else {
03401 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
03402 if (result)
03403 return result;
03404 }
03405 }
03406 result = ftp_easy_statemach(conn);
03407 }
03408
03409 if(ftp->no_transfer)
03410
03411
03412 result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
03413
03414
03415 DEBUGF(infof(data, "DO-MORE phase ends with %d\n", result));
03416
03417 return result;
03418 }
03419
03420
03421
03422
03423
03424
03425
03426
03427
03428
03429
03430 static
03431 CURLcode ftp_perform(struct connectdata *conn,
03432 bool *connected,
03433 bool *dophase_done)
03434 {
03435
03436 CURLcode result=CURLE_OK;
03437
03438 DEBUGF(infof(conn->data, "DO phase starts\n"));
03439
03440 if(conn->bits.no_body) {
03441
03442 struct FTP *ftp = conn->data->reqdata.proto.ftp;
03443 ftp->no_transfer = TRUE;
03444 }
03445
03446
03447 *dophase_done = FALSE;
03448
03449
03450 result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
03451 if(result)
03452 return result;
03453
03454
03455 if(conn->data->state.used_interface == Curl_if_multi)
03456 result = Curl_ftp_multi_statemach(conn, dophase_done);
03457 else {
03458 result = ftp_easy_statemach(conn);
03459 *dophase_done = TRUE;
03460 }
03461 *connected = conn->bits.tcpconnect;
03462
03463 if(*dophase_done)
03464 DEBUGF(infof(conn->data, "DO phase is complete\n"));
03465
03466 return result;
03467 }
03468
03469
03470
03471
03472
03473
03474
03475
03476
03477
03478 CURLcode Curl_ftp(struct connectdata *conn, bool *done)
03479 {
03480 CURLcode retcode = CURLE_OK;
03481
03482 *done = FALSE;
03483
03484
03485
03486
03487
03488
03489
03490 retcode = ftp_init(conn);
03491 if(retcode)
03492 return retcode;
03493
03494 retcode = ftp_parse_url_path(conn);
03495 if (retcode)
03496 return retcode;
03497
03498 retcode = ftp_regular_transfer(conn, done);
03499
03500 return retcode;
03501 }
03502
03503
03504
03505
03506
03507
03508
03509
03510
03511
03512
03513
03514 CURLcode Curl_nbftpsendf(struct connectdata *conn,
03515 const char *fmt, ...)
03516 {
03517 ssize_t bytes_written;
03518
03519 #define SBUF_SIZE 1024
03520 char s[SBUF_SIZE];
03521 size_t write_len;
03522 char *sptr=s;
03523 CURLcode res = CURLE_OK;
03524 struct SessionHandle *data = conn->data;
03525 struct ftp_conn *ftpc = &conn->proto.ftpc;
03526 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
03527 enum protection_level data_sec = conn->data_prot;
03528 #endif
03529
03530 va_list ap;
03531 va_start(ap, fmt);
03532 vsnprintf(s, SBUF_SIZE-3, fmt, ap);
03533 va_end(ap);
03534
03535 strcat(s, "\r\n");
03536
03537 bytes_written=0;
03538 write_len = strlen(s);
03539
03540 ftp_respinit(conn);
03541
03542 #ifdef CURL_DOES_CONVERSIONS
03543 res = Curl_convert_to_network(data, s, write_len);
03544
03545 if(res != CURLE_OK) {
03546 return res;
03547 }
03548 #endif
03549
03550 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
03551 conn->data_prot = prot_cmd;
03552 #endif
03553 res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
03554 &bytes_written);
03555 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
03556 conn->data_prot = data_sec;
03557 #endif
03558
03559 if(CURLE_OK != res)
03560 return res;
03561
03562 if(conn->data->set.verbose)
03563 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
03564 sptr, (size_t)bytes_written, conn);
03565
03566 if(bytes_written != (ssize_t)write_len) {
03567
03568 write_len -= bytes_written;
03569 sptr += bytes_written;
03570 ftpc->sendthis = malloc(write_len);
03571 if(ftpc->sendthis) {
03572 memcpy(ftpc->sendthis, sptr, write_len);
03573 ftpc->sendsize = ftpc->sendleft = write_len;
03574 }
03575 else {
03576 failf(data, "out of memory");
03577 res = CURLE_OUT_OF_MEMORY;
03578 }
03579 }
03580 else
03581 ftpc->response = Curl_tvnow();
03582
03583 return res;
03584 }
03585
03586 CURLcode Curl_ftpsendf(struct connectdata *conn,
03587 const char *fmt, ...)
03588 {
03589 ssize_t bytes_written;
03590 char s[SBUF_SIZE];
03591 size_t write_len;
03592 char *sptr=s;
03593 CURLcode res = CURLE_OK;
03594 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
03595 enum protection_level data_sec = conn->data_prot;
03596 #endif
03597
03598 va_list ap;
03599 va_start(ap, fmt);
03600 vsnprintf(s, SBUF_SIZE-3, fmt, ap);
03601 va_end(ap);
03602
03603 strcat(s, "\r\n");
03604
03605 bytes_written=0;
03606 write_len = strlen(s);
03607
03608 #ifdef CURL_DOES_CONVERSIONS
03609 res = Curl_convert_to_network(conn->data, s, write_len);
03610
03611 if(res != CURLE_OK) {
03612 return(res);
03613 }
03614 #endif
03615
03616 while(1) {
03617 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
03618 conn->data_prot = prot_cmd;
03619 #endif
03620 res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
03621 &bytes_written);
03622 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
03623 conn->data_prot = data_sec;
03624 #endif
03625
03626 if(CURLE_OK != res)
03627 break;
03628
03629 if(conn->data->set.verbose)
03630 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
03631 sptr, (size_t)bytes_written, conn);
03632
03633 if(bytes_written != (ssize_t)write_len) {
03634 write_len -= bytes_written;
03635 sptr += bytes_written;
03636 }
03637 else
03638 break;
03639 }
03640
03641 return res;
03642 }
03643
03644
03645
03646
03647
03648
03649
03650
03651
03652
03653
03654 static CURLcode ftp_quit(struct connectdata *conn)
03655 {
03656 CURLcode result = CURLE_OK;
03657
03658 if(conn->proto.ftpc.ctl_valid) {
03659 NBFTPSENDF(conn, "QUIT", NULL);
03660 state(conn, FTP_QUIT);
03661
03662 result = ftp_easy_statemach(conn);
03663 }
03664
03665 return result;
03666 }
03667
03668
03669
03670
03671
03672
03673
03674
03675 CURLcode Curl_ftp_disconnect(struct connectdata *conn)
03676 {
03677 struct ftp_conn *ftpc= &conn->proto.ftpc;
03678
03679
03680
03681
03682
03683
03684
03685
03686
03687
03688 if(conn->data->reqdata.proto.ftp) {
03689 (void)ftp_quit(conn);
03690
03691 if(ftpc->entrypath) {
03692 struct SessionHandle *data = conn->data;
03693 data->state.most_recent_ftp_entrypath = NULL;
03694 free(ftpc->entrypath);
03695 ftpc->entrypath = NULL;
03696 }
03697 if(ftpc->cache) {
03698 free(ftpc->cache);
03699 ftpc->cache = NULL;
03700 }
03701 freedirs(conn);
03702 if(ftpc->prevpath) {
03703 free(ftpc->prevpath);
03704 ftpc->prevpath = NULL;
03705 }
03706 }
03707 return CURLE_OK;
03708 }
03709
03710
03711
03712
03713
03714
03715
03716
03717 static
03718 CURLcode ftp_parse_url_path(struct connectdata *conn)
03719 {
03720 struct SessionHandle *data = conn->data;
03721
03722 struct FTP *ftp = data->reqdata.proto.ftp;
03723 struct ftp_conn *ftpc = &conn->proto.ftpc;
03724 size_t dlen;
03725 char *slash_pos;
03726 char *path_to_use = data->reqdata.path;
03727 char *cur_pos;
03728
03729 cur_pos = path_to_use;
03730
03731
03732 ftpc->ctl_valid = FALSE;
03733 ftpc->cwdfail = FALSE;
03734
03735 switch(data->set.ftp_filemethod) {
03736 case FTPFILE_NOCWD:
03737
03738 ftp->file = data->reqdata.path;
03739 break;
03740
03741 case FTPFILE_SINGLECWD:
03742
03743 if(!path_to_use[0]) {
03744
03745 ftpc->dirdepth = 0;
03746 ftp->file = NULL;
03747 break;
03748 }
03749 slash_pos=strrchr(cur_pos, '/');
03750 if(slash_pos || !*cur_pos) {
03751 ftpc->dirs = (char **)calloc(1, sizeof(ftpc->dirs[0]));
03752 if(!ftpc->dirs)
03753 return CURLE_OUT_OF_MEMORY;
03754
03755 ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
03756 slash_pos?(int)(slash_pos-cur_pos):1,
03757 NULL);
03758 if(!ftpc->dirs[0]) {
03759 freedirs(conn);
03760 return CURLE_OUT_OF_MEMORY;
03761 }
03762 ftpc->dirdepth = 1;
03763 ftp->file = slash_pos ? slash_pos+1 : cur_pos;
03764 }
03765 else
03766 ftp->file = cur_pos;
03767 break;
03768
03769 default:
03770 case FTPFILE_MULTICWD:
03771 ftpc->dirdepth = 0;
03772 ftpc->diralloc = 5;
03773 ftpc->dirs = (char **)calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
03774 if(!ftpc->dirs)
03775 return CURLE_OUT_OF_MEMORY;
03776
03777
03778 if(strequal(path_to_use, "/")) {
03779 cur_pos++;
03780 ftpc->dirs[0] = strdup("/");
03781 ftpc->dirdepth++;
03782 }
03783 else {
03784
03785 while ((slash_pos = strchr(cur_pos, '/')) != NULL) {
03786
03787 bool absolute_dir = (bool)((cur_pos - data->reqdata.path > 0) &&
03788 (ftpc->dirdepth == 0));
03789
03790
03791 if (slash_pos-cur_pos) {
03792
03793
03794
03795 int len = (int)(slash_pos - cur_pos + absolute_dir);
03796 ftpc->dirs[ftpc->dirdepth] =
03797 curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
03798 if (!ftpc->dirs[ftpc->dirdepth]) {
03799 failf(data, "no memory");
03800 freedirs(conn);
03801 return CURLE_OUT_OF_MEMORY;
03802 }
03803 if (isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
03804 free(ftpc->dirs[ftpc->dirdepth]);
03805 freedirs(conn);
03806 return CURLE_URL_MALFORMAT;
03807 }
03808 }
03809 else {
03810 cur_pos = slash_pos + 1;
03811 continue;
03812 }
03813
03814 cur_pos = slash_pos + 1;
03815 if(++ftpc->dirdepth >= ftpc->diralloc) {
03816
03817 char *bigger;
03818 ftpc->diralloc *= 2;
03819 bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
03820 if(!bigger) {
03821 freedirs(conn);
03822 return CURLE_OUT_OF_MEMORY;
03823 }
03824 ftpc->dirs = (char **)bigger;
03825 }
03826 }
03827 }
03828 ftp->file = cur_pos;
03829 }
03830
03831 if(ftp->file && *ftp->file) {
03832 ftp->file = curl_easy_unescape(conn->data, ftp->file, 0, NULL);
03833 if(NULL == ftp->file) {
03834 freedirs(conn);
03835 failf(data, "no memory");
03836 return CURLE_OUT_OF_MEMORY;
03837 }
03838 if (isBadFtpString(ftp->file)) {
03839 freedirs(conn);
03840 return CURLE_URL_MALFORMAT;
03841 }
03842 }
03843 else
03844 ftp->file=NULL;
03845
03846
03847 if(data->set.upload && !ftp->file && !ftp->no_transfer) {
03848
03849 failf(data, "Uploading to a URL without a file name!");
03850 return CURLE_URL_MALFORMAT;
03851 }
03852
03853 ftpc->cwddone = FALSE;
03854
03855 if(ftpc->prevpath) {
03856
03857
03858 char *path = curl_easy_unescape(conn->data, data->reqdata.path, 0, NULL);
03859 if(!path) {
03860 freedirs(conn);
03861 return CURLE_OUT_OF_MEMORY;
03862 }
03863
03864 dlen = strlen(path) - (ftp->file?strlen(ftp->file):0);
03865 if((dlen == strlen(ftpc->prevpath)) &&
03866 curl_strnequal(path, ftpc->prevpath, dlen)) {
03867 infof(data, "Request has same path as previous transfer\n");
03868 ftpc->cwddone = TRUE;
03869 }
03870 free(path);
03871 }
03872
03873 return CURLE_OK;
03874 }
03875
03876
03877 static CURLcode ftp_dophase_done(struct connectdata *conn,
03878 bool connected)
03879 {
03880 CURLcode result = CURLE_OK;
03881 struct FTP *ftp = conn->data->reqdata.proto.ftp;
03882 struct ftp_conn *ftpc = &conn->proto.ftpc;
03883
03884 if(connected)
03885 result = Curl_ftp_nextconnect(conn);
03886
03887 if(result && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
03888
03889 sclose(conn->sock[SECONDARYSOCKET]);
03890 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
03891 return result;
03892 }
03893
03894 if(ftp->no_transfer)
03895
03896 result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
03897 else if(!connected)
03898
03899 conn->bits.do_more = TRUE;
03900
03901 ftpc->ctl_valid = TRUE;
03902
03903 return result;
03904 }
03905
03906
03907 CURLcode Curl_ftp_doing(struct connectdata *conn,
03908 bool *dophase_done)
03909 {
03910 CURLcode result;
03911 result = Curl_ftp_multi_statemach(conn, dophase_done);
03912
03913 if(*dophase_done) {
03914 result = ftp_dophase_done(conn, FALSE );
03915
03916 DEBUGF(infof(conn->data, "DO phase is complete\n"));
03917 }
03918 return result;
03919 }
03920
03921
03922
03923
03924
03925
03926
03927
03928
03929
03930
03931
03932
03933 static
03934 CURLcode ftp_regular_transfer(struct connectdata *conn,
03935 bool *dophase_done)
03936 {
03937 CURLcode result=CURLE_OK;
03938 bool connected=0;
03939 struct SessionHandle *data = conn->data;
03940 struct ftp_conn *ftpc = &conn->proto.ftpc;
03941 data->reqdata.size = -1;
03942
03943 Curl_pgrsSetUploadCounter(data, 0);
03944 Curl_pgrsSetDownloadCounter(data, 0);
03945 Curl_pgrsSetUploadSize(data, 0);
03946 Curl_pgrsSetDownloadSize(data, 0);
03947
03948 ftpc->ctl_valid = TRUE;
03949
03950 result = ftp_perform(conn,
03951 &connected,
03952 dophase_done);
03953
03954 if(CURLE_OK == result) {
03955
03956 if(!*dophase_done)
03957
03958 return CURLE_OK;
03959
03960 result = ftp_dophase_done(conn, connected);
03961 if(result)
03962 return result;
03963 }
03964 else
03965 freedirs(conn);
03966
03967 return result;
03968 }
03969
03970 #endif