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