1 /***************************************************************************/
2 /* This code is part of WWW grabber called pavuk */
3 /* Copyright (c) 1997 - 2001 Stefan Ondrejicka */
4 /* Distributed under GPL 2 or later */
5 /***************************************************************************/
6
7 #include "config.h"
8
9 #include <ctype.h>
10 #include <errno.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <netdb.h>
14 #include <netinet/in.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/socket.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <time.h>
22 #include <unistd.h>
23 #include <unistd.h>
24 #ifdef HAVE_ARPA_INET_H
25 #include <arpa/inet.h>
26 #endif
27
28 #include "absio.h"
29 #include "abstract.h"
30 #include "dns.h"
31 #include "doc.h"
32 #include "errcode.h"
33 #include "ftp.h"
34 #include "http.h"
35 #include "mode.h"
36 #include "myssl.h"
37 #include "net.h"
38 #include "times.h"
39 #include "tools.h"
40 #include "uexit.h"
41 #include "url.h"
42
43 static ftp_handshake_info *ftp_handshake_info_data_find(char *, int);
44 static int ftp_do_login_handshake_cust(ftp_handshake_info *, doc *, char *,
45 char *);
46
ftp_control_write(doc * docp,char * buf,size_t bufsize)47 static int ftp_control_write(doc * docp, char *buf, size_t bufsize)
48 {
49 return bufio_write(docp->ftp_control, buf, bufsize);
50 }
51
ftp_control_readln(doc * docp,char * buf,int bufsize)52 static int ftp_control_readln(doc * docp, char *buf, int bufsize)
53 {
54 return bufio_readln(docp->ftp_control, buf, bufsize);
55 }
56
57 /********************************************************/
58 /* zistenie navratoveho kodu z FTP servera */
59 /* FIXME: Translate me! */
60 /********************************************************/
ftp_get_response(doc * docp,char ** mbuf,int setrc)61 int ftp_get_response(doc * docp, char **mbuf, int setrc)
62 {
63 char buf[1024];
64 bool_t end = FALSE;
65 int alen, tlen = 0;
66 char *sresp = NULL;
67
68 while(!end)
69 {
70 if((alen = ftp_control_readln(docp, buf, sizeof(buf))) > 0)
71 {
72 DEBUG_PROTOS("%s", buf);
73 if(mbuf)
74 {
75 tlen += alen;
76 sresp = _realloc(sresp, tlen + 1);
77 memcpy(sresp + tlen - alen, buf, alen + 1);
78 }
79
80 if(strlen(buf) > 3)
81 {
82 if(tl_ascii_isdigit(*(buf)) &&
83 tl_ascii_isdigit(*(buf + 1)) &&
84 tl_ascii_isdigit(*(buf + 2)) && tl_ascii_isspace(*(buf + 3)))
85 end = TRUE;
86 }
87 }
88 else
89 {
90 if(alen)
91 xperror("ftp_get_response");
92 else
93 xprintf(1,
94 gettext
95 ("ftp_get_response: ftp control connection closed before any response\n"));
96 if(setrc)
97 docp->ftp_respc = 600;
98 return 600;
99 }
100 }
101
102 if(mbuf)
103 *mbuf = sresp;
104
105 if(setrc)
106 docp->ftp_respc = _atoi(buf);
107
108 return _atoi(buf);
109 }
110
ftp_open_data_finish(doc * docp)111 static bufio *ftp_open_data_finish(doc * docp)
112 {
113 if(docp->ftp_data_con_finished)
114 return docp->datasock;
115
116 if(!cfg.ftp_activec || (priv_cfg.ftp_proxy && cfg.ftp_dirtyp))
117 {
118 if(priv_cfg.ftp_proxy && cfg.ftp_dirtyp)
119 {
120 if(!(docp->datasock =
121 bufio_sock_fdopen(net_connect(priv_cfg.ftp_proxy,
122 cfg.ftp_proxy_port, docp))))
123 {
124 if(_h_errno_ != 0)
125 xherror(priv_cfg.ftp_proxy);
126 else
127 xperror("net_connect");
128
129 docp->errcode = ERR_PROXY_CONNECT;
130 return NULL;
131 }
132 if(http_dumy_proxy_connect(docp, docp->ftp_pasv_host,
133 docp->ftp_pasv_port, priv_cfg.ftp_proxy, cfg.ftp_proxy_port))
134 {
135 docp->errcode = ERR_PROXY_CONNECT;
136 bufio_close(docp->datasock);
137 docp->datasock = NULL;
138 return NULL;
139 }
140 }
141 else
142 {
143 if(!(docp->datasock =
144 bufio_sock_fdopen(net_connect(docp->ftp_pasv_host,
145 docp->ftp_pasv_port, docp))))
146 {
147 if(_h_errno_ != 0)
148 xherror(priv_cfg.ftp_proxy);
149 else
150 xperror("net_connect");
151
152 docp->errcode = ERR_FTP_DATACON;
153 return NULL;
154 }
155 }
156 }
157 else
158 {
159 bufio *dsock = bufio_sock_fdopen(net_accept(bufio_getfd(docp->datasock)));
160 bufio_close(docp->datasock);
161 docp->datasock = dsock;
162 }
163
164 #ifdef IP_TOS
165 #ifdef IPTOS_THROUGHPUT
166 if(docp->datasock)
167 {
168 int v = IPTOS_THROUGHPUT;
169
170 if(setsockopt(bufio_getfd(docp->datasock),
171 IPPROTO_IP, IP_TOS, (char *) &v, sizeof(v)))
172 {
173 xperror(gettext("ftp: setsockopt TOS - THROUGHPUT failed"));
174 }
175 }
176 #endif
177 #endif
178
179 #ifdef USE_SSL
180 if(docp->doc_url->type == URLT_FTPS)
181 {
182 bufio *ssl_sock;
183
184 ssl_sock = my_ssl_do_connect(docp, docp->datasock,
185 bufio_get_ssl_hook_data(docp->ftp_control));
186
187 if(!ssl_sock)
188 {
189 if(!docp->errcode)
190 docp->errcode = ERR_FTPS_DATASSLCONNECT;
191 bufio_close(docp->datasock);
192 docp->datasock = NULL;
193 }
194 else
195 docp->datasock = ssl_sock;
196 }
197 #endif
198
199 if(docp->datasock)
200 docp->ftp_data_con_finished = TRUE;
201
202 return docp->datasock;
203 }
204
ftp_open_data_init(doc * docp)205 static int ftp_open_data_init(doc * docp)
206 {
207 char buf[256];
208 char *mbuf;
209 struct sockaddr_storage scaddr;
210 struct sockaddr *caddr;
211 int reply;
212 socklen_t n;
213
214 caddr = (struct sockaddr *) &scaddr;
215
216 n = sizeof(scaddr);
217 if(getsockname(bufio_getfd(docp->ftp_control), caddr, &n))
218 {
219 xperror("FTP control getsockname");
220 docp->datasock = NULL;
221 return -1;
222 }
223
224
225 if(!cfg.ftp_activec || (priv_cfg.ftp_proxy && cfg.ftp_dirtyp))
226 {
227 #ifdef HAVE_INET6
228 if(caddr->sa_family == AF_INET6)
229 {
230 sprintf(buf, "EPSV\r\n");
231 DEBUG_PROTOC("%s", buf);
232
233 ftp_control_write(docp, buf, strlen(buf));
234
235 mbuf = NULL;
236
237 if((reply = ftp_get_response(docp, &mbuf, TRUE)) >= 400)
238 {
239 int h[16], p[2], hal, af, pal;
240 abs_addr haddr;
241
242 _free(mbuf) if(reply == 600)
243 {
244 docp->ftp_fatal_err = TRUE;
245 return -1;
246 }
247 sprintf(buf, "LPSV\r\n");
248 DEBUG_PROTOC("%s", buf);
249
250 ftp_control_write(docp, buf, strlen(buf));
251
252 mbuf = NULL;
253
254 if((reply = ftp_get_response(docp, &mbuf, TRUE)) >= 400)
255 {
256 docp->ftp_fatal_err = (reply == 600);
257 _free(mbuf);
258 return -1;
259 }
260 n = sscanf(mbuf,
261 "%d %*[^0-9]%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
262 &reply, &af, &hal, &h[0], &h[1], &h[2], &h[3],
263 &h[4], &h[5], &h[6], &h[7], &h[8], &h[9],
264 &h[10], &h[11], &h[12], &h[13], &h[14], &h[15], &pal, &p[0], &p[1]);
265 if(n != 22 || reply != 228 || af != 6 || hal != 16 || pal != 2)
266 {
267 xprintf(1,
268 gettext("Error parsing FTP response to %s command - %s\n"),
269 "LPSV", mbuf);
270 _free(mbuf);
271 return -1;
272 }
273 _free(mbuf);
274 docp->ftp_pasv_port = (p[0] << 8) + p[1];
275 haddr.family = AF_INET6;
276 for(n = 0; n < 16; n++)
277 haddr.addr[n] = (unsigned char) h[n];
278 docp->ftp_pasv_host = dns_get_abs_addr_ip(&haddr);
279 }
280 else
281 {
282 int port;
283 char d[4];
284
285 n = sscanf(mbuf, "%d %*[^0-9(]\(%c%c%c%d%c", &reply,
286 &d[0], &d[1], &d[2], &port, &d[3]);
287 if(n != 6 || reply != 229 ||
288 d[0] != d[1] || d[0] != d[2] || d[0] != d[3])
289 {
290 xprintf(1,
291 gettext("Error parsing FTP response to %s command - %s\n"),
292 "EPSV", mbuf);
293 _free(mbuf);
294 return -1;
295 }
296 _free(mbuf);
297 docp->ftp_pasv_port = port;
298 docp->ftp_pasv_host = dns_get_sockaddr_ip(caddr);
299 }
300 }
301 else
302 #endif
303 {
304 int h0, h1, h2, h3, p0, p1;
305
306 sprintf(buf, "PASV\r\n");
307 DEBUG_PROTOC("%s", buf);
308
309 ftp_control_write(docp, buf, strlen(buf));
310
311 mbuf = NULL;
312
313 if((reply = ftp_get_response(docp, &mbuf, TRUE)) >= 400)
314 {
315 docp->ftp_fatal_err = (reply == 600);
316 _free(mbuf);
317 return -1;
318 }
319
320 if(!mbuf)
321 {
322 return -1;
323 }
324
325 n = sscanf(mbuf, "%d %*[^0-9]%d,%d,%d,%d,%d,%d", &reply,
326 &h0, &h1, &h2, &h3, &p0, &p1);
327
328
329 if(n != 7 || reply != 227)
330 {
331 xprintf(1, gettext("Error parsing FTP response to %s command - %s\n"),
332 "PASV", mbuf);
333 _free(mbuf);
334 return -1;
335 }
336 _free(mbuf);
337
338 docp->ftp_pasv_port = (p0 << 8) + p1;
339
340 sprintf(buf, "%d.%d.%d.%d", h0, h1, h2, h3);
341 docp->ftp_pasv_host = tl_strdup(buf);
342 }
343 }
344 else
345 {
346 struct sockaddr_storage saddr;
347 struct sockaddr *addr;
348 char *p;
349 int port;
350
351 addr = (struct sockaddr *) &saddr;
352
353 if(!docp->datasock)
354 {
355 int bfd;
356 abs_addr laddr;
357 memset(laddr.addr, '\0', sizeof(laddr.addr));
358 laddr.family = caddr->sa_family;
359
360 if(priv_cfg.local_ip)
361 {
362 memcpy(laddr.addr, cfg.local_ip_addr.addr, sizeof(laddr.addr));
363 laddr.family = cfg.local_ip_addr.family;
364 }
365
366 bfd = net_bindport(&laddr, cfg.active_ftp_min_port,
367 cfg.active_ftp_max_port);
368
369 if(!(docp->datasock = bufio_sock_fdopen(bfd)))
370 {
371 xperror("bind");
372 return -1;
373 }
374 }
375
376 n = sizeof(saddr);
377 if(getsockname(bufio_getfd(docp->datasock), addr, &n))
378 {
379 xperror("FTP data getsockname");
380 bufio_close(docp->datasock);
381 docp->datasock = NULL;
382 return -1;
383 }
384
385 port = dns_get_sockaddr_port(addr);
386 mbuf = dns_get_sockaddr_ip(caddr);
387 #ifdef HAVE_INET6
388 if(caddr->sa_family == AF_INET6)
389 {
390 snprintf(buf, sizeof(buf), "EPRT |2|%s|%d|\r\n", mbuf, port);
391 _free(mbuf);
392
393 ftp_control_write(docp, buf, strlen(buf));
394 DEBUG_PROTOC("%s", buf);
395
396 if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)
397 {
398 unsigned char *h;
399
400 if(reply == 600)
401 {
402 bufio_close(docp->datasock);
403 docp->datasock = NULL;
404 docp->ftp_fatal_err = TRUE;
405 return -1;
406 }
407 h = ((struct sockaddr_in6 *) caddr)->sin6_addr.s6_addr;
408
409 sprintf(buf,
410 "LPRT 6,16,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,2,%d,%d\r\n",
411 h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10],
412 h[11], h[12], h[13], h[14], h[15], port / 256, port % 256);
413
414 ftp_control_write(docp, buf, strlen(buf));
415 DEBUG_PROTOC("%s", buf);
416
417 if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)
418 {
419 bufio_close(docp->datasock);
420 docp->datasock = NULL;
421 docp->ftp_fatal_err = (reply == 600);
422 return -1;
423 }
424 }
425 }
426 else
427 #endif
428 {
429 for(p = mbuf; (p = strchr(p, '.')); *p = ',');
430 snprintf(buf, sizeof(buf), "PORT %s,%d,%d\r\n", mbuf, port / 256, port % 256);
431 _free(mbuf);
432
433 ftp_control_write(docp, buf, strlen(buf));
434 DEBUG_PROTOC("%s", buf);
435
436 if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)
437 {
438 bufio_close(docp->datasock);
439 docp->datasock = NULL;
440 docp->ftp_fatal_err = (reply == 600);
441 return -1;
442 }
443 }
444 }
445
446 return 0;
447 }
448
ftp_do_login_handshake(doc * docp,char * ruser,char * user,char * password)449 static int ftp_do_login_handshake(doc * docp, char *ruser, char *user,
450 char *password)
451 {
452 ftp_handshake_info *fhi;
453
454 fhi = ftp_handshake_info_data_find(docp->doc_url->p.ftp.host,
455 docp->doc_url->p.ftp.port);
456
457 if(!fhi)
458 fhi = ftp_handshake_info_data_find("", DEFAULT_FTP_PORT);
459
460 if(fhi)
461 {
462 if(ftp_do_login_handshake_cust(fhi, docp, ruser, password))
463 {
464 docp->ftp_fatal_err = TRUE;
465 docp->errcode = ERR_FTP_LOGIN_HANDSHAKE;
466 return -1;
467 }
468 }
469 else
470 {
471 char buf[2048];
472 int reply;
473
474 if(priv_cfg.ftp_proxy_user && priv_cfg.ftp_proxy &&
475 !cfg.ftp_via_http && !cfg.ftp_dirtyp)
476 {
477 snprintf(buf, sizeof(buf), "USER %s\r\n", priv_cfg.ftp_proxy_user);
478 ftp_control_write(docp, buf, strlen(buf));
479 DEBUG_PROTOC("%s", buf);
480
481 if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)
482 {
483 docp->ftp_fatal_err = TRUE;
484 docp->errcode = ERR_FTP_BPROXYUSER;
485 return -1;
486 }
487 }
488 else
489 reply = 0;
490
491 if(priv_cfg.ftp_proxy_pass && priv_cfg.ftp_proxy &&
492 !cfg.ftp_via_http && !cfg.ftp_dirtyp)
493 {
494
495 if(reply == 331) /*** we need password ***/
496 {
497 snprintf(buf, sizeof(buf), "PASS %s\r\n", priv_cfg.ftp_proxy_pass);
498 ftp_control_write(docp, buf, strlen(buf));
499 DEBUG_PROTOC("%s", buf);
500
501 if(ftp_get_response(docp, NULL, TRUE) >= 400)
502 {
503 docp->ftp_fatal_err = TRUE;
504 docp->errcode = ERR_FTP_BPROXYPASS;
505 return -1;
506 }
507 }
508 }
509
510 snprintf(buf, sizeof(buf), "USER %s\r\n", user);
511 ftp_control_write(docp, buf, strlen(buf));
512 DEBUG_PROTOC("%s", buf);
513
514 if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)
515 {
516 docp->ftp_fatal_err = TRUE;
517 docp->errcode = ERR_FTP_BUSER;
518 return -1;
519 }
520
521 if(reply == 331) /*** we need password ***/
522 {
523 snprintf(buf, sizeof(buf), "PASS %s\r\n", password);
524 ftp_control_write(docp, buf, strlen(buf));
525 DEBUG_PROTOC("%s", buf);
526
527 if(ftp_get_response(docp, NULL, TRUE) >= 400)
528 {
529 docp->ftp_fatal_err = TRUE;
530 docp->errcode = ERR_FTP_BPASS;
531 return -1;
532 }
533 }
534 }
535
536 return 0;
537 }
538
539 #define CLOSE_CONTROL \
540 bufio_close(docp->ftp_control);\
541 docp->ftp_control = NULL;
542
ftp_open_control_connection(doc * docp,char * host,int port,char * ruser,char * user,char * password)543 static bufio *ftp_open_control_connection(doc * docp, char *host, int port,
544 char *ruser, char *user, char *password)
545 {
546
547 docp->errcode = ERR_NOERROR;
548 docp->ftp_fatal_err = FALSE;
549 docp->ftp_respc = 0;
550
551 if(!docp->ftp_control)
552 {
553 if(priv_cfg.ftp_proxy && cfg.ftp_dirtyp)
554 {
555 if(!(docp->datasock =
556 bufio_sock_fdopen(net_connect(priv_cfg.ftp_proxy,
557 cfg.ftp_proxy_port, docp))))
558 {
559 if(_h_errno_ != 0)
560 xherror(priv_cfg.ftp_proxy);
561 else
562 xperror("net_connect");
563
564 docp->errcode = ERR_PROXY_CONNECT;
565 return NULL;
566 }
567
568 if(http_dumy_proxy_connect(docp, host, port, priv_cfg.ftp_proxy,
569 cfg.ftp_proxy_port))
570 {
571 docp->errcode = ERR_PROXY_CONNECT;
572 return NULL;
573 }
574 docp->ftp_control = docp->datasock;
575 docp->datasock = NULL;
576 }
577 else
578 {
579 if(!(docp->ftp_control =
580 bufio_sock_fdopen(net_connect(host, port, docp))))
581 {
582 if(_h_errno_ != 0)
583 xherror(host);
584 else
585 xperror("net_connect");
586
587 docp->errcode = ERR_FTP_CONNECT;
588 docp->ftp_fatal_err = TRUE;
589 return NULL;
590 }
591 }
592 if(ftp_get_response(docp, NULL, TRUE) >= 400)
593 {
594 CLOSE_CONTROL;
595 docp->ftp_fatal_err = TRUE;
596 docp->errcode = ERR_FTP_CONNECT;
597 return NULL;
598 }
599 #ifdef USE_SSL
600 if(docp->doc_url->type == URLT_FTPS)
601 {
602 char buf[2048];
603 int reply;
604 bufio *ssl_sock;
605
606 sprintf(buf, "AUTH SSL\r\n");
607 ftp_control_write(docp, buf, strlen(buf));
608 DEBUG_PROTOC("%s", buf);
609
610 reply = ftp_get_response(docp, NULL, TRUE);
611
612 /*** 234 code is used by SafeGossip ***/
613 /*** thank to Martijn ... ***/
614 if(reply != 334 && reply != 234)
615 {
616 CLOSE_CONTROL;
617 docp->ftp_fatal_err = (reply == 600);
618 docp->errcode = ERR_FTPS_UNSUPORTED;
619 return NULL;
620 }
621
622 ssl_sock = my_ssl_do_connect(docp, docp->ftp_control, NULL);
623
624 if(!ssl_sock)
625 {
626 if(!docp->errcode)
627 docp->errcode = ERR_FTPS_CONNECT;
628 CLOSE_CONTROL;
629 return NULL;
630 }
631 else
632 {
633 docp->ftp_control = ssl_sock;
634 }
635 }
636 #endif
637
638 if(ftp_do_login_handshake(docp, ruser, user, password))
639 {
640 CLOSE_CONTROL;
641 return NULL;
642 }
643
644 #ifdef IP_TOS
645 #ifdef IPTOS_LOWDELAY
646 if(docp->ftp_control)
647 {
648 int v = IPTOS_LOWDELAY;
649 if(setsockopt(bufio_getfd(docp->ftp_control),
650 IPPROTO_IP, IP_TOS, (char *) &v, sizeof(v)))
651 {
652 perror("ftp: setsockopt TOS - LOWDELAY failed");
653 }
654 }
655 #endif
656 #endif
657
658 }
659 #ifdef DEBUG
660 else
661 {
662 if(cfg.debug)
663 xprintf(1, gettext("Re-using established FTP control connection\n"));
664 }
665 #endif
666
667 return docp->ftp_control;
668 }
669
ftp_set_transfer_type(doc * docp,char * type)670 static int ftp_set_transfer_type(doc * docp, char *type)
671 {
672 char buf[20];
673 int reply;
674
675 snprintf(buf, sizeof(buf), "TYPE %s\r\n", type);
676 ftp_control_write(docp, buf, strlen(buf));
677 DEBUG_PROTOC("%s", buf);
678
679 if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)
680 {
681 CLOSE_CONTROL;
682 docp->ftp_fatal_err = (reply == 600);
683 docp->errcode = ERR_FTP_UNKNOWN;
684 return -1;
685 }
686
687 return 0;
688 }
689
ftp_send_list_command(doc * docp,char * filename)690 static int ftp_send_list_command(doc * docp, char *filename)
691 {
692 char buf[2148];
693 int l;
694
695 l = strlen(filename) - 1;
696 if(l)
697 {
698 if(tl_is_dirname(filename + 1) && strcmp(filename, "//"))
699 l--;
700 }
701
702 if(cfg.ftp_list)
703 strcpy(buf, "LIST");
704 else
705 strcpy(buf, "NLST");
706
707 if(cfg.ftp_list_options)
708 {
709 strcat(buf, " ");
710 strncat(buf, cfg.ftp_list_options, sizeof(buf) - strlen(buf));
711 buf[sizeof(buf) - 1] = '\0';
712 }
713
714 if(l)
715 {
716 strncat(buf, " ", sizeof(buf) - strlen(buf));
717 buf[sizeof(buf) - 1] = '\0';
718 strncat(buf, filename + 1, sizeof(buf) - strlen(buf));
719 buf[sizeof(buf) - 1] = '\0';
720 }
721
722 strncat(buf, "\r\n", sizeof(buf) - strlen(buf));
723 buf[sizeof(buf) - 1] = '\0';
724
725 ftp_control_write(docp, buf, strlen(buf));
726 DEBUG_PROTOC("%s", buf);
727
728 return 0;
729 }
730
ftp_check_directory_existence(doc * docp,char * filename)731 static int ftp_check_directory_existence(doc * docp, char *filename)
732 {
733 int rv = 0;
734
735 if(cfg.ftp_list && cfg.fix_wuftpd)
736 {
737 int l;
738 char buf[2148];
739 char *mbuf;
740
741 l = strlen(filename) - 1;
742 if(l)
743 {
744 if(tl_is_dirname(filename + 1) && strcmp(filename, "//"))
745 l--;
746 }
747
748 strcpy(buf, "STAT -d1 ");
749 if(l)
750 {
751 strncat(buf, filename + 1, sizeof(buf) - strlen(buf));
752 buf[sizeof(buf) - 1] = '\0';
753 strncat(buf, "\r\n", sizeof(buf) - strlen(buf));
754 buf[sizeof(buf) - 1] = '\0';
755 }
756 else
757 {
758 /* we can assume that login directory exists */
759 return 0;
760 }
761
762 ftp_control_write(docp, buf, strlen(buf));
763 DEBUG_PROTOC("%s", buf);
764
765 mbuf = NULL;
766 if(ftp_get_response(docp, &mbuf, TRUE) == 213)
767 {
768 char *p;
769
770 p = mbuf + strcspn(mbuf, "\r\n");
771 p += strspn(p, "\r\n");
772 if(strncmp(filename + 1, p, strcspn(p, "\r\n")))
773 rv = -1;
774 }
775
776 _free(mbuf);
777 }
778
779 return rv;
780 }
781
782 /****************************************************************/
783 /* otvorenie spojenia na FTP server, prihlasenie + zahajenie */
784 /* prenosu suboru / adresara */
785 /* FIXME: Translate me! */
786 /****************************************************************/
ftp_connect(doc * docp,char * host,int port,char * ruser,char * user,char * password,char * filename,bool_t * is_dir)787 static bufio *ftp_connect(doc * docp, char *host, int port, char *ruser,
788 char *user, char *password, char *filename, bool_t * is_dir)
789 {
790 char buf[2148];
791 int reply;
792 char *mbuf;
793
794 docp->errcode = ERR_NOERROR;
795 docp->ftp_fatal_err = FALSE;
796 docp->ftp_respc = 0;
797
798 if(!(docp->ftp_control =
799 ftp_open_control_connection(docp, host, port, ruser, user, password)))
800 return NULL;
801
802 if(!tl_is_dirname(filename) && cfg.mode != MODE_FTPDIR)
803 {
804 if(docp->doc_url->extension &&
805 ((ftp_url_extension *) docp->doc_url->extension)->size > 0)
806 {
807 docp->totsz = ((ftp_url_extension *) docp->doc_url->extension)->size;
808 reply = 213;
809 DEBUG_PROTOC("taking stored size\n");
810 }
811 else
812 {
813 snprintf(buf, sizeof(buf), "SIZE %s\r\n", filename + 1);
814 ftp_control_write(docp, buf, strlen(buf));
815 DEBUG_PROTOC("%s", buf);
816
817
818 mbuf = NULL;
819 if((reply = ftp_get_response(docp, &mbuf, TRUE)) == 213)
820 {
821 int sz;
822
823 sscanf(mbuf, "%d %d", &reply, &sz);
824 docp->totsz = sz;
825 }
826 else
827 {
828 if(reply == 600)
829 {
830 docp->errcode = ERR_READ;
831 docp->ftp_fatal_err = TRUE;
832 _free(mbuf);
833 return NULL;
834 }
835 }
836
837 _free(mbuf);
838 }
839
840 if(reply != 550) /*** file doesn't exist or not plain file == 550 ***/
841 {
842 if(!cfg.always_mdtm &&
843 docp->doc_url->extension &&
844 ((ftp_url_extension *) docp->doc_url->extension)->time != 0)
845 {
846 docp->dtime = ((ftp_url_extension *) docp->doc_url->extension)->time;
847 reply = 213;
848 DEBUG_PROTOC("taking stored MDTM %d\n", (int)
849 ((ftp_url_extension *) docp->doc_url->extension)->time);
850 }
851 else
852 {
853 snprintf(buf, sizeof(buf), "MDTM %s\r\n", filename + 1);
854 ftp_control_write(docp, buf, strlen(buf));
855 DEBUG_PROTOC("%s", buf);
856
857 mbuf = NULL;
858 if((reply = ftp_get_response(docp, &mbuf, TRUE)) == 213)
859 {
860 sscanf(mbuf, "%d %2147s", &reply, buf);
861 if(strlen(buf) == 14)
862 {
863 docp->dtime = time_ftp_scn(buf);
864 }
865 }
866 else
867 {
868 if(reply == 600)
869 {
870 docp->ftp_fatal_err = TRUE;
871 docp->errcode = ERR_READ;
872 _free(mbuf);
873 return NULL;
874 }
875 }
876 _free(mbuf);
877 }
878
879 DEBUG_PROTOC("Size: file %d, remote %d; time: file %d, remote %d\n",
880 docp->origsize, docp->totsz, docp->origtime, docp->dtime);
881
882 if(docp->origsize && (docp->totsz >= 0)
883 && (docp->origsize != docp->totsz))
884 {
885 xprintf(1, gettext("Size differs, regeting whole\n"));
886 docp->rest_pos = 0;
887 }
888 else if(docp->origtime && docp->dtime)
889 {
890 if((difftime(docp->dtime, docp->origtime) > 0))
891 {
892 if(docp->rest_pos)
893 {
894 docp->rest_pos = 0;
895 xprintf(1,
896 gettext("Modified from last download - regeting whole\n"));
897 }
898 }
899 else if((cfg.mode == MODE_SYNC || cfg.mode == MODE_MIRROR)
900 && !docp->rest_pos)
901 {
902 docp->errcode = ERR_FTP_ACTUAL;
903 return NULL;
904 }
905 }
906
907 if(docp->check_limits)
908 {
909 cond_info_t condp;
910 int r;
911
912 condp.level = 3;
913 condp.urlnr = docp->doc_nr;
914 condp.size = docp->totsz;
915 condp.time = docp->dtime;
916 condp.mimet = NULL;
917 condp.full_tag = NULL;
918 condp.params = NULL;
919 condp.html_doc = NULL;
920 condp.html_doc_offset = 0;
921 condp.tag = NULL;
922 condp.attrib = NULL;
923
924 r = url_append_condition(docp->doc_url, &condp);
925
926 if(!r)
927 {
928 switch (condp.reason)
929 {
930 case CONDT_MAX_SIZE:
931 docp->errcode = ERR_BIGGER;
932 break;
933 case CONDT_MIN_SIZE:
934 docp->errcode = ERR_SMALLER;
935 break;
936 case CONDT_NEWER_THAN:
937 case CONDT_OLDER_THAN:
938 docp->errcode = ERR_OUTTIME;
939 break;
940 case CONDT_USER_CONDITION:
941 docp->errcode = ERR_SCRIPT_DISABLED;
942 break;
943 default:
944 docp->errcode = ERR_RDISABLED;
945 break;
946 }
947 return NULL;
948 }
949 }
950
951 if(ftp_set_transfer_type(docp, "I"))
952 {
953 docp->ftp_fatal_err = TRUE;
954 docp->errcode = ERR_FTP_DATACON;
955 return NULL;
956 }
957
958 if(ftp_open_data_init(docp))
959 {
960 bufio_close(docp->ftp_control);
961 docp->ftp_control = NULL;
962 docp->errcode = ERR_FTP_DATACON;
963 return NULL;
964 }
965
966 if(docp->rest_pos)
967 {
968 char *rsp;
969
970 sprintf(buf, "REST %ld\r\n", (long) docp->rest_pos);
971 ftp_control_write(docp, buf, strlen(buf));
972 DEBUG_PROTOC("%s", buf);
973 if((reply = ftp_get_response(docp, &rsp, TRUE)) >= 400)
974 {
975 _free(rsp);
976 if(reply == 600)
977 {
978 docp->ftp_fatal_err = TRUE;
979 bufio_close(docp->datasock);
980 docp->datasock = NULL;
981 docp->errcode = ERR_READ;
982 return NULL;
983 }
984 docp->errcode = ERR_FTP_NOREGET;
985 }
986 else
987 {
988 sprintf(buf, "%ld", (long) docp->rest_pos);
989 if(!strstr(rsp + 3, buf))
990 {
991 xprintf(1,
992 gettext
993 ("Warning: FTP server understands REST command, but can't handle it properly.\n"));
994 docp->errcode = ERR_FTP_NOREGET;
995 }
996 _free(rsp);
997 }
998 }
999
1000 snprintf(buf, sizeof(buf), "RETR %s\r\n", filename + 1);
1001 ftp_control_write(docp, buf, strlen(buf));
1002 DEBUG_PROTOC("%s", buf);
1003
1004 /** check control connection if there is available **/
1005 /** server response. This is required to properly **/
1006 /** establish support active data connections, also **/
1007 /** in case of error **/
1008 if(!cfg.ftp_activec ||
1009 tl_selectr(bufio_getfd(docp->ftp_control), 10) == 0)
1010 {
1011 if(!ftp_open_data_finish(docp))
1012 {
1013 docp->ftp_fatal_err = TRUE;
1014 if(!docp->errcode)
1015 docp->errcode = ERR_FTP_DATACON;
1016 return NULL;
1017 }
1018 }
1019
1020 if(!((reply = ftp_get_response(docp, NULL, TRUE)) >= 400))
1021 {
1022 docp->errcode = ERR_NOERROR;
1023
1024 if(!ftp_open_data_finish(docp))
1025 {
1026 docp->ftp_fatal_err = TRUE;
1027 if(!docp->errcode)
1028 docp->errcode = ERR_FTP_DATACON;
1029 return NULL;
1030 }
1031
1032 return docp->datasock;
1033 }
1034
1035 if(reply == 600)
1036 {
1037 docp->ftp_fatal_err = TRUE;
1038 bufio_close(docp->datasock);
1039 docp->datasock = NULL;
1040 docp->errcode = ERR_READ;
1041 return NULL;
1042 }
1043 docp->errcode = ERR_FTP_GET;
1044 }
1045 else
1046 {
1047 docp->errcode = ERR_FTP_GET;
1048 }
1049 }
1050
1051 if(((docp->doc_url->extension &&
1052 ((ftp_url_extension *) docp->doc_url->extension)->type == FTP_TYPE_D)
1053 || !docp->doc_url->extension) && ((docp->check_limits
1054 && cfg.condition.ftpdir) || !docp->check_limits))
1055 {
1056 if(ftp_check_directory_existence(docp, filename))
1057 {
1058 docp->errcode = ERR_FTP_NODIR;
1059 docp->ftp_respc = 550;
1060 if(docp->datasock)
1061 {
1062 bufio_close(docp->datasock);
1063 docp->datasock = NULL;
1064 }
1065 return NULL;
1066 }
1067
1068 if(ftp_set_transfer_type(docp, "A"))
1069 {
1070 return NULL;
1071 }
1072
1073 if(!docp->datasock)
1074 {
1075 if(ftp_open_data_init(docp))
1076 {
1077 bufio_close(docp->ftp_control);
1078 docp->ftp_control = NULL;
1079 docp->errcode = ERR_FTP_DATACON;
1080 return NULL;
1081 }
1082 }
1083
1084 ftp_send_list_command(docp, filename);
1085
1086 /** check control connection if there is available **/
1087 /** server response. This is required to properly **/
1088 /** establish support active data connections, also **/
1089 /** in case of error **/
1090 if(!cfg.ftp_activec ||
1091 tl_selectr(bufio_getfd(docp->ftp_control), 10) == 0)
1092 {
1093 if(!ftp_open_data_finish(docp))
1094 {
1095 docp->ftp_fatal_err = TRUE;
1096 if(!docp->errcode)
1097 docp->errcode = ERR_FTP_DATACON;
1098 return NULL;
1099 }
1100 }
1101
1102 if(!((reply = ftp_get_response(docp, NULL, TRUE)) >= 400))
1103 {
1104 docp->errcode = ERR_NOERROR;
1105 *is_dir = TRUE;
1106
1107 if(!ftp_open_data_finish(docp))
1108 {
1109 docp->ftp_fatal_err = TRUE;
1110 if(!docp->errcode)
1111 docp->errcode = ERR_FTP_DATACON;
1112 return NULL;
1113 }
1114
1115 return docp->datasock;
1116 }
1117 docp->ftp_fatal_err = (reply == 600);
1118 docp->errcode = *is_dir ? ERR_FTP_NODIR : ERR_FTP_GET;
1119 }
1120 else if(!cfg.condition.ftpdir && reply == 550 && *is_dir)
1121 {
1122 docp->errcode = ERR_FTP_DIRNO;
1123 }
1124
1125 if(docp->datasock)
1126 {
1127 bufio_close(docp->datasock);
1128 docp->datasock = NULL;
1129 }
1130
1131 return NULL;
1132 }
1133
1134 /********************************************************/
1135 /* pre dane FTP URL vracia deskriptor datoveho spojenia */
1136 /* FIXME: Translate me! */
1137 /********************************************************/
ftp_get_data_socket(doc * docp)1138 bufio *ftp_get_data_socket(doc * docp)
1139 {
1140 char *user, *ruser;
1141 char *password;
1142 char pom[100];
1143 bufio *s;
1144 bool_t sdir;
1145 char *tmp_path;
1146
1147 user = url_get_user(docp->doc_url, NULL);
1148 password = url_get_pass(docp->doc_url, NULL);
1149
1150 if(!user)
1151 user = "anonymous";
1152 ruser = user;
1153
1154 if(!password)
1155 password = cfg.send_from ? priv_cfg.from : "pavuk@domain.xx";
1156
1157 if(priv_cfg.ftp_proxy && !cfg.ftp_dirtyp)
1158 {
1159 snprintf(pom, sizeof(pom), "%s@%s %hu", user, docp->doc_url->p.ftp.host,
1160 docp->doc_url->p.ftp.port);
1161 user = pom;
1162 }
1163
1164 sdir = docp->doc_url->p.ftp.dir;
1165 tmp_path = url_decode_str(docp->doc_url->p.ftp.path,
1166 strlen(docp->doc_url->p.ftp.path));
1167
1168 s = ftp_connect(docp, priv_cfg.ftp_proxy && !cfg.ftp_dirtyp ?
1169 priv_cfg.ftp_proxy : docp->doc_url->p.ftp.host,
1170 priv_cfg.ftp_proxy && !cfg.ftp_dirtyp ?
1171 priv_cfg.ftp_proxy_port : docp->doc_url->p.ftp.port,
1172 ruser, user, password, tmp_path, &sdir);
1173
1174 _free(tmp_path);
1175
1176 if(sdir != docp->doc_url->p.ftp.dir)
1177 {
1178 docp->doc_url->p.ftp.dir = sdir;
1179 url_changed_filename(docp->doc_url);
1180 }
1181
1182 return s;
1183 }
1184
1185 /*******************************/
1186 /* remove document from server */
1187 /*******************************/
ftp_remove(doc * docp)1188 int ftp_remove(doc * docp)
1189 {
1190 char *cmd;
1191 char *filename;
1192 int reply;
1193
1194 if(docp->doc_url->type != URLT_FTP && docp->doc_url->type != URLT_FTPS)
1195 return 0;
1196
1197 if(docp->doc_url->p.ftp.dir)
1198 return 0;
1199
1200 xprintf(1, "Deleting remote document ...\n");
1201
1202 filename = url_decode_str(docp->doc_url->p.ftp.path,
1203 strlen(docp->doc_url->p.ftp.path));
1204
1205 cmd = tl_str_concat(NULL, "DELE ", filename + 1, "\r\n", NULL);
1206 ftp_control_write(docp, cmd, strlen(cmd));
1207 DEBUG_PROTOC("%s", cmd);
1208
1209 _free(filename);
1210 _free(cmd);
1211
1212 if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)
1213 {
1214 if(reply == 600)
1215 {
1216 docp->ftp_fatal_err = TRUE;
1217 return -1;
1218 }
1219 }
1220
1221 return 0;
1222 }
1223
1224 /********************************************************/
1225 /* z FTP adresara urobi HTML dokument */
1226 /* FIXME: Translate me! */
1227 /********************************************************/
ftp_nlst_dir_to_html(doc * docp)1228 static void ftp_nlst_dir_to_html(doc * docp)
1229 {
1230 char *p, *n, *res = NULL;
1231 char pom[8192];
1232 int tsize;
1233 bool_t last = 1;
1234 int ilen;
1235
1236 snprintf(pom, sizeof(pom),
1237 gettext("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"
1238 "<HTML>\n<TITLE>\nDirectory of %s://%s:%hu%s\n</TITLE>\n<BODY>\n"
1239 "<H1 ALIGN=CENTER><B>List of FTP directory %s://%s:%hu/%s </H1><BR><UL>"),
1240 prottable[docp->doc_url->type].urlid, docp->doc_url->p.ftp.host,
1241 docp->doc_url->p.ftp.port, docp->doc_url->p.ftp.path,
1242 prottable[docp->doc_url->type].urlid, docp->doc_url->p.ftp.host,
1243 docp->doc_url->p.ftp.port, docp->doc_url->p.ftp.path);
1244
1245 res = tl_strdup(pom);
1246 tsize = strlen(pom);
1247
1248 p = docp->contents;
1249
1250 while(*p)
1251 {
1252 ilen = strcspn(p, "\r\n");
1253 if(*(p + ilen))
1254 *(p + ilen) = '\0';
1255 else
1256 last = 0;
1257
1258 _strtrchr(p, '\\', '/');
1259 n = strrchr(p, '/');
1260 if(n)
1261 n++;
1262 else
1263 n = p;
1264
1265 n = url_encode_str(n, URL_PATH_UNSAFE);
1266
1267 if(docp->doc_url->p.ftp.user && docp->doc_url->p.ftp.password)
1268 {
1269 snprintf(pom, sizeof(pom),
1270 "<LI><A HREF=\"%s://%s:%s@%s:%hu%s%s%s\">"%s"</A>\n",
1271 prottable[docp->doc_url->type].urlid,
1272 docp->doc_url->p.ftp.user, docp->doc_url->p.ftp.password,
1273 docp->doc_url->p.ftp.host, docp->doc_url->p.ftp.port,
1274 docp->doc_url->p.ftp.path,
1275 tl_is_dirname(docp->doc_url->p.ftp.path) ? "" : "/", n, n);
1276 }
1277 else if(docp->doc_url->p.ftp.user)
1278 {
1279 snprintf(pom, sizeof(pom),
1280 "<LI><A HREF=\"%s://%s@%s:%hu%s%s%s\">"%s"</A>\n",
1281 prottable[docp->doc_url->type].urlid,
1282 docp->doc_url->p.ftp.user,
1283 docp->doc_url->p.ftp.host, docp->doc_url->p.ftp.port,
1284 docp->doc_url->p.ftp.path,
1285 tl_is_dirname(docp->doc_url->p.ftp.path) ? "" : "/", n, n);
1286 }
1287 else
1288 snprintf(pom, sizeof(pom),
1289 "<LI><A HREF=\"%s://%s:%hu%s%s%s\">"%s"</A>\n",
1290 prottable[docp->doc_url->type].urlid,
1291 docp->doc_url->p.ftp.host, docp->doc_url->p.ftp.port,
1292 docp->doc_url->p.ftp.path,
1293 tl_is_dirname(docp->doc_url->p.ftp.path) ? "" : "/", n, n);
1294
1295 _free(n);
1296
1297 tsize += strlen(pom);
1298 res = _realloc(res, tsize + 1);
1299
1300 strcat(res, pom);
1301 p += ilen + last;
1302 p += strspn(p, "\r\n");
1303 }
1304
1305 tsize += 22;
1306 res = _realloc(res, tsize + 1);
1307
1308 strcat(res, "</UL>\n</BODY>\n</HTML>\n");
1309
1310 free(docp->contents);
1311
1312 docp->contents = res;
1313 docp->size = tsize;
1314 }
1315
ftp_list_unix_perm_parse(char * str)1316 static int ftp_list_unix_perm_parse(char *str)
1317 {
1318 int perm = 0;
1319 int i;
1320 char *s;
1321
1322 if(strlen(str) != 10)
1323 return -1;
1324
1325 for(s = str + 1, i = 0; i < 3; i++, s += 3)
1326 {
1327 perm <<= 3;
1328 if(s[0] == 'r')
1329 perm += 4;
1330 if(s[1] == 'w')
1331 perm += 2;
1332 if(s[2] == 'x')
1333 perm += 1;
1334 }
1335 return perm;
1336 }
1337
ftp_list_unix_perm_type(char * str)1338 static int ftp_list_unix_perm_type(char *str)
1339 {
1340 switch (str[0])
1341 {
1342 case 'd':
1343 return FTP_TYPE_D;
1344 case 'l':
1345 return FTP_TYPE_L;
1346 default:
1347 return FTP_TYPE_F;
1348 }
1349 }
1350
ftp_list_unix_get_slink(char * str,char ** nm,char ** ln)1351 static void ftp_list_unix_get_slink(char *str, char **nm, char **ln)
1352 {
1353 char *p;
1354
1355 *ln = NULL;
1356 *nm = str;
1357
1358 if((p = strstr(str, " -> ")))
1359 {
1360 *p = '\0';
1361 *ln = p + 4;
1362 }
1363 }
1364
ftp_list_get_month_index(char * month)1365 static int ftp_list_get_month_index(char *month)
1366 {
1367 static const char *months[] = { "jan", "feb", "mar", "apr", "may", "jun",
1368 "jul", "aug", "sep", "oct", "nov", "dec", NULL
1369 };
1370 int i;
1371
1372 if(strlen(month) != 3)
1373 return -1;
1374
1375 /* make lowercase month */
1376 for(i = 0; i < 3; ++i)
1377 {
1378 month[i] = tolower(month[i]);
1379 }
1380
1381 i = 0;
1382 while(months[i] != NULL)
1383 {
1384 if(strcmp(month, months[i]) == 0)
1385 return i + 1;
1386 i++;
1387 }
1388
1389 return 0;
1390 }
1391
1392
ftp_list_get_date(char * date)1393 static time_t ftp_list_get_date(char *date)
1394 {
1395 int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
1396 char m[PATH_MAX];
1397 int ok = 0;
1398
1399 static int our_year = 0;
1400 static int our_month = 0;
1401
1402 static char result[32];
1403 time_t t;
1404
1405 if(our_year == 0)
1406 {
1407 time_t t;
1408 struct tm *ptm;
1409
1410 t = time(NULL);
1411 ptm = gmtime(&t);
1412
1413 our_year = ptm->tm_year;
1414 our_month = ptm->tm_mon;
1415 }
1416
1417 if(sscanf(date, "%3[a-zA-Z] %2d %02d:%02d", m, &day, &hour, &minute) == 4)
1418 {
1419 month = ftp_list_get_month_index(m);
1420 if(month <= 0)
1421 return 0;
1422
1423 if(day < 1 || day > 31)
1424 return 0;
1425 if(hour < 0 || hour > 24)
1426 return 0;
1427 if(minute < 0 || minute > 60)
1428 return 0;
1429
1430 year = 0;
1431 second = 0;
1432
1433 ok = 1;
1434 }
1435
1436 if(!ok && sscanf(date, "%3[a-zA-Z] %2d %04d", m, &day, &year) == 3)
1437 {
1438 month = ftp_list_get_month_index(m);
1439
1440 if(month <= 0)
1441 return 0;
1442 if(day < 1 || day > 31)
1443 return 0;
1444 if(year < 1995 || year > 2100)
1445 return 0;
1446
1447 hour = 0;
1448 second = 0;
1449 minute = 0;
1450
1451 ok = 1;
1452 }
1453
1454 if(!ok)
1455 return 0;
1456
1457 if(year == 0)
1458 {
1459 year = our_year;
1460 if((month - 1) > our_month)
1461 year--;
1462 }
1463
1464 if(year < 1900)
1465 year += 1900;
1466
1467 sprintf(result, "%04d%02d%02d%02d%02d%02d",
1468 year, month, day, hour, minute, second);
1469
1470 t = time_ftp_scn(result);
1471
1472 /*
1473 printf ("Time conversion: %s == %s (%d)\n", date, result, (int) t);
1474 */
1475
1476 return t;
1477 }
1478
ftp_list_unix_parse_line(char * str,char ** fname,ftp_url_extension * ret)1479 static ftp_url_extension *ftp_list_unix_parse_line(char *str, char **fname,
1480 ftp_url_extension * ret)
1481 {
1482 char pom[2000];
1483 char name[2000];
1484 char attrib[2000];
1485 char month[2000];
1486 char rest[2000];
1487 unsigned int pi, day;
1488 unsigned long size;
1489 char *nm, *sln;
1490
1491 *fname = NULL;
1492
1493 if(str[0] == 'b' || /* block device */
1494 str[0] == 'u' || /* character device unbuffered */
1495 str[0] == 'c' || /* character device */
1496 str[0] == 'p' || /* FIFO */
1497 str[0] == 's') /* socket */
1498 {
1499 /* we don't support devices, FIFOs and sockets creation */
1500 return NULL;
1501 }
1502 /* for SYS V style ls -l */
1503 else if(sscanf(str, "%1999s %u %1999s %1999s %lu %1999s %u %1999s %1999[^\n\r]",
1504 attrib, &pi, pom, pom, &size, month, &day, rest, name) != 9)
1505 {
1506 /* for old BSD style ls -l */
1507 if(sscanf(str, "%1999s %u %1999s %lu %1999s %u %1999s %1999[^\n\r]",
1508 attrib, &pi, pom, &size, month, &day, rest, name) != 8)
1509 {
1510 return NULL;
1511 }
1512 }
1513 ret->size = size;
1514
1515 ret->type = ftp_list_unix_perm_type(attrib);
1516 ret->perm = ftp_list_unix_perm_parse(attrib);
1517 if(ret->perm == -1)
1518 return NULL;
1519 ftp_list_unix_get_slink(name, &nm, &sln);
1520
1521 ret->slink = tl_strdup(sln);
1522 snprintf(pom, sizeof(pom), "%s %d %s", month, day, rest);
1523 ret->time = ftp_list_get_date(pom);
1524 *fname = tl_strdup(nm);
1525
1526 return ret;
1527 }
1528
ftp_list_epfl_parse_line(char * str,char ** fname,ftp_url_extension * ret)1529 static ftp_url_extension *ftp_list_epfl_parse_line(char *str, char **fname,
1530 ftp_url_extension * ret)
1531 {
1532 char *p, *strtokbuf;
1533
1534 *fname = NULL;
1535
1536 if(*str != '+')
1537 {
1538 return NULL;
1539 }
1540
1541 p = strchr(str, '\x09');
1542 if(!p)
1543 {
1544 return NULL;
1545 }
1546 *fname = tl_strdup(p + 1);
1547 *p = '\0';
1548
1549 ret->type = FTP_TYPE_F;
1550 ret->size = 0;
1551
1552 p = strtokc_r(str + 1, ',', &strtokbuf);
1553
1554 while(p)
1555 {
1556 switch (*p)
1557 {
1558 case 'r':
1559 ret->type = FTP_TYPE_F;
1560 break;
1561 case '/':
1562 ret->type = FTP_TYPE_D;
1563 break;
1564 case 's':
1565 ret->size = _atoi(p + 1);
1566 break;
1567 }
1568 p = strtokc_r(NULL, ',', &strtokbuf);
1569 }
1570 ret->slink = NULL;
1571 ret->time = 0;
1572 ret->perm = (4 << 6) + (2 << 6) + (2 << 3) + 2;
1573
1574
1575 return ret;
1576 }
1577
ftp_list_novel_parse_line(char * str,char ** fname,ftp_url_extension * ret)1578 static ftp_url_extension *ftp_list_novel_parse_line(char *str, char **fname,
1579 ftp_url_extension * ret)
1580 {
1581 char pom[2000];
1582 char name[4000];
1583 char attrib[2000];
1584 unsigned int pi;
1585 unsigned long size;
1586
1587 *fname = NULL;
1588
1589 if(sscanf(str, "%1999s %u %1999s %lu %1999s %u %1999s %3999[^\n\r]",
1590 attrib, &pi, pom, &size, pom, &pi, pom, name) != 8)
1591 {
1592 return NULL;
1593 }
1594 ret->size = size;
1595
1596 ret->type = *attrib == 'd' ? FTP_TYPE_D : FTP_TYPE_F;
1597 ret->slink = NULL;
1598 ret->time = 0;
1599 ret->perm = (4 << 6) + (2 << 6) + (2 << 3) + 2;
1600
1601 *fname = tl_strdup(name);
1602
1603 return ret;
1604 }
1605
ftp_list_vms_parse_line(char * str,char ** fname,ftp_url_extension * ret)1606 static ftp_url_extension *ftp_list_vms_parse_line(char *str, char **fname,
1607 ftp_url_extension * ret)
1608 {
1609 int l;
1610 char *p = str;
1611
1612 *fname = NULL;
1613
1614 l = strcspn(p, " ");
1615
1616 ret->type = strncmp(p + l - 6, ".DIR;", 5) ? FTP_TYPE_F : FTP_TYPE_D;
1617
1618 if(ret->type == FTP_TYPE_D)
1619 *fname = tl_strndup(p, l - 6);
1620 else
1621 *fname = tl_strndup(p, l - 2);
1622 lowerstr(*fname);
1623
1624 ret->slink = NULL;
1625 ret->time = 0;
1626 ret->size = 0;
1627 ret->perm = (4 << 6) + (2 << 6) + (2 << 3) + 2;
1628
1629 return ret;
1630 }
1631
ftp_list_windos_parse_line(char * str,char ** fname,ftp_url_extension * ret)1632 static ftp_url_extension *ftp_list_windos_parse_line(char *str, char **fname,
1633 ftp_url_extension * ret)
1634 {
1635 char pom[2000];
1636 char pom2[2000];
1637 int ti;
1638
1639 *fname = NULL;
1640
1641 if(sscanf(str, "%2d-%2d-%2d %2d:%2d%*[AP]M %1999s %1999[^\n\r]",
1642 &ti, &ti, &ti, &ti, &ti, pom2, pom) != 7)
1643 return NULL;
1644
1645 ret->slink = NULL;
1646 ret->time = 0;
1647 ret->perm = (4 << 6) + (2 << 6) + (2 << 3) + 2;
1648
1649 if(strstr(pom2, "<DIR>"))
1650 {
1651 ret->type = FTP_TYPE_D;
1652 ret->size = 0;
1653 }
1654 else
1655 {
1656 ret->type = FTP_TYPE_F;
1657 ret->size = atoi(pom2);
1658 }
1659
1660 *fname = tl_strdup(pom);
1661
1662 return ret;
1663 }
1664
1665 /********************************************************/
1666 /* z vypisu FTP adresara urobi HTML dokument */
1667 /* FIXME: Translate me! */
1668 /********************************************************/
ftp_list_unix_dir_to_html(doc * docp)1669 static void ftp_list_unix_dir_to_html(doc * docp)
1670 {
1671 char *p, *res = NULL;
1672 char pom[8192];
1673 char urlstr[4096];
1674 int tsize;
1675 ftp_url_extension *ext = NULL;
1676 ftp_url_extension exta;
1677 char *name, *tmp;
1678 int ilen;
1679 bool_t last = 1;
1680 enum
1681 { FTP_DT_UNIXL, FTP_DT_VMS, FTP_DT_WINDOS } type;
1682
1683 snprintf(pom, sizeof(pom),
1684 gettext("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"
1685 "<HTML>\n<TITLE>\nDirectory of %s://%s:%hu%s\n</TITLE>\n<BODY>\n"
1686 "<H1 ALIGN=CENTER><B>List of FTP directory %s://%s:%hu/%s </H1><BR><UL>"),
1687 prottable[docp->doc_url->type].urlid,
1688 docp->doc_url->p.ftp.host, docp->doc_url->p.ftp.port,
1689 docp->doc_url->p.ftp.path, prottable[docp->doc_url->type].urlid,
1690 docp->doc_url->p.ftp.host, docp->doc_url->p.ftp.port,
1691 docp->doc_url->p.ftp.path);
1692
1693 res = tl_strdup(pom);
1694 tsize = strlen(pom);
1695
1696 /*** skip first total line ***/
1697 if(!strncmp(docp->contents, "total ", 6))
1698 {
1699 type = FTP_DT_UNIXL;
1700 p = docp->contents + strcspn(docp->contents, "\r\n");
1701 p += strspn(p, "\r\n");
1702 }
1703 else if(!strncmp(docp->contents, "Directory ", 10) ||
1704 !strncmp(docp->contents + strspn(docp->contents, " \r\n"), "Directory ",
1705 10))
1706 {
1707 type = FTP_DT_VMS;
1708 p = docp->contents + strspn(docp->contents, " \r\n");
1709 p += strcspn(p, "\r\n");
1710 p += strspn(p, "\r\n");
1711 }
1712 else
1713 {
1714 int ti;
1715
1716 if(sscanf(docp->contents,
1717 "%2d-%2d-%2d %2d:%2d%*[AP]M %8191s %8191[^\n\r]",
1718 &ti, &ti, &ti, &ti, &ti, pom, pom) == 7)
1719 {
1720 type = FTP_DT_WINDOS;
1721 p = docp->contents;
1722 }
1723 else
1724 {
1725 type = FTP_DT_UNIXL;
1726 p = docp->contents;
1727 }
1728 }
1729
1730 while(*p)
1731 {
1732 ilen = strcspn(p, "\r\n");
1733 if(*(p + ilen))
1734 *(p + ilen) = '\0';
1735 else
1736 last = 0;
1737
1738 if(type == FTP_DT_UNIXL)
1739 {
1740 if(*p == '+')
1741 ext = ftp_list_epfl_parse_line(p, &name, &exta);
1742 else if(*(p + 1) == '[')
1743 ext = ftp_list_novel_parse_line(p, &name, &exta);
1744 else
1745 ext = ftp_list_unix_parse_line(p, &name, &exta);
1746 }
1747 else if(type == FTP_DT_VMS)
1748 {
1749 if(strncmp(p, "Total of ", 9) && *p && *p != ' ')
1750 ext = ftp_list_vms_parse_line(p, &name, &exta);
1751 }
1752 else if(type == FTP_DT_WINDOS)
1753 {
1754 ext = ftp_list_windos_parse_line(p, &name, &exta);
1755 }
1756
1757 if(!ext)
1758 {
1759 xprintf(1, gettext("ERROR: unable to parse FTP list line :\n\t%s\n"),
1760 p);
1761 p += ilen + last;
1762 p += strspn(p, "\r\n");
1763 continue;
1764 }
1765
1766 if(!name || !strcmp(name, ".") || !strcmp(name, ".."))
1767 {
1768 p += ilen + last;
1769 p += strspn(p, "\r\n");
1770 continue;
1771 }
1772
1773 tmp = name;
1774 name = url_encode_str(name, URL_PATH_UNSAFE);
1775 _free(tmp);
1776
1777 if(docp->doc_url->p.ftp.user && docp->doc_url->p.ftp.password)
1778 {
1779 snprintf(urlstr, sizeof(urlstr), "%s://%s:%s@%s:%hu%s%s%s%s",
1780 prottable[docp->doc_url->type].urlid,
1781 docp->doc_url->p.ftp.user,
1782 docp->doc_url->p.ftp.password,
1783 docp->doc_url->p.ftp.host,
1784 docp->doc_url->p.ftp.port,
1785 docp->doc_url->p.ftp.path,
1786 tl_is_dirname(docp->doc_url->p.ftp.path) ?
1787 "" : "/", name, (ext->type == FTP_TYPE_D) ? "/" : "");
1788 }
1789 else if(docp->doc_url->p.ftp.user)
1790 {
1791 snprintf(urlstr, sizeof(urlstr), "%s://%s@%s:%hu%s%s%s%s",
1792 prottable[docp->doc_url->type].urlid,
1793 docp->doc_url->p.ftp.user,
1794 docp->doc_url->p.ftp.host,
1795 docp->doc_url->p.ftp.port,
1796 docp->doc_url->p.ftp.path,
1797 tl_is_dirname(docp->doc_url->p.ftp.path) ?
1798 "" : "/", name, (ext->type == FTP_TYPE_D) ? "/" : "");
1799 }
1800 else
1801 snprintf(urlstr, sizeof(urlstr), "%s://%s:%hu%s%s%s%s",
1802 prottable[docp->doc_url->type].urlid,
1803 docp->doc_url->p.ftp.host,
1804 docp->doc_url->p.ftp.port,
1805 docp->doc_url->p.ftp.path,
1806 tl_is_dirname(docp->doc_url->p.ftp.path) ?
1807 "" : "/", name, (ext->type == FTP_TYPE_D) ? "/" : "");
1808
1809 snprintf(pom, sizeof(pom),
1810 "<LI><A PAVUKEXT=\"FTPINF %u %hu %lu %u %s\" HREF=\"%s\">"%s"</A> (%lub)\n",
1811 (unsigned int) ext->type, ext->perm, (long)ext->size,
1812 (unsigned int) ext->time, (ext->slink ? ext->slink : ""), urlstr, name,
1813 (long)ext->size);
1814
1815 _free(name);
1816 _free(ext->slink);
1817
1818 tsize += strlen(pom);
1819 res = _realloc(res, tsize + 1);
1820 strcat(res, pom);
1821
1822 p += ilen + last;
1823 p += strspn(p, "\r\n");
1824 }
1825
1826 tsize += 22;
1827 res = _realloc(res, tsize + 1);
1828
1829 strcat(res, "</UL>\n</BODY>\n</HTML>\n");
1830
1831 free(docp->contents);
1832
1833 docp->contents = res;
1834 docp->size = tsize;
1835 }
1836
ftp_dir_to_html(doc * docp)1837 void ftp_dir_to_html(doc * docp)
1838 {
1839 if(!docp->contents)
1840 return;
1841
1842 if(!cfg.ftp_list)
1843 ftp_nlst_dir_to_html(docp);
1844 else
1845 {
1846 ftp_list_unix_dir_to_html(docp);
1847 }
1848 }
1849
ftp_url_ext_free(ftp_url_extension * fext)1850 void ftp_url_ext_free(ftp_url_extension * fext)
1851 {
1852 _free(fext->slink);
1853 _free(fext);
1854 }
1855
ftp_url_ext_new(int type,int perm,ssize_t size,char * slink,time_t time)1856 ftp_url_extension *ftp_url_ext_new(int type, int perm, ssize_t size,
1857 char *slink, time_t time)
1858 {
1859 ftp_url_extension *rv;
1860
1861 rv = _malloc(sizeof(ftp_url_extension));
1862
1863 rv->perm = perm;
1864 rv->size = size;
1865 rv->type = type;
1866 rv->slink = slink;
1867 rv->time = time;
1868
1869 return rv;
1870 }
1871
ftp_url_ext_dup(ftp_url_extension * ext)1872 ftp_url_extension *ftp_url_ext_dup(ftp_url_extension * ext)
1873 {
1874 return ftp_url_ext_new(ext->type, ext->perm, ext->size,
1875 tl_strdup(ext->slink), ext->time);
1876 }
1877
ftp_parse_ftpinf_ext(char * str)1878 ftp_url_extension *ftp_parse_ftpinf_ext(char *str)
1879 {
1880 char pom[8192];
1881 unsigned int t, p, s, tt;
1882 int num;
1883
1884 if(strncmp(str, "FTPINF", 6))
1885 return NULL;
1886
1887 num = sscanf(str, "FTPINF %u %u %u %u %8191[^\n\r]", &t, &p, &s, &tt, pom);
1888
1889 if(num < 4)
1890 return NULL;
1891
1892 return ftp_url_ext_new(t, p, s, (num == 5) ? tl_strdup(pom) : NULL, tt);
1893 }
1894
ftp_make_symlink(url * urlp)1895 int ftp_make_symlink(url * urlp) /* FIXME: Security */
1896 {
1897 char pom[PATH_MAX];
1898 char *frompath, *topath;
1899 char *p;
1900 ftp_url_extension *ext = (ftp_url_extension *) urlp->extension;
1901 int rv;
1902
1903 frompath = tl_strdup(url_to_filename(urlp, TRUE));
1904
1905 if(!cfg.preserve_links)
1906 {
1907 if(ext->slink[0] == '/')
1908 {
1909 p = urlp->p.ftp.path;
1910 urlp->p.ftp.path = ext->slink;
1911 topath = tl_strdup(url_get_local_name_real(urlp, NULL, FALSE));
1912 urlp->p.ftp.path = p;
1913 }
1914 else
1915 {
1916 strcpy(pom, urlp->p.ftp.path);
1917 p = strrchr(pom, '/');
1918 if(p)
1919 *(p + 1) = '\0';
1920 strcat(pom, ext->slink);
1921
1922 p = urlp->p.ftp.path;
1923 urlp->p.ftp.path = pom;
1924 topath = tl_strdup(url_get_local_name_real(urlp, NULL, FALSE));
1925 urlp->p.ftp.path = p;
1926 }
1927 p = topath;
1928 topath = get_relative_path(frompath, p);
1929 _free(p);
1930 }
1931 else
1932 topath = NULL;
1933
1934 /* don't make links to directory index files */
1935 /* but rather to directories */
1936 if(topath && tl_is_dirname(ext->slink))
1937 {
1938 p = tl_get_basename(topath);
1939 if(p > topath)
1940 *(p) = '\0';
1941 }
1942
1943 xprintf(1, gettext("Making symlink \"%s\" to \"%s\"\n"),
1944 frompath, topath ? topath : ext->slink);
1945
1946 if(makealldirs(frompath))
1947 xperror(frompath);
1948
1949 if(!access(frompath, F_OK))
1950 {
1951 if(unlink(frompath))
1952 xperror(frompath);
1953 }
1954
1955 rv = symlink(topath ? topath : ext->slink, frompath);
1956
1957 if(rv == -1)
1958 xperror("topath");
1959
1960 _free(topath);
1961 _free(frompath);
1962
1963 return rv;
1964 }
1965
ftp_handshake_info_free(ftp_handshake_info * fhi)1966 void ftp_handshake_info_free(ftp_handshake_info * fhi)
1967 {
1968 _free(fhi->host);
1969
1970 for(; fhi->infos; fhi->infos = dllist_remove_entry(fhi->infos, fhi->infos))
1971 {
1972 ftp_handshake_info_data *d = (ftp_handshake_info_data *) fhi->infos->data;
1973 _free(d->cmd);
1974 _free(d);
1975 }
1976 }
1977
ftp_handshake_info_parse(char * host,char * str)1978 ftp_handshake_info *ftp_handshake_info_parse(char *host, char *str)
1979 {
1980 ftp_handshake_info *rv = _malloc(sizeof(ftp_handshake_info));
1981 ftp_handshake_info_data *d;
1982 char *p;
1983 char **array;
1984 int i, ok;
1985
1986 rv->infos = NULL;
1987 p = strchr(host, ':');
1988 if(p)
1989 {
1990 rv->host = tl_strndup(host, p - host);
1991 rv->port = _atoi(p + 1);
1992 if(!rv->port)
1993 rv->port = DEFAULT_FTP_PORT;
1994 }
1995 else
1996 {
1997 rv->host = tl_strdup(host);
1998 rv->port = DEFAULT_FTP_PORT;
1999 }
2000
2001 array = tl_str_split(str, "\\");
2002
2003 d = NULL;
2004 ok = TRUE;
2005 if(array)
2006 {
2007 for(i = 0; array[i]; i++)
2008 {
2009 if(!ok)
2010 {
2011 _free(array[i]);
2012 continue;
2013 }
2014
2015 if(!d)
2016 {
2017 d = _malloc(sizeof(ftp_handshake_info_data));
2018 d->cmd = array[i];
2019 d->response = 0;
2020 array[i] = NULL;
2021 }
2022 else
2023 {
2024 d->response = _atoi(array[i]);
2025 if(!d->response && errno == ERANGE)
2026 ok = FALSE;
2027 _free(array[i]);
2028 rv->infos = dllist_append(rv->infos, (dllist_t) d);
2029 d = NULL;
2030 }
2031 }
2032 if(d)
2033 {
2034 _free(d->cmd);
2035 _free(d);
2036 ok = FALSE;
2037 }
2038
2039 _free(array);
2040 }
2041 else
2042 ok = FALSE;
2043
2044 if(!ok)
2045 {
2046 ftp_handshake_info_free(rv);
2047 rv = NULL;
2048 }
2049
2050 return rv;
2051 }
2052
ftp_handshake_info_dup(ftp_handshake_info * fhi)2053 ftp_handshake_info *ftp_handshake_info_dup(ftp_handshake_info * fhi)
2054 {
2055 dllist *ptr;
2056 ftp_handshake_info *rv = _malloc(sizeof(ftp_handshake_info));
2057
2058 rv->host = tl_strdup(fhi->host);
2059 rv->port = fhi->port;
2060 rv->infos = NULL;
2061
2062 for(ptr = fhi->infos; ptr; ptr = ptr->next)
2063 {
2064 ftp_handshake_info_data *d1, *d2;
2065
2066 d1 = (ftp_handshake_info_data *) ptr->data;
2067
2068 d2 = _malloc(sizeof(ftp_handshake_info_data));
2069 d2->response = d1->response;
2070 d2->cmd = tl_strdup(d1->cmd);
2071
2072 rv->infos = dllist_append(rv->infos, (dllist_t) d2);
2073 }
2074
2075 return rv;
2076 }
2077
ftp_handshake_info_data_dump(ftp_handshake_info * fhi)2078 char *ftp_handshake_info_data_dump(ftp_handshake_info * fhi)
2079 {
2080 ftp_handshake_info_data *d;
2081 dllist *ptr;
2082 char pom[512];
2083 char *rv = NULL;
2084
2085 if(fhi->infos)
2086 {
2087 d = (ftp_handshake_info_data *) fhi->infos->data;
2088 snprintf(pom, sizeof(pom), "%s\\%d", d->cmd, d->response);
2089 rv = tl_strdup(pom);
2090
2091 for(ptr = fhi->infos->next; ptr; ptr = ptr->next)
2092 {
2093 d = (ftp_handshake_info_data *) ptr->data;
2094 snprintf(pom, sizeof(pom), "\\%s\\%d", d->cmd, d->response);
2095 rv = tl_str_append(rv, pom);
2096 }
2097 }
2098 return rv;
2099 }
2100
ftp_handshake_info_data_find(char * host,int port)2101 static ftp_handshake_info *ftp_handshake_info_data_find(char *host, int port)
2102 {
2103 dllist *ptr;
2104
2105 for(ptr = priv_cfg.ftp_login_hs; ptr; ptr = ptr->next)
2106 {
2107 ftp_handshake_info *fhi = (ftp_handshake_info *) ptr->data;
2108
2109 if((fhi->port == port || !host[0]) && !strcmp(fhi->host, host))
2110 return fhi;
2111 }
2112
2113 return NULL;
2114 }
2115
ftp_handshake_expand_cmd(char * cmd,doc * docp,char * user,char * password)2116 static char *ftp_handshake_expand_cmd(char *cmd, doc * docp, char *user,
2117 char *password) /* FIXME: Security */
2118 {
2119 char ocmd[2048];
2120 char *p, *op;
2121
2122 p = cmd;
2123 op = ocmd;
2124 *op = '\0';
2125
2126 while(*p)
2127 {
2128 if(*p == '%')
2129 {
2130 p++;
2131 switch (*p)
2132 {
2133 case 'u':
2134 strcpy(op, user);
2135 break;
2136 case 'U':
2137 strcpy(op, priv_cfg.ftp_proxy_user);
2138 break;
2139 case 'p':
2140 strcpy(op, password);
2141 break;
2142 case 'P':
2143 strcpy(op, priv_cfg.ftp_proxy_pass);
2144 break;
2145 case 'h':
2146 strcpy(op, docp->doc_url->p.ftp.host);
2147 break;
2148 case 's':
2149 sprintf(op, "%hu", docp->doc_url->p.ftp.port);
2150 break;
2151 default:
2152 *op = '%';
2153 op++;
2154 *op = *p;
2155 op++;
2156 *op = '\0';
2157 break;
2158 }
2159 p++;
2160 while(*op)
2161 op++;
2162 }
2163 else
2164 {
2165 *op = *p;
2166 op++;
2167 p++;
2168 *op = '\0';
2169 }
2170 }
2171 strcat(ocmd, "\r\n");
2172
2173 return tl_strdup(ocmd);
2174 }
2175
ftp_do_login_handshake_cust(ftp_handshake_info * fhi,doc * docp,char * user,char * password)2176 static int ftp_do_login_handshake_cust(ftp_handshake_info * fhi, doc * docp,
2177 char *user, char *password)
2178 {
2179 dllist *ptr;
2180
2181 for(ptr = fhi->infos; ptr; ptr = ptr->next)
2182 {
2183 ftp_handshake_info_data *d = (ftp_handshake_info_data *) ptr->data;
2184 char *cmd;
2185 int response;
2186
2187 cmd = ftp_handshake_expand_cmd(d->cmd, docp, user, password);
2188 ftp_control_write(docp, cmd, strlen(cmd));
2189 DEBUG_PROTOC("%s", cmd);
2190 _free(cmd);
2191
2192 response = ftp_get_response(docp, NULL, TRUE);
2193
2194 if(response != d->response)
2195 return -1;
2196 }
2197
2198 return 0;
2199 }
2200