nanoftp.c 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118
  1. /*
  2. * nanoftp.c: basic FTP client support
  3. *
  4. * Reference: RFC 959
  5. */
  6. #ifdef TESTING
  7. #define STANDALONE
  8. #define HAVE_STDLIB_H
  9. #define HAVE_UNISTD_H
  10. #define HAVE_SYS_SOCKET_H
  11. #define HAVE_NETINET_IN_H
  12. #define HAVE_NETDB_H
  13. #define HAVE_SYS_TIME_H
  14. #endif /* TESTING */
  15. #define IN_LIBXML
  16. #include "libxml.h"
  17. #ifdef LIBXML_FTP_ENABLED
  18. #include <string.h>
  19. #ifdef HAVE_STDLIB_H
  20. #include <stdlib.h>
  21. #endif
  22. #ifdef HAVE_UNISTD_H
  23. #include <unistd.h>
  24. #endif
  25. #ifdef HAVE_SYS_SOCKET_H
  26. #include <sys/socket.h>
  27. #endif
  28. #ifdef HAVE_NETINET_IN_H
  29. #include <netinet/in.h>
  30. #endif
  31. #ifdef HAVE_ARPA_INET_H
  32. #include <arpa/inet.h>
  33. #endif
  34. #ifdef HAVE_NETDB_H
  35. #include <netdb.h>
  36. #endif
  37. #ifdef HAVE_FCNTL_H
  38. #include <fcntl.h>
  39. #endif
  40. #ifdef HAVE_ERRNO_H
  41. #include <errno.h>
  42. #endif
  43. #ifdef HAVE_SYS_TIME_H
  44. #include <sys/time.h>
  45. #endif
  46. #ifdef HAVE_SYS_SELECT_H
  47. #include <sys/select.h>
  48. #endif
  49. #ifdef HAVE_SYS_SOCKET_H
  50. #include <sys/socket.h>
  51. #endif
  52. #ifdef HAVE_SYS_TYPES_H
  53. #include <sys/types.h>
  54. #endif
  55. #ifdef HAVE_STRINGS_H
  56. #include <strings.h>
  57. #endif
  58. #include <libxml/xmlmemory.h>
  59. #include <libxml/parser.h>
  60. #include <libxml/xmlerror.h>
  61. #include <libxml/uri.h>
  62. #include <libxml/nanoftp.h>
  63. #include <libxml/globals.h>
  64. /* #define DEBUG_FTP 1 */
  65. #ifdef STANDALONE
  66. #ifndef DEBUG_FTP
  67. #define DEBUG_FTP 1
  68. #endif
  69. #endif
  70. #if defined(_WIN32) && !defined(__CYGWIN__)
  71. #include <wsockcompat.h>
  72. #endif
  73. /**
  74. * A couple portability macros
  75. */
  76. #ifndef _WINSOCKAPI_
  77. #if !defined(__BEOS__) || defined(__HAIKU__)
  78. #define closesocket(s) close(s)
  79. #endif
  80. #endif
  81. #ifdef __BEOS__
  82. #ifndef PF_INET
  83. #define PF_INET AF_INET
  84. #endif
  85. #endif
  86. #ifdef _AIX
  87. #ifdef HAVE_BROKEN_SS_FAMILY
  88. #define ss_family __ss_family
  89. #endif
  90. #endif
  91. #ifndef XML_SOCKLEN_T
  92. #define XML_SOCKLEN_T unsigned int
  93. #endif
  94. #define FTP_COMMAND_OK 200
  95. #define FTP_SYNTAX_ERROR 500
  96. #define FTP_GET_PASSWD 331
  97. #define FTP_BUF_SIZE 1024
  98. #define XML_NANO_MAX_URLBUF 4096
  99. typedef struct xmlNanoFTPCtxt {
  100. char *protocol; /* the protocol name */
  101. char *hostname; /* the host name */
  102. int port; /* the port */
  103. char *path; /* the path within the URL */
  104. char *user; /* user string */
  105. char *passwd; /* passwd string */
  106. #ifdef SUPPORT_IP6
  107. struct sockaddr_storage ftpAddr; /* this is large enough to hold IPv6 address*/
  108. #else
  109. struct sockaddr_in ftpAddr; /* the socket address struct */
  110. #endif
  111. int passive; /* currently we support only passive !!! */
  112. SOCKET controlFd; /* the file descriptor for the control socket */
  113. SOCKET dataFd; /* the file descriptor for the data socket */
  114. int state; /* WRITE / READ / CLOSED */
  115. int returnValue; /* the protocol return value */
  116. /* buffer for data received from the control connection */
  117. char controlBuf[FTP_BUF_SIZE + 1];
  118. int controlBufIndex;
  119. int controlBufUsed;
  120. int controlBufAnswer;
  121. } xmlNanoFTPCtxt, *xmlNanoFTPCtxtPtr;
  122. static int initialized = 0;
  123. static char *proxy = NULL; /* the proxy name if any */
  124. static int proxyPort = 0; /* the proxy port if any */
  125. static char *proxyUser = NULL; /* user for proxy authentication */
  126. static char *proxyPasswd = NULL;/* passwd for proxy authentication */
  127. static int proxyType = 0; /* uses TYPE or a@b ? */
  128. #ifdef SUPPORT_IP6
  129. static
  130. int have_ipv6(void) {
  131. int s;
  132. s = socket (AF_INET6, SOCK_STREAM, 0);
  133. if (s != -1) {
  134. close (s);
  135. return (1);
  136. }
  137. return (0);
  138. }
  139. #endif
  140. /**
  141. * xmlFTPErrMemory:
  142. * @extra: extra information
  143. *
  144. * Handle an out of memory condition
  145. */
  146. static void
  147. xmlFTPErrMemory(const char *extra)
  148. {
  149. __xmlSimpleError(XML_FROM_FTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
  150. }
  151. /**
  152. * xmlNanoFTPInit:
  153. *
  154. * Initialize the FTP protocol layer.
  155. * Currently it just checks for proxy information,
  156. * and get the hostname
  157. */
  158. void
  159. xmlNanoFTPInit(void) {
  160. const char *env;
  161. #ifdef _WINSOCKAPI_
  162. WSADATA wsaData;
  163. #endif
  164. if (initialized)
  165. return;
  166. #ifdef _WINSOCKAPI_
  167. if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
  168. return;
  169. #endif
  170. proxyPort = 21;
  171. env = getenv("no_proxy");
  172. if (env && ((env[0] == '*' ) && (env[1] == 0)))
  173. return;
  174. env = getenv("ftp_proxy");
  175. if (env != NULL) {
  176. xmlNanoFTPScanProxy(env);
  177. } else {
  178. env = getenv("FTP_PROXY");
  179. if (env != NULL) {
  180. xmlNanoFTPScanProxy(env);
  181. }
  182. }
  183. env = getenv("ftp_proxy_user");
  184. if (env != NULL) {
  185. proxyUser = xmlMemStrdup(env);
  186. }
  187. env = getenv("ftp_proxy_password");
  188. if (env != NULL) {
  189. proxyPasswd = xmlMemStrdup(env);
  190. }
  191. initialized = 1;
  192. }
  193. /**
  194. * xmlNanoFTPCleanup:
  195. *
  196. * Cleanup the FTP protocol layer. This cleanup proxy information.
  197. */
  198. void
  199. xmlNanoFTPCleanup(void) {
  200. if (proxy != NULL) {
  201. xmlFree(proxy);
  202. proxy = NULL;
  203. }
  204. if (proxyUser != NULL) {
  205. xmlFree(proxyUser);
  206. proxyUser = NULL;
  207. }
  208. if (proxyPasswd != NULL) {
  209. xmlFree(proxyPasswd);
  210. proxyPasswd = NULL;
  211. }
  212. #ifdef _WINSOCKAPI_
  213. if (initialized)
  214. WSACleanup();
  215. #endif
  216. initialized = 0;
  217. }
  218. /**
  219. * xmlNanoFTPProxy:
  220. * @host: the proxy host name
  221. * @port: the proxy port
  222. * @user: the proxy user name
  223. * @passwd: the proxy password
  224. * @type: the type of proxy 1 for using SITE, 2 for USER a@b
  225. *
  226. * Setup the FTP proxy information.
  227. * This can also be done by using ftp_proxy ftp_proxy_user and
  228. * ftp_proxy_password environment variables.
  229. */
  230. void
  231. xmlNanoFTPProxy(const char *host, int port, const char *user,
  232. const char *passwd, int type) {
  233. if (proxy != NULL) {
  234. xmlFree(proxy);
  235. proxy = NULL;
  236. }
  237. if (proxyUser != NULL) {
  238. xmlFree(proxyUser);
  239. proxyUser = NULL;
  240. }
  241. if (proxyPasswd != NULL) {
  242. xmlFree(proxyPasswd);
  243. proxyPasswd = NULL;
  244. }
  245. if (host)
  246. proxy = xmlMemStrdup(host);
  247. if (user)
  248. proxyUser = xmlMemStrdup(user);
  249. if (passwd)
  250. proxyPasswd = xmlMemStrdup(passwd);
  251. proxyPort = port;
  252. proxyType = type;
  253. }
  254. /**
  255. * xmlNanoFTPScanURL:
  256. * @ctx: an FTP context
  257. * @URL: The URL used to initialize the context
  258. *
  259. * (Re)Initialize an FTP context by parsing the URL and finding
  260. * the protocol host port and path it indicates.
  261. */
  262. static void
  263. xmlNanoFTPScanURL(void *ctx, const char *URL) {
  264. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  265. xmlURIPtr uri;
  266. /*
  267. * Clear any existing data from the context
  268. */
  269. if (ctxt->protocol != NULL) {
  270. xmlFree(ctxt->protocol);
  271. ctxt->protocol = NULL;
  272. }
  273. if (ctxt->hostname != NULL) {
  274. xmlFree(ctxt->hostname);
  275. ctxt->hostname = NULL;
  276. }
  277. if (ctxt->path != NULL) {
  278. xmlFree(ctxt->path);
  279. ctxt->path = NULL;
  280. }
  281. if (URL == NULL) return;
  282. uri = xmlParseURIRaw(URL, 1);
  283. if (uri == NULL)
  284. return;
  285. if ((uri->scheme == NULL) || (uri->server == NULL)) {
  286. xmlFreeURI(uri);
  287. return;
  288. }
  289. ctxt->protocol = xmlMemStrdup(uri->scheme);
  290. ctxt->hostname = xmlMemStrdup(uri->server);
  291. if (uri->path != NULL)
  292. ctxt->path = xmlMemStrdup(uri->path);
  293. else
  294. ctxt->path = xmlMemStrdup("/");
  295. if (uri->port != 0)
  296. ctxt->port = uri->port;
  297. if (uri->user != NULL) {
  298. char *cptr;
  299. if ((cptr=strchr(uri->user, ':')) == NULL)
  300. ctxt->user = xmlMemStrdup(uri->user);
  301. else {
  302. ctxt->user = (char *)xmlStrndup((xmlChar *)uri->user,
  303. (cptr - uri->user));
  304. ctxt->passwd = xmlMemStrdup(cptr+1);
  305. }
  306. }
  307. xmlFreeURI(uri);
  308. }
  309. /**
  310. * xmlNanoFTPUpdateURL:
  311. * @ctx: an FTP context
  312. * @URL: The URL used to update the context
  313. *
  314. * Update an FTP context by parsing the URL and finding
  315. * new path it indicates. If there is an error in the
  316. * protocol, hostname, port or other information, the
  317. * error is raised. It indicates a new connection has to
  318. * be established.
  319. *
  320. * Returns 0 if Ok, -1 in case of error (other host).
  321. */
  322. int
  323. xmlNanoFTPUpdateURL(void *ctx, const char *URL) {
  324. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  325. xmlURIPtr uri;
  326. if (URL == NULL)
  327. return(-1);
  328. if (ctxt == NULL)
  329. return(-1);
  330. if (ctxt->protocol == NULL)
  331. return(-1);
  332. if (ctxt->hostname == NULL)
  333. return(-1);
  334. uri = xmlParseURIRaw(URL, 1);
  335. if (uri == NULL)
  336. return(-1);
  337. if ((uri->scheme == NULL) || (uri->server == NULL)) {
  338. xmlFreeURI(uri);
  339. return(-1);
  340. }
  341. if ((strcmp(ctxt->protocol, uri->scheme)) ||
  342. (strcmp(ctxt->hostname, uri->server)) ||
  343. ((uri->port != 0) && (ctxt->port != uri->port))) {
  344. xmlFreeURI(uri);
  345. return(-1);
  346. }
  347. if (uri->port != 0)
  348. ctxt->port = uri->port;
  349. if (ctxt->path != NULL) {
  350. xmlFree(ctxt->path);
  351. ctxt->path = NULL;
  352. }
  353. if (uri->path == NULL)
  354. ctxt->path = xmlMemStrdup("/");
  355. else
  356. ctxt->path = xmlMemStrdup(uri->path);
  357. xmlFreeURI(uri);
  358. return(0);
  359. }
  360. /**
  361. * xmlNanoFTPScanProxy:
  362. * @URL: The proxy URL used to initialize the proxy context
  363. *
  364. * (Re)Initialize the FTP Proxy context by parsing the URL and finding
  365. * the protocol host port it indicates.
  366. * Should be like ftp://myproxy/ or ftp://myproxy:3128/
  367. * A NULL URL cleans up proxy information.
  368. */
  369. void
  370. xmlNanoFTPScanProxy(const char *URL) {
  371. xmlURIPtr uri;
  372. if (proxy != NULL) {
  373. xmlFree(proxy);
  374. proxy = NULL;
  375. }
  376. proxyPort = 0;
  377. #ifdef DEBUG_FTP
  378. if (URL == NULL)
  379. xmlGenericError(xmlGenericErrorContext,
  380. "Removing FTP proxy info\n");
  381. else
  382. xmlGenericError(xmlGenericErrorContext,
  383. "Using FTP proxy %s\n", URL);
  384. #endif
  385. if (URL == NULL) return;
  386. uri = xmlParseURIRaw(URL, 1);
  387. if ((uri == NULL) || (uri->scheme == NULL) ||
  388. (strcmp(uri->scheme, "ftp")) || (uri->server == NULL)) {
  389. __xmlIOErr(XML_FROM_FTP, XML_FTP_URL_SYNTAX, "Syntax Error\n");
  390. if (uri != NULL)
  391. xmlFreeURI(uri);
  392. return;
  393. }
  394. proxy = xmlMemStrdup(uri->server);
  395. if (uri->port != 0)
  396. proxyPort = uri->port;
  397. xmlFreeURI(uri);
  398. }
  399. /**
  400. * xmlNanoFTPNewCtxt:
  401. * @URL: The URL used to initialize the context
  402. *
  403. * Allocate and initialize a new FTP context.
  404. *
  405. * Returns an FTP context or NULL in case of error.
  406. */
  407. void*
  408. xmlNanoFTPNewCtxt(const char *URL) {
  409. xmlNanoFTPCtxtPtr ret;
  410. char *unescaped;
  411. ret = (xmlNanoFTPCtxtPtr) xmlMalloc(sizeof(xmlNanoFTPCtxt));
  412. if (ret == NULL) {
  413. xmlFTPErrMemory("allocating FTP context");
  414. return(NULL);
  415. }
  416. memset(ret, 0, sizeof(xmlNanoFTPCtxt));
  417. ret->port = 21;
  418. ret->passive = 1;
  419. ret->returnValue = 0;
  420. ret->controlBufIndex = 0;
  421. ret->controlBufUsed = 0;
  422. ret->controlFd = INVALID_SOCKET;
  423. unescaped = xmlURIUnescapeString(URL, 0, NULL);
  424. if (unescaped != NULL) {
  425. xmlNanoFTPScanURL(ret, unescaped);
  426. xmlFree(unescaped);
  427. } else if (URL != NULL)
  428. xmlNanoFTPScanURL(ret, URL);
  429. return(ret);
  430. }
  431. /**
  432. * xmlNanoFTPFreeCtxt:
  433. * @ctx: an FTP context
  434. *
  435. * Frees the context after closing the connection.
  436. */
  437. void
  438. xmlNanoFTPFreeCtxt(void * ctx) {
  439. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  440. if (ctxt == NULL) return;
  441. if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
  442. if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
  443. if (ctxt->path != NULL) xmlFree(ctxt->path);
  444. if (ctxt->user != NULL) xmlFree(ctxt->user);
  445. if (ctxt->passwd != NULL) xmlFree(ctxt->passwd);
  446. ctxt->passive = 1;
  447. if (ctxt->controlFd != INVALID_SOCKET) closesocket(ctxt->controlFd);
  448. ctxt->controlFd = INVALID_SOCKET;
  449. ctxt->controlBufIndex = -1;
  450. ctxt->controlBufUsed = -1;
  451. xmlFree(ctxt);
  452. }
  453. /**
  454. * xmlNanoFTPParseResponse:
  455. * @buf: the buffer containing the response
  456. * @len: the buffer length
  457. *
  458. * Parsing of the server answer, we just extract the code.
  459. *
  460. * returns 0 for errors
  461. * +XXX for last line of response
  462. * -XXX for response to be continued
  463. */
  464. static int
  465. xmlNanoFTPParseResponse(char *buf, int len) {
  466. int val = 0;
  467. if (len < 3) return(-1);
  468. if ((*buf >= '0') && (*buf <= '9'))
  469. val = val * 10 + (*buf - '0');
  470. else
  471. return(0);
  472. buf++;
  473. if ((*buf >= '0') && (*buf <= '9'))
  474. val = val * 10 + (*buf - '0');
  475. else
  476. return(0);
  477. buf++;
  478. if ((*buf >= '0') && (*buf <= '9'))
  479. val = val * 10 + (*buf - '0');
  480. else
  481. return(0);
  482. buf++;
  483. if (*buf == '-')
  484. return(-val);
  485. return(val);
  486. }
  487. /**
  488. * xmlNanoFTPGetMore:
  489. * @ctx: an FTP context
  490. *
  491. * Read more information from the FTP control connection
  492. * Returns the number of bytes read, < 0 indicates an error
  493. */
  494. static int
  495. xmlNanoFTPGetMore(void *ctx) {
  496. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  497. int len;
  498. int size;
  499. if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
  500. if ((ctxt->controlBufIndex < 0) || (ctxt->controlBufIndex > FTP_BUF_SIZE)) {
  501. #ifdef DEBUG_FTP
  502. xmlGenericError(xmlGenericErrorContext,
  503. "xmlNanoFTPGetMore : controlBufIndex = %d\n",
  504. ctxt->controlBufIndex);
  505. #endif
  506. return(-1);
  507. }
  508. if ((ctxt->controlBufUsed < 0) || (ctxt->controlBufUsed > FTP_BUF_SIZE)) {
  509. #ifdef DEBUG_FTP
  510. xmlGenericError(xmlGenericErrorContext,
  511. "xmlNanoFTPGetMore : controlBufUsed = %d\n",
  512. ctxt->controlBufUsed);
  513. #endif
  514. return(-1);
  515. }
  516. if (ctxt->controlBufIndex > ctxt->controlBufUsed) {
  517. #ifdef DEBUG_FTP
  518. xmlGenericError(xmlGenericErrorContext,
  519. "xmlNanoFTPGetMore : controlBufIndex > controlBufUsed %d > %d\n",
  520. ctxt->controlBufIndex, ctxt->controlBufUsed);
  521. #endif
  522. return(-1);
  523. }
  524. /*
  525. * First pack the control buffer
  526. */
  527. if (ctxt->controlBufIndex > 0) {
  528. memmove(&ctxt->controlBuf[0], &ctxt->controlBuf[ctxt->controlBufIndex],
  529. ctxt->controlBufUsed - ctxt->controlBufIndex);
  530. ctxt->controlBufUsed -= ctxt->controlBufIndex;
  531. ctxt->controlBufIndex = 0;
  532. }
  533. size = FTP_BUF_SIZE - ctxt->controlBufUsed;
  534. if (size == 0) {
  535. #ifdef DEBUG_FTP
  536. xmlGenericError(xmlGenericErrorContext,
  537. "xmlNanoFTPGetMore : buffer full %d \n", ctxt->controlBufUsed);
  538. #endif
  539. return(0);
  540. }
  541. /*
  542. * Read the amount left on the control connection
  543. */
  544. if ((len = recv(ctxt->controlFd, &ctxt->controlBuf[ctxt->controlBufIndex],
  545. size, 0)) < 0) {
  546. __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
  547. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  548. ctxt->controlFd = INVALID_SOCKET;
  549. return(-1);
  550. }
  551. #ifdef DEBUG_FTP
  552. xmlGenericError(xmlGenericErrorContext,
  553. "xmlNanoFTPGetMore : read %d [%d - %d]\n", len,
  554. ctxt->controlBufUsed, ctxt->controlBufUsed + len);
  555. #endif
  556. ctxt->controlBufUsed += len;
  557. ctxt->controlBuf[ctxt->controlBufUsed] = 0;
  558. return(len);
  559. }
  560. /**
  561. * xmlNanoFTPReadResponse:
  562. * @ctx: an FTP context
  563. *
  564. * Read the response from the FTP server after a command.
  565. * Returns the code number
  566. */
  567. static int
  568. xmlNanoFTPReadResponse(void *ctx) {
  569. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  570. char *ptr, *end;
  571. int len;
  572. int res = -1, cur = -1;
  573. if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
  574. get_more:
  575. /*
  576. * Assumes everything up to controlBuf[controlBufIndex] has been read
  577. * and analyzed.
  578. */
  579. len = xmlNanoFTPGetMore(ctx);
  580. if (len < 0) {
  581. return(-1);
  582. }
  583. if ((ctxt->controlBufUsed == 0) && (len == 0)) {
  584. return(-1);
  585. }
  586. ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
  587. end = &ctxt->controlBuf[ctxt->controlBufUsed];
  588. #ifdef DEBUG_FTP
  589. xmlGenericError(xmlGenericErrorContext,
  590. "\n<<<\n%s\n--\n", ptr);
  591. #endif
  592. while (ptr < end) {
  593. cur = xmlNanoFTPParseResponse(ptr, end - ptr);
  594. if (cur > 0) {
  595. /*
  596. * Successfully scanned the control code, scratch
  597. * till the end of the line, but keep the index to be
  598. * able to analyze the result if needed.
  599. */
  600. res = cur;
  601. ptr += 3;
  602. ctxt->controlBufAnswer = ptr - ctxt->controlBuf;
  603. while ((ptr < end) && (*ptr != '\n')) ptr++;
  604. if (*ptr == '\n') ptr++;
  605. if (*ptr == '\r') ptr++;
  606. break;
  607. }
  608. while ((ptr < end) && (*ptr != '\n')) ptr++;
  609. if (ptr >= end) {
  610. ctxt->controlBufIndex = ctxt->controlBufUsed;
  611. goto get_more;
  612. }
  613. if (*ptr != '\r') ptr++;
  614. }
  615. if (res < 0) goto get_more;
  616. ctxt->controlBufIndex = ptr - ctxt->controlBuf;
  617. #ifdef DEBUG_FTP
  618. ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
  619. xmlGenericError(xmlGenericErrorContext, "\n---\n%s\n--\n", ptr);
  620. #endif
  621. #ifdef DEBUG_FTP
  622. xmlGenericError(xmlGenericErrorContext, "Got %d\n", res);
  623. #endif
  624. return(res / 100);
  625. }
  626. /**
  627. * xmlNanoFTPGetResponse:
  628. * @ctx: an FTP context
  629. *
  630. * Get the response from the FTP server after a command.
  631. * Returns the code number
  632. */
  633. int
  634. xmlNanoFTPGetResponse(void *ctx) {
  635. int res;
  636. res = xmlNanoFTPReadResponse(ctx);
  637. return(res);
  638. }
  639. /**
  640. * xmlNanoFTPCheckResponse:
  641. * @ctx: an FTP context
  642. *
  643. * Check if there is a response from the FTP server after a command.
  644. * Returns the code number, or 0
  645. */
  646. int
  647. xmlNanoFTPCheckResponse(void *ctx) {
  648. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  649. fd_set rfd;
  650. struct timeval tv;
  651. if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
  652. tv.tv_sec = 0;
  653. tv.tv_usec = 0;
  654. FD_ZERO(&rfd);
  655. FD_SET(ctxt->controlFd, &rfd);
  656. switch(select(ctxt->controlFd + 1, &rfd, NULL, NULL, &tv)) {
  657. case 0:
  658. return(0);
  659. case -1:
  660. __xmlIOErr(XML_FROM_FTP, 0, "select");
  661. return(-1);
  662. }
  663. return(xmlNanoFTPReadResponse(ctx));
  664. }
  665. /**
  666. * Send the user authentication
  667. */
  668. static int
  669. xmlNanoFTPSendUser(void *ctx) {
  670. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  671. char buf[200];
  672. int len;
  673. int res;
  674. if (ctxt->user == NULL)
  675. snprintf(buf, sizeof(buf), "USER anonymous\r\n");
  676. else
  677. snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user);
  678. buf[sizeof(buf) - 1] = 0;
  679. len = strlen(buf);
  680. #ifdef DEBUG_FTP
  681. xmlGenericError(xmlGenericErrorContext, "%s", buf);
  682. #endif
  683. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  684. if (res < 0) {
  685. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  686. return(res);
  687. }
  688. return(0);
  689. }
  690. /**
  691. * Send the password authentication
  692. */
  693. static int
  694. xmlNanoFTPSendPasswd(void *ctx) {
  695. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  696. char buf[200];
  697. int len;
  698. int res;
  699. if (ctxt->passwd == NULL)
  700. snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
  701. else
  702. snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
  703. buf[sizeof(buf) - 1] = 0;
  704. len = strlen(buf);
  705. #ifdef DEBUG_FTP
  706. xmlGenericError(xmlGenericErrorContext, "%s", buf);
  707. #endif
  708. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  709. if (res < 0) {
  710. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  711. return(res);
  712. }
  713. return(0);
  714. }
  715. /**
  716. * xmlNanoFTPQuit:
  717. * @ctx: an FTP context
  718. *
  719. * Send a QUIT command to the server
  720. *
  721. * Returns -1 in case of error, 0 otherwise
  722. */
  723. int
  724. xmlNanoFTPQuit(void *ctx) {
  725. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  726. char buf[200];
  727. int len, res;
  728. if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
  729. snprintf(buf, sizeof(buf), "QUIT\r\n");
  730. len = strlen(buf);
  731. #ifdef DEBUG_FTP
  732. xmlGenericError(xmlGenericErrorContext, "%s", buf); /* Just to be consistent, even though we know it can't have a % in it */
  733. #endif
  734. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  735. if (res < 0) {
  736. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  737. return(res);
  738. }
  739. return(0);
  740. }
  741. /**
  742. * xmlNanoFTPConnect:
  743. * @ctx: an FTP context
  744. *
  745. * Tries to open a control connection
  746. *
  747. * Returns -1 in case of error, 0 otherwise
  748. */
  749. int
  750. xmlNanoFTPConnect(void *ctx) {
  751. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  752. struct hostent *hp;
  753. int port;
  754. int res;
  755. int addrlen = sizeof (struct sockaddr_in);
  756. if (ctxt == NULL)
  757. return(-1);
  758. if (ctxt->hostname == NULL)
  759. return(-1);
  760. /*
  761. * do the blocking DNS query.
  762. */
  763. if (proxy) {
  764. port = proxyPort;
  765. } else {
  766. port = ctxt->port;
  767. }
  768. if (port == 0)
  769. port = 21;
  770. memset (&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr));
  771. #ifdef SUPPORT_IP6
  772. if (have_ipv6 ()) {
  773. struct addrinfo hints, *tmp, *result;
  774. result = NULL;
  775. memset (&hints, 0, sizeof(hints));
  776. hints.ai_socktype = SOCK_STREAM;
  777. if (proxy) {
  778. if (getaddrinfo (proxy, NULL, &hints, &result) != 0) {
  779. __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
  780. return (-1);
  781. }
  782. }
  783. else
  784. if (getaddrinfo (ctxt->hostname, NULL, &hints, &result) != 0) {
  785. __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
  786. return (-1);
  787. }
  788. for (tmp = result; tmp; tmp = tmp->ai_next)
  789. if (tmp->ai_family == AF_INET || tmp->ai_family == AF_INET6)
  790. break;
  791. if (!tmp) {
  792. if (result)
  793. freeaddrinfo (result);
  794. __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
  795. return (-1);
  796. }
  797. if ((size_t)tmp->ai_addrlen > sizeof(ctxt->ftpAddr)) {
  798. if (result)
  799. freeaddrinfo (result);
  800. __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch");
  801. return (-1);
  802. }
  803. if (tmp->ai_family == AF_INET6) {
  804. memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
  805. ((struct sockaddr_in6 *) &ctxt->ftpAddr)->sin6_port = htons (port);
  806. ctxt->controlFd = socket (AF_INET6, SOCK_STREAM, 0);
  807. }
  808. else {
  809. memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
  810. ((struct sockaddr_in *) &ctxt->ftpAddr)->sin_port = htons (port);
  811. ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
  812. }
  813. addrlen = tmp->ai_addrlen;
  814. freeaddrinfo (result);
  815. }
  816. else
  817. #endif
  818. {
  819. if (proxy)
  820. hp = gethostbyname (GETHOSTBYNAME_ARG_CAST proxy);
  821. else
  822. hp = gethostbyname (GETHOSTBYNAME_ARG_CAST ctxt->hostname);
  823. if (hp == NULL) {
  824. __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname failed");
  825. return (-1);
  826. }
  827. if ((unsigned int) hp->h_length >
  828. sizeof(((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr)) {
  829. __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch");
  830. return (-1);
  831. }
  832. /*
  833. * Prepare the socket
  834. */
  835. ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_family = AF_INET;
  836. memcpy (&((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr,
  837. hp->h_addr_list[0], hp->h_length);
  838. ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_port =
  839. (unsigned short)htons ((unsigned short)port);
  840. ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
  841. addrlen = sizeof (struct sockaddr_in);
  842. }
  843. if (ctxt->controlFd == INVALID_SOCKET) {
  844. __xmlIOErr(XML_FROM_FTP, 0, "socket failed");
  845. return(-1);
  846. }
  847. /*
  848. * Do the connect.
  849. */
  850. if (connect(ctxt->controlFd, (struct sockaddr *) &ctxt->ftpAddr,
  851. addrlen) < 0) {
  852. __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a connection");
  853. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  854. ctxt->controlFd = INVALID_SOCKET;
  855. return(-1);
  856. }
  857. /*
  858. * Wait for the HELLO from the server.
  859. */
  860. res = xmlNanoFTPGetResponse(ctxt);
  861. if (res != 2) {
  862. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  863. ctxt->controlFd = INVALID_SOCKET;
  864. return(-1);
  865. }
  866. /*
  867. * State diagram for the login operation on the FTP server
  868. *
  869. * Reference: RFC 959
  870. *
  871. * 1
  872. * +---+ USER +---+------------->+---+
  873. * | B |---------->| W | 2 ---->| E |
  874. * +---+ +---+------ | -->+---+
  875. * | | | | |
  876. * 3 | | 4,5 | | |
  877. * -------------- ----- | | |
  878. * | | | | |
  879. * | | | | |
  880. * | --------- |
  881. * | 1| | | |
  882. * V | | | |
  883. * +---+ PASS +---+ 2 | ------>+---+
  884. * | |---------->| W |------------->| S |
  885. * +---+ +---+ ---------->+---+
  886. * | | | | |
  887. * 3 | |4,5| | |
  888. * -------------- -------- |
  889. * | | | | |
  890. * | | | | |
  891. * | -----------
  892. * | 1,3| | | |
  893. * V | 2| | |
  894. * +---+ ACCT +---+-- | ----->+---+
  895. * | |---------->| W | 4,5 -------->| F |
  896. * +---+ +---+------------->+---+
  897. *
  898. * Of course in case of using a proxy this get really nasty and is not
  899. * standardized at all :-(
  900. */
  901. if (proxy) {
  902. int len;
  903. char buf[400];
  904. if (proxyUser != NULL) {
  905. /*
  906. * We need proxy auth
  907. */
  908. snprintf(buf, sizeof(buf), "USER %s\r\n", proxyUser);
  909. buf[sizeof(buf) - 1] = 0;
  910. len = strlen(buf);
  911. #ifdef DEBUG_FTP
  912. xmlGenericError(xmlGenericErrorContext, "%s", buf);
  913. #endif
  914. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  915. if (res < 0) {
  916. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  917. closesocket(ctxt->controlFd);
  918. ctxt->controlFd = INVALID_SOCKET;
  919. return(res);
  920. }
  921. res = xmlNanoFTPGetResponse(ctxt);
  922. switch (res) {
  923. case 2:
  924. if (proxyPasswd == NULL)
  925. break;
  926. /* Falls through. */
  927. case 3:
  928. if (proxyPasswd != NULL)
  929. snprintf(buf, sizeof(buf), "PASS %s\r\n", proxyPasswd);
  930. else
  931. snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
  932. buf[sizeof(buf) - 1] = 0;
  933. len = strlen(buf);
  934. #ifdef DEBUG_FTP
  935. xmlGenericError(xmlGenericErrorContext, "%s", buf);
  936. #endif
  937. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  938. if (res < 0) {
  939. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  940. closesocket(ctxt->controlFd);
  941. ctxt->controlFd = INVALID_SOCKET;
  942. return(res);
  943. }
  944. res = xmlNanoFTPGetResponse(ctxt);
  945. if (res > 3) {
  946. closesocket(ctxt->controlFd);
  947. ctxt->controlFd = INVALID_SOCKET;
  948. return(-1);
  949. }
  950. break;
  951. case 1:
  952. break;
  953. case 4:
  954. case 5:
  955. case -1:
  956. default:
  957. closesocket(ctxt->controlFd);
  958. ctxt->controlFd = INVALID_SOCKET;
  959. return(-1);
  960. }
  961. }
  962. /*
  963. * We assume we don't need more authentication to the proxy
  964. * and that it succeeded :-\
  965. */
  966. switch (proxyType) {
  967. case 0:
  968. /* we will try in sequence */
  969. case 1:
  970. /* Using SITE command */
  971. snprintf(buf, sizeof(buf), "SITE %s\r\n", ctxt->hostname);
  972. buf[sizeof(buf) - 1] = 0;
  973. len = strlen(buf);
  974. #ifdef DEBUG_FTP
  975. xmlGenericError(xmlGenericErrorContext, "%s", buf);
  976. #endif
  977. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  978. if (res < 0) {
  979. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  980. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  981. ctxt->controlFd = INVALID_SOCKET;
  982. return(res);
  983. }
  984. res = xmlNanoFTPGetResponse(ctxt);
  985. if (res == 2) {
  986. /* we assume it worked :-\ 1 is error for SITE command */
  987. proxyType = 1;
  988. break;
  989. }
  990. if (proxyType == 1) {
  991. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  992. ctxt->controlFd = INVALID_SOCKET;
  993. return(-1);
  994. }
  995. /* Falls through. */
  996. case 2:
  997. /* USER user@host command */
  998. if (ctxt->user == NULL)
  999. snprintf(buf, sizeof(buf), "USER anonymous@%s\r\n",
  1000. ctxt->hostname);
  1001. else
  1002. snprintf(buf, sizeof(buf), "USER %s@%s\r\n",
  1003. ctxt->user, ctxt->hostname);
  1004. buf[sizeof(buf) - 1] = 0;
  1005. len = strlen(buf);
  1006. #ifdef DEBUG_FTP
  1007. xmlGenericError(xmlGenericErrorContext, "%s", buf);
  1008. #endif
  1009. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  1010. if (res < 0) {
  1011. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  1012. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  1013. ctxt->controlFd = INVALID_SOCKET;
  1014. return(res);
  1015. }
  1016. res = xmlNanoFTPGetResponse(ctxt);
  1017. if ((res == 1) || (res == 2)) {
  1018. /* we assume it worked :-\ */
  1019. proxyType = 2;
  1020. return(0);
  1021. }
  1022. if (ctxt->passwd == NULL)
  1023. snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
  1024. else
  1025. snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
  1026. buf[sizeof(buf) - 1] = 0;
  1027. len = strlen(buf);
  1028. #ifdef DEBUG_FTP
  1029. xmlGenericError(xmlGenericErrorContext, "%s", buf);
  1030. #endif
  1031. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  1032. if (res < 0) {
  1033. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  1034. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  1035. ctxt->controlFd = INVALID_SOCKET;
  1036. return(res);
  1037. }
  1038. res = xmlNanoFTPGetResponse(ctxt);
  1039. if ((res == 1) || (res == 2)) {
  1040. /* we assume it worked :-\ */
  1041. proxyType = 2;
  1042. return(0);
  1043. }
  1044. if (proxyType == 2) {
  1045. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  1046. ctxt->controlFd = INVALID_SOCKET;
  1047. return(-1);
  1048. }
  1049. /* Falls through. */
  1050. case 3:
  1051. /*
  1052. * If you need support for other Proxy authentication scheme
  1053. * send the code or at least the sequence in use.
  1054. */
  1055. default:
  1056. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  1057. ctxt->controlFd = INVALID_SOCKET;
  1058. return(-1);
  1059. }
  1060. }
  1061. /*
  1062. * Non-proxy handling.
  1063. */
  1064. res = xmlNanoFTPSendUser(ctxt);
  1065. if (res < 0) {
  1066. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  1067. ctxt->controlFd = INVALID_SOCKET;
  1068. return(-1);
  1069. }
  1070. res = xmlNanoFTPGetResponse(ctxt);
  1071. switch (res) {
  1072. case 2:
  1073. return(0);
  1074. case 3:
  1075. break;
  1076. case 1:
  1077. case 4:
  1078. case 5:
  1079. case -1:
  1080. default:
  1081. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  1082. ctxt->controlFd = INVALID_SOCKET;
  1083. return(-1);
  1084. }
  1085. res = xmlNanoFTPSendPasswd(ctxt);
  1086. if (res < 0) {
  1087. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  1088. ctxt->controlFd = INVALID_SOCKET;
  1089. return(-1);
  1090. }
  1091. res = xmlNanoFTPGetResponse(ctxt);
  1092. switch (res) {
  1093. case 2:
  1094. break;
  1095. case 3:
  1096. __xmlIOErr(XML_FROM_FTP, XML_FTP_ACCNT,
  1097. "FTP server asking for ACCNT on anonymous\n");
  1098. /* Falls through. */
  1099. case 1:
  1100. case 4:
  1101. case 5:
  1102. case -1:
  1103. default:
  1104. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  1105. ctxt->controlFd = INVALID_SOCKET;
  1106. return(-1);
  1107. }
  1108. return(0);
  1109. }
  1110. /**
  1111. * xmlNanoFTPConnectTo:
  1112. * @server: an FTP server name
  1113. * @port: the port (use 21 if 0)
  1114. *
  1115. * Tries to open a control connection to the given server/port
  1116. *
  1117. * Returns an fTP context or NULL if it failed
  1118. */
  1119. void*
  1120. xmlNanoFTPConnectTo(const char *server, int port) {
  1121. xmlNanoFTPCtxtPtr ctxt;
  1122. int res;
  1123. xmlNanoFTPInit();
  1124. if (server == NULL)
  1125. return(NULL);
  1126. if (port <= 0)
  1127. return(NULL);
  1128. ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(NULL);
  1129. if (ctxt == NULL)
  1130. return(NULL);
  1131. ctxt->hostname = xmlMemStrdup(server);
  1132. if (ctxt->hostname == NULL) {
  1133. xmlNanoFTPFreeCtxt(ctxt);
  1134. return(NULL);
  1135. }
  1136. ctxt->port = port;
  1137. res = xmlNanoFTPConnect(ctxt);
  1138. if (res < 0) {
  1139. xmlNanoFTPFreeCtxt(ctxt);
  1140. return(NULL);
  1141. }
  1142. return(ctxt);
  1143. }
  1144. /**
  1145. * xmlNanoFTPCwd:
  1146. * @ctx: an FTP context
  1147. * @directory: a directory on the server
  1148. *
  1149. * Tries to change the remote directory
  1150. *
  1151. * Returns -1 in case of error, 1 if CWD worked, 0 if it failed
  1152. */
  1153. int
  1154. xmlNanoFTPCwd(void *ctx, const char *directory) {
  1155. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  1156. char buf[400];
  1157. int len;
  1158. int res;
  1159. if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
  1160. if (directory == NULL) return 0;
  1161. /*
  1162. * Expected response code for CWD:
  1163. *
  1164. * CWD
  1165. * 250
  1166. * 500, 501, 502, 421, 530, 550
  1167. */
  1168. snprintf(buf, sizeof(buf), "CWD %s\r\n", directory);
  1169. buf[sizeof(buf) - 1] = 0;
  1170. len = strlen(buf);
  1171. #ifdef DEBUG_FTP
  1172. xmlGenericError(xmlGenericErrorContext, "%s", buf);
  1173. #endif
  1174. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  1175. if (res < 0) {
  1176. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  1177. return(res);
  1178. }
  1179. res = xmlNanoFTPGetResponse(ctxt);
  1180. if (res == 4) {
  1181. return(-1);
  1182. }
  1183. if (res == 2) return(1);
  1184. if (res == 5) {
  1185. return(0);
  1186. }
  1187. return(0);
  1188. }
  1189. /**
  1190. * xmlNanoFTPDele:
  1191. * @ctx: an FTP context
  1192. * @file: a file or directory on the server
  1193. *
  1194. * Tries to delete an item (file or directory) from server
  1195. *
  1196. * Returns -1 in case of error, 1 if DELE worked, 0 if it failed
  1197. */
  1198. int
  1199. xmlNanoFTPDele(void *ctx, const char *file) {
  1200. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  1201. char buf[400];
  1202. int len;
  1203. int res;
  1204. if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET) ||
  1205. (file == NULL)) return(-1);
  1206. /*
  1207. * Expected response code for DELE:
  1208. *
  1209. * DELE
  1210. * 250
  1211. * 450, 550
  1212. * 500, 501, 502, 421, 530
  1213. */
  1214. snprintf(buf, sizeof(buf), "DELE %s\r\n", file);
  1215. buf[sizeof(buf) - 1] = 0;
  1216. len = strlen(buf);
  1217. #ifdef DEBUG_FTP
  1218. xmlGenericError(xmlGenericErrorContext, "%s", buf);
  1219. #endif
  1220. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  1221. if (res < 0) {
  1222. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  1223. return(res);
  1224. }
  1225. res = xmlNanoFTPGetResponse(ctxt);
  1226. if (res == 4) {
  1227. return(-1);
  1228. }
  1229. if (res == 2) return(1);
  1230. if (res == 5) {
  1231. return(0);
  1232. }
  1233. return(0);
  1234. }
  1235. /**
  1236. * xmlNanoFTPGetConnection:
  1237. * @ctx: an FTP context
  1238. *
  1239. * Try to open a data connection to the server. Currently only
  1240. * passive mode is supported.
  1241. *
  1242. * Returns -1 in case of error, 0 otherwise
  1243. */
  1244. SOCKET
  1245. xmlNanoFTPGetConnection(void *ctx) {
  1246. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  1247. char buf[200], *cur;
  1248. int len, i;
  1249. int res;
  1250. unsigned char ad[6], *adp, *portp;
  1251. unsigned int temp[6];
  1252. #ifdef SUPPORT_IP6
  1253. struct sockaddr_storage dataAddr;
  1254. #else
  1255. struct sockaddr_in dataAddr;
  1256. #endif
  1257. XML_SOCKLEN_T dataAddrLen;
  1258. if (ctxt == NULL) return INVALID_SOCKET;
  1259. memset (&dataAddr, 0, sizeof(dataAddr));
  1260. #ifdef SUPPORT_IP6
  1261. if ((ctxt->ftpAddr).ss_family == AF_INET6) {
  1262. ctxt->dataFd = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
  1263. ((struct sockaddr_in6 *)&dataAddr)->sin6_family = AF_INET6;
  1264. dataAddrLen = sizeof(struct sockaddr_in6);
  1265. } else
  1266. #endif
  1267. {
  1268. ctxt->dataFd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
  1269. ((struct sockaddr_in *)&dataAddr)->sin_family = AF_INET;
  1270. dataAddrLen = sizeof (struct sockaddr_in);
  1271. }
  1272. if (ctxt->dataFd == INVALID_SOCKET) {
  1273. __xmlIOErr(XML_FROM_FTP, 0, "socket failed");
  1274. return INVALID_SOCKET;
  1275. }
  1276. if (ctxt->passive) {
  1277. #ifdef SUPPORT_IP6
  1278. if ((ctxt->ftpAddr).ss_family == AF_INET6)
  1279. snprintf (buf, sizeof(buf), "EPSV\r\n");
  1280. else
  1281. #endif
  1282. snprintf (buf, sizeof(buf), "PASV\r\n");
  1283. len = strlen (buf);
  1284. #ifdef DEBUG_FTP
  1285. xmlGenericError(xmlGenericErrorContext, "%s", buf);
  1286. #endif
  1287. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  1288. if (res < 0) {
  1289. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  1290. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1291. return INVALID_SOCKET;
  1292. }
  1293. res = xmlNanoFTPReadResponse(ctx);
  1294. if (res != 2) {
  1295. if (res == 5) {
  1296. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1297. return INVALID_SOCKET;
  1298. } else {
  1299. /*
  1300. * retry with an active connection
  1301. */
  1302. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1303. ctxt->passive = 0;
  1304. }
  1305. }
  1306. cur = &ctxt->controlBuf[ctxt->controlBufAnswer];
  1307. while (((*cur < '0') || (*cur > '9')) && *cur != '\0') cur++;
  1308. #ifdef SUPPORT_IP6
  1309. if ((ctxt->ftpAddr).ss_family == AF_INET6) {
  1310. if (sscanf (cur, "%u", &temp[0]) != 1) {
  1311. __xmlIOErr(XML_FROM_FTP, XML_FTP_EPSV_ANSWER,
  1312. "Invalid answer to EPSV\n");
  1313. if (ctxt->dataFd != INVALID_SOCKET) {
  1314. closesocket (ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1315. }
  1316. return INVALID_SOCKET;
  1317. }
  1318. memcpy (&((struct sockaddr_in6 *)&dataAddr)->sin6_addr, &((struct sockaddr_in6 *)&ctxt->ftpAddr)->sin6_addr, sizeof(struct in6_addr));
  1319. ((struct sockaddr_in6 *)&dataAddr)->sin6_port = htons (temp[0]);
  1320. }
  1321. else
  1322. #endif
  1323. {
  1324. if (sscanf (cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2],
  1325. &temp[3], &temp[4], &temp[5]) != 6) {
  1326. __xmlIOErr(XML_FROM_FTP, XML_FTP_PASV_ANSWER,
  1327. "Invalid answer to PASV\n");
  1328. if (ctxt->dataFd != INVALID_SOCKET) {
  1329. closesocket (ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1330. }
  1331. return INVALID_SOCKET;
  1332. }
  1333. for (i=0; i<6; i++) ad[i] = (unsigned char) (temp[i] & 0xff);
  1334. memcpy (&((struct sockaddr_in *)&dataAddr)->sin_addr, &ad[0], 4);
  1335. memcpy (&((struct sockaddr_in *)&dataAddr)->sin_port, &ad[4], 2);
  1336. }
  1337. if (connect(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
  1338. __xmlIOErr(XML_FROM_FTP, 0, "Failed to create a data connection");
  1339. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1340. return INVALID_SOCKET;
  1341. }
  1342. } else {
  1343. getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
  1344. #ifdef SUPPORT_IP6
  1345. if ((ctxt->ftpAddr).ss_family == AF_INET6)
  1346. ((struct sockaddr_in6 *)&dataAddr)->sin6_port = 0;
  1347. else
  1348. #endif
  1349. ((struct sockaddr_in *)&dataAddr)->sin_port = 0;
  1350. if (bind(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
  1351. __xmlIOErr(XML_FROM_FTP, 0, "bind failed");
  1352. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1353. return INVALID_SOCKET;
  1354. }
  1355. getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
  1356. if (listen(ctxt->dataFd, 1) < 0) {
  1357. __xmlIOErr(XML_FROM_FTP, 0, "listen failed");
  1358. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1359. return INVALID_SOCKET;
  1360. }
  1361. #ifdef SUPPORT_IP6
  1362. if ((ctxt->ftpAddr).ss_family == AF_INET6) {
  1363. char buf6[INET6_ADDRSTRLEN];
  1364. inet_ntop (AF_INET6, &((struct sockaddr_in6 *)&dataAddr)->sin6_addr,
  1365. buf6, INET6_ADDRSTRLEN);
  1366. adp = (unsigned char *) buf6;
  1367. portp = (unsigned char *) &((struct sockaddr_in6 *)&dataAddr)->sin6_port;
  1368. snprintf (buf, sizeof(buf), "EPRT |2|%s|%s|\r\n", adp, portp);
  1369. } else
  1370. #endif
  1371. {
  1372. adp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_addr;
  1373. portp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_port;
  1374. snprintf (buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n",
  1375. adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff,
  1376. portp[0] & 0xff, portp[1] & 0xff);
  1377. }
  1378. buf[sizeof(buf) - 1] = 0;
  1379. len = strlen(buf);
  1380. #ifdef DEBUG_FTP
  1381. xmlGenericError(xmlGenericErrorContext, "%s", buf);
  1382. #endif
  1383. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  1384. if (res < 0) {
  1385. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  1386. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1387. return INVALID_SOCKET;
  1388. }
  1389. res = xmlNanoFTPGetResponse(ctxt);
  1390. if (res != 2) {
  1391. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1392. return INVALID_SOCKET;
  1393. }
  1394. }
  1395. return(ctxt->dataFd);
  1396. }
  1397. /**
  1398. * xmlNanoFTPCloseConnection:
  1399. * @ctx: an FTP context
  1400. *
  1401. * Close the data connection from the server
  1402. *
  1403. * Returns -1 in case of error, 0 otherwise
  1404. */
  1405. int
  1406. xmlNanoFTPCloseConnection(void *ctx) {
  1407. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  1408. int res;
  1409. fd_set rfd, efd;
  1410. struct timeval tv;
  1411. if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
  1412. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1413. tv.tv_sec = 15;
  1414. tv.tv_usec = 0;
  1415. FD_ZERO(&rfd);
  1416. FD_SET(ctxt->controlFd, &rfd);
  1417. FD_ZERO(&efd);
  1418. FD_SET(ctxt->controlFd, &efd);
  1419. res = select(ctxt->controlFd + 1, &rfd, NULL, &efd, &tv);
  1420. if (res < 0) {
  1421. #ifdef DEBUG_FTP
  1422. perror("select");
  1423. #endif
  1424. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  1425. return(-1);
  1426. }
  1427. if (res == 0) {
  1428. #ifdef DEBUG_FTP
  1429. xmlGenericError(xmlGenericErrorContext,
  1430. "xmlNanoFTPCloseConnection: timeout\n");
  1431. #endif
  1432. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  1433. } else {
  1434. res = xmlNanoFTPGetResponse(ctxt);
  1435. if (res != 2) {
  1436. closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
  1437. return(-1);
  1438. }
  1439. }
  1440. return(0);
  1441. }
  1442. /**
  1443. * xmlNanoFTPParseList:
  1444. * @list: some data listing received from the server
  1445. * @callback: the user callback
  1446. * @userData: the user callback data
  1447. *
  1448. * Parse at most one entry from the listing.
  1449. *
  1450. * Returns -1 in case of error, the length of data parsed otherwise
  1451. */
  1452. static int
  1453. xmlNanoFTPParseList(const char *list, ftpListCallback callback, void *userData) {
  1454. const char *cur = list;
  1455. char filename[151];
  1456. char attrib[11];
  1457. char owner[11];
  1458. char group[11];
  1459. char month[4];
  1460. int year = 0;
  1461. int minute = 0;
  1462. int hour = 0;
  1463. int day = 0;
  1464. unsigned long size = 0;
  1465. int links = 0;
  1466. int i;
  1467. if (!strncmp(cur, "total", 5)) {
  1468. cur += 5;
  1469. while (*cur == ' ') cur++;
  1470. while ((*cur >= '0') && (*cur <= '9'))
  1471. links = (links * 10) + (*cur++ - '0');
  1472. while ((*cur == ' ') || (*cur == '\n') || (*cur == '\r'))
  1473. cur++;
  1474. return(cur - list);
  1475. } else if (*list == '+') {
  1476. return(0);
  1477. } else {
  1478. while ((*cur == ' ') || (*cur == '\n') || (*cur == '\r'))
  1479. cur++;
  1480. if (*cur == 0) return(0);
  1481. i = 0;
  1482. while (*cur != ' ') {
  1483. if (i < 10)
  1484. attrib[i++] = *cur;
  1485. cur++;
  1486. if (*cur == 0) return(0);
  1487. }
  1488. attrib[10] = 0;
  1489. while (*cur == ' ') cur++;
  1490. if (*cur == 0) return(0);
  1491. while ((*cur >= '0') && (*cur <= '9'))
  1492. links = (links * 10) + (*cur++ - '0');
  1493. while (*cur == ' ') cur++;
  1494. if (*cur == 0) return(0);
  1495. i = 0;
  1496. while (*cur != ' ') {
  1497. if (i < 10)
  1498. owner[i++] = *cur;
  1499. cur++;
  1500. if (*cur == 0) return(0);
  1501. }
  1502. owner[i] = 0;
  1503. while (*cur == ' ') cur++;
  1504. if (*cur == 0) return(0);
  1505. i = 0;
  1506. while (*cur != ' ') {
  1507. if (i < 10)
  1508. group[i++] = *cur;
  1509. cur++;
  1510. if (*cur == 0) return(0);
  1511. }
  1512. group[i] = 0;
  1513. while (*cur == ' ') cur++;
  1514. if (*cur == 0) return(0);
  1515. while ((*cur >= '0') && (*cur <= '9'))
  1516. size = (size * 10) + (*cur++ - '0');
  1517. while (*cur == ' ') cur++;
  1518. if (*cur == 0) return(0);
  1519. i = 0;
  1520. while (*cur != ' ') {
  1521. if (i < 3)
  1522. month[i++] = *cur;
  1523. cur++;
  1524. if (*cur == 0) return(0);
  1525. }
  1526. month[i] = 0;
  1527. while (*cur == ' ') cur++;
  1528. if (*cur == 0) return(0);
  1529. while ((*cur >= '0') && (*cur <= '9'))
  1530. day = (day * 10) + (*cur++ - '0');
  1531. while (*cur == ' ') cur++;
  1532. if (*cur == 0) return(0);
  1533. if ((cur[1] == 0) || (cur[2] == 0)) return(0);
  1534. if ((cur[1] == ':') || (cur[2] == ':')) {
  1535. while ((*cur >= '0') && (*cur <= '9'))
  1536. hour = (hour * 10) + (*cur++ - '0');
  1537. if (*cur == ':') cur++;
  1538. while ((*cur >= '0') && (*cur <= '9'))
  1539. minute = (minute * 10) + (*cur++ - '0');
  1540. } else {
  1541. while ((*cur >= '0') && (*cur <= '9'))
  1542. year = (year * 10) + (*cur++ - '0');
  1543. }
  1544. while (*cur == ' ') cur++;
  1545. if (*cur == 0) return(0);
  1546. i = 0;
  1547. while ((*cur != '\n') && (*cur != '\r')) {
  1548. if (i < 150)
  1549. filename[i++] = *cur;
  1550. cur++;
  1551. if (*cur == 0) return(0);
  1552. }
  1553. filename[i] = 0;
  1554. if ((*cur != '\n') && (*cur != '\r'))
  1555. return(0);
  1556. while ((*cur == '\n') || (*cur == '\r'))
  1557. cur++;
  1558. }
  1559. if (callback != NULL) {
  1560. callback(userData, filename, attrib, owner, group, size, links,
  1561. year, month, day, hour, minute);
  1562. }
  1563. return(cur - list);
  1564. }
  1565. /**
  1566. * xmlNanoFTPList:
  1567. * @ctx: an FTP context
  1568. * @callback: the user callback
  1569. * @userData: the user callback data
  1570. * @filename: optional files to list
  1571. *
  1572. * Do a listing on the server. All files info are passed back
  1573. * in the callbacks.
  1574. *
  1575. * Returns -1 in case of error, 0 otherwise
  1576. */
  1577. int
  1578. xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData,
  1579. const char *filename) {
  1580. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  1581. char buf[4096 + 1];
  1582. int len, res;
  1583. int indx = 0, base;
  1584. fd_set rfd, efd;
  1585. struct timeval tv;
  1586. if (ctxt == NULL) return (-1);
  1587. if (filename == NULL) {
  1588. if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
  1589. return(-1);
  1590. ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
  1591. if (ctxt->dataFd == INVALID_SOCKET)
  1592. return(-1);
  1593. snprintf(buf, sizeof(buf), "LIST -L\r\n");
  1594. } else {
  1595. if (filename[0] != '/') {
  1596. if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
  1597. return(-1);
  1598. }
  1599. ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
  1600. if (ctxt->dataFd == INVALID_SOCKET)
  1601. return(-1);
  1602. snprintf(buf, sizeof(buf), "LIST -L %s\r\n", filename);
  1603. }
  1604. buf[sizeof(buf) - 1] = 0;
  1605. len = strlen(buf);
  1606. #ifdef DEBUG_FTP
  1607. xmlGenericError(xmlGenericErrorContext, "%s", buf);
  1608. #endif
  1609. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  1610. if (res < 0) {
  1611. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  1612. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1613. return(res);
  1614. }
  1615. res = xmlNanoFTPReadResponse(ctxt);
  1616. if (res != 1) {
  1617. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1618. return(-res);
  1619. }
  1620. do {
  1621. tv.tv_sec = 1;
  1622. tv.tv_usec = 0;
  1623. FD_ZERO(&rfd);
  1624. FD_SET(ctxt->dataFd, &rfd);
  1625. FD_ZERO(&efd);
  1626. FD_SET(ctxt->dataFd, &efd);
  1627. res = select(ctxt->dataFd + 1, &rfd, NULL, &efd, &tv);
  1628. if (res < 0) {
  1629. #ifdef DEBUG_FTP
  1630. perror("select");
  1631. #endif
  1632. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1633. return(-1);
  1634. }
  1635. if (res == 0) {
  1636. res = xmlNanoFTPCheckResponse(ctxt);
  1637. if (res < 0) {
  1638. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1639. ctxt->dataFd = INVALID_SOCKET;
  1640. return(-1);
  1641. }
  1642. if (res == 2) {
  1643. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1644. return(0);
  1645. }
  1646. continue;
  1647. }
  1648. if ((len = recv(ctxt->dataFd, &buf[indx], sizeof(buf) - (indx + 1), 0)) < 0) {
  1649. __xmlIOErr(XML_FROM_FTP, 0, "recv");
  1650. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1651. ctxt->dataFd = INVALID_SOCKET;
  1652. return(-1);
  1653. }
  1654. #ifdef DEBUG_FTP
  1655. write(1, &buf[indx], len);
  1656. #endif
  1657. indx += len;
  1658. buf[indx] = 0;
  1659. base = 0;
  1660. do {
  1661. res = xmlNanoFTPParseList(&buf[base], callback, userData);
  1662. base += res;
  1663. } while (res > 0);
  1664. memmove(&buf[0], &buf[base], indx - base);
  1665. indx -= base;
  1666. } while (len != 0);
  1667. xmlNanoFTPCloseConnection(ctxt);
  1668. return(0);
  1669. }
  1670. /**
  1671. * xmlNanoFTPGetSocket:
  1672. * @ctx: an FTP context
  1673. * @filename: the file to retrieve (or NULL if path is in context).
  1674. *
  1675. * Initiate fetch of the given file from the server.
  1676. *
  1677. * Returns the socket for the data connection, or <0 in case of error
  1678. */
  1679. SOCKET
  1680. xmlNanoFTPGetSocket(void *ctx, const char *filename) {
  1681. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  1682. char buf[300];
  1683. int res, len;
  1684. if (ctx == NULL)
  1685. return INVALID_SOCKET;
  1686. if ((filename == NULL) && (ctxt->path == NULL))
  1687. return INVALID_SOCKET;
  1688. ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
  1689. if (ctxt->dataFd == INVALID_SOCKET)
  1690. return INVALID_SOCKET;
  1691. snprintf(buf, sizeof(buf), "TYPE I\r\n");
  1692. len = strlen(buf);
  1693. #ifdef DEBUG_FTP
  1694. xmlGenericError(xmlGenericErrorContext, "%s", buf);
  1695. #endif
  1696. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  1697. if (res < 0) {
  1698. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  1699. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1700. return INVALID_SOCKET;
  1701. }
  1702. res = xmlNanoFTPReadResponse(ctxt);
  1703. if (res != 2) {
  1704. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1705. return INVALID_SOCKET;
  1706. }
  1707. if (filename == NULL)
  1708. snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path);
  1709. else
  1710. snprintf(buf, sizeof(buf), "RETR %s\r\n", filename);
  1711. buf[sizeof(buf) - 1] = 0;
  1712. len = strlen(buf);
  1713. #ifdef DEBUG_FTP
  1714. xmlGenericError(xmlGenericErrorContext, "%s", buf);
  1715. #endif
  1716. res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
  1717. if (res < 0) {
  1718. __xmlIOErr(XML_FROM_FTP, 0, "send failed");
  1719. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1720. return INVALID_SOCKET;
  1721. }
  1722. res = xmlNanoFTPReadResponse(ctxt);
  1723. if (res != 1) {
  1724. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1725. return INVALID_SOCKET;
  1726. }
  1727. return(ctxt->dataFd);
  1728. }
  1729. /**
  1730. * xmlNanoFTPGet:
  1731. * @ctx: an FTP context
  1732. * @callback: the user callback
  1733. * @userData: the user callback data
  1734. * @filename: the file to retrieve
  1735. *
  1736. * Fetch the given file from the server. All data are passed back
  1737. * in the callbacks. The last callback has a size of 0 block.
  1738. *
  1739. * Returns -1 in case of error, 0 otherwise
  1740. */
  1741. int
  1742. xmlNanoFTPGet(void *ctx, ftpDataCallback callback, void *userData,
  1743. const char *filename) {
  1744. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  1745. char buf[4096];
  1746. int len = 0, res;
  1747. fd_set rfd;
  1748. struct timeval tv;
  1749. if (ctxt == NULL) return(-1);
  1750. if ((filename == NULL) && (ctxt->path == NULL))
  1751. return(-1);
  1752. if (callback == NULL)
  1753. return(-1);
  1754. if (xmlNanoFTPGetSocket(ctxt, filename) == INVALID_SOCKET)
  1755. return(-1);
  1756. do {
  1757. tv.tv_sec = 1;
  1758. tv.tv_usec = 0;
  1759. FD_ZERO(&rfd);
  1760. FD_SET(ctxt->dataFd, &rfd);
  1761. res = select(ctxt->dataFd + 1, &rfd, NULL, NULL, &tv);
  1762. if (res < 0) {
  1763. #ifdef DEBUG_FTP
  1764. perror("select");
  1765. #endif
  1766. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1767. return(-1);
  1768. }
  1769. if (res == 0) {
  1770. res = xmlNanoFTPCheckResponse(ctxt);
  1771. if (res < 0) {
  1772. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1773. ctxt->dataFd = INVALID_SOCKET;
  1774. return(-1);
  1775. }
  1776. if (res == 2) {
  1777. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1778. return(0);
  1779. }
  1780. continue;
  1781. }
  1782. if ((len = recv(ctxt->dataFd, buf, sizeof(buf), 0)) < 0) {
  1783. __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
  1784. callback(userData, buf, len);
  1785. closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
  1786. return(-1);
  1787. }
  1788. callback(userData, buf, len);
  1789. } while (len != 0);
  1790. return(xmlNanoFTPCloseConnection(ctxt));
  1791. }
  1792. /**
  1793. * xmlNanoFTPRead:
  1794. * @ctx: the FTP context
  1795. * @dest: a buffer
  1796. * @len: the buffer length
  1797. *
  1798. * This function tries to read @len bytes from the existing FTP connection
  1799. * and saves them in @dest. This is a blocking call.
  1800. *
  1801. * Returns the number of byte read. 0 is an indication of an end of connection.
  1802. * -1 indicates a parameter error.
  1803. */
  1804. int
  1805. xmlNanoFTPRead(void *ctx, void *dest, int len) {
  1806. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  1807. if (ctx == NULL) return(-1);
  1808. if (ctxt->dataFd == INVALID_SOCKET) return(0);
  1809. if (dest == NULL) return(-1);
  1810. if (len <= 0) return(0);
  1811. len = recv(ctxt->dataFd, dest, len, 0);
  1812. if (len <= 0) {
  1813. if (len < 0)
  1814. __xmlIOErr(XML_FROM_FTP, 0, "recv failed");
  1815. xmlNanoFTPCloseConnection(ctxt);
  1816. }
  1817. #ifdef DEBUG_FTP
  1818. xmlGenericError(xmlGenericErrorContext, "Recvd %d bytes\n", len);
  1819. #endif
  1820. return(len);
  1821. }
  1822. /**
  1823. * xmlNanoFTPOpen:
  1824. * @URL: the URL to the resource
  1825. *
  1826. * Start to fetch the given ftp:// resource
  1827. *
  1828. * Returns an FTP context, or NULL
  1829. */
  1830. void*
  1831. xmlNanoFTPOpen(const char *URL) {
  1832. xmlNanoFTPCtxtPtr ctxt;
  1833. SOCKET sock;
  1834. xmlNanoFTPInit();
  1835. if (URL == NULL) return(NULL);
  1836. if (strncmp("ftp://", URL, 6)) return(NULL);
  1837. ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(URL);
  1838. if (ctxt == NULL) return(NULL);
  1839. if (xmlNanoFTPConnect(ctxt) < 0) {
  1840. xmlNanoFTPFreeCtxt(ctxt);
  1841. return(NULL);
  1842. }
  1843. sock = xmlNanoFTPGetSocket(ctxt, ctxt->path);
  1844. if (sock == INVALID_SOCKET) {
  1845. xmlNanoFTPFreeCtxt(ctxt);
  1846. return(NULL);
  1847. }
  1848. return(ctxt);
  1849. }
  1850. /**
  1851. * xmlNanoFTPClose:
  1852. * @ctx: an FTP context
  1853. *
  1854. * Close the connection and both control and transport
  1855. *
  1856. * Returns -1 in case of error, 0 otherwise
  1857. */
  1858. int
  1859. xmlNanoFTPClose(void *ctx) {
  1860. xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
  1861. if (ctxt == NULL)
  1862. return(-1);
  1863. if (ctxt->dataFd != INVALID_SOCKET) {
  1864. closesocket(ctxt->dataFd);
  1865. ctxt->dataFd = INVALID_SOCKET;
  1866. }
  1867. if (ctxt->controlFd != INVALID_SOCKET) {
  1868. xmlNanoFTPQuit(ctxt);
  1869. closesocket(ctxt->controlFd);
  1870. ctxt->controlFd = INVALID_SOCKET;
  1871. }
  1872. xmlNanoFTPFreeCtxt(ctxt);
  1873. return(0);
  1874. }
  1875. #ifdef STANDALONE
  1876. /************************************************************************
  1877. * *
  1878. * Basic test in Standalone mode *
  1879. * *
  1880. ************************************************************************/
  1881. static
  1882. void ftpList(void *userData, const char *filename, const char* attrib,
  1883. const char *owner, const char *group, unsigned long size, int links,
  1884. int year, const char *month, int day, int hour, int minute) {
  1885. xmlGenericError(xmlGenericErrorContext,
  1886. "%s %s %s %ld %s\n", attrib, owner, group, size, filename);
  1887. }
  1888. static
  1889. void ftpData(void *userData, const char *data, int len) {
  1890. if (userData == NULL) return;
  1891. if (len <= 0) {
  1892. fclose((FILE*)userData);
  1893. return;
  1894. }
  1895. fwrite(data, len, 1, (FILE*)userData);
  1896. }
  1897. int main(int argc, char **argv) {
  1898. void *ctxt;
  1899. FILE *output;
  1900. char *tstfile = NULL;
  1901. xmlNanoFTPInit();
  1902. if (argc > 1) {
  1903. ctxt = xmlNanoFTPNewCtxt(argv[1]);
  1904. if (xmlNanoFTPConnect(ctxt) < 0) {
  1905. xmlGenericError(xmlGenericErrorContext,
  1906. "Couldn't connect to %s\n", argv[1]);
  1907. exit(1);
  1908. }
  1909. if (argc > 2)
  1910. tstfile = argv[2];
  1911. } else
  1912. ctxt = xmlNanoFTPConnectTo("localhost", 0);
  1913. if (ctxt == NULL) {
  1914. xmlGenericError(xmlGenericErrorContext,
  1915. "Couldn't connect to localhost\n");
  1916. exit(1);
  1917. }
  1918. xmlNanoFTPList(ctxt, ftpList, NULL, tstfile);
  1919. output = fopen("/tmp/tstdata", "w");
  1920. if (output != NULL) {
  1921. if (xmlNanoFTPGet(ctxt, ftpData, (void *) output, tstfile) < 0)
  1922. xmlGenericError(xmlGenericErrorContext,
  1923. "Failed to get file\n");
  1924. }
  1925. xmlNanoFTPClose(ctxt);
  1926. xmlMemoryDump();
  1927. exit(0);
  1928. }
  1929. #endif /* STANDALONE */
  1930. #else /* !LIBXML_FTP_ENABLED */
  1931. #ifdef STANDALONE
  1932. #include <stdio.h>
  1933. int main(int argc, char **argv) {
  1934. xmlGenericError(xmlGenericErrorContext,
  1935. "%s : FTP support not compiled in\n", argv[0]);
  1936. return(0);
  1937. }
  1938. #endif /* STANDALONE */
  1939. #endif /* LIBXML_FTP_ENABLED */
  1940. #define bottom_nanoftp
  1941. #include "elfgcchack.h"