This source file includes following definitions.
- ftpfs_set_blksize
- ftpfs_default_stat
- ftpfs_translate_path
- ftpfs_correct_url_parameters
- ftpfs_get_reply
- ftpfs_reconnect
- G_GNUC_PRINTF
- ftpfs_new_archive
- ftpfs_free_archive
- ftpfs_changetype
- ftpfs_login_server
- ftpfs_load_no_proxy_list
- ftpfs_check_proxy
- ftpfs_get_proxy_host_and_port
- ftpfs_open_socket
- ftpfs_open_archive_int
- ftpfs_open_archive
- ftpfs_archive_same
- ftpfs_get_current_directory
- ftpfs_setup_passive_pasv
- ftpfs_setup_passive_epsv
- ftpfs_setup_passive
- ftpfs_setup_active
- ftpfs_init_data_socket
- ftpfs_initconn
- ftpfs_open_data_connection
- ftpfs_linear_abort
- resolve_symlink_without_ls_options
- resolve_symlink_with_ls_options
- resolve_symlink
- ftpfs_dir_load
- ftpfs_file_store
- ftpfs_linear_start
- ftpfs_linear_read
- ftpfs_linear_close
- ftpfs_ctl
- ftpfs_send_command
- ftpfs_stat
- ftpfs_lstat
- ftpfs_fstat
- ftpfs_chmod
- ftpfs_chown
- ftpfs_unlink
- ftpfs_is_same_dir
- ftpfs_chdir_internal
- ftpfs_rename
- ftpfs_mkdir
- ftpfs_rmdir
- ftpfs_fh_new
- ftpfs_fh_open
- ftpfs_fh_close
- ftpfs_done
- ftpfs_fill_names
- ftpfs_netrc_next
- ftpfs_netrc_bad_mode
- ftpfs_find_machine
- ftpfs_netrc_lookup
- ftpfs_init_passwd
- vfs_init_ftpfs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 #include <config.h>
78 #include <stdio.h>
79 #include <stdlib.h>
80 #include <sys/types.h>
81 #include <netdb.h>
82 #include <sys/socket.h>
83 #include <netinet/in.h>
84 #ifdef HAVE_ARPA_INET_H
85 #include <arpa/inet.h>
86 #endif
87 #include <arpa/ftp.h>
88 #include <arpa/telnet.h>
89 #ifdef HAVE_SYS_PARAM_H
90 #include <sys/param.h>
91 #endif
92 #include <errno.h>
93 #include <ctype.h>
94 #include <fcntl.h>
95 #include <inttypes.h>
96
97 #include "lib/global.h"
98 #include "lib/file-entry.h"
99 #include "lib/util.h"
100 #include "lib/strutil.h"
101 #include "lib/mcconfig.h"
102
103 #include "lib/tty/tty.h"
104 #include "lib/widget.h"
105
106 #include "src/history.h"
107 #include "src/setup.h"
108
109 #include "lib/vfs/vfs.h"
110 #include "lib/vfs/utilvfs.h"
111 #include "lib/vfs/netutil.h"
112 #include "lib/vfs/xdirentry.h"
113 #include "lib/vfs/gc.h"
114
115 #include "ftpfs.h"
116
117
118
119
120 int ftpfs_retry_seconds = 30;
121
122
123 gboolean ftpfs_use_passive_connections = TRUE;
124 gboolean ftpfs_use_passive_connections_over_proxy = FALSE;
125
126
127
128
129
130
131 gboolean ftpfs_use_unix_list_options = TRUE;
132
133
134 gboolean ftpfs_first_cd_then_ls = TRUE;
135
136
137 gboolean ftpfs_use_netrc = TRUE;
138
139
140 char *ftpfs_anonymous_passwd = NULL;
141 int ftpfs_directory_timeout = 900;
142
143
144 char *ftpfs_proxy_host = NULL;
145
146
147 gboolean ftpfs_always_use_proxy = FALSE;
148
149 gboolean ftpfs_ignore_chattr_errors = TRUE;
150
151
152
153 #ifndef MAXHOSTNAMELEN
154 #define MAXHOSTNAMELEN 64
155 #endif
156
157 #define FTP_SUPER(super) ((ftp_super_t *) (super))
158 #define FTP_FILE_HANDLER(fh) ((ftp_file_handler_t *) (fh))
159 #define FH_SOCK FTP_FILE_HANDLER (fh)->sock
160
161 #ifndef INADDR_NONE
162 #define INADDR_NONE 0xffffffff
163 #endif
164
165 #define RFC_AUTODETECT 0
166 #define RFC_DARING 1
167 #define RFC_STRICT 2
168
169
170 #define NONE 0x00
171 #define WAIT_REPLY 0x01
172 #define WANT_STRING 0x02
173
174 #define FTP_COMMAND_PORT 21
175
176
177
178 #define TYPE_ASCII 0
179 #define TYPE_BINARY 1
180
181
182
183 #define TYPE_UNKNOWN -1
184
185 #define ABORT_TIMEOUT (5 * G_USEC_PER_SEC)
186
187
188 #ifndef HAVE_SOCKLEN_T
189 typedef int socklen_t;
190 #endif
191
192
193 typedef enum
194 {
195 NETRC_NONE = 0,
196 NETRC_DEFAULT,
197 NETRC_MACHINE,
198 NETRC_LOGIN,
199 NETRC_PASSWORD,
200 NETRC_PASSWD,
201 NETRC_ACCOUNT,
202 NETRC_MACDEF,
203 NETRC_UNKNOWN
204 } keyword_t;
205
206 typedef struct
207 {
208 struct vfs_s_super base;
209
210 int sock;
211
212 char *proxy;
213 gboolean failed_on_login;
214 gboolean use_passive_connection;
215 gboolean remote_is_amiga;
216 int isbinary;
217 gboolean cwd_deferred;
218
219 int strict;
220
221
222
223 gboolean ctl_connection_busy;
224 char *current_dir;
225 } ftp_super_t;
226
227 typedef struct
228 {
229 vfs_file_handler_t base;
230
231 int sock;
232 gboolean append;
233 } ftp_file_handler_t;
234
235
236
237 static char *ftpfs_get_current_directory (struct vfs_class *me, struct vfs_s_super *super);
238 static int ftpfs_chdir_internal (struct vfs_class *me, struct vfs_s_super *super,
239 const char *remote_path);
240 static int ftpfs_open_socket (struct vfs_class *me, struct vfs_s_super *super);
241 static gboolean ftpfs_login_server (struct vfs_class *me, struct vfs_s_super *super,
242 const char *netrcpass);
243 static gboolean ftpfs_netrc_lookup (const char *host, char **login, char **pass);
244
245
246
247 static int code;
248
249 static char reply_str[80];
250
251 static struct vfs_s_subclass ftpfs_subclass;
252 static struct vfs_class *vfs_ftpfs_ops = VFS_CLASS (&ftpfs_subclass);
253
254 static GSList *no_proxy = NULL;
255
256 static char buffer[BUF_MEDIUM];
257 static char *netrc = NULL;
258 static const char *netrcp;
259
260
261
262
263
264 static void
265 ftpfs_set_blksize (struct stat *s)
266 {
267 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
268
269 s->st_blksize = 64 * 1024;
270 #endif
271 }
272
273
274
275 static struct stat *
276 ftpfs_default_stat (struct vfs_class *me)
277 {
278 struct stat *s;
279
280 s = vfs_s_default_stat (me, S_IFDIR | 0755);
281 ftpfs_set_blksize (s);
282 vfs_adjust_stat (s);
283
284 return s;
285 }
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300 static char *
301 ftpfs_translate_path (struct vfs_class *me, struct vfs_s_super *super, const char *remote_path)
302 {
303 char *ret, *p;
304
305 if (!FTP_SUPER (super)->remote_is_amiga)
306 return g_strdup (remote_path);
307
308 if (me->logfile != NULL)
309 {
310 fprintf (me->logfile, "MC -- ftpfs_translate_path: %s\n", remote_path);
311 fflush (me->logfile);
312 }
313
314
315 while (IS_PATH_SEP (*remote_path))
316 remote_path++;
317
318
319 if (*remote_path == '\0')
320 return g_strdup (".");
321
322 ret = g_strdup (remote_path);
323
324
325 p = strchr (ret, ':');
326 if (p != NULL && IS_PATH_SEP (p[1]))
327 str_move (p + 1, p + 2);
328
329
330 p = strrchr (ret, PATH_SEP);
331 if ((p != NULL) && (*(p + 1) == '.') && (*(p + 2) == '\0'))
332 *p = '\0';
333
334 return ret;
335 }
336
337
338
339
340
341
342
343
344
345
346
347
348
349 static vfs_path_element_t *
350 ftpfs_correct_url_parameters (const vfs_path_element_t *velement)
351 {
352 vfs_path_element_t *path_element = vfs_path_element_clone (velement);
353
354 if (path_element->port == 0)
355 path_element->port = FTP_COMMAND_PORT;
356
357 if (path_element->user == NULL)
358 {
359
360 if (ftpfs_use_netrc)
361 ftpfs_netrc_lookup (path_element->host, &path_element->user, &path_element->password);
362 }
363 if (path_element->user == NULL)
364 path_element->user = g_strdup ("anonymous");
365
366
367 if (ftpfs_use_netrc && path_element->password == NULL)
368 {
369 char *new_user = NULL;
370 char *new_passwd = NULL;
371
372 ftpfs_netrc_lookup (path_element->host, &new_user, &new_passwd);
373
374
375 if (new_user != NULL && strcmp (path_element->user, new_user) == 0)
376 path_element->password = new_passwd;
377 else
378 g_free (new_passwd);
379
380 g_free (new_user);
381 }
382
383 return path_element;
384 }
385
386
387
388
389 static int
390 ftpfs_get_reply (struct vfs_class *me, int sock, char *string_buf, int string_len)
391 {
392 while (TRUE)
393 {
394 char answer[BUF_1K];
395
396 if (vfs_s_get_line (me, sock, answer, sizeof (answer), '\n') == 0)
397 {
398 if (string_buf != NULL)
399 *string_buf = '\0';
400 code = 421;
401 return 4;
402 }
403
404 switch (sscanf (answer, "%d", &code))
405 {
406 case 0:
407 if (string_buf != NULL)
408 g_strlcpy (string_buf, answer, string_len);
409 code = 500;
410 return 5;
411 case 1:
412 if (answer[3] == '-')
413 {
414 while (TRUE)
415 {
416 int i;
417
418 if (vfs_s_get_line (me, sock, answer, sizeof (answer), '\n') == 0)
419 {
420 if (string_buf != NULL)
421 *string_buf = '\0';
422 code = 421;
423 return 4;
424 }
425 if ((sscanf (answer, "%d", &i) > 0) && (code == i) && (answer[3] == ' '))
426 break;
427 }
428 }
429 if (string_buf != NULL)
430 g_strlcpy (string_buf, answer, string_len);
431 return code / 100;
432 default:
433 break;
434 }
435 }
436 }
437
438
439
440 static gboolean
441 ftpfs_reconnect (struct vfs_class *me, struct vfs_s_super *super)
442 {
443 ftp_super_t *ftp_super = FTP_SUPER (super);
444 int sock;
445
446 sock = ftpfs_open_socket (me, super);
447 if (sock != -1)
448 {
449 char *cwdir = ftp_super->current_dir;
450
451 close (ftp_super->sock);
452 ftp_super->sock = sock;
453 ftp_super->current_dir = NULL;
454
455 if (ftpfs_login_server (me, super, super->path_element->password))
456 {
457 if (cwdir == NULL)
458 return TRUE;
459
460 sock = ftpfs_chdir_internal (me, super, cwdir);
461 g_free (cwdir);
462 return (sock == COMPLETE);
463 }
464
465 ftp_super->current_dir = cwdir;
466 }
467
468 return FALSE;
469 }
470
471
472
473 static int G_GNUC_PRINTF (4, 5)
474 ftpfs_command (struct vfs_class *me, struct vfs_s_super *super, int wait_reply, const char *fmt,
475 ...)
476 {
477 ftp_super_t *ftp_super = FTP_SUPER (super);
478 va_list ap;
479 GString *cmdstr;
480 int status;
481 static gboolean retry = FALSE;
482 static int level = 0;
483
484 cmdstr = g_string_sized_new (32);
485 va_start (ap, fmt);
486 g_string_vprintf (cmdstr, fmt, ap);
487 va_end (ap);
488 g_string_append (cmdstr, "\r\n");
489
490 if (me->logfile != NULL)
491 {
492 if (strncmp (cmdstr->str, "PASS ", 5) == 0)
493 fputs ("PASS <Password not logged>\r\n", me->logfile);
494 else
495 {
496 size_t ret;
497
498 ret = fwrite (cmdstr->str, cmdstr->len, 1, me->logfile);
499 (void) ret;
500 }
501
502 fflush (me->logfile);
503 }
504
505 got_sigpipe = 0;
506 tty_enable_interrupt_key ();
507 status = write (ftp_super->sock, cmdstr->str, cmdstr->len);
508
509 if (status < 0)
510 {
511 code = 421;
512
513 if (errno == EPIPE)
514 {
515 if (level == 0)
516 {
517 level = 1;
518 status = ftpfs_reconnect (me, super) ? 1 : 0;
519 level = 0;
520 if (status != 0 && (write (ftp_super->sock, cmdstr->str, cmdstr->len) > 0))
521 goto ok;
522 }
523 got_sigpipe = 1;
524 }
525 g_string_free (cmdstr, TRUE);
526 tty_disable_interrupt_key ();
527 return TRANSIENT;
528 }
529
530 retry = FALSE;
531
532 ok:
533 tty_disable_interrupt_key ();
534
535 if (wait_reply != NONE)
536 {
537 status = ftpfs_get_reply (me, ftp_super->sock,
538 (wait_reply & WANT_STRING) != 0 ? reply_str : NULL,
539 sizeof (reply_str) - 1);
540 if ((wait_reply & WANT_STRING) != 0 && !retry && level == 0 && code == 421)
541 {
542 retry = TRUE;
543 level = 1;
544 status = ftpfs_reconnect (me, super) ? 1 : 0;
545 level = 0;
546 if (status != 0 && (write (ftp_super->sock, cmdstr->str, cmdstr->len) > 0))
547 goto ok;
548 }
549 retry = FALSE;
550 g_string_free (cmdstr, TRUE);
551 return status;
552 }
553
554 g_string_free (cmdstr, TRUE);
555 return COMPLETE;
556 }
557
558
559
560 static struct vfs_s_super *
561 ftpfs_new_archive (struct vfs_class *me)
562 {
563 ftp_super_t *arch;
564
565 arch = g_new0 (ftp_super_t, 1);
566 arch->base.me = me;
567 arch->base.name = g_strdup (PATH_SEP_STR);
568 arch->sock = -1;
569 arch->use_passive_connection = ftpfs_use_passive_connections;
570 arch->strict = ftpfs_use_unix_list_options ? RFC_AUTODETECT : RFC_STRICT;
571 arch->isbinary = TYPE_UNKNOWN;
572
573 return VFS_SUPER (arch);
574 }
575
576
577
578 static void
579 ftpfs_free_archive (struct vfs_class *me, struct vfs_s_super *super)
580 {
581 ftp_super_t *ftp_super = FTP_SUPER (super);
582
583 if (ftp_super->sock != -1)
584 {
585 vfs_print_message (_ ("ftpfs: Disconnecting from %s"), super->path_element->host);
586 ftpfs_command (me, super, NONE, "%s", "QUIT");
587 close (ftp_super->sock);
588 }
589 g_free (ftp_super->current_dir);
590 }
591
592
593
594 static int
595 ftpfs_changetype (struct vfs_class *me, struct vfs_s_super *super, int binary)
596 {
597 if (binary != FTP_SUPER (super)->isbinary)
598 {
599 if (ftpfs_command (me, super, WAIT_REPLY, "TYPE %c", binary ? 'I' : 'A') != COMPLETE)
600 ERRNOR (EIO, -1);
601 FTP_SUPER (super)->isbinary = binary;
602 }
603 return binary;
604 }
605
606
607
608
609 static int
610 ftpfs_login_server (struct vfs_class *me, struct vfs_s_super *super, const char *netrcpass)
611 {
612 ftp_super_t *ftp_super = FTP_SUPER (super);
613 char *pass;
614 char *op;
615 char *name;
616 gboolean anon = FALSE;
617 char reply_string[BUF_MEDIUM];
618
619 ftp_super->isbinary = TYPE_UNKNOWN;
620
621 if (super->path_element->password != NULL)
622 op = g_strdup (super->path_element->password);
623 else if (netrcpass != NULL)
624 op = g_strdup (netrcpass);
625 else if (strcmp (super->path_element->user, "anonymous") == 0
626 || strcmp (super->path_element->user, "ftp") == 0)
627 {
628 if (ftpfs_anonymous_passwd == NULL)
629 ftpfs_init_passwd ();
630 op = g_strdup (ftpfs_anonymous_passwd);
631 anon = TRUE;
632 }
633 else
634 {
635 char *p;
636
637 p = g_strdup_printf (_ ("FTP: Password required for %s"), super->path_element->user);
638 op = vfs_get_password (p);
639 g_free (p);
640 if (op == NULL)
641 ERRNOR (EPERM, 0);
642 super->path_element->password = g_strdup (op);
643 }
644
645 if (!anon || me->logfile != NULL)
646 pass = op;
647 else
648 {
649 pass = g_strconcat ("-", op, (char *) NULL);
650 wipe_password (op);
651 }
652
653
654 if (ftp_super->proxy != NULL)
655 name = g_strconcat (super->path_element->user, "@",
656 super->path_element->host[0] == '!' ? super->path_element->host + 1
657 : super->path_element->host,
658 (char *) NULL);
659 else
660 name = g_strdup (super->path_element->user);
661
662 if (ftpfs_get_reply (me, ftp_super->sock, reply_string, sizeof (reply_string) - 1) == COMPLETE)
663 {
664 char *reply_up;
665
666 reply_up = g_ascii_strup (reply_string, -1);
667 ftp_super->remote_is_amiga = strstr (reply_up, "AMIGA") != NULL;
668 if (strstr (reply_up, " SPFTP/1.0.0000 SERVER ")
669 != NULL)
670 ftp_super->strict = RFC_STRICT;
671 g_free (reply_up);
672
673 if (me->logfile != NULL)
674 {
675 fprintf (me->logfile, "MC -- remote_is_amiga = %s\n",
676 ftp_super->remote_is_amiga ? "yes" : "no");
677 fflush (me->logfile);
678 }
679
680 vfs_print_message ("%s", _ ("ftpfs: sending login name"));
681
682 switch (ftpfs_command (me, super, WAIT_REPLY, "USER %s", name))
683 {
684 case CONTINUE:
685 vfs_print_message ("%s", _ ("ftpfs: sending user password"));
686 code = ftpfs_command (me, super, WAIT_REPLY, "PASS %s", pass);
687 if (code == CONTINUE)
688 {
689 char *p;
690
691 p = g_strdup_printf (_ ("FTP: Account required for user %s"),
692 super->path_element->user);
693 op = input_dialog (p, _ ("Account:"), MC_HISTORY_FTPFS_ACCOUNT, "",
694 INPUT_COMPLETE_USERNAMES);
695 g_free (p);
696 if (op == NULL)
697 ERRNOR (EPERM, 0);
698 vfs_print_message ("%s", _ ("ftpfs: sending user account"));
699 code = ftpfs_command (me, super, WAIT_REPLY, "ACCT %s", op);
700 g_free (op);
701 }
702 if (code != COMPLETE)
703 break;
704
705 MC_FALLTHROUGH;
706
707 case COMPLETE:
708 vfs_print_message ("%s", _ ("ftpfs: logged in"));
709 wipe_password (pass);
710 g_free (name);
711 return TRUE;
712
713 default:
714 ftp_super->failed_on_login = TRUE;
715 wipe_password (super->path_element->password);
716 super->path_element->password = NULL;
717 goto login_fail;
718 }
719 }
720
721 message (D_ERROR, MSG_ERROR, _ ("ftpfs: Login incorrect for user %s "),
722 super->path_element->user);
723
724 login_fail:
725 wipe_password (pass);
726 g_free (name);
727 ERRNOR (EPERM, FALSE);
728 }
729
730
731
732 static void
733 ftpfs_load_no_proxy_list (void)
734 {
735
736 char *mc_file;
737
738 mc_file = g_build_filename (mc_global.sysconfig_dir, "mc.no_proxy", (char *) NULL);
739 if (exist_file (mc_file))
740 {
741 FILE *npf;
742
743 npf = fopen (mc_file, "r");
744 if (npf != NULL)
745 {
746 char s[BUF_LARGE];
747
748 while (fgets (s, sizeof (s), npf) != NULL)
749 {
750 char *p;
751
752 p = strchr (s, '\n');
753 if (p == NULL)
754 {
755 int c;
756
757 while ((c = fgetc (npf)) != EOF && c != '\n')
758 ;
759 }
760 else if (p != s)
761 {
762 *p = '\0';
763 no_proxy = g_slist_prepend (no_proxy, g_strdup (s));
764 }
765 }
766
767 fclose (npf);
768 }
769 }
770
771 g_free (mc_file);
772 }
773
774
775
776
777 static gboolean
778 ftpfs_check_proxy (const char *host)
779 {
780
781 if (ftpfs_proxy_host == NULL || *ftpfs_proxy_host == '\0' || host == NULL || *host == '\0')
782 return FALSE;
783
784 if (*host == '!')
785 return TRUE;
786
787 if (!ftpfs_always_use_proxy)
788 return FALSE;
789
790 if (strchr (host, '.') == NULL)
791 return FALSE;
792
793 if (no_proxy == NULL)
794 {
795 GSList *npe;
796
797 ftpfs_load_no_proxy_list ();
798
799 for (npe = no_proxy; npe != NULL; npe = g_slist_next (npe))
800 {
801 const char *domain = (const char *) npe->data;
802
803 if (domain[0] == '.')
804 {
805 size_t ld, lh;
806
807 ld = strlen (domain);
808 lh = strlen (host);
809
810 while (ld != 0 && lh != 0 && host[lh - 1] == domain[ld - 1])
811 {
812 ld--;
813 lh--;
814 }
815
816 if (ld == 0)
817 return FALSE;
818 }
819 else if (g_ascii_strcasecmp (host, domain) == 0)
820 return FALSE;
821 }
822 }
823
824 return TRUE;
825 }
826
827
828
829 static void
830 ftpfs_get_proxy_host_and_port (const char *proxy, char **host, int *port)
831 {
832 vfs_path_element_t *path_element;
833
834 path_element = vfs_url_split (proxy, FTP_COMMAND_PORT, URL_USE_ANONYMOUS);
835 *host = path_element->host;
836 path_element->host = NULL;
837 *port = path_element->port;
838 vfs_path_element_free (path_element);
839 }
840
841
842
843 static int
844 ftpfs_open_socket (struct vfs_class *me, struct vfs_s_super *super)
845 {
846 struct addrinfo hints, *res, *curr_res;
847 int my_socket = 0;
848 char *host = NULL;
849 char port[8];
850 int tmp_port = 0;
851 int e;
852
853 (void) me;
854
855 if (super->path_element->host == NULL || *super->path_element->host == '\0')
856 {
857 vfs_print_message ("%s", _ ("ftpfs: Invalid host name."));
858 me->verrno = EINVAL;
859 return (-1);
860 }
861
862
863
864 if (FTP_SUPER (super)->proxy != NULL)
865 ftpfs_get_proxy_host_and_port (ftpfs_proxy_host, &host, &tmp_port);
866 else
867 {
868 host = g_strdup (super->path_element->host);
869 tmp_port = super->path_element->port;
870 }
871
872 g_snprintf (port, sizeof (port), "%hu", (unsigned short) tmp_port);
873
874 tty_enable_interrupt_key ();
875
876 memset (&hints, 0, sizeof (hints));
877 hints.ai_family = AF_UNSPEC;
878 hints.ai_socktype = SOCK_STREAM;
879
880 #ifdef AI_ADDRCONFIG
881
882
883
884 hints.ai_flags = AI_ADDRCONFIG;
885 #endif
886
887 e = getaddrinfo (host, port, &hints, &res);
888
889 #ifdef AI_ADDRCONFIG
890 if (e == EAI_BADFLAGS)
891 {
892
893 hints.ai_flags = 0;
894 e = getaddrinfo (host, port, &hints, &res);
895 }
896 #endif
897
898 *port = '\0';
899
900 if (e != 0)
901 {
902 tty_disable_interrupt_key ();
903 vfs_print_message (_ ("ftpfs: %s"), gai_strerror (e));
904 g_free (host);
905 me->verrno = EINVAL;
906 return (-1);
907 }
908
909 for (curr_res = res; curr_res != NULL; curr_res = curr_res->ai_next)
910 {
911 my_socket = socket (curr_res->ai_family, curr_res->ai_socktype, curr_res->ai_protocol);
912
913 if (my_socket < 0)
914 {
915 if (curr_res->ai_next != NULL)
916 continue;
917
918 tty_disable_interrupt_key ();
919 vfs_print_message (_ ("ftpfs: %s"), unix_error_string (errno));
920 g_free (host);
921 freeaddrinfo (res);
922 me->verrno = errno;
923 return (-1);
924 }
925
926 vfs_print_message (_ ("ftpfs: making connection to %s"), host);
927 MC_PTR_FREE (host);
928
929 if (connect (my_socket, curr_res->ai_addr, curr_res->ai_addrlen) >= 0)
930 break;
931
932 me->verrno = errno;
933 close (my_socket);
934
935 if (me->verrno == EINTR && tty_got_interrupt ())
936 vfs_print_message ("%s", _ ("ftpfs: connection interrupted by user"));
937 else if (res->ai_next == NULL)
938 vfs_print_message (_ ("ftpfs: connection to server failed: %s"),
939 unix_error_string (errno));
940 else
941 continue;
942
943 freeaddrinfo (res);
944 tty_disable_interrupt_key ();
945 return (-1);
946 }
947
948 freeaddrinfo (res);
949 tty_disable_interrupt_key ();
950 return my_socket;
951 }
952
953
954
955 static int
956 ftpfs_open_archive_int (struct vfs_class *me, struct vfs_s_super *super)
957 {
958 ftp_super_t *ftp_super = FTP_SUPER (super);
959 int retry_seconds = 0;
960
961
962 if (ftp_super->proxy != NULL)
963 ftp_super->use_passive_connection = ftpfs_use_passive_connections_over_proxy;
964
965 do
966 {
967 ftp_super->failed_on_login = FALSE;
968
969 ftp_super->sock = ftpfs_open_socket (me, super);
970 if (ftp_super->sock == -1)
971 return (-1);
972
973 if (ftpfs_login_server (me, super, NULL))
974 {
975
976 break;
977 }
978
979 if (!ftp_super->failed_on_login)
980 return (-1);
981
982
983 close (ftp_super->sock);
984
985 if (ftpfs_retry_seconds != 0)
986 {
987 int count_down;
988
989 retry_seconds = ftpfs_retry_seconds;
990 tty_enable_interrupt_key ();
991 for (count_down = retry_seconds; count_down != 0; count_down--)
992 {
993 vfs_print_message (_ ("Waiting to retry... %d (Control-G to cancel)"), count_down);
994 sleep (1);
995 if (tty_got_interrupt ())
996 {
997
998 tty_disable_interrupt_key ();
999 return 0;
1000 }
1001 }
1002 tty_disable_interrupt_key ();
1003 }
1004 }
1005 while (retry_seconds != 0);
1006
1007 ftp_super->current_dir = ftpfs_get_current_directory (me, super);
1008 if (ftp_super->current_dir == NULL)
1009 ftp_super->current_dir = g_strdup (PATH_SEP_STR);
1010
1011 return 0;
1012 }
1013
1014
1015
1016 static int
1017 ftpfs_open_archive (struct vfs_s_super *super, const vfs_path_t *vpath,
1018 const vfs_path_element_t *vpath_element)
1019 {
1020 (void) vpath;
1021
1022 super->path_element = ftpfs_correct_url_parameters (vpath_element);
1023 if (ftpfs_check_proxy (super->path_element->host))
1024 FTP_SUPER (super)->proxy = ftpfs_proxy_host;
1025 super->root =
1026 vfs_s_new_inode (vpath_element->class, super, ftpfs_default_stat (vpath_element->class));
1027
1028 return ftpfs_open_archive_int (vpath_element->class, super);
1029 }
1030
1031
1032
1033 static int
1034 ftpfs_archive_same (const vfs_path_element_t *vpath_element, struct vfs_s_super *super,
1035 const vfs_path_t *vpath, void *cookie)
1036 {
1037 vfs_path_element_t *path_element;
1038 int result;
1039
1040 (void) vpath;
1041 (void) cookie;
1042
1043 path_element = ftpfs_correct_url_parameters (vpath_element);
1044
1045 result = ((strcmp (path_element->host, super->path_element->host) == 0)
1046 && (strcmp (path_element->user, super->path_element->user) == 0)
1047 && (path_element->port == super->path_element->port))
1048 ? 1
1049 : 0;
1050
1051 vfs_path_element_free (path_element);
1052 return result;
1053 }
1054
1055
1056
1057
1058 static char *
1059 ftpfs_get_current_directory (struct vfs_class *me, struct vfs_s_super *super)
1060 {
1061 char buf[MC_MAXPATHLEN + 1];
1062
1063 if (ftpfs_command (me, super, NONE, "%s", "PWD") == COMPLETE
1064 && ftpfs_get_reply (me, FTP_SUPER (super)->sock, buf, sizeof (buf)) == COMPLETE)
1065 {
1066 char *bufp = NULL;
1067 char *bufq;
1068
1069 for (bufq = buf; *bufq != '\0'; bufq++)
1070 if (*bufq == '"')
1071 {
1072 if (bufp == NULL)
1073 bufp = bufq + 1;
1074 else
1075 {
1076 *bufq = '\0';
1077
1078 if (*bufp != '\0')
1079 {
1080 if (!IS_PATH_SEP (bufq[-1]))
1081 {
1082 *bufq++ = PATH_SEP;
1083 *bufq = '\0';
1084 }
1085
1086 if (IS_PATH_SEP (*bufp))
1087 return g_strdup (bufp);
1088
1089
1090
1091
1092 return g_strconcat (PATH_SEP_STR, bufp, (char *) NULL);
1093 }
1094
1095 break;
1096 }
1097 }
1098 }
1099
1100 me->verrno = EIO;
1101 return NULL;
1102 }
1103
1104
1105
1106
1107 static gboolean
1108 ftpfs_setup_passive_pasv (struct vfs_class *me, struct vfs_s_super *super, int my_socket,
1109 struct sockaddr_storage *sa, socklen_t *salen)
1110 {
1111 char *c;
1112 char n[6];
1113 int xa, xb, xc, xd, xe, xf;
1114
1115 if (ftpfs_command (me, super, WAIT_REPLY | WANT_STRING, "%s", "PASV") != COMPLETE)
1116 return FALSE;
1117
1118
1119 for (c = reply_str + 4; *c != '\0' && !isdigit ((unsigned char) *c); c++)
1120 ;
1121
1122 if (*c == '\0' || !isdigit ((unsigned char) *c))
1123 return FALSE;
1124
1125 if (sscanf (c, "%d,%d,%d,%d,%d,%d", &xa, &xb, &xc, &xd, &xe, &xf) != 6)
1126 return FALSE;
1127
1128 n[0] = (unsigned char) xa;
1129 n[1] = (unsigned char) xb;
1130 n[2] = (unsigned char) xc;
1131 n[3] = (unsigned char) xd;
1132 n[4] = (unsigned char) xe;
1133 n[5] = (unsigned char) xf;
1134
1135 memcpy (&(((struct sockaddr_in *) sa)->sin_addr.s_addr), (void *) n, 4);
1136 memcpy (&(((struct sockaddr_in *) sa)->sin_port), (void *) &n[4], 2);
1137
1138 return (connect (my_socket, (struct sockaddr *) sa, *salen) >= 0);
1139 }
1140
1141
1142
1143
1144 static gboolean
1145 ftpfs_setup_passive_epsv (struct vfs_class *me, struct vfs_s_super *super, int my_socket,
1146 struct sockaddr_storage *sa, socklen_t *salen)
1147 {
1148 char *c;
1149 int port;
1150
1151 if (ftpfs_command (me, super, WAIT_REPLY | WANT_STRING, "%s", "EPSV") != COMPLETE)
1152 return FALSE;
1153
1154
1155 c = strchr (reply_str, '|');
1156 if (c == NULL || strlen (c) <= 3)
1157 return FALSE;
1158
1159 c += 3;
1160 port = atoi (c);
1161 if (port < 0 || port > 65535)
1162 return FALSE;
1163
1164 port = htons (port);
1165
1166 switch (sa->ss_family)
1167 {
1168 case AF_INET:
1169 ((struct sockaddr_in *) sa)->sin_port = port;
1170 break;
1171 case AF_INET6:
1172 ((struct sockaddr_in6 *) sa)->sin6_port = port;
1173 break;
1174 default:
1175 break;
1176 }
1177
1178 return (connect (my_socket, (struct sockaddr *) sa, *salen) >= 0);
1179 }
1180
1181
1182
1183
1184 static gboolean
1185 ftpfs_setup_passive (struct vfs_class *me, struct vfs_s_super *super, int my_socket,
1186 struct sockaddr_storage *sa, socklen_t *salen)
1187 {
1188
1189 if (sa->ss_family == AF_INET)
1190 {
1191 if (!ftpfs_setup_passive_pasv (me, super, my_socket, sa, salen))
1192
1193 if (!ftpfs_setup_passive_epsv (me, super, my_socket, sa, salen))
1194 return FALSE;
1195 }
1196
1197 else if (!ftpfs_setup_passive_epsv (me, super, my_socket, sa, salen))
1198 return FALSE;
1199
1200 return TRUE;
1201 }
1202
1203
1204
1205
1206 static int
1207 ftpfs_setup_active (struct vfs_class *me, struct vfs_s_super *super,
1208 struct sockaddr_storage data_addr, socklen_t data_addrlen)
1209 {
1210 unsigned short int port;
1211 char *addr;
1212 unsigned int af;
1213 int res;
1214
1215 switch (data_addr.ss_family)
1216 {
1217 case AF_INET:
1218 af = FTP_INET;
1219 port = ((struct sockaddr_in *) &data_addr)->sin_port;
1220 break;
1221 case AF_INET6:
1222 af = FTP_INET6;
1223 port = ((struct sockaddr_in6 *) &data_addr)->sin6_port;
1224 break;
1225 default:
1226
1227 return 0;
1228 }
1229
1230 addr = g_try_malloc (NI_MAXHOST);
1231 if (addr == NULL)
1232 ERRNOR (ENOMEM, -1);
1233
1234 res = getnameinfo ((struct sockaddr *) &data_addr, data_addrlen, addr, NI_MAXHOST, NULL, 0,
1235 NI_NUMERICHOST);
1236 if (res != 0)
1237 {
1238 const char *err_str;
1239
1240 g_free (addr);
1241
1242 if (res == EAI_SYSTEM)
1243 {
1244 me->verrno = errno;
1245 err_str = unix_error_string (me->verrno);
1246 }
1247 else
1248 {
1249 me->verrno = EIO;
1250 err_str = gai_strerror (res);
1251 }
1252
1253 vfs_print_message (_ ("ftpfs: could not make address-to-name translation: %s"), err_str);
1254
1255 return (-1);
1256 }
1257
1258
1259 if (af == FTP_INET)
1260 {
1261 unsigned char *a = (unsigned char *) &((struct sockaddr_in *) &data_addr)->sin_addr;
1262 unsigned char *p = (unsigned char *) &port;
1263
1264 if (ftpfs_command (me, super, WAIT_REPLY, "PORT %u,%u,%u,%u,%u,%u", a[0], a[1], a[2], a[3],
1265 p[0], p[1])
1266 == COMPLETE)
1267 {
1268 g_free (addr);
1269 return 1;
1270 }
1271 }
1272
1273
1274
1275
1276
1277
1278
1279 port = ntohs (port);
1280
1281
1282 res = (ftpfs_command (me, super, WAIT_REPLY, "EPRT |%u|%s|%hu|", af, addr, port) == COMPLETE)
1283 ? 1
1284 : 0;
1285 g_free (addr);
1286 return res;
1287 }
1288
1289
1290
1291
1292 static int
1293 ftpfs_init_data_socket (struct vfs_class *me, struct vfs_s_super *super,
1294 struct sockaddr_storage *data_addr, socklen_t *data_addrlen)
1295 {
1296 const unsigned int attempts = 10;
1297 unsigned int i;
1298 ftp_super_t *ftp_super = FTP_SUPER (super);
1299 int result;
1300
1301 for (i = 0; i < attempts; i++)
1302 {
1303 memset (data_addr, 0, sizeof (*data_addr));
1304 *data_addrlen = sizeof (*data_addr);
1305
1306 if (ftp_super->use_passive_connection)
1307 {
1308 result = getpeername (ftp_super->sock, (struct sockaddr *) data_addr, data_addrlen);
1309 if (result == 0)
1310 break;
1311
1312 me->verrno = errno;
1313
1314 if (me->verrno == ENOTCONN)
1315 {
1316 vfs_print_message (_ ("ftpfs: try reconnect to server, attempt %u"), i);
1317 if (ftpfs_reconnect (me, super))
1318 continue;
1319 }
1320 else
1321 {
1322
1323 vfs_print_message (_ ("ftpfs: could not get socket name: %s"),
1324 unix_error_string (me->verrno));
1325 }
1326 }
1327 else
1328 {
1329 result = getsockname (ftp_super->sock, (struct sockaddr *) data_addr, data_addrlen);
1330 if (result == 0)
1331 break;
1332
1333 me->verrno = errno;
1334
1335 vfs_print_message (_ ("ftpfs: try reconnect to server, attempt %u"), i);
1336 if (ftpfs_reconnect (me, super))
1337 continue;
1338
1339
1340 vfs_print_message ("%s", _ ("ftpfs: could not reconnect to server"));
1341 }
1342
1343 i = attempts;
1344 }
1345
1346 if (i >= attempts)
1347 return (-1);
1348
1349 switch (data_addr->ss_family)
1350 {
1351 case AF_INET:
1352 ((struct sockaddr_in *) data_addr)->sin_port = 0;
1353 break;
1354 case AF_INET6:
1355 ((struct sockaddr_in6 *) data_addr)->sin6_port = 0;
1356 break;
1357 default:
1358 vfs_print_message ("%s", _ ("ftpfs: invalid address family"));
1359 ERRNOR (EINVAL, -1);
1360 }
1361
1362 result = socket (data_addr->ss_family, SOCK_STREAM, IPPROTO_TCP);
1363 if (result < 0)
1364 {
1365 me->verrno = errno;
1366 vfs_print_message (_ ("ftpfs: could not create socket: %s"),
1367 unix_error_string (me->verrno));
1368 result = -1;
1369 }
1370
1371 return result;
1372 }
1373
1374
1375
1376
1377 static int
1378 ftpfs_initconn (struct vfs_class *me, struct vfs_s_super *super)
1379 {
1380 ftp_super_t *ftp_super = FTP_SUPER (super);
1381 struct sockaddr_storage data_addr;
1382 socklen_t data_addrlen;
1383
1384
1385
1386
1387
1388
1389
1390
1391 if (ftp_super->use_passive_connection)
1392 {
1393 int data_sock;
1394
1395 data_sock = ftpfs_init_data_socket (me, super, &data_addr, &data_addrlen);
1396 if (data_sock < 0)
1397 return (-1);
1398
1399 if (ftpfs_setup_passive (me, super, data_sock, &data_addr, &data_addrlen))
1400 return data_sock;
1401
1402 vfs_print_message ("%s", _ ("ftpfs: could not setup passive mode"));
1403 ftp_super->use_passive_connection = FALSE;
1404
1405 close (data_sock);
1406 }
1407
1408
1409 if (!ftp_super->use_passive_connection)
1410 {
1411 int data_sock;
1412
1413 data_sock = ftpfs_init_data_socket (me, super, &data_addr, &data_addrlen);
1414 if (data_sock < 0)
1415 return (-1);
1416
1417 if ((bind (data_sock, (struct sockaddr *) &data_addr, data_addrlen) != 0)
1418 || (getsockname (data_sock, (struct sockaddr *) &data_addr, &data_addrlen) != 0)
1419 || (listen (data_sock, 1) != 0))
1420 {
1421 close (data_sock);
1422 ERRNOR (errno, -1);
1423 }
1424
1425 if (ftpfs_setup_active (me, super, data_addr, data_addrlen) != 0)
1426 return data_sock;
1427
1428 close (data_sock);
1429 }
1430
1431
1432 ftp_super->use_passive_connection = ftp_super->proxy != NULL
1433 ? ftpfs_use_passive_connections_over_proxy
1434 : ftpfs_use_passive_connections;
1435
1436 me->verrno = EIO;
1437 return (-1);
1438 }
1439
1440
1441
1442 static int
1443 ftpfs_open_data_connection (struct vfs_class *me, struct vfs_s_super *super, const char *cmd,
1444 const char *remote, int isbinary, int reget)
1445 {
1446 ftp_super_t *ftp_super = FTP_SUPER (super);
1447 int s, j, data;
1448
1449
1450 if (ftp_super->ctl_connection_busy)
1451 return (-1);
1452
1453 s = ftpfs_initconn (me, super);
1454 if (s == -1)
1455 return (-1);
1456
1457 if (ftpfs_changetype (me, super, isbinary) == -1)
1458 {
1459 close (s);
1460 return (-1);
1461 }
1462
1463 if (reget > 0)
1464 {
1465 j = ftpfs_command (me, super, WAIT_REPLY, "REST %d", reget);
1466 if (j != CONTINUE)
1467 {
1468 close (s);
1469 ERRNOR (EIO, -1);
1470 }
1471 }
1472
1473 if (remote == NULL)
1474 j = ftpfs_command (me, super, WAIT_REPLY, "%s", cmd);
1475 else
1476 {
1477 char *remote_path;
1478
1479 remote_path = ftpfs_translate_path (me, super, remote);
1480 j = ftpfs_command (me, super, WAIT_REPLY, "%s /%s", cmd,
1481
1482 IS_PATH_SEP (*remote_path) ? remote_path + 1 : remote_path);
1483 g_free (remote_path);
1484 }
1485
1486 if (j != PRELIM)
1487 {
1488 close (s);
1489 ERRNOR (EPERM, -1);
1490 }
1491
1492 if (ftp_super->use_passive_connection)
1493 data = s;
1494 else
1495 {
1496 struct sockaddr_storage from;
1497 socklen_t fromlen = sizeof (from);
1498
1499 tty_enable_interrupt_key ();
1500 data = accept (s, (struct sockaddr *) &from, &fromlen);
1501 if (data < 0)
1502 me->verrno = errno;
1503 tty_disable_interrupt_key ();
1504 close (s);
1505 if (data < 0)
1506 return (-1);
1507 }
1508
1509 ftp_super->ctl_connection_busy = TRUE;
1510 return data;
1511 }
1512
1513
1514
1515 static void
1516 ftpfs_linear_abort (struct vfs_class *me, vfs_file_handler_t *fh)
1517 {
1518 struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
1519 ftp_super_t *ftp_super = FTP_SUPER (super);
1520 static unsigned char const ipbuf[3] = { IAC, IP, IAC };
1521 fd_set mask;
1522 int dsock = FH_SOCK;
1523
1524 FH_SOCK = -1;
1525 ftp_super->ctl_connection_busy = FALSE;
1526
1527 vfs_print_message ("%s", _ ("ftpfs: aborting transfer."));
1528
1529 if (send (ftp_super->sock, ipbuf, sizeof (ipbuf), MSG_OOB) != sizeof (ipbuf))
1530 {
1531 vfs_print_message (_ ("ftpfs: abort error: %s"), unix_error_string (errno));
1532 if (dsock != -1)
1533 close (dsock);
1534 return;
1535 }
1536
1537 if (ftpfs_command (me, super, NONE, "%cABOR", DM) != COMPLETE)
1538 {
1539 vfs_print_message ("%s", _ ("ftpfs: abort failed"));
1540 if (dsock != -1)
1541 close (dsock);
1542 return;
1543 }
1544
1545 if (dsock != -1)
1546 {
1547 FD_ZERO (&mask);
1548 FD_SET (dsock, &mask);
1549
1550 if (select (dsock + 1, &mask, NULL, NULL, NULL) > 0)
1551 {
1552 gint64 start_tim;
1553 char buf[BUF_8K];
1554
1555 start_tim = g_get_monotonic_time ();
1556
1557
1558 while (read (dsock, buf, sizeof (buf)) > 0)
1559 {
1560 gint64 tim;
1561
1562 tim = g_get_monotonic_time ();
1563
1564 if (tim > start_tim + ABORT_TIMEOUT)
1565 {
1566
1567 close (dsock);
1568 ftpfs_reconnect (me, super);
1569 return;
1570 }
1571 }
1572 }
1573 close (dsock);
1574 }
1575
1576 if ((ftpfs_get_reply (me, ftp_super->sock, NULL, 0) == TRANSIENT) && (code == 426))
1577 ftpfs_get_reply (me, ftp_super->sock, NULL, 0);
1578 }
1579
1580
1581
1582 #if 0
1583 static void
1584 resolve_symlink_without_ls_options (struct vfs_class *me, struct vfs_s_super *super,
1585 struct vfs_s_inode *dir)
1586 {
1587 struct linklist *flist;
1588 struct direntry *fe, *fel;
1589 char tmp[MC_MAXPATHLEN];
1590
1591 dir->symlink_status = FTPFS_RESOLVING_SYMLINKS;
1592 for (flist = dir->file_list->next; flist != dir->file_list; flist = flist->next)
1593 {
1594
1595 fel = flist->data;
1596 if (S_ISLNK (fel->s.st_mode) && fel->linkname != NULL)
1597 {
1598 int depth;
1599
1600 if (IS_PATH_SEP (fel->linkname[0]))
1601 {
1602 if (strlen (fel->linkname) >= MC_MAXPATHLEN)
1603 continue;
1604 strcpy (tmp, fel->linkname);
1605 }
1606 else
1607 {
1608 if ((strlen (dir->remote_path) + strlen (fel->linkname)) >= MC_MAXPATHLEN)
1609 continue;
1610 strcpy (tmp, dir->remote_path);
1611 if (tmp[1] != '\0')
1612 strcat (tmp, PATH_SEP_STR);
1613 strcat (tmp + 1, fel->linkname);
1614 }
1615
1616 for (depth = 0; depth < 100; depth++)
1617 {
1618 canonicalize_pathname (tmp);
1619 fe = _get_file_entry_t (bucket, tmp, 0, 0);
1620 if (fe != NULL)
1621 {
1622 if (S_ISLNK (fe->s.st_mode) && fe->l_stat == 0)
1623 {
1624
1625 if (IS_PATH_SEP (fe->linkname[0]))
1626 {
1627 if (strlen (fe->linkname) >= MC_MAXPATHLEN)
1628 break;
1629 strcpy (tmp, fe->linkname);
1630 }
1631 else
1632 {
1633
1634
1635
1636 *(strrchr (tmp, PATH_SEP) + 1) = '\0';
1637 if ((strlen (tmp) + strlen (fe->linkname)) >= MC_MAXPATHLEN)
1638 break;
1639 strcat (tmp, fe->linkname);
1640 }
1641 continue;
1642 }
1643 else
1644 {
1645 fel->l_stat = g_new (struct stat, 1);
1646 if (S_ISLNK (fe->s.st_mode))
1647 *fel->l_stat = *fe->l_stat;
1648 else
1649 *fel->l_stat = fe->s;
1650 (*fel->l_stat).st_ino = bucket->__inode_counter++;
1651 }
1652 }
1653 break;
1654 }
1655 }
1656 }
1657
1658 dir->symlink_status = FTPFS_RESOLVED_SYMLINKS;
1659 }
1660
1661
1662
1663 static void
1664 resolve_symlink_with_ls_options (struct vfs_class *me, struct vfs_s_super *super,
1665 struct vfs_s_inode *dir)
1666 {
1667 char buffer[BUF_2K] = "";
1668 char *filename;
1669 int sock;
1670 FILE *fp;
1671 struct stat s;
1672 struct linklist *flist;
1673 struct direntry *fe;
1674 int switch_method = 0;
1675
1676 dir->symlink_status = FTPFS_RESOLVED_SYMLINKS;
1677 if (strchr (dir->remote_path, ' ') == NULL)
1678 sock = ftpfs_open_data_connection (bucket, "LIST -lLa", dir->remote_path, TYPE_ASCII, 0);
1679 else
1680 {
1681 if (ftpfs_chdir_internal (bucket, dir->remote_path) != COMPLETE)
1682 {
1683 vfs_print_message ("%s", _("ftpfs: CWD failed."));
1684 return;
1685 }
1686
1687 sock = ftpfs_open_data_connection (bucket, "LIST -lLa", ".", TYPE_ASCII, 0);
1688 }
1689
1690 if (sock == -1)
1691 {
1692 vfs_print_message ("%s", _("ftpfs: couldn't resolve symlink"));
1693 return;
1694 }
1695
1696 fp = fdopen (sock, "r");
1697 if (fp == NULL)
1698 {
1699 close (sock);
1700 vfs_print_message ("%s", _("ftpfs: couldn't resolve symlink"));
1701 return;
1702 }
1703 tty_enable_interrupt_key ();
1704 flist = dir->file_list->next;
1705
1706 while (TRUE)
1707 {
1708 do
1709 {
1710 if (flist == dir->file_list)
1711 goto done;
1712
1713 fe = flist->data;
1714 flist = flist->next;
1715 }
1716 while (!S_ISLNK (fe->s.st_mode));
1717
1718 while (TRUE)
1719 {
1720 if (fgets (buffer, sizeof (buffer), fp) == NULL)
1721 goto done;
1722
1723 if (me->logfile != NULL)
1724 {
1725 fputs (buffer, me->logfile);
1726 fflush (me->logfile);
1727 }
1728
1729 vfs_die ("This code should be commented out\n");
1730
1731 if (vfs_parse_ls_lga (buffer, &s, &filename, NULL))
1732 {
1733 int r;
1734
1735 r = strcmp (fe->name, filename);
1736 g_free (filename);
1737 if (r == 0)
1738 {
1739 if (S_ISLNK (s.st_mode))
1740 {
1741
1742 switch_method = 1;
1743 goto done;
1744 }
1745
1746 fe->l_stat = g_try_new (struct stat, 1);
1747 if (fe->l_stat == NULL)
1748 goto done;
1749
1750 *fe->l_stat = s;
1751 (*fe->l_stat).st_ino = bucket->__inode_counter++;
1752 break;
1753 }
1754
1755 if (r < 0)
1756 break;
1757 }
1758 }
1759 }
1760
1761 done:
1762 while (fgets (buffer, sizeof (buffer), fp) != NULL)
1763 ;
1764 tty_disable_interrupt_key ();
1765 fclose (fp);
1766 ftpfs_get_reply (me, FTP_SUPER (super)->sock, NULL, 0);
1767 }
1768
1769
1770
1771 static void
1772 resolve_symlink (struct vfs_class *me, struct vfs_s_super *super, struct vfs_s_inode *dir)
1773 {
1774 vfs_print_message ("%s", _("Resolving symlink..."));
1775
1776 if (FTP_SUPER (super)->strict_rfc959_list_cmd)
1777 resolve_symlink_without_ls_options (me, super, dir);
1778 else
1779 resolve_symlink_with_ls_options (me, super, dir);
1780 }
1781 #endif
1782
1783
1784
1785 static int
1786 ftpfs_dir_load (struct vfs_class *me, struct vfs_s_inode *dir, const char *remote_path)
1787 {
1788 struct vfs_s_super *super = dir->super;
1789 ftp_super_t *ftp_super = FTP_SUPER (super);
1790 int sock;
1791 char lc_buffer[BUF_8K];
1792 int res;
1793 gboolean cd_first;
1794 GSList *dirlist = NULL;
1795 GSList *entlist;
1796 GSList *iter;
1797 int err_count = 0;
1798
1799 cd_first = ftpfs_first_cd_then_ls || (ftp_super->strict == RFC_STRICT)
1800 || (strchr (remote_path, ' ') != NULL);
1801
1802 again:
1803 vfs_print_message (_ ("ftpfs: Reading FTP directory %s... %s%s"), remote_path,
1804 ftp_super->strict == RFC_STRICT ? _ ("(strict rfc959)") : "",
1805 cd_first ? _ ("(chdir first)") : "");
1806
1807 if (cd_first && ftpfs_chdir_internal (me, super, remote_path) != COMPLETE)
1808 {
1809 me->verrno = ENOENT;
1810 vfs_print_message ("%s", _ ("ftpfs: CWD failed."));
1811 return (-1);
1812 }
1813
1814 dir->timestamp = g_get_monotonic_time () + ftpfs_directory_timeout * G_USEC_PER_SEC;
1815
1816 if (ftp_super->strict == RFC_STRICT)
1817 sock = ftpfs_open_data_connection (me, super, "LIST", 0, TYPE_ASCII, 0);
1818 else if (cd_first)
1819
1820
1821 sock = ftpfs_open_data_connection (me, super, "LIST -la", 0, TYPE_ASCII, 0);
1822 else
1823 {
1824 char *path;
1825
1826
1827 path = g_strconcat (remote_path, PATH_SEP_STR ".", (char *) NULL);
1828 sock = ftpfs_open_data_connection (me, super, "LIST -la", path, TYPE_ASCII, 0);
1829 g_free (path);
1830 }
1831
1832 if (sock == -1)
1833 {
1834 fallback:
1835 if (ftp_super->strict == RFC_AUTODETECT)
1836 {
1837
1838
1839 ftp_super->strict = RFC_STRICT;
1840
1841
1842 cd_first = TRUE;
1843 goto again;
1844 }
1845
1846 vfs_print_message ("%s", _ ("ftpfs: failed; nowhere to fallback to"));
1847 ERRNOR (EACCES, -1);
1848 }
1849
1850
1851 while ((res = vfs_s_get_line_interruptible (me, lc_buffer, sizeof (lc_buffer), sock)) != 0)
1852 {
1853 if (res == EINTR)
1854 {
1855 me->verrno = ECONNRESET;
1856 close (sock);
1857 ftp_super->ctl_connection_busy = FALSE;
1858 ftpfs_get_reply (me, ftp_super->sock, NULL, 0);
1859 g_slist_free_full (dirlist, g_free);
1860 vfs_print_message (_ ("%s: failure"), me->name);
1861 return (-1);
1862 }
1863
1864 if (me->logfile != NULL)
1865 {
1866 fputs (lc_buffer, me->logfile);
1867 fputs ("\n", me->logfile);
1868 fflush (me->logfile);
1869 }
1870
1871 dirlist = g_slist_prepend (dirlist, g_strdup (lc_buffer));
1872 }
1873
1874 close (sock);
1875 ftp_super->ctl_connection_busy = FALSE;
1876 me->verrno = E_REMOTE;
1877 if ((ftpfs_get_reply (me, ftp_super->sock, NULL, 0) != COMPLETE))
1878 {
1879 g_slist_free_full (dirlist, g_free);
1880 goto fallback;
1881 }
1882
1883 if (dirlist == NULL && !cd_first)
1884 {
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895 cd_first = TRUE;
1896 goto again;
1897 }
1898
1899
1900 dirlist = g_slist_reverse (dirlist);
1901 entlist = ftpfs_parse_long_list (me, dir, dirlist, &err_count);
1902 g_slist_free_full (dirlist, g_free);
1903
1904 for (iter = entlist; iter != NULL; iter = g_slist_next (iter))
1905 vfs_s_insert_entry (me, dir, VFS_ENTRY (iter->data));
1906
1907 g_slist_free (entlist);
1908
1909 if (ftp_super->strict == RFC_AUTODETECT)
1910 ftp_super->strict = RFC_DARING;
1911
1912 vfs_print_message (_ ("%s: done."), me->name);
1913 return 0;
1914 }
1915
1916
1917
1918 static int
1919 ftpfs_file_store (struct vfs_class *me, vfs_file_handler_t *fh, char *name, char *localname)
1920 {
1921 struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
1922 ftp_super_t *ftp_super = FTP_SUPER (super);
1923 ftp_file_handler_t *ftp = FTP_FILE_HANDLER (fh);
1924
1925 int h, sock;
1926 off_t n_stored = 0;
1927 #ifdef HAVE_STRUCT_LINGER_L_LINGER
1928 struct linger li;
1929 #else
1930 int flag_one = 1;
1931 #endif
1932 char lc_buffer[BUF_8K];
1933 struct stat s;
1934 char *w_buf;
1935
1936 h = open (localname, O_RDONLY);
1937 if (h == -1)
1938 ERRNOR (EIO, -1);
1939
1940 if (fstat (h, &s) == -1)
1941 {
1942 me->verrno = errno;
1943 close (h);
1944 return (-1);
1945 }
1946
1947 sock =
1948 ftpfs_open_data_connection (me, super, ftp->append ? "APPE" : "STOR", name, TYPE_BINARY, 0);
1949 if (sock < 0)
1950 {
1951 close (h);
1952 return (-1);
1953 }
1954 #ifdef HAVE_STRUCT_LINGER_L_LINGER
1955 li.l_onoff = 1;
1956 li.l_linger = 120;
1957 setsockopt (sock, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof (li));
1958 #else
1959 setsockopt (sock, SOL_SOCKET, SO_LINGER, &flag_one, sizeof (flag_one));
1960 #endif
1961
1962 tty_enable_interrupt_key ();
1963 while (TRUE)
1964 {
1965 ssize_t n_read, n_written;
1966
1967 while ((n_read = read (h, lc_buffer, sizeof (lc_buffer))) == -1)
1968 {
1969 if (errno != EINTR)
1970 {
1971 me->verrno = errno;
1972 goto error_return;
1973 }
1974 if (tty_got_interrupt ())
1975 {
1976 me->verrno = EINTR;
1977 goto error_return;
1978 }
1979 }
1980 if (n_read == 0)
1981 break;
1982
1983 n_stored += n_read;
1984 w_buf = lc_buffer;
1985
1986 while ((n_written = write (sock, w_buf, n_read)) != n_read)
1987 {
1988 if (n_written == -1)
1989 {
1990 if (errno == EINTR && !tty_got_interrupt ())
1991 continue;
1992
1993 me->verrno = errno;
1994 goto error_return;
1995 }
1996
1997 w_buf += n_written;
1998 n_read -= n_written;
1999 }
2000
2001 vfs_print_message ("%s: %" PRIuMAX "/%" PRIuMAX, _ ("ftpfs: storing file"),
2002 (uintmax_t) n_stored, (uintmax_t) s.st_size);
2003 }
2004 tty_disable_interrupt_key ();
2005
2006 close (sock);
2007 ftp_super->ctl_connection_busy = FALSE;
2008 close (h);
2009
2010 if (ftpfs_get_reply (me, ftp_super->sock, NULL, 0) != COMPLETE)
2011 ERRNOR (EIO, -1);
2012 return 0;
2013
2014 error_return:
2015 tty_disable_interrupt_key ();
2016 close (sock);
2017 ftp_super->ctl_connection_busy = FALSE;
2018 close (h);
2019
2020 ftpfs_get_reply (me, ftp_super->sock, NULL, 0);
2021 return (-1);
2022 }
2023
2024
2025
2026 static int
2027 ftpfs_linear_start (struct vfs_class *me, vfs_file_handler_t *fh, off_t offset)
2028 {
2029 char *name;
2030
2031 name = vfs_s_fullpath (me, fh->ino);
2032 if (name == NULL)
2033 return 0;
2034
2035 FH_SOCK = ftpfs_open_data_connection (me, VFS_FILE_HANDLER_SUPER (fh), "RETR", name,
2036 TYPE_BINARY, offset);
2037 g_free (name);
2038 if (FH_SOCK == -1)
2039 ERRNOR (EACCES, 0);
2040
2041 fh->linear = LS_LINEAR_OPEN;
2042 FTP_FILE_HANDLER (fh)->append = FALSE;
2043 return 1;
2044 }
2045
2046
2047
2048 static ssize_t
2049 ftpfs_linear_read (struct vfs_class *me, vfs_file_handler_t *fh, void *buf, size_t len)
2050 {
2051 ssize_t n;
2052 struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
2053
2054 while ((n = read (FH_SOCK, buf, len)) < 0)
2055 {
2056 if ((errno == EINTR) && !tty_got_interrupt ())
2057 continue;
2058 break;
2059 }
2060
2061 if (n < 0)
2062 ftpfs_linear_abort (me, fh);
2063 else if (n == 0)
2064 {
2065 FTP_SUPER (super)->ctl_connection_busy = FALSE;
2066 close (FH_SOCK);
2067 FH_SOCK = -1;
2068 if ((ftpfs_get_reply (me, FTP_SUPER (super)->sock, NULL, 0) != COMPLETE))
2069 ERRNOR (E_REMOTE, -1);
2070 return 0;
2071 }
2072
2073 ERRNOR (errno, n);
2074 }
2075
2076
2077
2078 static void
2079 ftpfs_linear_close (struct vfs_class *me, vfs_file_handler_t *fh)
2080 {
2081 if (FH_SOCK != -1)
2082 ftpfs_linear_abort (me, fh);
2083 }
2084
2085
2086
2087 static int
2088 ftpfs_ctl (void *fh, int ctlop, void *arg)
2089 {
2090 (void) arg;
2091
2092 switch (ctlop)
2093 {
2094 case VFS_CTL_IS_NOTREADY:
2095 {
2096 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
2097 int v;
2098
2099 if (file->linear == LS_NOT_LINEAR)
2100 vfs_die ("You may not do this");
2101 if (file->linear == LS_LINEAR_CLOSED || file->linear == LS_LINEAR_PREOPEN)
2102 return 0;
2103
2104 v = vfs_s_select_on_two (FH_SOCK, 0);
2105 return (((v < 0) && (errno == EINTR)) || v == 0) ? 1 : 0;
2106 }
2107 default:
2108 return 0;
2109 }
2110 }
2111
2112
2113
2114 static int
2115 ftpfs_send_command (const vfs_path_t *vpath, const char *cmd, int flags)
2116 {
2117 const char *rpath;
2118 char *p;
2119 struct vfs_s_super *super;
2120 int r;
2121 struct vfs_class *me;
2122 gboolean flush_directory_cache = (flags & OPT_FLUSH) != 0;
2123
2124 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
2125
2126 rpath = vfs_s_get_path (vpath, &super, 0);
2127 if (rpath == NULL)
2128 return (-1);
2129
2130 p = ftpfs_translate_path (me, super, rpath);
2131 r = ftpfs_command (me, super, WAIT_REPLY, cmd, p);
2132 g_free (p);
2133 vfs_stamp_create (vfs_ftpfs_ops, super);
2134 if ((flags & OPT_IGNORE_ERROR) != 0)
2135 r = COMPLETE;
2136 if (r != COMPLETE)
2137 {
2138 me->verrno = EPERM;
2139 return (-1);
2140 }
2141 if (flush_directory_cache)
2142 vfs_s_invalidate (me, super);
2143 return 0;
2144 }
2145
2146
2147
2148 static int
2149 ftpfs_stat (const vfs_path_t *vpath, struct stat *buf)
2150 {
2151 int ret;
2152
2153 ret = vfs_s_stat (vpath, buf);
2154 ftpfs_set_blksize (buf);
2155 return ret;
2156 }
2157
2158
2159
2160 static int
2161 ftpfs_lstat (const vfs_path_t *vpath, struct stat *buf)
2162 {
2163 int ret;
2164
2165 ret = vfs_s_lstat (vpath, buf);
2166 ftpfs_set_blksize (buf);
2167 return ret;
2168 }
2169
2170
2171
2172 static int
2173 ftpfs_fstat (void *vfs_info, struct stat *buf)
2174 {
2175 int ret;
2176
2177 ret = vfs_s_fstat (vfs_info, buf);
2178 ftpfs_set_blksize (buf);
2179 return ret;
2180 }
2181
2182
2183
2184 static int
2185 ftpfs_chmod (const vfs_path_t *vpath, mode_t mode)
2186 {
2187 char buf[BUF_SMALL];
2188 int ret;
2189
2190 g_snprintf (buf, sizeof (buf), "SITE CHMOD %4.4o /%%s", (unsigned int) (mode & 07777));
2191 ret = ftpfs_send_command (vpath, buf, OPT_FLUSH);
2192 return ftpfs_ignore_chattr_errors ? 0 : ret;
2193 }
2194
2195
2196
2197 static int
2198 ftpfs_chown (const vfs_path_t *vpath, uid_t owner, gid_t group)
2199 {
2200 #if 0
2201 (void) vpath;
2202 (void) owner;
2203 (void) group;
2204
2205 me->verrno = EPERM;
2206 return (-1);
2207 #else
2208
2209
2210 (void) vpath;
2211 (void) owner;
2212 (void) group;
2213 return 0;
2214 #endif
2215 }
2216
2217
2218
2219 static int
2220 ftpfs_unlink (const vfs_path_t *vpath)
2221 {
2222 return ftpfs_send_command (vpath, "DELE /%s", OPT_FLUSH);
2223 }
2224
2225
2226
2227
2228 static gboolean
2229 ftpfs_is_same_dir (struct vfs_class *me, struct vfs_s_super *super, const char *path)
2230 {
2231 (void) me;
2232
2233 return (FTP_SUPER (super)->current_dir != NULL
2234 && strcmp (path, FTP_SUPER (super)->current_dir) == 0);
2235 }
2236
2237
2238
2239 static int
2240 ftpfs_chdir_internal (struct vfs_class *me, struct vfs_s_super *super, const char *remote_path)
2241 {
2242 ftp_super_t *ftp_super = FTP_SUPER (super);
2243 int r;
2244 char *p;
2245
2246 if (!ftp_super->cwd_deferred && ftpfs_is_same_dir (me, super, remote_path))
2247 return COMPLETE;
2248
2249 p = ftpfs_translate_path (me, super, remote_path);
2250 r = ftpfs_command (me, super, WAIT_REPLY, "CWD /%s", p);
2251 g_free (p);
2252
2253 if (r != COMPLETE)
2254 me->verrno = EIO;
2255 else
2256 {
2257 g_free (ftp_super->current_dir);
2258 ftp_super->current_dir = g_strdup (remote_path);
2259 ftp_super->cwd_deferred = FALSE;
2260 }
2261 return r;
2262 }
2263
2264
2265
2266 static int
2267 ftpfs_rename (const vfs_path_t *vpath1, const vfs_path_t *vpath2)
2268 {
2269 ftpfs_send_command (vpath1, "RNFR /%s", OPT_FLUSH);
2270 return ftpfs_send_command (vpath2, "RNTO /%s", OPT_FLUSH);
2271 }
2272
2273
2274
2275 static int
2276 ftpfs_mkdir (const vfs_path_t *vpath, mode_t mode)
2277 {
2278 (void) mode;
2279
2280 return ftpfs_send_command (vpath, "MKD /%s", OPT_FLUSH);
2281 }
2282
2283
2284
2285 static int
2286 ftpfs_rmdir (const vfs_path_t *vpath)
2287 {
2288 return ftpfs_send_command (vpath, "RMD /%s", OPT_FLUSH);
2289 }
2290
2291
2292
2293 static vfs_file_handler_t *
2294 ftpfs_fh_new (struct vfs_s_inode *ino, gboolean changed)
2295 {
2296 ftp_file_handler_t *fh;
2297
2298 fh = g_new0 (ftp_file_handler_t, 1);
2299 vfs_s_init_fh (VFS_FILE_HANDLER (fh), ino, changed);
2300 fh->sock = -1;
2301
2302 return VFS_FILE_HANDLER (fh);
2303 }
2304
2305
2306
2307 static int
2308 ftpfs_fh_open (struct vfs_class *me, vfs_file_handler_t *fh, int flags, mode_t mode)
2309 {
2310 ftp_file_handler_t *ftp = FTP_FILE_HANDLER (fh);
2311
2312 (void) mode;
2313
2314
2315 if (((flags & O_WRONLY) == O_WRONLY) && ((flags & (O_RDONLY | O_RDWR)) == 0))
2316 {
2317 #ifdef HAVE_STRUCT_LINGER_L_LINGER
2318 struct linger li;
2319 #else
2320 int li = 1;
2321 #endif
2322 char *name;
2323
2324
2325
2326
2327
2328 if (FTP_SUPER (VFS_FILE_HANDLER_SUPER (fh))->ctl_connection_busy)
2329 {
2330 if (fh->ino->localname == NULL)
2331 {
2332 vfs_path_t *vpath;
2333 int handle;
2334
2335 handle = vfs_mkstemps (&vpath, me->name, fh->ino->ent->name);
2336 if (handle == -1)
2337 return (-1);
2338
2339 close (handle);
2340 fh->ino->localname = vfs_path_free (vpath, FALSE);
2341 ftp->append = (flags & O_APPEND) != 0;
2342 }
2343 return 0;
2344 }
2345 name = vfs_s_fullpath (me, fh->ino);
2346 if (name == NULL)
2347 return (-1);
2348
2349 fh->handle = ftpfs_open_data_connection (me, VFS_FILE_HANDLER_SUPER (fh),
2350 (flags & O_APPEND) != 0 ? "APPE" : "STOR", name,
2351 TYPE_BINARY, 0);
2352 g_free (name);
2353
2354 if (fh->handle < 0)
2355 return (-1);
2356
2357 #ifdef HAVE_STRUCT_LINGER_L_LINGER
2358 li.l_onoff = 1;
2359 li.l_linger = 120;
2360 #endif
2361 setsockopt (fh->handle, SOL_SOCKET, SO_LINGER, &li, sizeof (li));
2362
2363 if (fh->ino->localname != NULL)
2364 {
2365 unlink (fh->ino->localname);
2366 MC_PTR_FREE (fh->ino->localname);
2367 }
2368 return 0;
2369 }
2370
2371 if (fh->ino->localname == NULL && vfs_s_retrieve_file (me, fh->ino) == -1)
2372 return (-1);
2373
2374 if (fh->ino->localname == NULL)
2375 vfs_die ("retrieve_file failed to fill in localname");
2376 return 0;
2377 }
2378
2379
2380
2381 static int
2382 ftpfs_fh_close (struct vfs_class *me, vfs_file_handler_t *fh)
2383 {
2384 if (fh->handle != -1 && fh->ino->localname == NULL)
2385 {
2386 ftp_super_t *ftp = FTP_SUPER (VFS_FILE_HANDLER_SUPER (fh));
2387
2388 close (fh->handle);
2389 fh->handle = -1;
2390 ftp->ctl_connection_busy = FALSE;
2391
2392
2393
2394 fh->changed = FALSE;
2395 if (ftpfs_get_reply (me, ftp->sock, NULL, 0) != COMPLETE)
2396 ERRNOR (EIO, -1);
2397 vfs_s_invalidate (me, VFS_FILE_HANDLER_SUPER (fh));
2398 }
2399
2400 return 0;
2401 }
2402
2403
2404
2405 static void
2406 ftpfs_done (struct vfs_class *me)
2407 {
2408 (void) me;
2409
2410 g_slist_free_full (no_proxy, g_free);
2411
2412 g_free (ftpfs_anonymous_passwd);
2413 g_free (ftpfs_proxy_host);
2414 }
2415
2416
2417
2418 static void
2419 ftpfs_fill_names (struct vfs_class *me, fill_names_f func)
2420 {
2421 GList *iter;
2422
2423 for (iter = VFS_SUBCLASS (me)->supers; iter != NULL; iter = g_list_next (iter))
2424 {
2425 const struct vfs_s_super *super = (const struct vfs_s_super *) iter->data;
2426 GString *name;
2427
2428 name = vfs_path_element_build_pretty_path_str (super->path_element);
2429
2430 func (name->str);
2431 g_string_free (name, TRUE);
2432 }
2433 }
2434
2435
2436
2437 static keyword_t
2438 ftpfs_netrc_next (void)
2439 {
2440 char *p;
2441 keyword_t i;
2442 static const char *const keywords[] = {
2443 "default", "machine", "login", "password", "passwd", "account", "macdef", NULL,
2444 };
2445
2446 while (TRUE)
2447 {
2448 netrcp = skip_separators (netrcp);
2449 if (*netrcp != '\n')
2450 break;
2451 netrcp++;
2452 }
2453 if (*netrcp == '\0')
2454 return NETRC_NONE;
2455
2456 p = buffer;
2457 if (*netrcp == '"')
2458 {
2459 for (netrcp++; *netrcp != '"' && *netrcp != '\0'; netrcp++)
2460 {
2461 if (*netrcp == '\\')
2462 netrcp++;
2463 *p++ = *netrcp;
2464 }
2465 }
2466 else
2467 {
2468 for (; *netrcp != '\0' && !whiteness (*netrcp) && *netrcp != ','; netrcp++)
2469 {
2470 if (*netrcp == '\\')
2471 netrcp++;
2472 *p++ = *netrcp;
2473 }
2474 }
2475
2476 *p = '\0';
2477 if (*buffer == '\0')
2478 return NETRC_NONE;
2479
2480 for (i = NETRC_DEFAULT; keywords[i - 1] != NULL; i++)
2481 if (strcmp (keywords[i - 1], buffer) == 0)
2482 return i;
2483
2484 return NETRC_UNKNOWN;
2485 }
2486
2487
2488
2489 static gboolean
2490 ftpfs_netrc_bad_mode (const char *netrcname)
2491 {
2492 struct stat mystat;
2493
2494 if (stat (netrcname, &mystat) >= 0 && (mystat.st_mode & 077) != 0)
2495 {
2496 static gboolean be_angry = TRUE;
2497
2498 if (be_angry)
2499 {
2500 message (D_ERROR, MSG_ERROR,
2501 _ ("~/.netrc file has incorrect mode\nRemove password or correct mode"));
2502 be_angry = FALSE;
2503 }
2504 return TRUE;
2505 }
2506
2507 return FALSE;
2508 }
2509
2510
2511
2512
2513
2514
2515
2516 static gboolean
2517 ftpfs_find_machine (const char *host, const char *domain)
2518 {
2519 keyword_t keyword;
2520
2521 if (host == NULL)
2522 host = "";
2523 if (domain == NULL)
2524 domain = "";
2525
2526 while ((keyword = ftpfs_netrc_next ()) != NETRC_NONE)
2527 {
2528 if (keyword == NETRC_DEFAULT)
2529 return TRUE;
2530
2531 if (keyword == NETRC_MACDEF)
2532 {
2533
2534 do
2535 {
2536 while (*netrcp != '\0' && *netrcp != '\n')
2537 netrcp++;
2538 if (*netrcp != '\n')
2539 break;
2540 netrcp++;
2541 }
2542 while (*netrcp != '\0' && *netrcp != '\n');
2543
2544 continue;
2545 }
2546
2547 if (keyword != NETRC_MACHINE)
2548 continue;
2549
2550
2551 if (ftpfs_netrc_next () == NETRC_NONE)
2552 break;
2553
2554 if (g_ascii_strcasecmp (host, buffer) != 0)
2555 {
2556 const char *host_domain;
2557
2558
2559 host_domain = strchr (host, '.');
2560 if (host_domain == NULL)
2561 continue;
2562
2563
2564 if (g_ascii_strcasecmp (host_domain, domain) != 0)
2565 continue;
2566
2567
2568 if (g_ascii_strncasecmp (host, buffer, host_domain - host) != 0)
2569 continue;
2570 }
2571
2572 return TRUE;
2573 }
2574
2575
2576 return FALSE;
2577 }
2578
2579
2580
2581
2582
2583
2584 static gboolean
2585 ftpfs_netrc_lookup (const char *host, char **login, char **pass)
2586 {
2587 char *netrcname;
2588 char *tmp_pass = NULL;
2589 char hostname[MAXHOSTNAMELEN];
2590 const char *domain;
2591 static struct rupcache
2592 {
2593 struct rupcache *next;
2594 char *host;
2595 char *login;
2596 char *pass;
2597 } *rup_cache = NULL, *rupp;
2598
2599
2600 MC_PTR_FREE (*login);
2601 MC_PTR_FREE (*pass);
2602
2603
2604 for (rupp = rup_cache; rupp != NULL; rupp = rupp->next)
2605 if (strcmp (host, rupp->host) == 0)
2606 {
2607 *login = g_strdup (rupp->login);
2608 *pass = g_strdup (rupp->pass);
2609 return TRUE;
2610 }
2611
2612
2613 netrcname = g_build_filename (mc_config_get_home_dir (), ".netrc", (char *) NULL);
2614 if (!g_file_get_contents (netrcname, &netrc, NULL, NULL))
2615 {
2616 g_free (netrcname);
2617 return TRUE;
2618 }
2619
2620 netrcp = netrc;
2621
2622
2623 if (gethostname (hostname, sizeof (hostname)) < 0)
2624 *hostname = '\0';
2625
2626 domain = strchr (hostname, '.');
2627 if (domain == NULL)
2628 domain = "";
2629
2630
2631 ftpfs_find_machine (host, domain);
2632
2633
2634 while (TRUE)
2635 {
2636 keyword_t keyword;
2637
2638 gboolean need_break = FALSE;
2639 keyword = ftpfs_netrc_next ();
2640
2641 switch (keyword)
2642 {
2643 case NETRC_LOGIN:
2644 if (ftpfs_netrc_next () == NETRC_NONE)
2645 {
2646 need_break = TRUE;
2647 break;
2648 }
2649
2650
2651 if (*login != NULL)
2652 {
2653 need_break = TRUE;
2654 break;
2655 }
2656
2657
2658 *login = g_strdup (buffer);
2659 break;
2660
2661 case NETRC_PASSWORD:
2662 case NETRC_PASSWD:
2663 if (ftpfs_netrc_next () == NETRC_NONE)
2664 {
2665 need_break = TRUE;
2666 break;
2667 }
2668
2669
2670 if (*login != NULL && strcmp (*login, "anonymous") != 0 && strcmp (*login, "ftp") != 0
2671 && ftpfs_netrc_bad_mode (netrcname))
2672 {
2673 need_break = TRUE;
2674 break;
2675 }
2676
2677
2678 if (tmp_pass == NULL)
2679 tmp_pass = g_strdup (buffer);
2680 break;
2681
2682 case NETRC_ACCOUNT:
2683
2684 if (ftpfs_netrc_next () == NETRC_NONE)
2685 {
2686 need_break = TRUE;
2687 break;
2688 }
2689
2690
2691 ftpfs_netrc_bad_mode (netrcname);
2692 break;
2693
2694 default:
2695
2696 need_break = TRUE;
2697 break;
2698 }
2699
2700 if (need_break)
2701 break;
2702 }
2703
2704 MC_PTR_FREE (netrc);
2705 g_free (netrcname);
2706
2707 rupp = g_new (struct rupcache, 1);
2708 rupp->host = g_strdup (host);
2709 rupp->login = g_strdup (*login);
2710 rupp->pass = g_strdup (tmp_pass);
2711
2712 rupp->next = rup_cache;
2713 rup_cache = rupp;
2714
2715 *pass = tmp_pass;
2716
2717 return TRUE;
2718 }
2719
2720
2721
2722
2723
2724
2725 void
2726 ftpfs_init_passwd (void)
2727 {
2728 ftpfs_anonymous_passwd = load_anon_passwd ();
2729
2730 if (ftpfs_anonymous_passwd == NULL)
2731 {
2732
2733
2734
2735
2736
2737
2738
2739
2740 ftpfs_anonymous_passwd = g_strdup ("anonymous@");
2741 }
2742 }
2743
2744
2745
2746 void
2747 vfs_init_ftpfs (void)
2748 {
2749 tcp_init ();
2750
2751 vfs_init_subclass (&ftpfs_subclass, "ftpfs", VFSF_NOLINKS | VFSF_REMOTE | VFSF_USETMP, "ftp");
2752 vfs_ftpfs_ops->done = ftpfs_done;
2753 vfs_ftpfs_ops->fill_names = ftpfs_fill_names;
2754 vfs_ftpfs_ops->stat = ftpfs_stat;
2755 vfs_ftpfs_ops->lstat = ftpfs_lstat;
2756 vfs_ftpfs_ops->fstat = ftpfs_fstat;
2757 vfs_ftpfs_ops->chmod = ftpfs_chmod;
2758 vfs_ftpfs_ops->chown = ftpfs_chown;
2759 vfs_ftpfs_ops->unlink = ftpfs_unlink;
2760 vfs_ftpfs_ops->rename = ftpfs_rename;
2761 vfs_ftpfs_ops->mkdir = ftpfs_mkdir;
2762 vfs_ftpfs_ops->rmdir = ftpfs_rmdir;
2763 vfs_ftpfs_ops->ctl = ftpfs_ctl;
2764 ftpfs_subclass.archive_same = ftpfs_archive_same;
2765 ftpfs_subclass.new_archive = ftpfs_new_archive;
2766 ftpfs_subclass.open_archive = ftpfs_open_archive;
2767 ftpfs_subclass.free_archive = ftpfs_free_archive;
2768 ftpfs_subclass.fh_new = ftpfs_fh_new;
2769 ftpfs_subclass.fh_open = ftpfs_fh_open;
2770 ftpfs_subclass.fh_close = ftpfs_fh_close;
2771 ftpfs_subclass.dir_load = ftpfs_dir_load;
2772 ftpfs_subclass.file_store = ftpfs_file_store;
2773 ftpfs_subclass.linear_start = ftpfs_linear_start;
2774 ftpfs_subclass.linear_read = ftpfs_linear_read;
2775 ftpfs_subclass.linear_close = ftpfs_linear_close;
2776 vfs_register_class (vfs_ftpfs_ops);
2777 }
2778
2779