12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445 |
- #include "curl_setup.h"
- #ifndef CURL_DISABLE_FTP
- #ifdef HAVE_NETINET_IN_H
- #include <netinet/in.h>
- #endif
- #ifdef HAVE_ARPA_INET_H
- #include <arpa/inet.h>
- #endif
- #ifdef HAVE_UTSNAME_H
- #include <sys/utsname.h>
- #endif
- #ifdef HAVE_NETDB_H
- #include <netdb.h>
- #endif
- #ifdef __VMS
- #include <in.h>
- #include <inet.h>
- #endif
- #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
- #undef in_addr_t
- #define in_addr_t unsigned long
- #endif
- #include <curl/curl.h>
- #include "urldata.h"
- #include "sendf.h"
- #include "if2ip.h"
- #include "hostip.h"
- #include "progress.h"
- #include "transfer.h"
- #include "escape.h"
- #include "http.h"
- #include "socks.h"
- #include "ftp.h"
- #include "fileinfo.h"
- #include "ftplistparser.h"
- #include "curl_range.h"
- #include "curl_sec.h"
- #include "strtoofft.h"
- #include "strcase.h"
- #include "vtls/vtls.h"
- #include "connect.h"
- #include "strerror.h"
- #include "inet_ntop.h"
- #include "inet_pton.h"
- #include "select.h"
- #include "parsedate.h"
- #include "sockaddr.h"
- #include "multiif.h"
- #include "url.h"
- #include "strcase.h"
- #include "speedcheck.h"
- #include "warnless.h"
- #include "http_proxy.h"
- #include "non-ascii.h"
- #include "curl_printf.h"
- #include "curl_memory.h"
- #include "memdebug.h"
- #ifndef NI_MAXHOST
- #define NI_MAXHOST 1025
- #endif
- #ifndef INET_ADDRSTRLEN
- #define INET_ADDRSTRLEN 16
- #endif
- #ifdef CURL_DISABLE_VERBOSE_STRINGS
- #define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
- #endif
- #ifndef DEBUGBUILD
- static void _state(struct connectdata *conn,
- ftpstate newstate);
- #define state(x,y) _state(x,y)
- #else
- static void _state(struct connectdata *conn,
- ftpstate newstate,
- int lineno);
- #define state(x,y) _state(x,y,__LINE__)
- #endif
- static CURLcode ftp_sendquote(struct connectdata *conn,
- struct curl_slist *quote);
- static CURLcode ftp_quit(struct connectdata *conn);
- static CURLcode ftp_parse_url_path(struct connectdata *conn);
- static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
- #ifndef CURL_DISABLE_VERBOSE_STRINGS
- static void ftp_pasv_verbose(struct connectdata *conn,
- Curl_addrinfo *ai,
- char *newhost,
- int port);
- #endif
- static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
- static CURLcode ftp_state_mdtm(struct connectdata *conn);
- static CURLcode ftp_state_quote(struct connectdata *conn,
- bool init, ftpstate instate);
- static CURLcode ftp_nb_type(struct connectdata *conn,
- bool ascii, ftpstate newstate);
- static int ftp_need_type(struct connectdata *conn,
- bool ascii);
- static CURLcode ftp_do(struct connectdata *conn, bool *done);
- static CURLcode ftp_done(struct connectdata *conn,
- CURLcode, bool premature);
- static CURLcode ftp_connect(struct connectdata *conn, bool *done);
- static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
- static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
- static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
- static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
- int numsocks);
- static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
- int numsocks);
- static CURLcode ftp_doing(struct connectdata *conn,
- bool *dophase_done);
- static CURLcode ftp_setup_connection(struct connectdata * conn);
- static CURLcode init_wc_data(struct connectdata *conn);
- static CURLcode wc_statemach(struct connectdata *conn);
- static void wc_data_dtor(void *ptr);
- static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
- static CURLcode ftp_readresp(curl_socket_t sockfd,
- struct pingpong *pp,
- int *ftpcode,
- size_t *size);
- static CURLcode ftp_dophase_done(struct connectdata *conn,
- bool connected);
- #define PPSENDF(x,y,z) result = Curl_pp_sendf(x,y,z); \
- if(result) \
- return result
- const struct Curl_handler Curl_handler_ftp = {
- "FTP",
- ftp_setup_connection,
- ftp_do,
- ftp_done,
- ftp_do_more,
- ftp_connect,
- ftp_multi_statemach,
- ftp_doing,
- ftp_getsock,
- ftp_getsock,
- ftp_domore_getsock,
- ZERO_NULL,
- ftp_disconnect,
- ZERO_NULL,
- ZERO_NULL,
- PORT_FTP,
- CURLPROTO_FTP,
- PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD |
- PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP |
- PROTOPT_WILDCARD
- };
- #ifdef USE_SSL
- const struct Curl_handler Curl_handler_ftps = {
- "FTPS",
- ftp_setup_connection,
- ftp_do,
- ftp_done,
- ftp_do_more,
- ftp_connect,
- ftp_multi_statemach,
- ftp_doing,
- ftp_getsock,
- ftp_getsock,
- ftp_domore_getsock,
- ZERO_NULL,
- ftp_disconnect,
- ZERO_NULL,
- ZERO_NULL,
- PORT_FTPS,
- CURLPROTO_FTPS,
- PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
- PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD
- };
- #endif
- static void close_secondarysocket(struct connectdata *conn)
- {
- if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
- Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
- conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
- }
- conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
- }
- #define CURL_FTP_HTTPSTYLE_HEAD 1
- static void freedirs(struct ftp_conn *ftpc)
- {
- if(ftpc->dirs) {
- int i;
- for(i = 0; i < ftpc->dirdepth; i++) {
- free(ftpc->dirs[i]);
- ftpc->dirs[i] = NULL;
- }
- free(ftpc->dirs);
- ftpc->dirs = NULL;
- ftpc->dirdepth = 0;
- }
- Curl_safefree(ftpc->file);
-
- Curl_safefree(ftpc->newhost);
- }
- static bool isBadFtpString(const char *string)
- {
- return ((NULL != strchr(string, '\r')) ||
- (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
- }
- static CURLcode AcceptServerConnect(struct connectdata *conn)
- {
- struct Curl_easy *data = conn->data;
- curl_socket_t sock = conn->sock[SECONDARYSOCKET];
- curl_socket_t s = CURL_SOCKET_BAD;
- #ifdef ENABLE_IPV6
- struct Curl_sockaddr_storage add;
- #else
- struct sockaddr_in add;
- #endif
- curl_socklen_t size = (curl_socklen_t) sizeof(add);
- if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
- size = sizeof(add);
- s = accept(sock, (struct sockaddr *) &add, &size);
- }
- Curl_closesocket(conn, sock);
- if(CURL_SOCKET_BAD == s) {
- failf(data, "Error accept()ing server connect");
- return CURLE_FTP_PORT_FAILED;
- }
- infof(data, "Connection accepted from server\n");
-
- conn->bits.do_more = FALSE;
- conn->sock[SECONDARYSOCKET] = s;
- (void)curlx_nonblock(s, TRUE);
- conn->sock_accepted[SECONDARYSOCKET] = TRUE;
- if(data->set.fsockopt) {
- int error = 0;
-
- Curl_set_in_callback(data, true);
- error = data->set.fsockopt(data->set.sockopt_client,
- s,
- CURLSOCKTYPE_ACCEPT);
- Curl_set_in_callback(data, false);
- if(error) {
- close_secondarysocket(conn);
- return CURLE_ABORTED_BY_CALLBACK;
- }
- }
- return CURLE_OK;
- }
- static timediff_t ftp_timeleft_accept(struct Curl_easy *data)
- {
- timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
- timediff_t other;
- struct curltime now;
- if(data->set.accepttimeout > 0)
- timeout_ms = data->set.accepttimeout;
- now = Curl_now();
-
- other = Curl_timeleft(data, &now, FALSE);
- if(other && (other < timeout_ms))
-
- timeout_ms = other;
- else {
-
- timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata);
- if(!timeout_ms)
-
- return -1;
- }
- return timeout_ms;
- }
- static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
- {
- struct Curl_easy *data = conn->data;
- curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
- curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
- int result;
- time_t timeout_ms;
- ssize_t nread;
- int ftpcode;
- *received = FALSE;
- timeout_ms = ftp_timeleft_accept(data);
- infof(data, "Checking for server connect\n");
- if(timeout_ms < 0) {
-
- failf(data, "Accept timeout occurred while waiting server connect");
- return CURLE_FTP_ACCEPT_TIMEOUT;
- }
-
- if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
-
- infof(data, "There is negative response in cache while serv connect\n");
- Curl_GetFTPResponse(&nread, conn, &ftpcode);
- return CURLE_FTP_ACCEPT_FAILED;
- }
- result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
-
- switch(result) {
- case -1:
-
- failf(data, "Error while waiting for server connect");
- return CURLE_FTP_ACCEPT_FAILED;
- case 0:
- break;
- default:
- if(result & CURL_CSELECT_IN2) {
- infof(data, "Ready to accept data connection from server\n");
- *received = TRUE;
- }
- else if(result & CURL_CSELECT_IN) {
- infof(data, "Ctrl conn has data while waiting for data conn\n");
- Curl_GetFTPResponse(&nread, conn, &ftpcode);
- if(ftpcode/100 > 3)
- return CURLE_FTP_ACCEPT_FAILED;
- return CURLE_WEIRD_SERVER_REPLY;
- }
- break;
- }
- return CURLE_OK;
- }
- static CURLcode InitiateTransfer(struct connectdata *conn)
- {
- struct Curl_easy *data = conn->data;
- struct FTP *ftp = data->req.protop;
- CURLcode result = CURLE_OK;
- if(conn->bits.ftp_use_data_ssl) {
-
- infof(data, "Doing the SSL/TLS handshake on the data stream\n");
- result = Curl_ssl_connect(conn, SECONDARYSOCKET);
- if(result)
- return result;
- }
- if(conn->proto.ftpc.state_saved == FTP_STOR) {
- *(ftp->bytecountp) = 0;
-
- Curl_pgrsSetUploadSize(data, data->state.infilesize);
-
- Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL,
- SECONDARYSOCKET, ftp->bytecountp);
- }
- else {
-
- Curl_setup_transfer(conn, SECONDARYSOCKET,
- conn->proto.ftpc.retr_size_saved, FALSE,
- ftp->bytecountp, -1, NULL);
- }
- conn->proto.ftpc.pp.pending_resp = TRUE;
- state(conn, FTP_STOP);
- return CURLE_OK;
- }
- static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
- {
- struct Curl_easy *data = conn->data;
- time_t timeout_ms;
- CURLcode result = CURLE_OK;
- *connected = FALSE;
- infof(data, "Preparing for accepting server on data port\n");
-
- Curl_pgrsTime(data, TIMER_STARTACCEPT);
- timeout_ms = ftp_timeleft_accept(data);
- if(timeout_ms < 0) {
-
- failf(data, "Accept timeout occurred while waiting server connect");
- return CURLE_FTP_ACCEPT_TIMEOUT;
- }
-
- result = ReceivedServerConnect(conn, connected);
- if(result)
- return result;
- if(*connected) {
- result = AcceptServerConnect(conn);
- if(result)
- return result;
- result = InitiateTransfer(conn);
- if(result)
- return result;
- }
- else {
-
- if(!result && *connected == FALSE) {
- Curl_expire(data, data->set.accepttimeout > 0 ?
- data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, 0);
- }
- }
- return result;
- }
- #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
- ISDIGIT(line[2]))
- #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
- static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
- int *code)
- {
- (void)conn;
- if((len > 3) && LASTLINE(line)) {
- *code = curlx_sltosi(strtol(line, NULL, 10));
- return TRUE;
- }
- return FALSE;
- }
- static CURLcode ftp_readresp(curl_socket_t sockfd,
- struct pingpong *pp,
- int *ftpcode,
- size_t *size)
- {
- struct connectdata *conn = pp->conn;
- struct Curl_easy *data = conn->data;
- #ifdef HAVE_GSSAPI
- char * const buf = data->state.buffer;
- #endif
- CURLcode result = CURLE_OK;
- int code;
- result = Curl_pp_readresp(sockfd, pp, &code, size);
- #if defined(HAVE_GSSAPI)
-
-
- switch(code) {
- case 631:
- code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
- break;
- case 632:
- code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
- break;
- case 633:
- code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
- break;
- default:
-
- break;
- }
- #endif
-
- data->info.httpcode = code;
- if(ftpcode)
- *ftpcode = code;
- if(421 == code) {
-
- infof(data, "We got a 421 - timeout!\n");
- state(conn, FTP_STOP);
- return CURLE_OPERATION_TIMEDOUT;
- }
- return result;
- }
- CURLcode Curl_GetFTPResponse(ssize_t *nreadp,
- struct connectdata *conn,
- int *ftpcode)
- {
-
- curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
- struct Curl_easy *data = conn->data;
- CURLcode result = CURLE_OK;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
- size_t nread;
- int cache_skip = 0;
- int value_to_be_ignored = 0;
- if(ftpcode)
- *ftpcode = 0;
- else
-
- ftpcode = &value_to_be_ignored;
- *nreadp = 0;
- while(!*ftpcode && !result) {
-
- time_t timeout = Curl_pp_state_timeout(pp);
- time_t interval_ms;
- if(timeout <= 0) {
- failf(data, "FTP response timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
- interval_ms = 1000;
- if(timeout < interval_ms)
- interval_ms = timeout;
-
- if(pp->cache && (cache_skip < 2)) {
-
- }
- else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) {
- switch(SOCKET_READABLE(sockfd, interval_ms)) {
- case -1:
- failf(data, "FTP response aborted due to select/poll error: %d",
- SOCKERRNO);
- return CURLE_RECV_ERROR;
- case 0:
- if(Curl_pgrsUpdate(conn))
- return CURLE_ABORTED_BY_CALLBACK;
- continue;
- default:
- break;
- }
- }
- result = ftp_readresp(sockfd, pp, ftpcode, &nread);
- if(result)
- break;
- if(!nread && pp->cache)
-
- cache_skip++;
- else
-
- cache_skip = 0;
- *nreadp += nread;
- }
- pp->pending_resp = FALSE;
- return result;
- }
- #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
-
- static const char * const ftp_state_names[]={
- "STOP",
- "WAIT220",
- "AUTH",
- "USER",
- "PASS",
- "ACCT",
- "PBSZ",
- "PROT",
- "CCC",
- "PWD",
- "SYST",
- "NAMEFMT",
- "QUOTE",
- "RETR_PREQUOTE",
- "STOR_PREQUOTE",
- "POSTQUOTE",
- "CWD",
- "MKD",
- "MDTM",
- "TYPE",
- "LIST_TYPE",
- "RETR_TYPE",
- "STOR_TYPE",
- "SIZE",
- "RETR_SIZE",
- "STOR_SIZE",
- "REST",
- "RETR_REST",
- "PORT",
- "PRET",
- "PASV",
- "LIST",
- "RETR",
- "STOR",
- "QUIT"
- };
- #endif
- static void _state(struct connectdata *conn,
- ftpstate newstate
- #ifdef DEBUGBUILD
- , int lineno
- #endif
- )
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- #if defined(DEBUGBUILD)
- #if defined(CURL_DISABLE_VERBOSE_STRINGS)
- (void) lineno;
- #else
- if(ftpc->state != newstate)
- infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
- (void *)ftpc, lineno, ftp_state_names[ftpc->state],
- ftp_state_names[newstate]);
- #endif
- #endif
- ftpc->state = newstate;
- }
- static CURLcode ftp_state_user(struct connectdata *conn)
- {
- CURLcode result;
- struct FTP *ftp = conn->data->req.protop;
-
- PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
- state(conn, FTP_USER);
- conn->data->state.ftp_trying_alternative = FALSE;
- return CURLE_OK;
- }
- static CURLcode ftp_state_pwd(struct connectdata *conn)
- {
- CURLcode result;
-
- PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
- state(conn, FTP_PWD);
- return CURLE_OK;
- }
- static int ftp_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks)
- {
- return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
- }
- static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
- int numsocks)
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- if(!numsocks)
- return GETSOCK_BLANK;
-
- if(FTP_STOP == ftpc->state) {
- int bits = GETSOCK_READSOCK(0);
-
- socks[0] = conn->sock[FIRSTSOCKET];
- if(!conn->data->set.ftp_use_port) {
- int s;
- int i;
-
- for(s = 1, i = 0; i<2; i++) {
- if(conn->tempsock[i] != CURL_SOCKET_BAD) {
- socks[s] = conn->tempsock[i];
- bits |= GETSOCK_WRITESOCK(s++);
- }
- }
- }
- else {
- socks[1] = conn->sock[SECONDARYSOCKET];
- bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1);
- }
- return bits;
- }
- return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
- }
- static CURLcode ftp_state_cwd(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- if(ftpc->cwddone)
-
- result = ftp_state_mdtm(conn);
- else {
- ftpc->count2 = 0;
-
- ftpc->count3 = (conn->data->set.ftp_create_missing_dirs == 2)?1:0;
- if((conn->data->set.ftp_filemethod == FTPFILE_NOCWD) && !ftpc->cwdcount)
-
- result = ftp_state_mdtm(conn);
- else if(conn->bits.reuse && ftpc->entrypath) {
-
- ftpc->cwdcount = 0;
- PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
- state(conn, FTP_CWD);
- }
- else {
- if(ftpc->dirdepth) {
- ftpc->cwdcount = 1;
-
- PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->cwdcount -1]);
- state(conn, FTP_CWD);
- }
- else {
-
- result = ftp_state_mdtm(conn);
- }
- }
- }
- return result;
- }
- typedef enum {
- EPRT,
- PORT,
- DONE
- } ftpport;
- static CURLcode ftp_state_use_port(struct connectdata *conn,
- ftpport fcmd)
- {
- CURLcode result = CURLE_OK;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct Curl_easy *data = conn->data;
- curl_socket_t portsock = CURL_SOCKET_BAD;
- char myhost[256] = "";
- struct Curl_sockaddr_storage ss;
- Curl_addrinfo *res, *ai;
- curl_socklen_t sslen;
- char hbuf[NI_MAXHOST];
- struct sockaddr *sa = (struct sockaddr *)&ss;
- struct sockaddr_in * const sa4 = (void *)sa;
- #ifdef ENABLE_IPV6
- struct sockaddr_in6 * const sa6 = (void *)sa;
- #endif
- char tmp[1024];
- static const char mode[][5] = { "EPRT", "PORT" };
- int rc;
- int error;
- char *host = NULL;
- char *string_ftpport = data->set.str[STRING_FTPPORT];
- struct Curl_dns_entry *h = NULL;
- unsigned short port_min = 0;
- unsigned short port_max = 0;
- unsigned short port;
- bool possibly_non_local = TRUE;
- char *addr = NULL;
-
- if(data->set.str[STRING_FTPPORT] &&
- (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
- #ifdef ENABLE_IPV6
- size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
- INET6_ADDRSTRLEN : strlen(string_ftpport);
- #else
- size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
- INET_ADDRSTRLEN : strlen(string_ftpport);
- #endif
- char *ip_start = string_ftpport;
- char *ip_end = NULL;
- char *port_start = NULL;
- char *port_sep = NULL;
- addr = calloc(addrlen + 1, 1);
- if(!addr)
- return CURLE_OUT_OF_MEMORY;
- #ifdef ENABLE_IPV6
- if(*string_ftpport == '[') {
-
- ip_start = string_ftpport + 1;
- ip_end = strchr(string_ftpport, ']');
- if(ip_end)
- strncpy(addr, ip_start, ip_end - ip_start);
- }
- else
- #endif
- if(*string_ftpport == ':') {
-
- ip_end = string_ftpport;
- }
- else {
- ip_end = strchr(string_ftpport, ':');
- if(ip_end) {
-
- #ifdef ENABLE_IPV6
- if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
-
- port_min = port_max = 0;
- strcpy(addr, string_ftpport);
- ip_end = NULL;
- }
- else
- #endif
-
- strncpy(addr, string_ftpport, ip_end - ip_start);
- }
- else
-
- strcpy(addr, string_ftpport);
- }
-
- if(ip_end != NULL) {
- port_start = strchr(ip_end, ':');
- if(port_start) {
- port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
- port_sep = strchr(port_start, '-');
- if(port_sep) {
- port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
- }
- else
- port_max = port_min;
- }
- }
-
- if(port_min > port_max)
- port_min = port_max = 0;
- if(*addr != '\0') {
-
- switch(Curl_if2ip(conn->ip_addr->ai_family,
- Curl_ipv6_scope(conn->ip_addr->ai_addr),
- conn->scope_id, addr, hbuf, sizeof(hbuf))) {
- case IF2IP_NOT_FOUND:
-
- host = addr;
- break;
- case IF2IP_AF_NOT_SUPPORTED:
- return CURLE_FTP_PORT_FAILED;
- case IF2IP_FOUND:
- host = hbuf;
- }
- }
- else
-
- host = NULL;
- }
- if(!host) {
-
- sslen = sizeof(ss);
- if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
- failf(data, "getsockname() failed: %s",
- Curl_strerror(conn, SOCKERRNO) );
- free(addr);
- return CURLE_FTP_PORT_FAILED;
- }
- switch(sa->sa_family) {
- #ifdef ENABLE_IPV6
- case AF_INET6:
- Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
- break;
- #endif
- default:
- Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
- break;
- }
- host = hbuf;
- possibly_non_local = FALSE;
- }
-
- rc = Curl_resolv(conn, host, 0, &h);
- if(rc == CURLRESOLV_PENDING)
- (void)Curl_resolver_wait_resolv(conn, &h);
- if(h) {
- res = h->addr;
-
- Curl_resolv_unlock(data, h);
- }
- else
- res = NULL;
- if(res == NULL) {
- failf(data, "failed to resolve the address provided to PORT: %s", host);
- free(addr);
- return CURLE_FTP_PORT_FAILED;
- }
- free(addr);
- host = NULL;
-
- portsock = CURL_SOCKET_BAD;
- error = 0;
- for(ai = res; ai; ai = ai->ai_next) {
- result = Curl_socket(conn, ai, NULL, &portsock);
- if(result) {
- error = SOCKERRNO;
- continue;
- }
- break;
- }
- if(!ai) {
- failf(data, "socket failure: %s", Curl_strerror(conn, error));
- return CURLE_FTP_PORT_FAILED;
- }
-
- memcpy(sa, ai->ai_addr, ai->ai_addrlen);
- sslen = ai->ai_addrlen;
- for(port = port_min; port <= port_max;) {
- if(sa->sa_family == AF_INET)
- sa4->sin_port = htons(port);
- #ifdef ENABLE_IPV6
- else
- sa6->sin6_port = htons(port);
- #endif
-
- if(bind(portsock, sa, sslen) ) {
-
- error = SOCKERRNO;
- if(possibly_non_local && (error == EADDRNOTAVAIL)) {
-
- infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
- Curl_strerror(conn, error) );
- sslen = sizeof(ss);
- if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
- failf(data, "getsockname() failed: %s",
- Curl_strerror(conn, SOCKERRNO) );
- Curl_closesocket(conn, portsock);
- return CURLE_FTP_PORT_FAILED;
- }
- port = port_min;
- possibly_non_local = FALSE;
- continue;
- }
- if(error != EADDRINUSE && error != EACCES) {
- failf(data, "bind(port=%hu) failed: %s", port,
- Curl_strerror(conn, error) );
- Curl_closesocket(conn, portsock);
- return CURLE_FTP_PORT_FAILED;
- }
- }
- else
- break;
- port++;
- }
-
- if(port > port_max) {
- failf(data, "bind() failed, we ran out of ports!");
- Curl_closesocket(conn, portsock);
- return CURLE_FTP_PORT_FAILED;
- }
-
- sslen = sizeof(ss);
- if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
- failf(data, "getsockname() failed: %s",
- Curl_strerror(conn, SOCKERRNO) );
- Curl_closesocket(conn, portsock);
- return CURLE_FTP_PORT_FAILED;
- }
-
- if(listen(portsock, 1)) {
- failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
- Curl_closesocket(conn, portsock);
- return CURLE_FTP_PORT_FAILED;
- }
-
-
- Curl_printable_address(ai, myhost, sizeof(myhost));
- #ifdef ENABLE_IPV6
- if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
-
- conn->bits.ftp_use_eprt = TRUE;
- #endif
- for(; fcmd != DONE; fcmd++) {
- if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
-
- continue;
- if((PORT == fcmd) && sa->sa_family != AF_INET)
-
- continue;
- switch(sa->sa_family) {
- case AF_INET:
- port = ntohs(sa4->sin_port);
- break;
- #ifdef ENABLE_IPV6
- case AF_INET6:
- port = ntohs(sa6->sin6_port);
- break;
- #endif
- default:
- continue;
- }
- if(EPRT == fcmd) {
-
- result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
- sa->sa_family == AF_INET?1:2,
- myhost, port);
- if(result) {
- failf(data, "Failure sending EPRT command: %s",
- curl_easy_strerror(result));
- Curl_closesocket(conn, portsock);
-
- ftpc->count1 = PORT;
-
- state(conn, FTP_STOP);
- return result;
- }
- break;
- }
- if(PORT == fcmd) {
- char *source = myhost;
- char *dest = tmp;
-
- while(source && *source) {
- if(*source == '.')
- *dest = ',';
- else
- *dest = *source;
- dest++;
- source++;
- }
- *dest = 0;
- snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
- result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
- if(result) {
- failf(data, "Failure sending PORT command: %s",
- curl_easy_strerror(result));
- Curl_closesocket(conn, portsock);
-
- state(conn, FTP_STOP);
- return result;
- }
- break;
- }
- }
-
- ftpc->count1 = fcmd;
- close_secondarysocket(conn);
-
- conn->sock[SECONDARYSOCKET] = portsock;
-
- conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
- state(conn, FTP_PORT);
- return result;
- }
- static CURLcode ftp_state_use_pasv(struct connectdata *conn)
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result = CURLE_OK;
-
- static const char mode[][5] = { "EPSV", "PASV" };
- int modeoff;
- #ifdef PF_INET6
- if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
-
- conn->bits.ftp_use_epsv = TRUE;
- #endif
- modeoff = conn->bits.ftp_use_epsv?0:1;
- PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
- ftpc->count1 = modeoff;
- state(conn, FTP_PASV);
- infof(conn->data, "Connect data stream passively\n");
- return result;
- }
- static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->req.protop;
- struct Curl_easy *data = conn->data;
- if(ftp->transfer != FTPTRANSFER_BODY) {
-
-
- state(conn, FTP_RETR_PREQUOTE);
- result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
- }
- else if(data->set.ftp_use_port) {
-
- result = ftp_state_use_port(conn, EPRT);
- }
- else {
-
- if(data->set.ftp_use_pret) {
-
- if(!conn->proto.ftpc.file) {
- PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
- data->set.str[STRING_CUSTOMREQUEST]?
- data->set.str[STRING_CUSTOMREQUEST]:
- (data->set.ftp_list_only?"NLST":"LIST"));
- }
- else if(data->set.upload) {
- PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
- }
- else {
- PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
- }
- state(conn, FTP_PRET);
- }
- else {
- result = ftp_state_use_pasv(conn);
- }
- }
- return result;
- }
- static CURLcode ftp_state_rest(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
-
-
- PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
- state(conn, FTP_REST);
- }
- else
- result = ftp_state_prepare_transfer(conn);
- return result;
- }
- static CURLcode ftp_state_size(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
-
-
- PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
- state(conn, FTP_SIZE);
- }
- else
- result = ftp_state_rest(conn);
- return result;
- }
- static CURLcode ftp_state_list(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- struct Curl_easy *data = conn->data;
-
-
- char *cmd, *lstArg, *slashPos;
- const char *inpath = data->state.path;
- lstArg = NULL;
- if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
- inpath && inpath[0] && strchr(inpath, '/')) {
- size_t n = strlen(inpath);
-
- if(inpath[n - 1] != '/') {
-
- slashPos = strrchr(inpath, '/');
- n = slashPos - inpath;
- }
- result = Curl_urldecode(data, inpath, n, &lstArg, NULL, TRUE);
- if(result)
- return result;
- }
- cmd = aprintf("%s%s%s",
- data->set.str[STRING_CUSTOMREQUEST]?
- data->set.str[STRING_CUSTOMREQUEST]:
- (data->set.ftp_list_only?"NLST":"LIST"),
- lstArg? " ": "",
- lstArg? lstArg: "");
- if(!cmd) {
- free(lstArg);
- return CURLE_OUT_OF_MEMORY;
- }
- result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
- free(lstArg);
- free(cmd);
- if(result)
- return result;
- state(conn, FTP_LIST);
- return result;
- }
- static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
-
- result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
- return result;
- }
- static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
-
- result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
- return result;
- }
- static CURLcode ftp_state_type(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->req.protop;
- struct Curl_easy *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
-
- if(data->set.opt_no_body && ftpc->file &&
- ftp_need_type(conn, data->set.prefer_ascii)) {
-
- ftp->transfer = FTPTRANSFER_INFO;
-
-
- result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
- if(result)
- return result;
- }
- else
- result = ftp_state_size(conn);
- return result;
- }
- static CURLcode ftp_state_mdtm(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- struct Curl_easy *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
-
- if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
-
- PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
- state(conn, FTP_MDTM);
- }
- else
- result = ftp_state_type(conn);
- return result;
- }
- static CURLcode ftp_state_ul_setup(struct connectdata *conn,
- bool sizechecked)
- {
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->req.protop;
- struct Curl_easy *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- if((data->state.resume_from && !sizechecked) ||
- ((data->state.resume_from > 0) && sizechecked)) {
-
-
-
-
-
-
- int seekerr = CURL_SEEKFUNC_OK;
- if(data->state.resume_from < 0) {
-
- PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
- state(conn, FTP_STOR_SIZE);
- return result;
- }
-
- data->set.ftp_append = TRUE;
-
- if(conn->seek_func) {
- Curl_set_in_callback(data, true);
- seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
- SEEK_SET);
- Curl_set_in_callback(data, false);
- }
- if(seekerr != CURL_SEEKFUNC_OK) {
- curl_off_t passed = 0;
- if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
- failf(data, "Could not seek stream");
- return CURLE_FTP_COULDNT_USE_REST;
- }
-
- do {
- size_t readthisamountnow =
- (data->state.resume_from - passed > data->set.buffer_size) ?
- (size_t)data->set.buffer_size :
- curlx_sotouz(data->state.resume_from - passed);
- size_t actuallyread =
- data->state.fread_func(data->state.buffer, 1, readthisamountnow,
- data->state.in);
- passed += actuallyread;
- if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
-
- failf(data, "Failed to read data");
- return CURLE_FTP_COULDNT_USE_REST;
- }
- } while(passed < data->state.resume_from);
- }
-
- if(data->state.infilesize>0) {
- data->state.infilesize -= data->state.resume_from;
- if(data->state.infilesize <= 0) {
- infof(data, "File already completely uploaded\n");
-
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
-
- ftp->transfer = FTPTRANSFER_NONE;
- state(conn, FTP_STOP);
- return CURLE_OK;
- }
- }
-
- }
- PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
- ftpc->file);
- state(conn, FTP_STOR);
- return result;
- }
- static CURLcode ftp_state_quote(struct connectdata *conn,
- bool init,
- ftpstate instate)
- {
- CURLcode result = CURLE_OK;
- struct Curl_easy *data = conn->data;
- struct FTP *ftp = data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- bool quote = FALSE;
- struct curl_slist *item;
- switch(instate) {
- case FTP_QUOTE:
- default:
- item = data->set.quote;
- break;
- case FTP_RETR_PREQUOTE:
- case FTP_STOR_PREQUOTE:
- item = data->set.prequote;
- break;
- case FTP_POSTQUOTE:
- item = data->set.postquote;
- break;
- }
-
- if(init)
- ftpc->count1 = 0;
- else
- ftpc->count1++;
- if(item) {
- int i = 0;
-
- while((i< ftpc->count1) && item) {
- item = item->next;
- i++;
- }
- if(item) {
- char *cmd = item->data;
- if(cmd[0] == '*') {
- cmd++;
- ftpc->count2 = 1;
- }
- else
- ftpc->count2 = 0;
- PPSENDF(&ftpc->pp, "%s", cmd);
- state(conn, instate);
- quote = TRUE;
- }
- }
- if(!quote) {
-
- switch(instate) {
- case FTP_QUOTE:
- default:
- result = ftp_state_cwd(conn);
- break;
- case FTP_RETR_PREQUOTE:
- if(ftp->transfer != FTPTRANSFER_BODY)
- state(conn, FTP_STOP);
- else {
- if(ftpc->known_filesize != -1) {
- Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
- result = ftp_state_retr(conn, ftpc->known_filesize);
- }
- else {
- if(data->set.ignorecl) {
-
- PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
- state(conn, FTP_RETR);
- }
- else {
- PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
- state(conn, FTP_RETR_SIZE);
- }
- }
- }
- break;
- case FTP_STOR_PREQUOTE:
- result = ftp_state_ul_setup(conn, FALSE);
- break;
- case FTP_POSTQUOTE:
- break;
- }
- }
- return result;
- }
- static CURLcode ftp_epsv_disable(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- if(conn->bits.ipv6 && !(conn->bits.tunnel_proxy || conn->bits.socksproxy)) {
-
- failf(conn->data, "Failed EPSV attempt, exiting\n");
- return CURLE_WEIRD_SERVER_REPLY;
- }
- infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
-
- conn->bits.ftp_use_epsv = FALSE;
- conn->data->state.errorbuf = FALSE;
- PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
- conn->proto.ftpc.count1++;
-
- state(conn, FTP_PASV);
- return result;
- }
- static char *control_address(struct connectdata *conn)
- {
-
- if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
- return conn->host.name;
- return conn->ip_addr_str;
- }
- static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
- int ftpcode)
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result;
- struct Curl_easy *data = conn->data;
- struct Curl_dns_entry *addr = NULL;
- int rc;
- unsigned short connectport;
- char *str = &data->state.buffer[4];
-
- Curl_safefree(ftpc->newhost);
- if((ftpc->count1 == 0) &&
- (ftpcode == 229)) {
-
- char *ptr = strchr(str, '(');
- if(ptr) {
- unsigned int num;
- char separator[4];
- ptr++;
- if(5 == sscanf(ptr, "%c%c%c%u%c",
- &separator[0],
- &separator[1],
- &separator[2],
- &num,
- &separator[3])) {
- const char sep1 = separator[0];
- int i;
-
- for(i = 1; i<4; i++) {
- if(separator[i] != sep1) {
- ptr = NULL;
- break;
- }
- }
- if(num > 0xffff) {
- failf(data, "Illegal port number in EPSV reply");
- return CURLE_FTP_WEIRD_PASV_REPLY;
- }
- if(ptr) {
- ftpc->newport = (unsigned short)(num & 0xffff);
- ftpc->newhost = strdup(control_address(conn));
- if(!ftpc->newhost)
- return CURLE_OUT_OF_MEMORY;
- }
- }
- else
- ptr = NULL;
- }
- if(!ptr) {
- failf(data, "Weirdly formatted EPSV reply");
- return CURLE_FTP_WEIRD_PASV_REPLY;
- }
- }
- else if((ftpc->count1 == 1) &&
- (ftpcode == 227)) {
-
- unsigned int ip[4];
- unsigned int port[2];
-
- while(*str) {
- if(6 == sscanf(str, "%u,%u,%u,%u,%u,%u",
- &ip[0], &ip[1], &ip[2], &ip[3],
- &port[0], &port[1]))
- break;
- str++;
- }
- if(!*str || (ip[0] > 255) || (ip[1] > 255) || (ip[2] > 255) ||
- (ip[3] > 255) || (port[0] > 255) || (port[1] > 255) ) {
- failf(data, "Couldn't interpret the 227-response");
- return CURLE_FTP_WEIRD_227_FORMAT;
- }
-
- if(data->set.ftp_skip_ip) {
-
- infof(data, "Skip %u.%u.%u.%u for data connection, re-use %s instead\n",
- ip[0], ip[1], ip[2], ip[3],
- conn->host.name);
- ftpc->newhost = strdup(control_address(conn));
- }
- else
- ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
- if(!ftpc->newhost)
- return CURLE_OUT_OF_MEMORY;
- ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
- }
- else if(ftpc->count1 == 0) {
-
- return ftp_epsv_disable(conn);
- }
- else {
- failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
- return CURLE_FTP_WEIRD_PASV_REPLY;
- }
- if(conn->bits.proxy) {
-
- const char * const host_name = conn->bits.socksproxy ?
- conn->socks_proxy.host.name : conn->http_proxy.host.name;
- rc = Curl_resolv(conn, host_name, (int)conn->port, &addr);
- if(rc == CURLRESOLV_PENDING)
-
- (void)Curl_resolver_wait_resolv(conn, &addr);
- connectport =
- (unsigned short)conn->port;
- if(!addr) {
- failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
- return CURLE_COULDNT_RESOLVE_PROXY;
- }
- }
- else {
-
- rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
- if(rc == CURLRESOLV_PENDING)
-
- (void)Curl_resolver_wait_resolv(conn, &addr);
- connectport = ftpc->newport;
- if(!addr) {
- failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
- return CURLE_FTP_CANT_GET_HOST;
- }
- }
- conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
- result = Curl_connecthost(conn, addr);
- if(result) {
- Curl_resolv_unlock(data, addr);
- if(ftpc->count1 == 0 && ftpcode == 229)
- return ftp_epsv_disable(conn);
- return result;
- }
-
- if(data->set.verbose)
-
- ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport);
- Curl_resolv_unlock(data, addr);
- Curl_safefree(conn->secondaryhostname);
- conn->secondary_port = ftpc->newport;
- conn->secondaryhostname = strdup(ftpc->newhost);
- if(!conn->secondaryhostname)
- return CURLE_OUT_OF_MEMORY;
- conn->bits.do_more = TRUE;
- state(conn, FTP_STOP);
- return result;
- }
- static CURLcode ftp_state_port_resp(struct connectdata *conn,
- int ftpcode)
- {
- struct Curl_easy *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- ftpport fcmd = (ftpport)ftpc->count1;
- CURLcode result = CURLE_OK;
-
- if(ftpcode / 100 != 2) {
-
- if(EPRT == fcmd) {
- infof(data, "disabling EPRT usage\n");
- conn->bits.ftp_use_eprt = FALSE;
- }
- fcmd++;
- if(fcmd == DONE) {
- failf(data, "Failed to do PORT");
- result = CURLE_FTP_PORT_FAILED;
- }
- else
-
- result = ftp_state_use_port(conn, fcmd);
- }
- else {
- infof(data, "Connect data stream actively\n");
- state(conn, FTP_STOP);
- result = ftp_dophase_done(conn, FALSE);
- }
- return result;
- }
- static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
- int ftpcode)
- {
- CURLcode result = CURLE_OK;
- struct Curl_easy *data = conn->data;
- struct FTP *ftp = data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- switch(ftpcode) {
- case 213:
- {
-
- int year, month, day, hour, minute, second;
- if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d",
- &year, &month, &day, &hour, &minute, &second)) {
-
- char timebuf[24];
- time_t secs = time(NULL);
- snprintf(timebuf, sizeof(timebuf),
- "%04d%02d%02d %02d:%02d:%02d GMT",
- year, month, day, hour, minute, second);
-
- data->info.filetime = curl_getdate(timebuf, &secs);
- }
- #ifdef CURL_FTP_HTTPSTYLE_HEAD
-
- if(data->set.opt_no_body &&
- ftpc->file &&
- data->set.get_filetime &&
- (data->info.filetime >= 0) ) {
- char headerbuf[128];
- time_t filetime = data->info.filetime;
- struct tm buffer;
- const struct tm *tm = &buffer;
- result = Curl_gmtime(filetime, &buffer);
- if(result)
- return result;
-
- snprintf(headerbuf, sizeof(headerbuf),
- "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
- Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
- tm->tm_mday,
- Curl_month[tm->tm_mon],
- tm->tm_year + 1900,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
- result = Curl_client_write(conn, CLIENTWRITE_BOTH, headerbuf, 0);
- if(result)
- return result;
- }
- #endif
- }
- break;
- default:
- infof(data, "unsupported MDTM reply format\n");
- break;
- case 550:
- failf(data, "Given file does not exist");
- result = CURLE_FTP_COULDNT_RETR_FILE;
- break;
- }
- if(data->set.timecondition) {
- if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
- switch(data->set.timecondition) {
- case CURL_TIMECOND_IFMODSINCE:
- default:
- if(data->info.filetime <= data->set.timevalue) {
- infof(data, "The requested document is not new enough\n");
- ftp->transfer = FTPTRANSFER_NONE;
- data->info.timecond = TRUE;
- state(conn, FTP_STOP);
- return CURLE_OK;
- }
- break;
- case CURL_TIMECOND_IFUNMODSINCE:
- if(data->info.filetime > data->set.timevalue) {
- infof(data, "The requested document is not old enough\n");
- ftp->transfer = FTPTRANSFER_NONE;
- data->info.timecond = TRUE;
- state(conn, FTP_STOP);
- return CURLE_OK;
- }
- break;
- }
- }
- else {
- infof(data, "Skipping time comparison\n");
- }
- }
- if(!result)
- result = ftp_state_type(conn);
- return result;
- }
- static CURLcode ftp_state_type_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
- {
- CURLcode result = CURLE_OK;
- struct Curl_easy *data = conn->data;
- if(ftpcode/100 != 2) {
-
- failf(data, "Couldn't set desired mode");
- return CURLE_FTP_COULDNT_SET_TYPE;
- }
- if(ftpcode != 200)
- infof(data, "Got a %03d response code instead of the assumed 200\n",
- ftpcode);
- if(instate == FTP_TYPE)
- result = ftp_state_size(conn);
- else if(instate == FTP_LIST_TYPE)
- result = ftp_state_list(conn);
- else if(instate == FTP_RETR_TYPE)
- result = ftp_state_retr_prequote(conn);
- else if(instate == FTP_STOR_TYPE)
- result = ftp_state_stor_prequote(conn);
- return result;
- }
- static CURLcode ftp_state_retr(struct connectdata *conn,
- curl_off_t filesize)
- {
- CURLcode result = CURLE_OK;
- struct Curl_easy *data = conn->data;
- struct FTP *ftp = data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
- failf(data, "Maximum file size exceeded");
- return CURLE_FILESIZE_EXCEEDED;
- }
- ftp->downloadsize = filesize;
- if(data->state.resume_from) {
-
- if(filesize == -1) {
- infof(data, "ftp server doesn't support SIZE\n");
-
- }
- else {
-
- if(data->state.resume_from< 0) {
-
- if(filesize < -data->state.resume_from) {
- failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
- ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
- data->state.resume_from, filesize);
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
-
- ftp->downloadsize = -data->state.resume_from;
-
- data->state.resume_from = filesize - ftp->downloadsize;
- }
- else {
- if(filesize < data->state.resume_from) {
- failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
- ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
- data->state.resume_from, filesize);
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
-
- ftp->downloadsize = filesize-data->state.resume_from;
- }
- }
- if(ftp->downloadsize == 0) {
-
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
- infof(data, "File already completely downloaded\n");
-
- ftp->transfer = FTPTRANSFER_NONE;
- state(conn, FTP_STOP);
- return CURLE_OK;
- }
-
- infof(data, "Instructs server to resume from offset %"
- CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
- PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
- data->state.resume_from);
- state(conn, FTP_RETR_REST);
- }
- else {
-
- PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
- state(conn, FTP_RETR);
- }
- return result;
- }
- static CURLcode ftp_state_size_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
- {
- CURLcode result = CURLE_OK;
- struct Curl_easy *data = conn->data;
- curl_off_t filesize = -1;
- char *buf = data->state.buffer;
-
- if(ftpcode == 213)
-
- (void)curlx_strtoofft(buf + 4, NULL, 0, &filesize);
- if(instate == FTP_SIZE) {
- #ifdef CURL_FTP_HTTPSTYLE_HEAD
- if(-1 != filesize) {
- char clbuf[128];
- snprintf(clbuf, sizeof(clbuf),
- "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
- result = Curl_client_write(conn, CLIENTWRITE_BOTH, clbuf, 0);
- if(result)
- return result;
- }
- #endif
- Curl_pgrsSetDownloadSize(data, filesize);
- result = ftp_state_rest(conn);
- }
- else if(instate == FTP_RETR_SIZE) {
- Curl_pgrsSetDownloadSize(data, filesize);
- result = ftp_state_retr(conn, filesize);
- }
- else if(instate == FTP_STOR_SIZE) {
- data->state.resume_from = filesize;
- result = ftp_state_ul_setup(conn, TRUE);
- }
- return result;
- }
- static CURLcode ftp_state_rest_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
- {
- CURLcode result = CURLE_OK;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- switch(instate) {
- case FTP_REST:
- default:
- #ifdef CURL_FTP_HTTPSTYLE_HEAD
- if(ftpcode == 350) {
- char buffer[24]= { "Accept-ranges: bytes\r\n" };
- result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
- if(result)
- return result;
- }
- #endif
- result = ftp_state_prepare_transfer(conn);
- break;
- case FTP_RETR_REST:
- if(ftpcode != 350) {
- failf(conn->data, "Couldn't use REST");
- result = CURLE_FTP_COULDNT_USE_REST;
- }
- else {
- PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
- state(conn, FTP_RETR);
- }
- break;
- }
- return result;
- }
- static CURLcode ftp_state_stor_resp(struct connectdata *conn,
- int ftpcode, ftpstate instate)
- {
- CURLcode result = CURLE_OK;
- struct Curl_easy *data = conn->data;
- if(ftpcode >= 400) {
- failf(data, "Failed FTP upload: %0d", ftpcode);
- state(conn, FTP_STOP);
-
- return CURLE_UPLOAD_FAILED;
- }
- conn->proto.ftpc.state_saved = instate;
-
- if(data->set.ftp_use_port) {
- bool connected;
- state(conn, FTP_STOP);
- result = AllowServerConnect(conn, &connected);
- if(result)
- return result;
- if(!connected) {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- infof(data, "Data conn was not available immediately\n");
- ftpc->wait_data_conn = TRUE;
- }
- return CURLE_OK;
- }
- return InitiateTransfer(conn);
- }
- static CURLcode ftp_state_get_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
- {
- CURLcode result = CURLE_OK;
- struct Curl_easy *data = conn->data;
- struct FTP *ftp = data->req.protop;
- if((ftpcode == 150) || (ftpcode == 125)) {
-
- curl_off_t size = -1;
-
- if((instate != FTP_LIST) &&
- !data->set.prefer_ascii &&
- (ftp->downloadsize < 1)) {
-
- char *bytes;
- char *buf = data->state.buffer;
- bytes = strstr(buf, " bytes");
- if(bytes) {
- long in = (long)(--bytes-buf);
-
- while(--in) {
-
- if('(' == *bytes)
- break;
-
- if(!ISDIGIT(*bytes)) {
- bytes = NULL;
- break;
- }
-
- bytes--;
- }
-
- if(bytes++) {
-
- (void)curlx_strtoofft(bytes, NULL, 0, &size);
- }
- }
- }
- else if(ftp->downloadsize > -1)
- size = ftp->downloadsize;
- if(size > data->req.maxdownload && data->req.maxdownload > 0)
- size = data->req.size = data->req.maxdownload;
- else if((instate != FTP_LIST) && (data->set.prefer_ascii))
- size = -1;
- infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
- data->req.maxdownload);
- if(instate != FTP_LIST)
- infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
- size);
-
- conn->proto.ftpc.state_saved = instate;
- conn->proto.ftpc.retr_size_saved = size;
- if(data->set.ftp_use_port) {
- bool connected;
- result = AllowServerConnect(conn, &connected);
- if(result)
- return result;
- if(!connected) {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- infof(data, "Data conn was not available immediately\n");
- state(conn, FTP_STOP);
- ftpc->wait_data_conn = TRUE;
- }
- }
- else
- return InitiateTransfer(conn);
- }
- else {
- if((instate == FTP_LIST) && (ftpcode == 450)) {
-
- ftp->transfer = FTPTRANSFER_NONE;
- state(conn, FTP_STOP);
- }
- else {
- failf(data, "RETR response: %03d", ftpcode);
- return instate == FTP_RETR && ftpcode == 550?
- CURLE_REMOTE_FILE_NOT_FOUND:
- CURLE_FTP_COULDNT_RETR_FILE;
- }
- }
- return result;
- }
- static CURLcode ftp_state_loggedin(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- if(conn->ssl[FIRSTSOCKET].use) {
-
- PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
- state(conn, FTP_PBSZ);
- }
- else {
- result = ftp_state_pwd(conn);
- }
- return result;
- }
- static CURLcode ftp_state_user_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
- {
- CURLcode result = CURLE_OK;
- struct Curl_easy *data = conn->data;
- struct FTP *ftp = data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- (void)instate;
-
- if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
-
- PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
- state(conn, FTP_PASS);
- }
- else if(ftpcode/100 == 2) {
-
- result = ftp_state_loggedin(conn);
- }
- else if(ftpcode == 332) {
- if(data->set.str[STRING_FTP_ACCOUNT]) {
- PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
- state(conn, FTP_ACCT);
- }
- else {
- failf(data, "ACCT requested but none available");
- result = CURLE_LOGIN_DENIED;
- }
- }
- else {
-
- if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
- !conn->data->state.ftp_trying_alternative) {
-
- PPSENDF(&conn->proto.ftpc.pp, "%s",
- conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
- conn->data->state.ftp_trying_alternative = TRUE;
- state(conn, FTP_USER);
- result = CURLE_OK;
- }
- else {
- failf(data, "Access denied: %03d", ftpcode);
- result = CURLE_LOGIN_DENIED;
- }
- }
- return result;
- }
- static CURLcode ftp_state_acct_resp(struct connectdata *conn,
- int ftpcode)
- {
- CURLcode result = CURLE_OK;
- struct Curl_easy *data = conn->data;
- if(ftpcode != 230) {
- failf(data, "ACCT rejected by server: %03d", ftpcode);
- result = CURLE_FTP_WEIRD_PASS_REPLY;
- }
- else
- result = ftp_state_loggedin(conn);
- return result;
- }
- static CURLcode ftp_statemach_act(struct connectdata *conn)
- {
- CURLcode result;
- curl_socket_t sock = conn->sock[FIRSTSOCKET];
- struct Curl_easy *data = conn->data;
- int ftpcode;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
- static const char ftpauth[][4] = { "SSL", "TLS" };
- size_t nread = 0;
- if(pp->sendleft)
- return Curl_pp_flushsend(pp);
- result = ftp_readresp(sock, pp, &ftpcode, &nread);
- if(result)
- return result;
- if(ftpcode) {
-
- switch(ftpc->state) {
- case FTP_WAIT220:
- if(ftpcode == 230)
-
- return ftp_state_user_resp(conn, ftpcode, ftpc->state);
- else if(ftpcode != 220) {
- failf(data, "Got a %03d ftp-server response when 220 was expected",
- ftpcode);
- return CURLE_WEIRD_SERVER_REPLY;
- }
-
- #ifdef HAVE_GSSAPI
- if(data->set.krb) {
-
- Curl_sec_request_prot(conn, "private");
-
- Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
- if(Curl_sec_login(conn))
- infof(data, "Logging in with password in cleartext!\n");
- else
- infof(data, "Authentication successful\n");
- }
- #endif
- if(data->set.use_ssl &&
- (!conn->ssl[FIRSTSOCKET].use ||
- (conn->bits.proxy_ssl_connected[FIRSTSOCKET] &&
- !conn->proxy_ssl[FIRSTSOCKET].use))) {
-
- ftpc->count3 = 0;
- switch(data->set.ftpsslauth) {
- case CURLFTPAUTH_DEFAULT:
- case CURLFTPAUTH_SSL:
- ftpc->count2 = 1;
- ftpc->count1 = 0;
- break;
- case CURLFTPAUTH_TLS:
- ftpc->count2 = -1;
- ftpc->count1 = 1;
- break;
- default:
- failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
- (int)data->set.ftpsslauth);
- return CURLE_UNKNOWN_OPTION;
- }
- PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
- state(conn, FTP_AUTH);
- }
- else {
- result = ftp_state_user(conn);
- if(result)
- return result;
- }
- break;
- case FTP_AUTH:
-
-
- if((ftpcode == 234) || (ftpcode == 334)) {
-
- result = Curl_ssl_connect(conn, FIRSTSOCKET);
- if(!result) {
- conn->bits.ftp_use_data_ssl = FALSE;
- result = ftp_state_user(conn);
- }
- }
- else if(ftpc->count3 < 1) {
- ftpc->count3++;
- ftpc->count1 += ftpc->count2;
- result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
-
- }
- else {
- if(data->set.use_ssl > CURLUSESSL_TRY)
-
- result = CURLE_USE_SSL_FAILED;
- else
-
- result = ftp_state_user(conn);
- }
- if(result)
- return result;
- break;
- case FTP_USER:
- case FTP_PASS:
- result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
- break;
- case FTP_ACCT:
- result = ftp_state_acct_resp(conn, ftpcode);
- break;
- case FTP_PBSZ:
- PPSENDF(&ftpc->pp, "PROT %c",
- data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
- state(conn, FTP_PROT);
- break;
- case FTP_PROT:
- if(ftpcode/100 == 2)
-
- conn->bits.ftp_use_data_ssl =
- (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
-
- else if(data->set.use_ssl > CURLUSESSL_CONTROL)
-
- return CURLE_USE_SSL_FAILED;
- if(data->set.ftp_ccc) {
-
- PPSENDF(&ftpc->pp, "%s", "CCC");
- state(conn, FTP_CCC);
- }
- else {
- result = ftp_state_pwd(conn);
- if(result)
- return result;
- }
- break;
- case FTP_CCC:
- if(ftpcode < 500) {
-
- result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
- if(result) {
- failf(conn->data, "Failed to clear the command channel (CCC)");
- return result;
- }
- }
-
- result = ftp_state_pwd(conn);
- if(result)
- return result;
- break;
- case FTP_PWD:
- if(ftpcode == 257) {
- char *ptr = &data->state.buffer[4];
- const size_t buf_size = data->set.buffer_size;
- char *dir;
- bool entry_extracted = FALSE;
- dir = malloc(nread + 1);
- if(!dir)
- return CURLE_OUT_OF_MEMORY;
-
-
- while(ptr < &data->state.buffer[buf_size]
- && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
- ptr++;
- if('\"' == *ptr) {
-
- char *store;
- ptr++;
- for(store = dir; *ptr;) {
- if('\"' == *ptr) {
- if('\"' == ptr[1]) {
-
- *store = ptr[1];
- ptr++;
- }
- else {
-
- entry_extracted = TRUE;
- break;
- }
- }
- else
- *store = *ptr;
- store++;
- ptr++;
- }
- *store = '\0';
- }
- if(entry_extracted) {
-
- if(!ftpc->server_os && dir[0] != '/') {
- result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
- if(result) {
- free(dir);
- return result;
- }
- Curl_safefree(ftpc->entrypath);
- ftpc->entrypath = dir;
- infof(data, "Entry path is '%s'\n", ftpc->entrypath);
-
- data->state.most_recent_ftp_entrypath = ftpc->entrypath;
- state(conn, FTP_SYST);
- break;
- }
- Curl_safefree(ftpc->entrypath);
- ftpc->entrypath = dir;
- infof(data, "Entry path is '%s'\n", ftpc->entrypath);
-
- data->state.most_recent_ftp_entrypath = ftpc->entrypath;
- }
- else {
-
- free(dir);
- infof(data, "Failed to figure out path\n");
- }
- }
- state(conn, FTP_STOP);
- DEBUGF(infof(data, "protocol connect phase DONE\n"));
- break;
- case FTP_SYST:
- if(ftpcode == 215) {
- char *ptr = &data->state.buffer[4];
- char *os;
- char *store;
- os = malloc(nread + 1);
- if(!os)
- return CURLE_OUT_OF_MEMORY;
-
- while(*ptr == ' ')
- ptr++;
- for(store = os; *ptr && *ptr != ' ';)
- *store++ = *ptr++;
- *store = '\0';
-
- if(strcasecompare(os, "OS/400")) {
-
- result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
- if(result) {
- free(os);
- return result;
- }
-
- Curl_safefree(ftpc->server_os);
- ftpc->server_os = os;
- state(conn, FTP_NAMEFMT);
- break;
- }
-
-
- Curl_safefree(ftpc->server_os);
- ftpc->server_os = os;
- }
- else {
-
- }
- state(conn, FTP_STOP);
- DEBUGF(infof(data, "protocol connect phase DONE\n"));
- break;
- case FTP_NAMEFMT:
- if(ftpcode == 250) {
-
- ftp_state_pwd(conn);
- break;
- }
- state(conn, FTP_STOP);
- DEBUGF(infof(data, "protocol connect phase DONE\n"));
- break;
- case FTP_QUOTE:
- case FTP_POSTQUOTE:
- case FTP_RETR_PREQUOTE:
- case FTP_STOR_PREQUOTE:
- if((ftpcode >= 400) && !ftpc->count2) {
-
- failf(conn->data, "QUOT command failed with %03d", ftpcode);
- return CURLE_QUOTE_ERROR;
- }
- result = ftp_state_quote(conn, FALSE, ftpc->state);
- if(result)
- return result;
- break;
- case FTP_CWD:
- if(ftpcode/100 != 2) {
-
- if(conn->data->set.ftp_create_missing_dirs &&
- ftpc->cwdcount && !ftpc->count2) {
-
- ftpc->count2++;
- PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->cwdcount - 1]);
- state(conn, FTP_MKD);
- }
- else {
-
- failf(data, "Server denied you to change to the given directory");
- ftpc->cwdfail = TRUE;
- return CURLE_REMOTE_ACCESS_DENIED;
- }
- }
- else {
-
- ftpc->count2 = 0;
- if(++ftpc->cwdcount <= ftpc->dirdepth) {
-
- PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]);
- }
- else {
- result = ftp_state_mdtm(conn);
- if(result)
- return result;
- }
- }
- break;
- case FTP_MKD:
- if((ftpcode/100 != 2) && !ftpc->count3--) {
-
- failf(data, "Failed to MKD dir: %03d", ftpcode);
- return CURLE_REMOTE_ACCESS_DENIED;
- }
- state(conn, FTP_CWD);
-
- PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]);
- break;
- case FTP_MDTM:
- result = ftp_state_mdtm_resp(conn, ftpcode);
- break;
- case FTP_TYPE:
- case FTP_LIST_TYPE:
- case FTP_RETR_TYPE:
- case FTP_STOR_TYPE:
- result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
- break;
- case FTP_SIZE:
- case FTP_RETR_SIZE:
- case FTP_STOR_SIZE:
- result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
- break;
- case FTP_REST:
- case FTP_RETR_REST:
- result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
- break;
- case FTP_PRET:
- if(ftpcode != 200) {
-
- failf(data, "PRET command not accepted: %03d", ftpcode);
- return CURLE_FTP_PRET_FAILED;
- }
- result = ftp_state_use_pasv(conn);
- break;
- case FTP_PASV:
- result = ftp_state_pasv_resp(conn, ftpcode);
- break;
- case FTP_PORT:
- result = ftp_state_port_resp(conn, ftpcode);
- break;
- case FTP_LIST:
- case FTP_RETR:
- result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
- break;
- case FTP_STOR:
- result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
- break;
- case FTP_QUIT:
-
- default:
-
- state(conn, FTP_STOP);
- break;
- }
- }
- return result;
- }
- static CURLcode ftp_multi_statemach(struct connectdata *conn,
- bool *done)
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
-
- *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
- return result;
- }
- static CURLcode ftp_block_statemach(struct connectdata *conn)
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
- CURLcode result = CURLE_OK;
- while(ftpc->state != FTP_STOP) {
- result = Curl_pp_statemach(pp, TRUE);
- if(result)
- break;
- }
- return result;
- }
- static CURLcode ftp_connect(struct connectdata *conn,
- bool *done)
- {
- CURLcode result;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
- *done = FALSE;
-
- connkeep(conn, "FTP default");
- pp->response_time = RESP_TIMEOUT;
- pp->statemach_act = ftp_statemach_act;
- pp->endofresp = ftp_endofresp;
- pp->conn = conn;
- if(conn->handler->flags & PROTOPT_SSL) {
-
- result = Curl_ssl_connect(conn, FIRSTSOCKET);
- if(result)
- return result;
- }
- Curl_pp_init(pp);
-
- state(conn, FTP_WAIT220);
- result = ftp_multi_statemach(conn, done);
- return result;
- }
- static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
- bool premature)
- {
- struct Curl_easy *data = conn->data;
- struct FTP *ftp = data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
- ssize_t nread;
- int ftpcode;
- CURLcode result = CURLE_OK;
- char *path = NULL;
- const char *path_to_use = data->state.path;
- if(!ftp)
- return CURLE_OK;
- switch(status) {
- case CURLE_BAD_DOWNLOAD_RESUME:
- case CURLE_FTP_WEIRD_PASV_REPLY:
- case CURLE_FTP_PORT_FAILED:
- case CURLE_FTP_ACCEPT_FAILED:
- case CURLE_FTP_ACCEPT_TIMEOUT:
- case CURLE_FTP_COULDNT_SET_TYPE:
- case CURLE_FTP_COULDNT_RETR_FILE:
- case CURLE_PARTIAL_FILE:
- case CURLE_UPLOAD_FAILED:
- case CURLE_REMOTE_ACCESS_DENIED:
- case CURLE_FILESIZE_EXCEEDED:
- case CURLE_REMOTE_FILE_NOT_FOUND:
- case CURLE_WRITE_ERROR:
-
-
- case CURLE_OK:
- if(!premature)
- break;
-
-
- default:
- ftpc->ctl_valid = FALSE;
- ftpc->cwdfail = TRUE;
- connclose(conn, "FTP ended with bad error code");
- result = status;
- break;
- }
-
- free(ftpc->prevpath);
- if(data->state.wildcardmatch) {
- if(data->set.chunk_end && ftpc->file) {
- Curl_set_in_callback(data, true);
- data->set.chunk_end(data->wildcard.customptr);
- Curl_set_in_callback(data, false);
- }
- ftpc->known_filesize = -1;
- }
- if(!result)
-
- result = Curl_urldecode(data, path_to_use, 0, &path, NULL, TRUE);
- if(result) {
-
- ftpc->ctl_valid = FALSE;
- connclose(conn, "FTP: out of memory!");
- ftpc->prevpath = NULL;
- }
- else {
- size_t flen = ftpc->file?strlen(ftpc->file):0;
- size_t dlen = strlen(path)-flen;
- if(!ftpc->cwdfail) {
- ftpc->prevmethod = data->set.ftp_filemethod;
- if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
- ftpc->prevpath = path;
- if(flen)
-
- ftpc->prevpath[dlen] = 0;
- }
- else {
-
- ftpc->prevpath = strdup("");
- free(path);
- }
- if(ftpc->prevpath)
- infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
- }
- else {
- ftpc->prevpath = NULL;
- free(path);
- }
- }
-
- freedirs(ftpc);
-
- #ifdef _WIN32_WCE
- shutdown(conn->sock[SECONDARYSOCKET], 2);
- #endif
- if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
- if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
-
- result = Curl_pp_sendf(pp, "%s", "ABOR");
- if(result) {
- failf(data, "Failure sending ABOR command: %s",
- curl_easy_strerror(result));
- ftpc->ctl_valid = FALSE;
- connclose(conn, "ABOR command failed");
- }
- }
- if(conn->ssl[SECONDARYSOCKET].use) {
-
- Curl_ssl_close(conn, SECONDARYSOCKET);
-
- }
- close_secondarysocket(conn);
- }
- if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
- pp->pending_resp && !premature) {
-
- long old_time = pp->response_time;
- pp->response_time = 60*1000;
- pp->response = Curl_now();
- result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
- pp->response_time = old_time;
- if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
- failf(data, "control connection looks dead");
- ftpc->ctl_valid = FALSE;
- connclose(conn, "Timeout or similar in FTP DONE operation");
- }
- if(result)
- return result;
- if(ftpc->dont_check && data->req.maxdownload > 0) {
-
- infof(data, "partial download completed, closing connection\n");
- connclose(conn, "Partial download with no ability to check");
- return result;
- }
- if(!ftpc->dont_check) {
-
- if((ftpcode != 226) && (ftpcode != 250)) {
- failf(data, "server did not report OK, got %d", ftpcode);
- result = CURLE_PARTIAL_FILE;
- }
- }
- }
- if(result || premature)
-
- ;
- else if(data->set.upload) {
- if((-1 != data->state.infilesize) &&
- (data->state.infilesize != *ftp->bytecountp) &&
- !data->set.crlf &&
- (ftp->transfer == FTPTRANSFER_BODY)) {
- failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
- " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
- *ftp->bytecountp, data->state.infilesize);
- result = CURLE_PARTIAL_FILE;
- }
- }
- else {
- if((-1 != data->req.size) &&
- (data->req.size != *ftp->bytecountp) &&
- #ifdef CURL_DO_LINEEND_CONV
-
- ((data->req.size + data->state.crlf_conversions) !=
- *ftp->bytecountp) &&
- #endif
- (data->req.maxdownload != *ftp->bytecountp)) {
- failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
- " bytes", *ftp->bytecountp);
- result = CURLE_PARTIAL_FILE;
- }
- else if(!ftpc->dont_check &&
- !*ftp->bytecountp &&
- (data->req.size>0)) {
- failf(data, "No data was received!");
- result = CURLE_FTP_COULDNT_RETR_FILE;
- }
- }
-
- ftp->transfer = FTPTRANSFER_BODY;
- ftpc->dont_check = FALSE;
-
- if(!status && !result && !premature && data->set.postquote)
- result = ftp_sendquote(conn, data->set.postquote);
- return result;
- }
- static
- CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
- {
- struct curl_slist *item;
- ssize_t nread;
- int ftpcode;
- CURLcode result;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
- item = quote;
- while(item) {
- if(item->data) {
- char *cmd = item->data;
- bool acceptfail = FALSE;
-
- if(cmd[0] == '*') {
- cmd++;
- acceptfail = TRUE;
- }
- PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
- pp->response = Curl_now();
- result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
- if(result)
- return result;
- if(!acceptfail && (ftpcode >= 400)) {
- failf(conn->data, "QUOT string not accepted: %s", cmd);
- return CURLE_QUOTE_ERROR;
- }
- }
- item = item->next;
- }
- return CURLE_OK;
- }
- static int ftp_need_type(struct connectdata *conn,
- bool ascii_wanted)
- {
- return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
- }
- static CURLcode ftp_nb_type(struct connectdata *conn,
- bool ascii, ftpstate newstate)
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result;
- char want = (char)(ascii?'A':'I');
- if(ftpc->transfertype == want) {
- state(conn, newstate);
- return ftp_state_type_resp(conn, 200, newstate);
- }
- PPSENDF(&ftpc->pp, "TYPE %c", want);
- state(conn, newstate);
-
- ftpc->transfertype = want;
- return CURLE_OK;
- }
- #ifndef CURL_DISABLE_VERBOSE_STRINGS
- static void
- ftp_pasv_verbose(struct connectdata *conn,
- Curl_addrinfo *ai,
- char *newhost,
- int port)
- {
- char buf[256];
- Curl_printable_address(ai, buf, sizeof(buf));
- infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
- }
- #endif
- static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
- {
- struct Curl_easy *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result = CURLE_OK;
- bool connected = FALSE;
- bool complete = FALSE;
-
- struct FTP *ftp = data->req.protop;
-
- if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
- if(Curl_connect_ongoing(conn)) {
-
- result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
- return result;
- }
- result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
-
- if(connected) {
- DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
- }
- else {
- if(result && (ftpc->count1 == 0)) {
- *completep = -1;
-
- return ftp_epsv_disable(conn);
- }
- return result;
- }
- }
- result = Curl_proxy_connect(conn, SECONDARYSOCKET);
- if(result)
- return result;
- if(CONNECT_SECONDARYSOCKET_PROXY_SSL())
- return result;
- if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
- Curl_connect_ongoing(conn))
- return result;
- if(ftpc->state) {
-
- result = ftp_multi_statemach(conn, &complete);
- *completep = (int)complete;
-
- if(result || (ftpc->wait_data_conn != TRUE))
- return result;
- if(ftpc->wait_data_conn)
-
- *completep = 0;
- }
- if(ftp->transfer <= FTPTRANSFER_INFO) {
-
- if(ftpc->wait_data_conn == TRUE) {
- bool serv_conned;
- result = ReceivedServerConnect(conn, &serv_conned);
- if(result)
- return result;
- if(serv_conned) {
-
- result = AcceptServerConnect(conn);
- ftpc->wait_data_conn = FALSE;
- if(!result)
- result = InitiateTransfer(conn);
- if(result)
- return result;
- *completep = 1;
- }
- }
- else if(data->set.upload) {
- result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
- if(result)
- return result;
- result = ftp_multi_statemach(conn, &complete);
- if(ftpc->wait_data_conn)
-
- *completep = 0;
- else
- *completep = (int)complete;
- }
- else {
-
- ftp->downloadsize = -1;
- result = Curl_range(conn);
- if(result == CURLE_OK && data->req.maxdownload >= 0) {
-
- ftpc->dont_check = TRUE;
- }
- if(result)
- ;
- else if(data->set.ftp_list_only || !ftpc->file) {
-
-
- if(ftp->transfer == FTPTRANSFER_BODY) {
- result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
- if(result)
- return result;
- }
-
- }
- else {
- result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
- if(result)
- return result;
- }
- result = ftp_multi_statemach(conn, &complete);
- *completep = (int)complete;
- }
- return result;
- }
- if(!result && (ftp->transfer != FTPTRANSFER_BODY))
-
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
- if(!ftpc->wait_data_conn) {
-
- *completep = 1;
- DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
- }
- return result;
- }
- static
- CURLcode ftp_perform(struct connectdata *conn,
- bool *connected,
- bool *dophase_done)
- {
-
- CURLcode result = CURLE_OK;
- DEBUGF(infof(conn->data, "DO phase starts\n"));
- if(conn->data->set.opt_no_body) {
-
- struct FTP *ftp = conn->data->req.protop;
- ftp->transfer = FTPTRANSFER_INFO;
- }
- *dophase_done = FALSE;
-
- result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
- if(result)
- return result;
-
- result = ftp_multi_statemach(conn, dophase_done);
- *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
- infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
- if(*dophase_done)
- DEBUGF(infof(conn->data, "DO phase is complete1\n"));
- return result;
- }
- static void wc_data_dtor(void *ptr)
- {
- struct ftp_wc *ftpwc = ptr;
- if(ftpwc && ftpwc->parser)
- Curl_ftp_parselist_data_free(&ftpwc->parser);
- free(ftpwc);
- }
- static CURLcode init_wc_data(struct connectdata *conn)
- {
- char *last_slash;
- char *path = conn->data->state.path;
- struct WildcardData *wildcard = &(conn->data->wildcard);
- CURLcode result = CURLE_OK;
- struct ftp_wc *ftpwc = NULL;
- last_slash = strrchr(conn->data->state.path, '/');
- if(last_slash) {
- last_slash++;
- if(last_slash[0] == '\0') {
- wildcard->state = CURLWC_CLEAN;
- result = ftp_parse_url_path(conn);
- return result;
- }
- wildcard->pattern = strdup(last_slash);
- if(!wildcard->pattern)
- return CURLE_OUT_OF_MEMORY;
- last_slash[0] = '\0';
- }
- else {
- if(path[0]) {
- wildcard->pattern = strdup(path);
- if(!wildcard->pattern)
- return CURLE_OUT_OF_MEMORY;
- path[0] = '\0';
- }
- else {
- wildcard->state = CURLWC_CLEAN;
- result = ftp_parse_url_path(conn);
- return result;
- }
- }
-
-
- ftpwc = calloc(1, sizeof(struct ftp_wc));
- if(!ftpwc) {
- result = CURLE_OUT_OF_MEMORY;
- goto fail;
- }
-
- ftpwc->parser = Curl_ftp_parselist_data_alloc();
- if(!ftpwc->parser) {
- result = CURLE_OUT_OF_MEMORY;
- goto fail;
- }
- wildcard->protdata = ftpwc;
- wildcard->dtor = wc_data_dtor;
-
- if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
- conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
-
- result = ftp_parse_url_path(conn);
- if(result) {
- goto fail;
- }
- wildcard->path = strdup(conn->data->state.path);
- if(!wildcard->path) {
- result = CURLE_OUT_OF_MEMORY;
- goto fail;
- }
-
- ftpwc->backup.write_function = conn->data->set.fwrite_func;
-
- conn->data->set.fwrite_func = Curl_ftp_parselist;
-
- ftpwc->backup.file_descriptor = conn->data->set.out;
-
- conn->data->set.out = conn;
- infof(conn->data, "Wildcard - Parsing started\n");
- return CURLE_OK;
- fail:
- if(ftpwc) {
- Curl_ftp_parselist_data_free(&ftpwc->parser);
- free(ftpwc);
- }
- Curl_safefree(wildcard->pattern);
- wildcard->dtor = ZERO_NULL;
- wildcard->protdata = NULL;
- return result;
- }
- static CURLcode wc_statemach(struct connectdata *conn)
- {
- struct WildcardData * const wildcard = &(conn->data->wildcard);
- CURLcode result = CURLE_OK;
- switch(wildcard->state) {
- case CURLWC_INIT:
- result = init_wc_data(conn);
- if(wildcard->state == CURLWC_CLEAN)
-
- break;
- wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
- break;
- case CURLWC_MATCHING: {
-
- struct ftp_wc *ftpwc = wildcard->protdata;
- conn->data->set.fwrite_func = ftpwc->backup.write_function;
- conn->data->set.out = ftpwc->backup.file_descriptor;
- ftpwc->backup.write_function = ZERO_NULL;
- ftpwc->backup.file_descriptor = NULL;
- wildcard->state = CURLWC_DOWNLOADING;
- if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
-
- wildcard->state = CURLWC_CLEAN;
- return wc_statemach(conn);
- }
- if(wildcard->filelist.size == 0) {
-
- wildcard->state = CURLWC_CLEAN;
- return CURLE_REMOTE_FILE_NOT_FOUND;
- }
- return wc_statemach(conn);
- }
- case CURLWC_DOWNLOADING: {
-
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
- char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
- if(!tmp_path)
- return CURLE_OUT_OF_MEMORY;
-
- Curl_safefree(conn->data->state.pathbuffer);
- conn->data->state.pathbuffer = tmp_path;
- conn->data->state.path = tmp_path;
- infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
- if(conn->data->set.chunk_bgn) {
- long userresponse;
- Curl_set_in_callback(conn->data, true);
- userresponse = conn->data->set.chunk_bgn(
- finfo, wildcard->customptr, (int)wildcard->filelist.size);
- Curl_set_in_callback(conn->data, false);
- switch(userresponse) {
- case CURL_CHUNK_BGN_FUNC_SKIP:
- infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
- finfo->filename);
- wildcard->state = CURLWC_SKIP;
- return wc_statemach(conn);
- case CURL_CHUNK_BGN_FUNC_FAIL:
- return CURLE_CHUNK_FAILED;
- }
- }
- if(finfo->filetype != CURLFILETYPE_FILE) {
- wildcard->state = CURLWC_SKIP;
- return wc_statemach(conn);
- }
- if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
- ftpc->known_filesize = finfo->size;
- result = ftp_parse_url_path(conn);
- if(result)
- return result;
-
- Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
- if(wildcard->filelist.size == 0) {
- wildcard->state = CURLWC_CLEAN;
-
- return CURLE_OK;
- }
- } break;
- case CURLWC_SKIP: {
- if(conn->data->set.chunk_end) {
- Curl_set_in_callback(conn->data, true);
- conn->data->set.chunk_end(conn->data->wildcard.customptr);
- Curl_set_in_callback(conn->data, false);
- }
- Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
- wildcard->state = (wildcard->filelist.size == 0) ?
- CURLWC_CLEAN : CURLWC_DOWNLOADING;
- return wc_statemach(conn);
- }
- case CURLWC_CLEAN: {
- struct ftp_wc *ftpwc = wildcard->protdata;
- result = CURLE_OK;
- if(ftpwc)
- result = Curl_ftp_parselist_geterror(ftpwc->parser);
- wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
- } break;
- case CURLWC_DONE:
- case CURLWC_ERROR:
- case CURLWC_CLEAR:
- if(wildcard->dtor)
- wildcard->dtor(wildcard->protdata);
- break;
- }
- return result;
- }
- static CURLcode ftp_do(struct connectdata *conn, bool *done)
- {
- CURLcode result = CURLE_OK;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- *done = FALSE;
- ftpc->wait_data_conn = FALSE;
- if(conn->data->state.wildcardmatch) {
- result = wc_statemach(conn);
- if(conn->data->wildcard.state == CURLWC_SKIP ||
- conn->data->wildcard.state == CURLWC_DONE) {
-
- return CURLE_OK;
- }
- if(result)
- return result;
- }
- else {
- result = ftp_parse_url_path(conn);
- if(result)
- return result;
- }
- result = ftp_regular_transfer(conn, done);
- return result;
- }
- CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
- {
- ssize_t bytes_written;
- #define SBUF_SIZE 1024
- char s[SBUF_SIZE];
- size_t write_len;
- char *sptr = s;
- CURLcode result = CURLE_OK;
- #ifdef HAVE_GSSAPI
- enum protection_level data_sec = conn->data_prot;
- #endif
- write_len = strlen(cmd);
- if(write_len > (sizeof(s) -3))
- return CURLE_BAD_FUNCTION_ARGUMENT;
- strcpy(&s[write_len], "\r\n");
- write_len += 2;
- bytes_written = 0;
- result = Curl_convert_to_network(conn->data, s, write_len);
-
- if(result)
- return result;
- for(;;) {
- #ifdef HAVE_GSSAPI
- conn->data_prot = PROT_CMD;
- #endif
- result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
- &bytes_written);
- #ifdef HAVE_GSSAPI
- DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
- conn->data_prot = data_sec;
- #endif
- if(result)
- break;
- if(conn->data->set.verbose)
- Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, (size_t)bytes_written);
- if(bytes_written != (ssize_t)write_len) {
- write_len -= bytes_written;
- sptr += bytes_written;
- }
- else
- break;
- }
- return result;
- }
- static CURLcode ftp_quit(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- if(conn->proto.ftpc.ctl_valid) {
- result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
- if(result) {
- failf(conn->data, "Failure sending QUIT command: %s",
- curl_easy_strerror(result));
- conn->proto.ftpc.ctl_valid = FALSE;
- connclose(conn, "QUIT command failed");
- state(conn, FTP_STOP);
- return result;
- }
- state(conn, FTP_QUIT);
- result = ftp_block_statemach(conn);
- }
- return result;
- }
- static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
-
- if(dead_connection)
- ftpc->ctl_valid = FALSE;
-
- (void)ftp_quit(conn);
- if(ftpc->entrypath) {
- struct Curl_easy *data = conn->data;
- if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
- data->state.most_recent_ftp_entrypath = NULL;
- }
- free(ftpc->entrypath);
- ftpc->entrypath = NULL;
- }
- freedirs(ftpc);
- free(ftpc->prevpath);
- ftpc->prevpath = NULL;
- free(ftpc->server_os);
- ftpc->server_os = NULL;
- Curl_pp_disconnect(pp);
- #ifdef HAVE_GSSAPI
- Curl_sec_end(conn);
- #endif
- return CURLE_OK;
- }
- static
- CURLcode ftp_parse_url_path(struct connectdata *conn)
- {
- struct Curl_easy *data = conn->data;
-
- struct FTP *ftp = data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- const char *slash_pos;
- const char *path_to_use = data->state.path;
- const char *cur_pos;
- const char *filename = NULL;
- cur_pos = path_to_use;
- ftpc->ctl_valid = FALSE;
- ftpc->cwdfail = FALSE;
- switch(data->set.ftp_filemethod) {
- case FTPFILE_NOCWD:
-
-
- if(path_to_use[0] &&
- (path_to_use[strlen(path_to_use) - 1] != '/') )
- filename = path_to_use;
-
- break;
- case FTPFILE_SINGLECWD:
-
- if(!path_to_use[0]) {
-
- ftpc->dirdepth = 0;
- break;
- }
- slash_pos = strrchr(cur_pos, '/');
- if(slash_pos || !*cur_pos) {
- size_t dirlen = slash_pos-cur_pos;
- CURLcode result;
- ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
- if(!ftpc->dirs)
- return CURLE_OUT_OF_MEMORY;
- if(!dirlen)
- dirlen++;
- result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/",
- slash_pos ? dirlen : 1,
- &ftpc->dirs[0], NULL,
- TRUE);
- if(result) {
- freedirs(ftpc);
- return result;
- }
- ftpc->dirdepth = 1;
- filename = slash_pos ? slash_pos + 1 : cur_pos;
- }
- else
- filename = cur_pos;
- break;
- default:
- case FTPFILE_MULTICWD:
- ftpc->dirdepth = 0;
- ftpc->diralloc = 5;
- ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
- if(!ftpc->dirs)
- return CURLE_OUT_OF_MEMORY;
-
- if(!strcmp(path_to_use, "/")) {
- cur_pos++;
- ftpc->dirs[0] = strdup("/");
- ftpc->dirdepth++;
- }
- else {
-
- while((slash_pos = strchr(cur_pos, '/')) != NULL) {
-
- ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
- (ftpc->dirdepth == 0))?1:0;
-
- if(slash_pos-cur_pos) {
-
- size_t len = slash_pos - cur_pos + absolute_dir;
- CURLcode result =
- Curl_urldecode(conn->data, cur_pos - absolute_dir, len,
- &ftpc->dirs[ftpc->dirdepth], NULL,
- TRUE);
- if(result) {
- freedirs(ftpc);
- return result;
- }
- }
- else {
- cur_pos = slash_pos + 1;
- if(!ftpc->dirdepth) {
-
- ftpc->dirs[ftpc->dirdepth] = strdup("/");
- if(!ftpc->dirs[ftpc->dirdepth++]) {
- failf(data, "no memory");
- freedirs(ftpc);
- return CURLE_OUT_OF_MEMORY;
- }
- }
- continue;
- }
- cur_pos = slash_pos + 1;
- if(++ftpc->dirdepth >= ftpc->diralloc) {
-
- char **bigger;
- ftpc->diralloc *= 2;
- bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
- if(!bigger) {
- freedirs(ftpc);
- return CURLE_OUT_OF_MEMORY;
- }
- ftpc->dirs = bigger;
- }
- }
- }
- filename = cur_pos;
- break;
- }
- if(filename && *filename) {
- CURLcode result =
- Curl_urldecode(conn->data, filename, 0, &ftpc->file, NULL, TRUE);
- if(result) {
- freedirs(ftpc);
- return result;
- }
- }
- else
- ftpc->file = NULL;
- if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
-
- failf(data, "Uploading to a URL without a file name!");
- return CURLE_URL_MALFORMAT;
- }
- ftpc->cwddone = FALSE;
- if(ftpc->prevpath) {
-
- size_t dlen;
- char *path;
- CURLcode result =
- Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, TRUE);
- if(result) {
- freedirs(ftpc);
- return result;
- }
- dlen -= ftpc->file?strlen(ftpc->file):0;
- if((dlen == strlen(ftpc->prevpath)) &&
- !strncmp(path, ftpc->prevpath, dlen) &&
- (ftpc->prevmethod == data->set.ftp_filemethod)) {
- infof(data, "Request has same path as previous transfer\n");
- ftpc->cwddone = TRUE;
- }
- free(path);
- }
- return CURLE_OK;
- }
- static CURLcode ftp_dophase_done(struct connectdata *conn,
- bool connected)
- {
- struct FTP *ftp = conn->data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- if(connected) {
- int completed;
- CURLcode result = ftp_do_more(conn, &completed);
- if(result) {
- close_secondarysocket(conn);
- return result;
- }
- }
- if(ftp->transfer != FTPTRANSFER_BODY)
-
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
- else if(!connected)
-
- conn->bits.do_more = TRUE;
- ftpc->ctl_valid = TRUE;
- return CURLE_OK;
- }
- static CURLcode ftp_doing(struct connectdata *conn,
- bool *dophase_done)
- {
- CURLcode result = ftp_multi_statemach(conn, dophase_done);
- if(result)
- DEBUGF(infof(conn->data, "DO phase failed\n"));
- else if(*dophase_done) {
- result = ftp_dophase_done(conn, FALSE );
- DEBUGF(infof(conn->data, "DO phase is complete2\n"));
- }
- return result;
- }
- static
- CURLcode ftp_regular_transfer(struct connectdata *conn,
- bool *dophase_done)
- {
- CURLcode result = CURLE_OK;
- bool connected = FALSE;
- struct Curl_easy *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- data->req.size = -1;
- Curl_pgrsSetUploadCounter(data, 0);
- Curl_pgrsSetDownloadCounter(data, 0);
- Curl_pgrsSetUploadSize(data, -1);
- Curl_pgrsSetDownloadSize(data, -1);
- ftpc->ctl_valid = TRUE;
- result = ftp_perform(conn,
- &connected,
- dophase_done);
- if(!result) {
- if(!*dophase_done)
-
- return CURLE_OK;
- result = ftp_dophase_done(conn, connected);
- if(result)
- return result;
- }
- else
- freedirs(ftpc);
- return result;
- }
- static CURLcode ftp_setup_connection(struct connectdata *conn)
- {
- struct Curl_easy *data = conn->data;
- char *type;
- struct FTP *ftp;
- conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
- if(NULL == ftp)
- return CURLE_OUT_OF_MEMORY;
- data->state.path++;
- data->state.slash_removed = TRUE;
-
- type = strstr(data->state.path, ";type=");
- if(!type)
- type = strstr(conn->host.rawalloc, ";type=");
- if(type) {
- char command;
- *type = 0;
- command = Curl_raw_toupper(type[6]);
- conn->bits.type_set = TRUE;
- switch(command) {
- case 'A':
- data->set.prefer_ascii = TRUE;
- break;
- case 'D':
- data->set.ftp_list_only = TRUE;
- break;
- case 'I':
- default:
-
- data->set.prefer_ascii = FALSE;
- break;
- }
- }
-
- ftp->bytecountp = &conn->data->req.bytecount;
- ftp->transfer = FTPTRANSFER_BODY;
- ftp->downloadsize = 0;
-
- ftp->user = conn->user;
- ftp->passwd = conn->passwd;
- if(isBadFtpString(ftp->user))
- return CURLE_URL_MALFORMAT;
- if(isBadFtpString(ftp->passwd))
- return CURLE_URL_MALFORMAT;
- conn->proto.ftpc.known_filesize = -1;
- return CURLE_OK;
- }
- #endif
|