ftp.c 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 7 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2018 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Andrew Skalski <askalski@chek.com> |
  16. | Stefan Esser <sesser@php.net> (resume functions) |
  17. +----------------------------------------------------------------------+
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. #include "config.h"
  21. #endif
  22. #include "php.h"
  23. #if HAVE_FTP
  24. #include <stdio.h>
  25. #include <ctype.h>
  26. #include <stdlib.h>
  27. #ifdef HAVE_UNISTD_H
  28. #include <unistd.h>
  29. #endif
  30. #include <fcntl.h>
  31. #include <string.h>
  32. #include <time.h>
  33. #ifdef PHP_WIN32
  34. #include <winsock2.h>
  35. #else
  36. #ifdef HAVE_SYS_TYPES_H
  37. #include <sys/types.h>
  38. #endif
  39. #include <sys/socket.h>
  40. #include <netinet/in.h>
  41. #include <arpa/inet.h>
  42. #include <netdb.h>
  43. #endif
  44. #include <errno.h>
  45. #if HAVE_SYS_TIME_H
  46. #include <sys/time.h>
  47. #endif
  48. #ifdef HAVE_SYS_SELECT_H
  49. #include <sys/select.h>
  50. #endif
  51. #ifdef HAVE_FTP_SSL
  52. #include <openssl/ssl.h>
  53. #include <openssl/err.h>
  54. #endif
  55. #include "ftp.h"
  56. #include "ext/standard/fsock.h"
  57. /* sends an ftp command, returns true on success, false on error.
  58. * it sends the string "cmd args\r\n" if args is non-null, or
  59. * "cmd\r\n" if args is null
  60. */
  61. static int ftp_putcmd( ftpbuf_t *ftp,
  62. const char *cmd,
  63. const size_t cmd_len,
  64. const char *args,
  65. const size_t args_len);
  66. /* wrapper around send/recv to handle timeouts */
  67. static int my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len);
  68. static int my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len);
  69. static int my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen);
  70. /* reads a line the socket , returns true on success, false on error */
  71. static int ftp_readline(ftpbuf_t *ftp);
  72. /* reads an ftp response, returns true on success, false on error */
  73. static int ftp_getresp(ftpbuf_t *ftp);
  74. /* sets the ftp transfer type */
  75. static int ftp_type(ftpbuf_t *ftp, ftptype_t type);
  76. /* opens up a data stream */
  77. static databuf_t* ftp_getdata(ftpbuf_t *ftp);
  78. /* accepts the data connection, returns updated data buffer */
  79. static databuf_t* data_accept(databuf_t *data, ftpbuf_t *ftp);
  80. /* closes the data connection, returns NULL */
  81. static databuf_t* data_close(ftpbuf_t *ftp, databuf_t *data);
  82. /* generic file lister */
  83. static char** ftp_genlist(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, const char *path, const size_t path_len);
  84. #ifdef HAVE_FTP_SSL
  85. /* shuts down a TLS/SSL connection */
  86. static void ftp_ssl_shutdown(ftpbuf_t *ftp, php_socket_t fd, SSL *ssl_handle);
  87. #endif
  88. /* IP and port conversion box */
  89. union ipbox {
  90. struct in_addr ia[2];
  91. unsigned short s[4];
  92. unsigned char c[8];
  93. };
  94. /* {{{ ftp_open
  95. */
  96. ftpbuf_t*
  97. ftp_open(const char *host, short port, zend_long timeout_sec)
  98. {
  99. ftpbuf_t *ftp;
  100. socklen_t size;
  101. struct timeval tv;
  102. /* alloc the ftp structure */
  103. ftp = ecalloc(1, sizeof(*ftp));
  104. tv.tv_sec = timeout_sec;
  105. tv.tv_usec = 0;
  106. ftp->fd = php_network_connect_socket_to_host(host,
  107. (unsigned short) (port ? port : 21), SOCK_STREAM,
  108. 0, &tv, NULL, NULL, NULL, 0, STREAM_SOCKOP_NONE);
  109. if (ftp->fd == -1) {
  110. goto bail;
  111. }
  112. /* Default Settings */
  113. ftp->timeout_sec = timeout_sec;
  114. ftp->nb = 0;
  115. size = sizeof(ftp->localaddr);
  116. memset(&ftp->localaddr, 0, size);
  117. if (getsockname(ftp->fd, (struct sockaddr*) &ftp->localaddr, &size) != 0) {
  118. php_error_docref(NULL, E_WARNING, "getsockname failed: %s (%d)", strerror(errno), errno);
  119. goto bail;
  120. }
  121. if (!ftp_getresp(ftp) || ftp->resp != 220) {
  122. goto bail;
  123. }
  124. return ftp;
  125. bail:
  126. if (ftp->fd != -1) {
  127. closesocket(ftp->fd);
  128. }
  129. efree(ftp);
  130. return NULL;
  131. }
  132. /* }}} */
  133. /* {{{ ftp_close
  134. */
  135. ftpbuf_t*
  136. ftp_close(ftpbuf_t *ftp)
  137. {
  138. if (ftp == NULL) {
  139. return NULL;
  140. }
  141. if (ftp->data) {
  142. data_close(ftp, ftp->data);
  143. }
  144. if (ftp->stream && ftp->closestream) {
  145. php_stream_close(ftp->stream);
  146. }
  147. if (ftp->fd != -1) {
  148. #ifdef HAVE_FTP_SSL
  149. if (ftp->ssl_active) {
  150. ftp_ssl_shutdown(ftp, ftp->fd, ftp->ssl_handle);
  151. }
  152. #endif
  153. closesocket(ftp->fd);
  154. }
  155. ftp_gc(ftp);
  156. efree(ftp);
  157. return NULL;
  158. }
  159. /* }}} */
  160. /* {{{ ftp_gc
  161. */
  162. void
  163. ftp_gc(ftpbuf_t *ftp)
  164. {
  165. if (ftp == NULL) {
  166. return;
  167. }
  168. if (ftp->pwd) {
  169. efree(ftp->pwd);
  170. ftp->pwd = NULL;
  171. }
  172. if (ftp->syst) {
  173. efree(ftp->syst);
  174. ftp->syst = NULL;
  175. }
  176. }
  177. /* }}} */
  178. /* {{{ ftp_quit
  179. */
  180. int
  181. ftp_quit(ftpbuf_t *ftp)
  182. {
  183. if (ftp == NULL) {
  184. return 0;
  185. }
  186. if (!ftp_putcmd(ftp, "QUIT", sizeof("QUIT")-1, NULL, (size_t) 0)) {
  187. return 0;
  188. }
  189. if (!ftp_getresp(ftp) || ftp->resp != 221) {
  190. return 0;
  191. }
  192. if (ftp->pwd) {
  193. efree(ftp->pwd);
  194. ftp->pwd = NULL;
  195. }
  196. return 1;
  197. }
  198. /* }}} */
  199. /* {{{ ftp_login
  200. */
  201. int
  202. ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pass, const size_t pass_len)
  203. {
  204. #ifdef HAVE_FTP_SSL
  205. SSL_CTX *ctx = NULL;
  206. long ssl_ctx_options = SSL_OP_ALL;
  207. int err, res;
  208. zend_bool retry;
  209. #endif
  210. if (ftp == NULL) {
  211. return 0;
  212. }
  213. #ifdef HAVE_FTP_SSL
  214. if (ftp->use_ssl && !ftp->ssl_active) {
  215. if (!ftp_putcmd(ftp, "AUTH", sizeof("AUTH")-1, "TLS", sizeof("TLS")-1)) {
  216. return 0;
  217. }
  218. if (!ftp_getresp(ftp)) {
  219. return 0;
  220. }
  221. if (ftp->resp != 234) {
  222. if (!ftp_putcmd(ftp, "AUTH", sizeof("AUTH")-1, "SSL", sizeof("SSL")-1)) {
  223. return 0;
  224. }
  225. if (!ftp_getresp(ftp)) {
  226. return 0;
  227. }
  228. if (ftp->resp != 334) {
  229. return 0;
  230. } else {
  231. ftp->old_ssl = 1;
  232. ftp->use_ssl_for_data = 1;
  233. }
  234. }
  235. ctx = SSL_CTX_new(SSLv23_client_method());
  236. if (ctx == NULL) {
  237. php_error_docref(NULL, E_WARNING, "failed to create the SSL context");
  238. return 0;
  239. }
  240. #if OPENSSL_VERSION_NUMBER >= 0x0090605fL
  241. ssl_ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
  242. #endif
  243. SSL_CTX_set_options(ctx, ssl_ctx_options);
  244. /* allow SSL to re-use sessions */
  245. SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
  246. ftp->ssl_handle = SSL_new(ctx);
  247. SSL_CTX_free(ctx);
  248. if (ftp->ssl_handle == NULL) {
  249. php_error_docref(NULL, E_WARNING, "failed to create the SSL handle");
  250. return 0;
  251. }
  252. SSL_set_fd(ftp->ssl_handle, ftp->fd);
  253. do {
  254. res = SSL_connect(ftp->ssl_handle);
  255. err = SSL_get_error(ftp->ssl_handle, res);
  256. /* TODO check if handling other error codes would make sense */
  257. switch (err) {
  258. case SSL_ERROR_NONE:
  259. retry = 0;
  260. break;
  261. case SSL_ERROR_ZERO_RETURN:
  262. retry = 0;
  263. SSL_shutdown(ftp->ssl_handle);
  264. break;
  265. case SSL_ERROR_WANT_READ:
  266. case SSL_ERROR_WANT_WRITE: {
  267. php_pollfd p;
  268. int i;
  269. p.fd = ftp->fd;
  270. p.events = (err == SSL_ERROR_WANT_READ) ? (POLLIN|POLLPRI) : POLLOUT;
  271. p.revents = 0;
  272. i = php_poll2(&p, 1, 300);
  273. retry = i > 0;
  274. }
  275. break;
  276. default:
  277. php_error_docref(NULL, E_WARNING, "SSL/TLS handshake failed");
  278. SSL_shutdown(ftp->ssl_handle);
  279. SSL_free(ftp->ssl_handle);
  280. return 0;
  281. }
  282. } while (retry);
  283. ftp->ssl_active = 1;
  284. if (!ftp->old_ssl) {
  285. /* set protection buffersize to zero */
  286. if (!ftp_putcmd(ftp, "PBSZ", sizeof("PBSZ")-1, "0", sizeof("0")-1)) {
  287. return 0;
  288. }
  289. if (!ftp_getresp(ftp)) {
  290. return 0;
  291. }
  292. /* enable data conn encryption */
  293. if (!ftp_putcmd(ftp, "PROT", sizeof("PROT")-1, "P", sizeof("P")-1)) {
  294. return 0;
  295. }
  296. if (!ftp_getresp(ftp)) {
  297. return 0;
  298. }
  299. ftp->use_ssl_for_data = (ftp->resp >= 200 && ftp->resp <=299);
  300. }
  301. }
  302. #endif
  303. if (!ftp_putcmd(ftp, "USER", sizeof("USER")-1, user, user_len)) {
  304. return 0;
  305. }
  306. if (!ftp_getresp(ftp)) {
  307. return 0;
  308. }
  309. if (ftp->resp == 230) {
  310. return 1;
  311. }
  312. if (ftp->resp != 331) {
  313. return 0;
  314. }
  315. if (!ftp_putcmd(ftp, "PASS", sizeof("PASS")-1, pass, pass_len)) {
  316. return 0;
  317. }
  318. if (!ftp_getresp(ftp)) {
  319. return 0;
  320. }
  321. return (ftp->resp == 230);
  322. }
  323. /* }}} */
  324. /* {{{ ftp_reinit
  325. */
  326. int
  327. ftp_reinit(ftpbuf_t *ftp)
  328. {
  329. if (ftp == NULL) {
  330. return 0;
  331. }
  332. ftp_gc(ftp);
  333. ftp->nb = 0;
  334. if (!ftp_putcmd(ftp, "REIN", sizeof("REIN")-1, NULL, (size_t) 0)) {
  335. return 0;
  336. }
  337. if (!ftp_getresp(ftp) || ftp->resp != 220) {
  338. return 0;
  339. }
  340. return 1;
  341. }
  342. /* }}} */
  343. /* {{{ ftp_syst
  344. */
  345. const char*
  346. ftp_syst(ftpbuf_t *ftp)
  347. {
  348. char *syst, *end;
  349. if (ftp == NULL) {
  350. return NULL;
  351. }
  352. /* default to cached value */
  353. if (ftp->syst) {
  354. return ftp->syst;
  355. }
  356. if (!ftp_putcmd(ftp, "SYST", sizeof("SYST")-1, NULL, (size_t) 0)) {
  357. return NULL;
  358. }
  359. if (!ftp_getresp(ftp) || ftp->resp != 215) {
  360. return NULL;
  361. }
  362. syst = ftp->inbuf;
  363. while (*syst == ' ') {
  364. syst++;
  365. }
  366. if ((end = strchr(syst, ' '))) {
  367. *end = 0;
  368. }
  369. ftp->syst = estrdup(syst);
  370. if (end) {
  371. *end = ' ';
  372. }
  373. return ftp->syst;
  374. }
  375. /* }}} */
  376. /* {{{ ftp_pwd
  377. */
  378. const char*
  379. ftp_pwd(ftpbuf_t *ftp)
  380. {
  381. char *pwd, *end;
  382. if (ftp == NULL) {
  383. return NULL;
  384. }
  385. /* default to cached value */
  386. if (ftp->pwd) {
  387. return ftp->pwd;
  388. }
  389. if (!ftp_putcmd(ftp, "PWD", sizeof("PWD")-1, NULL, (size_t) 0)) {
  390. return NULL;
  391. }
  392. if (!ftp_getresp(ftp) || ftp->resp != 257) {
  393. return NULL;
  394. }
  395. /* copy out the pwd from response */
  396. if ((pwd = strchr(ftp->inbuf, '"')) == NULL) {
  397. return NULL;
  398. }
  399. if ((end = strrchr(++pwd, '"')) == NULL) {
  400. return NULL;
  401. }
  402. ftp->pwd = estrndup(pwd, end - pwd);
  403. return ftp->pwd;
  404. }
  405. /* }}} */
  406. /* {{{ ftp_exec
  407. */
  408. int
  409. ftp_exec(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len)
  410. {
  411. if (ftp == NULL) {
  412. return 0;
  413. }
  414. if (!ftp_putcmd(ftp, "SITE EXEC", sizeof("SITE EXEC")-1, cmd, cmd_len)) {
  415. return 0;
  416. }
  417. if (!ftp_getresp(ftp) || ftp->resp != 200) {
  418. return 0;
  419. }
  420. return 1;
  421. }
  422. /* }}} */
  423. /* {{{ ftp_raw
  424. */
  425. void
  426. ftp_raw(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, zval *return_value)
  427. {
  428. if (ftp == NULL || cmd == NULL) {
  429. RETURN_NULL();
  430. }
  431. if (!ftp_putcmd(ftp, cmd, cmd_len, NULL, (size_t) 0)) {
  432. RETURN_NULL();
  433. }
  434. array_init(return_value);
  435. while (ftp_readline(ftp)) {
  436. add_next_index_string(return_value, ftp->inbuf);
  437. if (isdigit(ftp->inbuf[0]) && isdigit(ftp->inbuf[1]) && isdigit(ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
  438. return;
  439. }
  440. }
  441. }
  442. /* }}} */
  443. /* {{{ ftp_chdir
  444. */
  445. int
  446. ftp_chdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len)
  447. {
  448. if (ftp == NULL) {
  449. return 0;
  450. }
  451. if (ftp->pwd) {
  452. efree(ftp->pwd);
  453. ftp->pwd = NULL;
  454. }
  455. if (!ftp_putcmd(ftp, "CWD", sizeof("CWD")-1, dir, dir_len)) {
  456. return 0;
  457. }
  458. if (!ftp_getresp(ftp) || ftp->resp != 250) {
  459. return 0;
  460. }
  461. return 1;
  462. }
  463. /* }}} */
  464. /* {{{ ftp_cdup
  465. */
  466. int
  467. ftp_cdup(ftpbuf_t *ftp)
  468. {
  469. if (ftp == NULL) {
  470. return 0;
  471. }
  472. if (ftp->pwd) {
  473. efree(ftp->pwd);
  474. ftp->pwd = NULL;
  475. }
  476. if (!ftp_putcmd(ftp, "CDUP", sizeof("CDUP")-1, NULL, (size_t) 0)) {
  477. return 0;
  478. }
  479. if (!ftp_getresp(ftp) || ftp->resp != 250) {
  480. return 0;
  481. }
  482. return 1;
  483. }
  484. /* }}} */
  485. /* {{{ ftp_mkdir
  486. */
  487. zend_string*
  488. ftp_mkdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len)
  489. {
  490. char *mkd, *end;
  491. zend_string *ret;
  492. if (ftp == NULL) {
  493. return NULL;
  494. }
  495. if (!ftp_putcmd(ftp, "MKD", sizeof("MKD")-1, dir, dir_len)) {
  496. return NULL;
  497. }
  498. if (!ftp_getresp(ftp) || ftp->resp != 257) {
  499. return NULL;
  500. }
  501. /* copy out the dir from response */
  502. if ((mkd = strchr(ftp->inbuf, '"')) == NULL) {
  503. return zend_string_init(dir, dir_len, 0);
  504. }
  505. if ((end = strrchr(++mkd, '"')) == NULL) {
  506. return NULL;
  507. }
  508. *end = 0;
  509. ret = zend_string_init(mkd, end - mkd, 0);
  510. *end = '"';
  511. return ret;
  512. }
  513. /* }}} */
  514. /* {{{ ftp_rmdir
  515. */
  516. int
  517. ftp_rmdir(ftpbuf_t *ftp, const char *dir, const size_t dir_len)
  518. {
  519. if (ftp == NULL) {
  520. return 0;
  521. }
  522. if (!ftp_putcmd(ftp, "RMD", sizeof("RMD")-1, dir, dir_len)) {
  523. return 0;
  524. }
  525. if (!ftp_getresp(ftp) || ftp->resp != 250) {
  526. return 0;
  527. }
  528. return 1;
  529. }
  530. /* }}} */
  531. /* {{{ ftp_chmod
  532. */
  533. int
  534. ftp_chmod(ftpbuf_t *ftp, const int mode, const char *filename, const int filename_len)
  535. {
  536. char *buffer;
  537. size_t buffer_len;
  538. if (ftp == NULL || filename_len <= 0) {
  539. return 0;
  540. }
  541. buffer_len = spprintf(&buffer, 0, "CHMOD %o %s", mode, filename);
  542. if (!buffer) {
  543. return 0;
  544. }
  545. if (!ftp_putcmd(ftp, "SITE", sizeof("SITE")-1, buffer, buffer_len)) {
  546. efree(buffer);
  547. return 0;
  548. }
  549. efree(buffer);
  550. if (!ftp_getresp(ftp) || ftp->resp != 200) {
  551. return 0;
  552. }
  553. return 1;
  554. }
  555. /* }}} */
  556. /* {{{ ftp_alloc
  557. */
  558. int
  559. ftp_alloc(ftpbuf_t *ftp, const zend_long size, zend_string **response)
  560. {
  561. char buffer[64];
  562. int buffer_len;
  563. if (ftp == NULL || size <= 0) {
  564. return 0;
  565. }
  566. buffer_len = snprintf(buffer, sizeof(buffer) - 1, ZEND_LONG_FMT, size);
  567. if (buffer_len < 0) {
  568. return 0;
  569. }
  570. if (!ftp_putcmd(ftp, "ALLO", sizeof("ALLO")-1, buffer, buffer_len)) {
  571. return 0;
  572. }
  573. if (!ftp_getresp(ftp)) {
  574. return 0;
  575. }
  576. if (response) {
  577. *response = zend_string_init(ftp->inbuf, strlen(ftp->inbuf), 0);
  578. }
  579. if (ftp->resp < 200 || ftp->resp >= 300) {
  580. return 0;
  581. }
  582. return 1;
  583. }
  584. /* }}} */
  585. /* {{{ ftp_nlist
  586. */
  587. char**
  588. ftp_nlist(ftpbuf_t *ftp, const char *path, const size_t path_len)
  589. {
  590. return ftp_genlist(ftp, "NLST", sizeof("NLST")-1, path, path_len);
  591. }
  592. /* }}} */
  593. /* {{{ ftp_list
  594. */
  595. char**
  596. ftp_list(ftpbuf_t *ftp, const char *path, const size_t path_len, int recursive)
  597. {
  598. return ftp_genlist(ftp, ((recursive) ? "LIST -R" : "LIST"), ((recursive) ? sizeof("LIST -R")-1 : sizeof("LIST")-1), path, path_len);
  599. }
  600. /* }}} */
  601. /* {{{ ftp_mlsd
  602. */
  603. char**
  604. ftp_mlsd(ftpbuf_t *ftp, const char *path, const size_t path_len)
  605. {
  606. return ftp_genlist(ftp, "MLSD", sizeof("MLSD")-1, path, path_len);
  607. }
  608. /* }}} */
  609. /* {{{ ftp_mlsd_parse_line
  610. */
  611. int
  612. ftp_mlsd_parse_line(HashTable *ht, const char *input) {
  613. zval zstr;
  614. const char *end = input + strlen(input);
  615. const char *sp = memchr(input, ' ', end - input);
  616. if (!sp) {
  617. php_error_docref(NULL, E_WARNING, "Missing pathname in MLSD response");
  618. return FAILURE;
  619. }
  620. /* Extract pathname */
  621. ZVAL_STRINGL(&zstr, sp + 1, end - sp - 1);
  622. zend_hash_str_update(ht, "name", sizeof("name")-1, &zstr);
  623. end = sp;
  624. while (input < end) {
  625. const char *semi, *eq;
  626. /* Find end of fact */
  627. semi = memchr(input, ';', end - input);
  628. if (!semi) {
  629. php_error_docref(NULL, E_WARNING, "Malformed fact in MLSD response");
  630. return FAILURE;
  631. }
  632. /* Separate fact key and value */
  633. eq = memchr(input, '=', semi - input);
  634. if (!eq) {
  635. php_error_docref(NULL, E_WARNING, "Malformed fact in MLSD response");
  636. return FAILURE;
  637. }
  638. ZVAL_STRINGL(&zstr, eq + 1, semi - eq - 1);
  639. zend_hash_str_update(ht, input, eq - input, &zstr);
  640. input = semi + 1;
  641. }
  642. return SUCCESS;
  643. }
  644. /* }}} */
  645. /* {{{ ftp_type
  646. */
  647. int
  648. ftp_type(ftpbuf_t *ftp, ftptype_t type)
  649. {
  650. const char *typechar;
  651. if (ftp == NULL) {
  652. return 0;
  653. }
  654. if (type == ftp->type) {
  655. return 1;
  656. }
  657. if (type == FTPTYPE_ASCII) {
  658. typechar = "A";
  659. } else if (type == FTPTYPE_IMAGE) {
  660. typechar = "I";
  661. } else {
  662. return 0;
  663. }
  664. if (!ftp_putcmd(ftp, "TYPE", sizeof("TYPE")-1, typechar, 1)) {
  665. return 0;
  666. }
  667. if (!ftp_getresp(ftp) || ftp->resp != 200) {
  668. return 0;
  669. }
  670. ftp->type = type;
  671. return 1;
  672. }
  673. /* }}} */
  674. /* {{{ ftp_pasv
  675. */
  676. int
  677. ftp_pasv(ftpbuf_t *ftp, int pasv)
  678. {
  679. char *ptr;
  680. union ipbox ipbox;
  681. unsigned long b[6];
  682. socklen_t n;
  683. struct sockaddr *sa;
  684. struct sockaddr_in *sin;
  685. if (ftp == NULL) {
  686. return 0;
  687. }
  688. if (pasv && ftp->pasv == 2) {
  689. return 1;
  690. }
  691. ftp->pasv = 0;
  692. if (!pasv) {
  693. return 1;
  694. }
  695. n = sizeof(ftp->pasvaddr);
  696. memset(&ftp->pasvaddr, 0, n);
  697. sa = (struct sockaddr *) &ftp->pasvaddr;
  698. if (getpeername(ftp->fd, sa, &n) < 0) {
  699. return 0;
  700. }
  701. #if HAVE_IPV6
  702. if (sa->sa_family == AF_INET6) {
  703. struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
  704. char *endptr, delimiter;
  705. /* try EPSV first */
  706. if (!ftp_putcmd(ftp, "EPSV", sizeof("EPSV")-1, NULL, (size_t) 0)) {
  707. return 0;
  708. }
  709. if (!ftp_getresp(ftp)) {
  710. return 0;
  711. }
  712. if (ftp->resp == 229) {
  713. /* parse out the port */
  714. for (ptr = ftp->inbuf; *ptr && *ptr != '('; ptr++);
  715. if (!*ptr) {
  716. return 0;
  717. }
  718. delimiter = *++ptr;
  719. for (n = 0; *ptr && n < 3; ptr++) {
  720. if (*ptr == delimiter) {
  721. n++;
  722. }
  723. }
  724. sin6->sin6_port = htons((unsigned short) strtoul(ptr, &endptr, 10));
  725. if (ptr == endptr || *endptr != delimiter) {
  726. return 0;
  727. }
  728. ftp->pasv = 2;
  729. return 1;
  730. }
  731. }
  732. /* fall back to PASV */
  733. #endif
  734. if (!ftp_putcmd(ftp, "PASV", sizeof("PASV")-1, NULL, (size_t) 0)) {
  735. return 0;
  736. }
  737. if (!ftp_getresp(ftp) || ftp->resp != 227) {
  738. return 0;
  739. }
  740. /* parse out the IP and port */
  741. for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
  742. n = sscanf(ptr, "%lu,%lu,%lu,%lu,%lu,%lu", &b[0], &b[1], &b[2], &b[3], &b[4], &b[5]);
  743. if (n != 6) {
  744. return 0;
  745. }
  746. for (n = 0; n < 6; n++) {
  747. ipbox.c[n] = (unsigned char) b[n];
  748. }
  749. sin = (struct sockaddr_in *) sa;
  750. if (ftp->usepasvaddress) {
  751. sin->sin_addr = ipbox.ia[0];
  752. }
  753. sin->sin_port = ipbox.s[2];
  754. ftp->pasv = 2;
  755. return 1;
  756. }
  757. /* }}} */
  758. /* {{{ ftp_get
  759. */
  760. int
  761. ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t path_len, ftptype_t type, zend_long resumepos)
  762. {
  763. databuf_t *data = NULL;
  764. size_t rcvd;
  765. char arg[11];
  766. if (ftp == NULL) {
  767. return 0;
  768. }
  769. if (!ftp_type(ftp, type)) {
  770. goto bail;
  771. }
  772. if ((data = ftp_getdata(ftp)) == NULL) {
  773. goto bail;
  774. }
  775. ftp->data = data;
  776. if (resumepos > 0) {
  777. int arg_len = snprintf(arg, sizeof(arg), ZEND_LONG_FMT, resumepos);
  778. if (arg_len < 0) {
  779. goto bail;
  780. }
  781. if (!ftp_putcmd(ftp, "REST", sizeof("REST")-1, arg, arg_len)) {
  782. goto bail;
  783. }
  784. if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
  785. goto bail;
  786. }
  787. }
  788. if (!ftp_putcmd(ftp, "RETR", sizeof("RETR")-1, path, path_len)) {
  789. goto bail;
  790. }
  791. if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
  792. goto bail;
  793. }
  794. if ((data = data_accept(data, ftp)) == NULL) {
  795. goto bail;
  796. }
  797. while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
  798. if (rcvd == (size_t)-1) {
  799. goto bail;
  800. }
  801. if (type == FTPTYPE_ASCII) {
  802. #ifndef PHP_WIN32
  803. char *s;
  804. #endif
  805. char *ptr = data->buf;
  806. char *e = ptr + rcvd;
  807. /* logic depends on the OS EOL
  808. * Win32 -> \r\n
  809. * Everything Else \n
  810. */
  811. #ifdef PHP_WIN32
  812. php_stream_write(outstream, ptr, (e - ptr));
  813. ptr = e;
  814. #else
  815. while (e > ptr && (s = memchr(ptr, '\r', (e - ptr)))) {
  816. php_stream_write(outstream, ptr, (s - ptr));
  817. if (*(s + 1) == '\n') {
  818. s++;
  819. php_stream_putc(outstream, '\n');
  820. }
  821. ptr = s + 1;
  822. }
  823. #endif
  824. if (ptr < e) {
  825. php_stream_write(outstream, ptr, (e - ptr));
  826. }
  827. } else if (rcvd != php_stream_write(outstream, data->buf, rcvd)) {
  828. goto bail;
  829. }
  830. }
  831. ftp->data = data = data_close(ftp, data);
  832. if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
  833. goto bail;
  834. }
  835. return 1;
  836. bail:
  837. ftp->data = data_close(ftp, data);
  838. return 0;
  839. }
  840. /* }}} */
  841. /* {{{ ftp_put
  842. */
  843. int
  844. ftp_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type, zend_long startpos)
  845. {
  846. databuf_t *data = NULL;
  847. zend_long size;
  848. char *ptr;
  849. int ch;
  850. char arg[11];
  851. if (ftp == NULL) {
  852. return 0;
  853. }
  854. if (!ftp_type(ftp, type)) {
  855. goto bail;
  856. }
  857. if ((data = ftp_getdata(ftp)) == NULL) {
  858. goto bail;
  859. }
  860. ftp->data = data;
  861. if (startpos > 0) {
  862. int arg_len = snprintf(arg, sizeof(arg), ZEND_LONG_FMT, startpos);
  863. if (arg_len < 0) {
  864. goto bail;
  865. }
  866. if (!ftp_putcmd(ftp, "REST", sizeof("REST")-1, arg, arg_len)) {
  867. goto bail;
  868. }
  869. if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
  870. goto bail;
  871. }
  872. }
  873. if (!ftp_putcmd(ftp, "STOR", sizeof("STOR")-1, path, path_len)) {
  874. goto bail;
  875. }
  876. if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
  877. goto bail;
  878. }
  879. if ((data = data_accept(data, ftp)) == NULL) {
  880. goto bail;
  881. }
  882. size = 0;
  883. ptr = data->buf;
  884. while (!php_stream_eof(instream) && (ch = php_stream_getc(instream))!=EOF) {
  885. /* flush if necessary */
  886. if (FTP_BUFSIZE - size < 2) {
  887. if (my_send(ftp, data->fd, data->buf, size) != size) {
  888. goto bail;
  889. }
  890. ptr = data->buf;
  891. size = 0;
  892. }
  893. if (ch == '\n' && type == FTPTYPE_ASCII) {
  894. *ptr++ = '\r';
  895. size++;
  896. }
  897. *ptr++ = ch;
  898. size++;
  899. }
  900. if (size && my_send(ftp, data->fd, data->buf, size) != size) {
  901. goto bail;
  902. }
  903. ftp->data = data = data_close(ftp, data);
  904. if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250 && ftp->resp != 200)) {
  905. goto bail;
  906. }
  907. return 1;
  908. bail:
  909. ftp->data = data_close(ftp, data);
  910. return 0;
  911. }
  912. /* }}} */
  913. /* {{{ ftp_append
  914. */
  915. int
  916. ftp_append(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type)
  917. {
  918. databuf_t *data = NULL;
  919. zend_long size;
  920. char *ptr;
  921. int ch;
  922. if (ftp == NULL) {
  923. return 0;
  924. }
  925. if (!ftp_type(ftp, type)) {
  926. goto bail;
  927. }
  928. if ((data = ftp_getdata(ftp)) == NULL) {
  929. goto bail;
  930. }
  931. ftp->data = data;
  932. if (!ftp_putcmd(ftp, "APPE", sizeof("APPE")-1, path, path_len)) {
  933. goto bail;
  934. }
  935. if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
  936. goto bail;
  937. }
  938. if ((data = data_accept(data, ftp)) == NULL) {
  939. goto bail;
  940. }
  941. size = 0;
  942. ptr = data->buf;
  943. while (!php_stream_eof(instream) && (ch = php_stream_getc(instream))!=EOF) {
  944. /* flush if necessary */
  945. if (FTP_BUFSIZE - size < 2) {
  946. if (my_send(ftp, data->fd, data->buf, size) != size) {
  947. goto bail;
  948. }
  949. ptr = data->buf;
  950. size = 0;
  951. }
  952. if (ch == '\n' && type == FTPTYPE_ASCII) {
  953. *ptr++ = '\r';
  954. size++;
  955. }
  956. *ptr++ = ch;
  957. size++;
  958. }
  959. if (size && my_send(ftp, data->fd, data->buf, size) != size) {
  960. goto bail;
  961. }
  962. ftp->data = data = data_close(ftp, data);
  963. if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250 && ftp->resp != 200)) {
  964. goto bail;
  965. }
  966. return 1;
  967. bail:
  968. ftp->data = data_close(ftp, data);
  969. return 0;
  970. }
  971. /* }}} */
  972. /* {{{ ftp_size
  973. */
  974. zend_long
  975. ftp_size(ftpbuf_t *ftp, const char *path, const size_t path_len)
  976. {
  977. zend_long res;
  978. if (ftp == NULL) {
  979. return -1;
  980. }
  981. if (!ftp_type(ftp, FTPTYPE_IMAGE)) {
  982. return -1;
  983. }
  984. if (!ftp_putcmd(ftp, "SIZE", sizeof("SIZE")-1, path, path_len)) {
  985. return -1;
  986. }
  987. if (!ftp_getresp(ftp) || ftp->resp != 213) {
  988. return -1;
  989. }
  990. ZEND_ATOL(res, ftp->inbuf);
  991. return res;
  992. }
  993. /* }}} */
  994. /* {{{ ftp_mdtm
  995. */
  996. time_t
  997. ftp_mdtm(ftpbuf_t *ftp, const char *path, const size_t path_len)
  998. {
  999. time_t stamp;
  1000. struct tm *gmt, tmbuf;
  1001. struct tm tm;
  1002. char *ptr;
  1003. int n;
  1004. if (ftp == NULL) {
  1005. return -1;
  1006. }
  1007. if (!ftp_putcmd(ftp, "MDTM", sizeof("MDTM")-1, path, path_len)) {
  1008. return -1;
  1009. }
  1010. if (!ftp_getresp(ftp) || ftp->resp != 213) {
  1011. return -1;
  1012. }
  1013. /* parse out the timestamp */
  1014. for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
  1015. n = sscanf(ptr, "%4u%2u%2u%2u%2u%2u", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
  1016. if (n != 6) {
  1017. return -1;
  1018. }
  1019. tm.tm_year -= 1900;
  1020. tm.tm_mon--;
  1021. tm.tm_isdst = -1;
  1022. /* figure out the GMT offset */
  1023. stamp = time(NULL);
  1024. gmt = php_gmtime_r(&stamp, &tmbuf);
  1025. if (!gmt) {
  1026. return -1;
  1027. }
  1028. gmt->tm_isdst = -1;
  1029. /* apply the GMT offset */
  1030. tm.tm_sec += stamp - mktime(gmt);
  1031. tm.tm_isdst = gmt->tm_isdst;
  1032. stamp = mktime(&tm);
  1033. return stamp;
  1034. }
  1035. /* }}} */
  1036. /* {{{ ftp_delete
  1037. */
  1038. int
  1039. ftp_delete(ftpbuf_t *ftp, const char *path, const size_t path_len)
  1040. {
  1041. if (ftp == NULL) {
  1042. return 0;
  1043. }
  1044. if (!ftp_putcmd(ftp, "DELE", sizeof("DELE")-1, path, path_len)) {
  1045. return 0;
  1046. }
  1047. if (!ftp_getresp(ftp) || ftp->resp != 250) {
  1048. return 0;
  1049. }
  1050. return 1;
  1051. }
  1052. /* }}} */
  1053. /* {{{ ftp_rename
  1054. */
  1055. int
  1056. ftp_rename(ftpbuf_t *ftp, const char *src, const size_t src_len, const char *dest, const size_t dest_len)
  1057. {
  1058. if (ftp == NULL) {
  1059. return 0;
  1060. }
  1061. if (!ftp_putcmd(ftp, "RNFR", sizeof("RNFR")-1, src, src_len)) {
  1062. return 0;
  1063. }
  1064. if (!ftp_getresp(ftp) || ftp->resp != 350) {
  1065. return 0;
  1066. }
  1067. if (!ftp_putcmd(ftp, "RNTO", sizeof("RNTO")-1, dest, dest_len)) {
  1068. return 0;
  1069. }
  1070. if (!ftp_getresp(ftp) || ftp->resp != 250) {
  1071. return 0;
  1072. }
  1073. return 1;
  1074. }
  1075. /* }}} */
  1076. /* {{{ ftp_site
  1077. */
  1078. int
  1079. ftp_site(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len)
  1080. {
  1081. if (ftp == NULL) {
  1082. return 0;
  1083. }
  1084. if (!ftp_putcmd(ftp, "SITE", sizeof("SITE")-1, cmd, cmd_len)) {
  1085. return 0;
  1086. }
  1087. if (!ftp_getresp(ftp) || ftp->resp < 200 || ftp->resp >= 300) {
  1088. return 0;
  1089. }
  1090. return 1;
  1091. }
  1092. /* }}} */
  1093. /* static functions */
  1094. /* {{{ ftp_putcmd
  1095. */
  1096. int
  1097. ftp_putcmd(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, const char *args, const size_t args_len)
  1098. {
  1099. int size;
  1100. char *data;
  1101. if (strpbrk(cmd, "\r\n")) {
  1102. return 0;
  1103. }
  1104. /* build the output buffer */
  1105. if (args && args[0]) {
  1106. /* "cmd args\r\n\0" */
  1107. if (cmd_len + args_len + 4 > FTP_BUFSIZE) {
  1108. return 0;
  1109. }
  1110. if (strpbrk(args, "\r\n")) {
  1111. return 0;
  1112. }
  1113. size = slprintf(ftp->outbuf, sizeof(ftp->outbuf), "%s %s\r\n", cmd, args);
  1114. } else {
  1115. /* "cmd\r\n\0" */
  1116. if (cmd_len + 3 > FTP_BUFSIZE) {
  1117. return 0;
  1118. }
  1119. size = slprintf(ftp->outbuf, sizeof(ftp->outbuf), "%s\r\n", cmd);
  1120. }
  1121. data = ftp->outbuf;
  1122. /* Clear the extra-lines buffer */
  1123. ftp->extra = NULL;
  1124. if (my_send(ftp, ftp->fd, data, size) != size) {
  1125. return 0;
  1126. }
  1127. return 1;
  1128. }
  1129. /* }}} */
  1130. /* {{{ ftp_readline
  1131. */
  1132. int
  1133. ftp_readline(ftpbuf_t *ftp)
  1134. {
  1135. long size, rcvd;
  1136. char *data, *eol;
  1137. /* shift the extra to the front */
  1138. size = FTP_BUFSIZE;
  1139. rcvd = 0;
  1140. if (ftp->extra) {
  1141. memmove(ftp->inbuf, ftp->extra, ftp->extralen);
  1142. rcvd = ftp->extralen;
  1143. }
  1144. data = ftp->inbuf;
  1145. do {
  1146. size -= rcvd;
  1147. for (eol = data; rcvd; rcvd--, eol++) {
  1148. if (*eol == '\r') {
  1149. *eol = 0;
  1150. ftp->extra = eol + 1;
  1151. if (rcvd > 1 && *(eol + 1) == '\n') {
  1152. ftp->extra++;
  1153. rcvd--;
  1154. }
  1155. if ((ftp->extralen = --rcvd) == 0) {
  1156. ftp->extra = NULL;
  1157. }
  1158. return 1;
  1159. } else if (*eol == '\n') {
  1160. *eol = 0;
  1161. ftp->extra = eol + 1;
  1162. if ((ftp->extralen = --rcvd) == 0) {
  1163. ftp->extra = NULL;
  1164. }
  1165. return 1;
  1166. }
  1167. }
  1168. data = eol;
  1169. if ((rcvd = my_recv(ftp, ftp->fd, data, size)) < 1) {
  1170. return 0;
  1171. }
  1172. } while (size);
  1173. return 0;
  1174. }
  1175. /* }}} */
  1176. /* {{{ ftp_getresp
  1177. */
  1178. int
  1179. ftp_getresp(ftpbuf_t *ftp)
  1180. {
  1181. if (ftp == NULL) {
  1182. return 0;
  1183. }
  1184. ftp->resp = 0;
  1185. while (1) {
  1186. if (!ftp_readline(ftp)) {
  1187. return 0;
  1188. }
  1189. /* Break out when the end-tag is found */
  1190. if (isdigit(ftp->inbuf[0]) && isdigit(ftp->inbuf[1]) && isdigit(ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
  1191. break;
  1192. }
  1193. }
  1194. /* translate the tag */
  1195. if (!isdigit(ftp->inbuf[0]) || !isdigit(ftp->inbuf[1]) || !isdigit(ftp->inbuf[2])) {
  1196. return 0;
  1197. }
  1198. ftp->resp = 100 * (ftp->inbuf[0] - '0') + 10 * (ftp->inbuf[1] - '0') + (ftp->inbuf[2] - '0');
  1199. memmove(ftp->inbuf, ftp->inbuf + 4, FTP_BUFSIZE - 4);
  1200. if (ftp->extra) {
  1201. ftp->extra -= 4;
  1202. }
  1203. return 1;
  1204. }
  1205. /* }}} */
  1206. /* {{{ my_send
  1207. */
  1208. int
  1209. my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
  1210. {
  1211. zend_long size, sent;
  1212. int n;
  1213. #ifdef HAVE_FTP_SSL
  1214. int err;
  1215. zend_bool retry = 0;
  1216. SSL *handle = NULL;
  1217. php_socket_t fd;
  1218. #endif
  1219. size = len;
  1220. while (size) {
  1221. n = php_pollfd_for_ms(s, POLLOUT, ftp->timeout_sec * 1000);
  1222. if (n < 1) {
  1223. #ifdef PHP_WIN32
  1224. if (n == 0) {
  1225. _set_errno(ETIMEDOUT);
  1226. }
  1227. #else
  1228. if (n == 0) {
  1229. errno = ETIMEDOUT;
  1230. }
  1231. #endif
  1232. return -1;
  1233. }
  1234. #ifdef HAVE_FTP_SSL
  1235. if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
  1236. handle = ftp->ssl_handle;
  1237. fd = ftp->fd;
  1238. } else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
  1239. handle = ftp->data->ssl_handle;
  1240. fd = ftp->data->fd;
  1241. }
  1242. if (handle) {
  1243. do {
  1244. sent = SSL_write(handle, buf, size);
  1245. err = SSL_get_error(handle, sent);
  1246. switch (err) {
  1247. case SSL_ERROR_NONE:
  1248. retry = 0;
  1249. break;
  1250. case SSL_ERROR_ZERO_RETURN:
  1251. retry = 0;
  1252. SSL_shutdown(handle);
  1253. break;
  1254. case SSL_ERROR_WANT_READ:
  1255. case SSL_ERROR_WANT_CONNECT: {
  1256. php_pollfd p;
  1257. int i;
  1258. p.fd = fd;
  1259. p.events = POLLOUT;
  1260. p.revents = 0;
  1261. i = php_poll2(&p, 1, 300);
  1262. retry = i > 0;
  1263. }
  1264. break;
  1265. default:
  1266. php_error_docref(NULL, E_WARNING, "SSL write failed");
  1267. return -1;
  1268. }
  1269. } while (retry);
  1270. } else {
  1271. #endif
  1272. sent = send(s, buf, size, 0);
  1273. #ifdef HAVE_FTP_SSL
  1274. }
  1275. #endif
  1276. if (sent == -1) {
  1277. return -1;
  1278. }
  1279. buf = (char*) buf + sent;
  1280. size -= sent;
  1281. }
  1282. return len;
  1283. }
  1284. /* }}} */
  1285. /* {{{ my_recv
  1286. */
  1287. int
  1288. my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
  1289. {
  1290. int n, nr_bytes;
  1291. #ifdef HAVE_FTP_SSL
  1292. int err;
  1293. zend_bool retry = 0;
  1294. SSL *handle = NULL;
  1295. php_socket_t fd;
  1296. #endif
  1297. n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
  1298. if (n < 1) {
  1299. #ifdef PHP_WIN32
  1300. if (n == 0) {
  1301. _set_errno(ETIMEDOUT);
  1302. }
  1303. #else
  1304. if (n == 0) {
  1305. errno = ETIMEDOUT;
  1306. }
  1307. #endif
  1308. return -1;
  1309. }
  1310. #ifdef HAVE_FTP_SSL
  1311. if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
  1312. handle = ftp->ssl_handle;
  1313. fd = ftp->fd;
  1314. } else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
  1315. handle = ftp->data->ssl_handle;
  1316. fd = ftp->data->fd;
  1317. }
  1318. if (handle) {
  1319. do {
  1320. nr_bytes = SSL_read(handle, buf, len);
  1321. err = SSL_get_error(handle, nr_bytes);
  1322. switch (err) {
  1323. case SSL_ERROR_NONE:
  1324. retry = 0;
  1325. break;
  1326. case SSL_ERROR_ZERO_RETURN:
  1327. retry = 0;
  1328. SSL_shutdown(handle);
  1329. break;
  1330. case SSL_ERROR_WANT_READ:
  1331. case SSL_ERROR_WANT_CONNECT: {
  1332. php_pollfd p;
  1333. int i;
  1334. p.fd = fd;
  1335. p.events = POLLIN|POLLPRI;
  1336. p.revents = 0;
  1337. i = php_poll2(&p, 1, 300);
  1338. retry = i > 0;
  1339. }
  1340. break;
  1341. default:
  1342. php_error_docref(NULL, E_WARNING, "SSL read failed");
  1343. return -1;
  1344. }
  1345. } while (retry);
  1346. } else {
  1347. #endif
  1348. nr_bytes = recv(s, buf, len, 0);
  1349. #ifdef HAVE_FTP_SSL
  1350. }
  1351. #endif
  1352. return (nr_bytes);
  1353. }
  1354. /* }}} */
  1355. /* {{{ data_available
  1356. */
  1357. int
  1358. data_available(ftpbuf_t *ftp, php_socket_t s)
  1359. {
  1360. int n;
  1361. n = php_pollfd_for_ms(s, PHP_POLLREADABLE, 1000);
  1362. if (n < 1) {
  1363. #ifdef PHP_WIN32
  1364. if (n == 0) {
  1365. _set_errno(ETIMEDOUT);
  1366. }
  1367. #else
  1368. if (n == 0) {
  1369. errno = ETIMEDOUT;
  1370. }
  1371. #endif
  1372. return 0;
  1373. }
  1374. return 1;
  1375. }
  1376. /* }}} */
  1377. /* {{{ data_writeable
  1378. */
  1379. int
  1380. data_writeable(ftpbuf_t *ftp, php_socket_t s)
  1381. {
  1382. int n;
  1383. n = php_pollfd_for_ms(s, POLLOUT, 1000);
  1384. if (n < 1) {
  1385. #ifdef PHP_WIN32
  1386. if (n == 0) {
  1387. _set_errno(ETIMEDOUT);
  1388. }
  1389. #else
  1390. if (n == 0) {
  1391. errno = ETIMEDOUT;
  1392. }
  1393. #endif
  1394. return 0;
  1395. }
  1396. return 1;
  1397. }
  1398. /* }}} */
  1399. /* {{{ my_accept
  1400. */
  1401. int
  1402. my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen)
  1403. {
  1404. int n;
  1405. n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
  1406. if (n < 1) {
  1407. #ifdef PHP_WIN32
  1408. if (n == 0) {
  1409. _set_errno(ETIMEDOUT);
  1410. }
  1411. #else
  1412. if (n == 0) {
  1413. errno = ETIMEDOUT;
  1414. }
  1415. #endif
  1416. return -1;
  1417. }
  1418. return accept(s, addr, addrlen);
  1419. }
  1420. /* }}} */
  1421. /* {{{ ftp_getdata
  1422. */
  1423. databuf_t*
  1424. ftp_getdata(ftpbuf_t *ftp)
  1425. {
  1426. int fd = -1;
  1427. databuf_t *data;
  1428. php_sockaddr_storage addr;
  1429. struct sockaddr *sa;
  1430. socklen_t size;
  1431. union ipbox ipbox;
  1432. char arg[sizeof("255, 255, 255, 255, 255, 255")];
  1433. struct timeval tv;
  1434. int arg_len;
  1435. /* ask for a passive connection if we need one */
  1436. if (ftp->pasv && !ftp_pasv(ftp, 1)) {
  1437. return NULL;
  1438. }
  1439. /* alloc the data structure */
  1440. data = ecalloc(1, sizeof(*data));
  1441. data->listener = -1;
  1442. data->fd = -1;
  1443. data->type = ftp->type;
  1444. sa = (struct sockaddr *) &ftp->localaddr;
  1445. /* bind/listen */
  1446. if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == SOCK_ERR) {
  1447. php_error_docref(NULL, E_WARNING, "socket() failed: %s (%d)", strerror(errno), errno);
  1448. goto bail;
  1449. }
  1450. /* passive connection handler */
  1451. if (ftp->pasv) {
  1452. /* clear the ready status */
  1453. ftp->pasv = 1;
  1454. /* connect */
  1455. /* Win 95/98 seems not to like size > sizeof(sockaddr_in) */
  1456. size = php_sockaddr_size(&ftp->pasvaddr);
  1457. tv.tv_sec = ftp->timeout_sec;
  1458. tv.tv_usec = 0;
  1459. if (php_connect_nonb(fd, (struct sockaddr*) &ftp->pasvaddr, size, &tv) == -1) {
  1460. php_error_docref(NULL, E_WARNING, "php_connect_nonb() failed: %s (%d)", strerror(errno), errno);
  1461. goto bail;
  1462. }
  1463. data->fd = fd;
  1464. ftp->data = data;
  1465. return data;
  1466. }
  1467. /* active (normal) connection */
  1468. /* bind to a local address */
  1469. php_any_addr(sa->sa_family, &addr, 0);
  1470. size = php_sockaddr_size(&addr);
  1471. if (bind(fd, (struct sockaddr*) &addr, size) != 0) {
  1472. php_error_docref(NULL, E_WARNING, "bind() failed: %s (%d)", strerror(errno), errno);
  1473. goto bail;
  1474. }
  1475. if (getsockname(fd, (struct sockaddr*) &addr, &size) != 0) {
  1476. php_error_docref(NULL, E_WARNING, "getsockname() failed: %s (%d)", strerror(errno), errno);
  1477. goto bail;
  1478. }
  1479. if (listen(fd, 5) != 0) {
  1480. php_error_docref(NULL, E_WARNING, "listen() failed: %s (%d)", strerror(errno), errno);
  1481. goto bail;
  1482. }
  1483. data->listener = fd;
  1484. #if HAVE_IPV6 && HAVE_INET_NTOP
  1485. if (sa->sa_family == AF_INET6) {
  1486. /* need to use EPRT */
  1487. char eprtarg[INET6_ADDRSTRLEN + sizeof("|x||xxxxx|")];
  1488. char out[INET6_ADDRSTRLEN];
  1489. int eprtarg_len;
  1490. inet_ntop(AF_INET6, &((struct sockaddr_in6*) sa)->sin6_addr, out, sizeof(out));
  1491. eprtarg_len = snprintf(eprtarg, sizeof(eprtarg), "|2|%s|%hu|", out, ntohs(((struct sockaddr_in6 *) &addr)->sin6_port));
  1492. if (eprtarg_len < 0) {
  1493. goto bail;
  1494. }
  1495. if (!ftp_putcmd(ftp, "EPRT", sizeof("EPRT")-1, eprtarg, eprtarg_len)) {
  1496. goto bail;
  1497. }
  1498. if (!ftp_getresp(ftp) || ftp->resp != 200) {
  1499. goto bail;
  1500. }
  1501. ftp->data = data;
  1502. return data;
  1503. }
  1504. #endif
  1505. /* send the PORT */
  1506. ipbox.ia[0] = ((struct sockaddr_in*) sa)->sin_addr;
  1507. ipbox.s[2] = ((struct sockaddr_in*) &addr)->sin_port;
  1508. arg_len = snprintf(arg, sizeof(arg), "%u,%u,%u,%u,%u,%u", ipbox.c[0], ipbox.c[1], ipbox.c[2], ipbox.c[3], ipbox.c[4], ipbox.c[5]);
  1509. if (arg_len < 0) {
  1510. goto bail;
  1511. }
  1512. if (!ftp_putcmd(ftp, "PORT", sizeof("PORT")-1, arg, arg_len)) {
  1513. goto bail;
  1514. }
  1515. if (!ftp_getresp(ftp) || ftp->resp != 200) {
  1516. goto bail;
  1517. }
  1518. ftp->data = data;
  1519. return data;
  1520. bail:
  1521. if (fd != -1) {
  1522. closesocket(fd);
  1523. }
  1524. efree(data);
  1525. return NULL;
  1526. }
  1527. /* }}} */
  1528. /* {{{ data_accept
  1529. */
  1530. databuf_t*
  1531. data_accept(databuf_t *data, ftpbuf_t *ftp)
  1532. {
  1533. php_sockaddr_storage addr;
  1534. socklen_t size;
  1535. #ifdef HAVE_FTP_SSL
  1536. SSL_CTX *ctx;
  1537. SSL_SESSION *session;
  1538. int err, res;
  1539. zend_bool retry;
  1540. #endif
  1541. if (data->fd != -1) {
  1542. goto data_accepted;
  1543. }
  1544. size = sizeof(addr);
  1545. data->fd = my_accept(ftp, data->listener, (struct sockaddr*) &addr, &size);
  1546. closesocket(data->listener);
  1547. data->listener = -1;
  1548. if (data->fd == -1) {
  1549. efree(data);
  1550. return NULL;
  1551. }
  1552. data_accepted:
  1553. #ifdef HAVE_FTP_SSL
  1554. /* now enable ssl if we need to */
  1555. if (ftp->use_ssl && ftp->use_ssl_for_data) {
  1556. ctx = SSL_get_SSL_CTX(ftp->ssl_handle);
  1557. if (ctx == NULL) {
  1558. php_error_docref(NULL, E_WARNING, "data_accept: failed to retrieve the existing SSL context");
  1559. return 0;
  1560. }
  1561. data->ssl_handle = SSL_new(ctx);
  1562. if (data->ssl_handle == NULL) {
  1563. php_error_docref(NULL, E_WARNING, "data_accept: failed to create the SSL handle");
  1564. return 0;
  1565. }
  1566. SSL_set_fd(data->ssl_handle, data->fd);
  1567. if (ftp->old_ssl) {
  1568. SSL_copy_session_id(data->ssl_handle, ftp->ssl_handle);
  1569. }
  1570. /* get the session from the control connection so we can re-use it */
  1571. session = SSL_get_session(ftp->ssl_handle);
  1572. if (session == NULL) {
  1573. php_error_docref(NULL, E_WARNING, "data_accept: failed to retrieve the existing SSL session");
  1574. SSL_free(data->ssl_handle);
  1575. return 0;
  1576. }
  1577. /* and set it on the data connection */
  1578. res = SSL_set_session(data->ssl_handle, session);
  1579. if (res == 0) {
  1580. php_error_docref(NULL, E_WARNING, "data_accept: failed to set the existing SSL session");
  1581. SSL_free(data->ssl_handle);
  1582. return 0;
  1583. }
  1584. do {
  1585. res = SSL_connect(data->ssl_handle);
  1586. err = SSL_get_error(data->ssl_handle, res);
  1587. switch (err) {
  1588. case SSL_ERROR_NONE:
  1589. retry = 0;
  1590. break;
  1591. case SSL_ERROR_ZERO_RETURN:
  1592. retry = 0;
  1593. SSL_shutdown(data->ssl_handle);
  1594. break;
  1595. case SSL_ERROR_WANT_READ:
  1596. case SSL_ERROR_WANT_WRITE: {
  1597. php_pollfd p;
  1598. int i;
  1599. p.fd = data->fd;
  1600. p.events = (err == SSL_ERROR_WANT_READ) ? (POLLIN|POLLPRI) : POLLOUT;
  1601. p.revents = 0;
  1602. i = php_poll2(&p, 1, 300);
  1603. retry = i > 0;
  1604. }
  1605. break;
  1606. default:
  1607. php_error_docref(NULL, E_WARNING, "data_accept: SSL/TLS handshake failed");
  1608. SSL_shutdown(data->ssl_handle);
  1609. SSL_free(data->ssl_handle);
  1610. return 0;
  1611. }
  1612. } while (retry);
  1613. data->ssl_active = 1;
  1614. }
  1615. #endif
  1616. return data;
  1617. }
  1618. /* }}} */
  1619. /* {{{ ftp_ssl_shutdown
  1620. */
  1621. #ifdef HAVE_FTP_SSL
  1622. static void ftp_ssl_shutdown(ftpbuf_t *ftp, php_socket_t fd, SSL *ssl_handle) {
  1623. /* In TLS 1.3 it's common to receive session tickets after the handshake has completed. We need to train
  1624. the socket (read the tickets until EOF/close_notify alert) before closing the socket. Otherwise the
  1625. server might get an ECONNRESET which might lead to data truncation on server side.
  1626. */
  1627. char buf[256]; /* We will use this for the OpenSSL error buffer, so it has
  1628. to be at least 256 bytes long.*/
  1629. int done = 1, err, nread;
  1630. unsigned long sslerror;
  1631. err = SSL_shutdown(ssl_handle);
  1632. if (err < 0) {
  1633. php_error_docref(NULL, E_WARNING, "SSL_shutdown failed");
  1634. }
  1635. else if (err == 0) {
  1636. /* The shutdown is not yet finished. Call SSL_read() to do a bidirectional shutdown. */
  1637. done = 0;
  1638. }
  1639. while (!done && data_available(ftp, fd)) {
  1640. ERR_clear_error();
  1641. nread = SSL_read(ssl_handle, buf, sizeof(buf));
  1642. if (nread <= 0) {
  1643. err = SSL_get_error(ssl_handle, nread);
  1644. switch (err) {
  1645. case SSL_ERROR_NONE: /* this is not an error */
  1646. case SSL_ERROR_ZERO_RETURN: /* no more data */
  1647. /* This is the expected response. There was no data but only
  1648. the close notify alert */
  1649. done = 1;
  1650. break;
  1651. case SSL_ERROR_WANT_READ:
  1652. /* there's data pending, re-invoke SSL_read() */
  1653. break;
  1654. case SSL_ERROR_WANT_WRITE:
  1655. /* SSL wants a write. Really odd. Let's bail out. */
  1656. done = 1;
  1657. break;
  1658. default:
  1659. if ((sslerror = ERR_get_error())) {
  1660. ERR_error_string_n(sslerror, buf, sizeof(buf));
  1661. php_error_docref(NULL, E_WARNING, "SSL_read on shutdown: %s", buf);
  1662. } else if (errno) {
  1663. php_error_docref(NULL, E_WARNING, "SSL_read on shutdown: %s (%d)", strerror(errno), errno);
  1664. }
  1665. done = 1;
  1666. break;
  1667. }
  1668. }
  1669. }
  1670. (void)SSL_free(ssl_handle);
  1671. }
  1672. #endif
  1673. /* }}} */
  1674. /* {{{ data_close
  1675. */
  1676. databuf_t*
  1677. data_close(ftpbuf_t *ftp, databuf_t *data)
  1678. {
  1679. if (data == NULL) {
  1680. return NULL;
  1681. }
  1682. if (data->listener != -1) {
  1683. #ifdef HAVE_FTP_SSL
  1684. if (data->ssl_active) {
  1685. /* don't free the data context, it's the same as the control */
  1686. ftp_ssl_shutdown(ftp, data->listener, data->ssl_handle);
  1687. data->ssl_active = 0;
  1688. }
  1689. #endif
  1690. closesocket(data->listener);
  1691. }
  1692. if (data->fd != -1) {
  1693. #ifdef HAVE_FTP_SSL
  1694. if (data->ssl_active) {
  1695. /* don't free the data context, it's the same as the control */
  1696. ftp_ssl_shutdown(ftp, data->fd, data->ssl_handle);
  1697. data->ssl_active = 0;
  1698. }
  1699. #endif
  1700. closesocket(data->fd);
  1701. }
  1702. if (ftp) {
  1703. ftp->data = NULL;
  1704. }
  1705. efree(data);
  1706. return NULL;
  1707. }
  1708. /* }}} */
  1709. /* {{{ ftp_genlist
  1710. */
  1711. char**
  1712. ftp_genlist(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, const char *path, const size_t path_len)
  1713. {
  1714. php_stream *tmpstream = NULL;
  1715. databuf_t *data = NULL;
  1716. char *ptr;
  1717. int ch, lastch;
  1718. size_t size, rcvd;
  1719. size_t lines;
  1720. char **ret = NULL;
  1721. char **entry;
  1722. char *text;
  1723. if ((tmpstream = php_stream_fopen_tmpfile()) == NULL) {
  1724. php_error_docref(NULL, E_WARNING, "Unable to create temporary file. Check permissions in temporary files directory.");
  1725. return NULL;
  1726. }
  1727. if (!ftp_type(ftp, FTPTYPE_ASCII)) {
  1728. goto bail;
  1729. }
  1730. if ((data = ftp_getdata(ftp)) == NULL) {
  1731. goto bail;
  1732. }
  1733. ftp->data = data;
  1734. if (!ftp_putcmd(ftp, cmd, cmd_len, path, path_len)) {
  1735. goto bail;
  1736. }
  1737. if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125 && ftp->resp != 226)) {
  1738. goto bail;
  1739. }
  1740. /* some servers don't open a ftp-data connection if the directory is empty */
  1741. if (ftp->resp == 226) {
  1742. ftp->data = data_close(ftp, data);
  1743. php_stream_close(tmpstream);
  1744. return ecalloc(1, sizeof(char*));
  1745. }
  1746. /* pull data buffer into tmpfile */
  1747. if ((data = data_accept(data, ftp)) == NULL) {
  1748. goto bail;
  1749. }
  1750. size = 0;
  1751. lines = 0;
  1752. lastch = 0;
  1753. while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
  1754. if (rcvd == (size_t)-1 || rcvd > ((size_t)(-1))-size) {
  1755. goto bail;
  1756. }
  1757. php_stream_write(tmpstream, data->buf, rcvd);
  1758. size += rcvd;
  1759. for (ptr = data->buf; rcvd; rcvd--, ptr++) {
  1760. if (*ptr == '\n' && lastch == '\r') {
  1761. lines++;
  1762. }
  1763. lastch = *ptr;
  1764. }
  1765. }
  1766. ftp->data = data_close(ftp, data);
  1767. php_stream_rewind(tmpstream);
  1768. ret = safe_emalloc((lines + 1), sizeof(char*), size);
  1769. entry = ret;
  1770. text = (char*) (ret + lines + 1);
  1771. *entry = text;
  1772. lastch = 0;
  1773. while ((ch = php_stream_getc(tmpstream)) != EOF) {
  1774. if (ch == '\n' && lastch == '\r') {
  1775. *(text - 1) = 0;
  1776. *++entry = text;
  1777. } else {
  1778. *text++ = ch;
  1779. }
  1780. lastch = ch;
  1781. }
  1782. *entry = NULL;
  1783. php_stream_close(tmpstream);
  1784. if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
  1785. efree(ret);
  1786. return NULL;
  1787. }
  1788. return ret;
  1789. bail:
  1790. ftp->data = data_close(ftp, data);
  1791. php_stream_close(tmpstream);
  1792. if (ret)
  1793. efree(ret);
  1794. return NULL;
  1795. }
  1796. /* }}} */
  1797. /* {{{ ftp_nb_get
  1798. */
  1799. int
  1800. ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t path_len, ftptype_t type, zend_long resumepos)
  1801. {
  1802. databuf_t *data = NULL;
  1803. char arg[11];
  1804. if (ftp == NULL) {
  1805. return PHP_FTP_FAILED;
  1806. }
  1807. if (!ftp_type(ftp, type)) {
  1808. goto bail;
  1809. }
  1810. if ((data = ftp_getdata(ftp)) == NULL) {
  1811. goto bail;
  1812. }
  1813. if (resumepos>0) {
  1814. int arg_len = snprintf(arg, sizeof(arg), ZEND_LONG_FMT, resumepos);
  1815. if (arg_len < 0) {
  1816. goto bail;
  1817. }
  1818. if (!ftp_putcmd(ftp, "REST", sizeof("REST")-1, arg, arg_len)) {
  1819. goto bail;
  1820. }
  1821. if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
  1822. goto bail;
  1823. }
  1824. }
  1825. if (!ftp_putcmd(ftp, "RETR", sizeof("RETR")-1, path, path_len)) {
  1826. goto bail;
  1827. }
  1828. if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
  1829. goto bail;
  1830. }
  1831. if ((data = data_accept(data, ftp)) == NULL) {
  1832. goto bail;
  1833. }
  1834. ftp->data = data;
  1835. ftp->stream = outstream;
  1836. ftp->lastch = 0;
  1837. ftp->nb = 1;
  1838. return (ftp_nb_continue_read(ftp));
  1839. bail:
  1840. ftp->data = data_close(ftp, data);
  1841. return PHP_FTP_FAILED;
  1842. }
  1843. /* }}} */
  1844. /* {{{ ftp_nb_continue_read
  1845. */
  1846. int
  1847. ftp_nb_continue_read(ftpbuf_t *ftp)
  1848. {
  1849. databuf_t *data = NULL;
  1850. char *ptr;
  1851. int lastch;
  1852. size_t rcvd;
  1853. ftptype_t type;
  1854. data = ftp->data;
  1855. /* check if there is already more data */
  1856. if (!data_available(ftp, data->fd)) {
  1857. return PHP_FTP_MOREDATA;
  1858. }
  1859. type = ftp->type;
  1860. lastch = ftp->lastch;
  1861. if ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
  1862. if (rcvd == (size_t)-1) {
  1863. goto bail;
  1864. }
  1865. if (type == FTPTYPE_ASCII) {
  1866. for (ptr = data->buf; rcvd; rcvd--, ptr++) {
  1867. if (lastch == '\r' && *ptr != '\n') {
  1868. php_stream_putc(ftp->stream, '\r');
  1869. }
  1870. if (*ptr != '\r') {
  1871. php_stream_putc(ftp->stream, *ptr);
  1872. }
  1873. lastch = *ptr;
  1874. }
  1875. } else if (rcvd != php_stream_write(ftp->stream, data->buf, rcvd)) {
  1876. goto bail;
  1877. }
  1878. ftp->lastch = lastch;
  1879. return PHP_FTP_MOREDATA;
  1880. }
  1881. if (type == FTPTYPE_ASCII && lastch == '\r') {
  1882. php_stream_putc(ftp->stream, '\r');
  1883. }
  1884. ftp->data = data = data_close(ftp, data);
  1885. if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
  1886. goto bail;
  1887. }
  1888. ftp->nb = 0;
  1889. return PHP_FTP_FINISHED;
  1890. bail:
  1891. ftp->nb = 0;
  1892. ftp->data = data_close(ftp, data);
  1893. return PHP_FTP_FAILED;
  1894. }
  1895. /* }}} */
  1896. /* {{{ ftp_nb_put
  1897. */
  1898. int
  1899. ftp_nb_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type, zend_long startpos)
  1900. {
  1901. databuf_t *data = NULL;
  1902. char arg[11];
  1903. if (ftp == NULL) {
  1904. return 0;
  1905. }
  1906. if (!ftp_type(ftp, type)) {
  1907. goto bail;
  1908. }
  1909. if ((data = ftp_getdata(ftp)) == NULL) {
  1910. goto bail;
  1911. }
  1912. if (startpos > 0) {
  1913. int arg_len = snprintf(arg, sizeof(arg), ZEND_LONG_FMT, startpos);
  1914. if (arg_len < 0) {
  1915. goto bail;
  1916. }
  1917. if (!ftp_putcmd(ftp, "REST", sizeof("REST")-1, arg, arg_len)) {
  1918. goto bail;
  1919. }
  1920. if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
  1921. goto bail;
  1922. }
  1923. }
  1924. if (!ftp_putcmd(ftp, "STOR", sizeof("STOR")-1, path, path_len)) {
  1925. goto bail;
  1926. }
  1927. if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
  1928. goto bail;
  1929. }
  1930. if ((data = data_accept(data, ftp)) == NULL) {
  1931. goto bail;
  1932. }
  1933. ftp->data = data;
  1934. ftp->stream = instream;
  1935. ftp->lastch = 0;
  1936. ftp->nb = 1;
  1937. return (ftp_nb_continue_write(ftp));
  1938. bail:
  1939. ftp->data = data_close(ftp, data);
  1940. return PHP_FTP_FAILED;
  1941. }
  1942. /* }}} */
  1943. /* {{{ ftp_nb_continue_write
  1944. */
  1945. int
  1946. ftp_nb_continue_write(ftpbuf_t *ftp)
  1947. {
  1948. long size;
  1949. char *ptr;
  1950. int ch;
  1951. /* check if we can write more data */
  1952. if (!data_writeable(ftp, ftp->data->fd)) {
  1953. return PHP_FTP_MOREDATA;
  1954. }
  1955. size = 0;
  1956. ptr = ftp->data->buf;
  1957. while (!php_stream_eof(ftp->stream) && (ch = php_stream_getc(ftp->stream)) != EOF) {
  1958. if (ch == '\n' && ftp->type == FTPTYPE_ASCII) {
  1959. *ptr++ = '\r';
  1960. size++;
  1961. }
  1962. *ptr++ = ch;
  1963. size++;
  1964. /* flush if necessary */
  1965. if (FTP_BUFSIZE - size < 2) {
  1966. if (my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size) {
  1967. goto bail;
  1968. }
  1969. return PHP_FTP_MOREDATA;
  1970. }
  1971. }
  1972. if (size && my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size) {
  1973. goto bail;
  1974. }
  1975. ftp->data = data_close(ftp, ftp->data);
  1976. if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
  1977. goto bail;
  1978. }
  1979. ftp->nb = 0;
  1980. return PHP_FTP_FINISHED;
  1981. bail:
  1982. ftp->data = data_close(ftp, ftp->data);
  1983. ftp->nb = 0;
  1984. return PHP_FTP_FAILED;
  1985. }
  1986. /* }}} */
  1987. #endif /* HAVE_FTP */
  1988. /*
  1989. * Local variables:
  1990. * tab-width: 4
  1991. * c-basic-offset: 4
  1992. * End:
  1993. * vim600: sw=4 ts=4 fdm=marker
  1994. * vim<600: sw=4 ts=4
  1995. */