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