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