ftpfs.c 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043
  1. /* Virtual File System: FTP file system.
  2. Copyright (C) 1995 The Free Software Foundation
  3. Written by: 1995 Ching Hui
  4. 1995 Jakub Jelinek
  5. 1995, 1996, 1997 Miguel de Icaza
  6. 1997 Norbert Warmuth
  7. 1998 Pavel Machek
  8. $Id$
  9. This program is free software; you can redistribute it and/or
  10. modify it under the terms of the GNU Library General Public License
  11. as published by the Free Software Foundation; either version 2 of
  12. the License, or (at your option) any later version.
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. GNU Library General Public License for more details.
  17. You should have received a copy of the GNU Library General Public
  18. License along with this program; if not, write to the Free Software
  19. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  20. /* FTPfs TODO:
  21. - make it more robust - all the connects etc. should handle EADDRINUSE and
  22. ERETRY (have I spelled these names correctly?)
  23. - make the user able to flush a connection - all the caches will get empty
  24. etc., (tarfs as well), we should give there a user selectable timeout
  25. and assign a key sequence.
  26. - use hash table instead of linklist to cache ftpfs directory.
  27. What to do with this?
  28. * NOTE: Usage of tildes is deprecated, consider:
  29. * cd /#ftp:pavel@hobit
  30. * cd ~
  31. * And now: what do I want to do? Do I want to go to /home/pavel or to
  32. * /#ftp:hobit/home/pavel? I think first has better sense...
  33. *
  34. {
  35. int f = !strcmp( remote_path, "/~" );
  36. if (f || !strncmp( remote_path, "/~/", 3 )) {
  37. char *s;
  38. s = concat_dir_and_file( qhome (*bucket), remote_path +3-f );
  39. g_free (remote_path);
  40. remote_path = s;
  41. }
  42. }
  43. */
  44. /* Namespace pollution: horrible */
  45. #include <config.h>
  46. #include <sys/types.h> /* POSIX-required by sys/socket.h and netdb.h */
  47. #include <netdb.h> /* struct hostent */
  48. #include <sys/socket.h> /* AF_INET */
  49. #include <netinet/in.h> /* struct in_addr */
  50. #ifdef HAVE_SETSOCKOPT
  51. # include <netinet/ip.h> /* IP options */
  52. #endif
  53. #include <arpa/inet.h>
  54. #include <arpa/ftp.h>
  55. #include <arpa/telnet.h>
  56. #include <sys/param.h>
  57. #ifdef USE_TERMNET
  58. #include <termnet.h>
  59. #endif
  60. #include "utilvfs.h"
  61. #include "xdirentry.h"
  62. #include "vfs.h"
  63. #include "tcputil.h"
  64. #include "../src/dialog.h"
  65. #include "../src/setup.h" /* for load_anon_passwd */
  66. #include "container.h"
  67. #include "ftpfs.h"
  68. #ifndef MAXHOSTNAMELEN
  69. # define MAXHOSTNAMELEN 64
  70. #endif
  71. #define UPLOAD_ZERO_LENGTH_FILE
  72. #define SUP super->u.ftp
  73. #define FH_SOCK fh->u.ftp.sock
  74. static int my_errno;
  75. static int code;
  76. /* Delay to retry a connection */
  77. int ftpfs_retry_seconds = 30;
  78. /* Method to use to connect to ftp sites */
  79. int ftpfs_use_passive_connections = 1;
  80. /* Method used to get directory listings:
  81. * 1: try 'LIST -la <path>', if it fails
  82. * fall back to CWD <path>; LIST
  83. * 0: always use CWD <path>; LIST
  84. */
  85. int ftpfs_use_unix_list_options = 1;
  86. /* First "CWD <path>", then "LIST -la ." */
  87. int ftpfs_first_cd_then_ls;
  88. /* Use the ~/.netrc */
  89. int use_netrc = 1;
  90. extern char *home_dir;
  91. /* Anonymous setup */
  92. char *ftpfs_anonymous_passwd = NULL;
  93. int ftpfs_directory_timeout = 900;
  94. /* Proxy host */
  95. char *ftpfs_proxy_host = NULL;
  96. /* wether we have to use proxy by default? */
  97. int ftpfs_always_use_proxy;
  98. /* source routing host */
  99. extern int source_route;
  100. /* Where we store the transactions */
  101. static FILE *logfile = NULL;
  102. /* If true, the directory cache is forced to reload */
  103. static int force_expiration = 0;
  104. #ifdef FIXME_LATER_ALIGATOR
  105. static struct linklist *connections_list;
  106. #endif
  107. /* command wait_flag: */
  108. #define NONE 0x00
  109. #define WAIT_REPLY 0x01
  110. #define WANT_STRING 0x02
  111. static char reply_str [80];
  112. /* char *translate_path (struct ftpfs_connection *bucket, char *remote_path)
  113. Translate a Unix path, i.e. MC's internal path representation (e.g.
  114. /somedir/somefile) to a path valid for the remote server. Every path
  115. transfered to the remote server has to be mangled by this function
  116. right prior to sending it.
  117. Currently only Amiga ftp servers are handled in a special manner.
  118. When the remote server is an amiga:
  119. a) strip leading slash if necesarry
  120. b) replace first occurance of ":/" with ":"
  121. c) strip trailing "/."
  122. */
  123. static char *ftpfs_get_current_directory (vfs *me, vfs_s_super *super);
  124. static int ftpfs_chdir_internal (vfs *me, vfs_s_super *super, char *remote_path);
  125. static int command (vfs *me, vfs_s_super *super, int wait_reply, char *fmt, ...)
  126. __attribute__ ((format (printf, 4, 5)));
  127. static int ftpfs_open_socket (vfs *me, vfs_s_super *super);
  128. static int login_server (vfs *me, vfs_s_super *super, const char *netrcpass);
  129. static int lookup_netrc (char *host, char **login, char **pass);
  130. static char *
  131. translate_path (vfs *me, vfs_s_super *super, const char *remote_path)
  132. {
  133. if (!SUP.remote_is_amiga)
  134. return g_strdup (remote_path);
  135. else {
  136. char *ret, *p;
  137. if (logfile) {
  138. fprintf (logfile, "MC -- translate_path: %s\n", remote_path);
  139. fflush (logfile);
  140. }
  141. /* strip leading slash(es) */
  142. while (*remote_path == '/')
  143. remote_path++;
  144. /*
  145. * Don't change "/" into "", e.g. "CWD " would be
  146. * invalid.
  147. */
  148. if (*remote_path == '\0')
  149. return g_strdup (".");
  150. ret = g_strdup (remote_path);
  151. /* replace first occurance of ":/" with ":" */
  152. if ((p = strchr (ret, ':')) && *(p + 1) == '/')
  153. strcpy (p + 1, p + 2);
  154. /* strip trailing "/." */
  155. if ((p = strrchr (ret, '/')) && *(p + 1) == '.' && *(p + 2) == '\0')
  156. *p = '\0';
  157. return ret;
  158. }
  159. }
  160. /* Extract the hostname and username from the path */
  161. /*
  162. * path is in the form: [user@]hostname:port/remote-dir, e.g.:
  163. * ftp://sunsite.unc.edu/pub/linux
  164. * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
  165. * ftp://tsx-11.mit.edu:8192/
  166. * ftp://joe@foo.edu:11321/private
  167. * If the user is empty, e.g. ftp://@roxanne/private, then your login name
  168. * is supplied.
  169. *
  170. */
  171. #define FTP_COMMAND_PORT 21
  172. #define HSC_PROXY_PORT 9875
  173. #define my_get_host_and_username(path, host, user, port, pass) \
  174. vfs_split_url (path, host, user, port, pass, FTP_COMMAND_PORT, URL_DEFAULTANON)
  175. /* Returns a reply code, check /usr/include/arpa/ftp.h for possible values */
  176. static int
  177. get_reply (vfs *me, int sock, char *string_buf, int string_len)
  178. {
  179. char answer[BUF_1K];
  180. int i;
  181. for (;;) {
  182. if (!vfs_s_get_line (me, sock, answer, sizeof (answer), '\n')){
  183. if (string_buf)
  184. *string_buf = 0;
  185. code = 421;
  186. return 4;
  187. }
  188. switch (sscanf(answer, "%d", &code)){
  189. case 0:
  190. if (string_buf) {
  191. strncpy (string_buf, answer, string_len - 1);
  192. *(string_buf + string_len - 1) = 0;
  193. }
  194. code = 500;
  195. return 5;
  196. case 1:
  197. if (answer[3] == '-') {
  198. while (1) {
  199. if (!vfs_s_get_line (me, sock, answer, sizeof(answer), '\n')){
  200. if (string_buf)
  201. *string_buf = 0;
  202. code = 421;
  203. return 4;
  204. }
  205. if ((sscanf (answer, "%d", &i) > 0) &&
  206. (code == i) && (answer[3] == ' '))
  207. break;
  208. }
  209. }
  210. if (string_buf){
  211. strncpy (string_buf, answer, string_len - 1);
  212. *(string_buf + string_len - 1) = 0;
  213. }
  214. return code / 100;
  215. }
  216. }
  217. }
  218. static int
  219. reconnect (vfs *me, vfs_s_super *super)
  220. {
  221. int sock = ftpfs_open_socket (me, super);
  222. if (sock != -1){
  223. char *cwdir = SUP.cwdir;
  224. close (SUP.sock);
  225. SUP.sock = sock;
  226. SUP.cwdir = NULL;
  227. if (login_server (me, super, SUP.password)){
  228. if (!cwdir)
  229. return 1;
  230. sock = ftpfs_chdir_internal (me, super, cwdir);
  231. g_free (cwdir);
  232. return sock == COMPLETE;
  233. }
  234. SUP.cwdir = cwdir;
  235. }
  236. return 0;
  237. }
  238. static int
  239. command (vfs *me, vfs_s_super *super, int wait_reply, char *fmt, ...)
  240. {
  241. va_list ap;
  242. char *str, *fmt_str;
  243. int status;
  244. int sock = SUP.sock;
  245. va_start (ap, fmt);
  246. fmt_str = g_strdup_vprintf (fmt, ap);
  247. va_end (ap);
  248. status = strlen (fmt_str);
  249. str = g_realloc (fmt_str, status + 3);
  250. strcpy (str + status, "\r\n");
  251. if (logfile){
  252. if (strncmp (str, "PASS ", 5) == 0){
  253. fputs ("PASS <Password not logged>\r\n", logfile);
  254. } else
  255. fwrite (str, status + 2, 1, logfile);
  256. fflush (logfile);
  257. }
  258. got_sigpipe = 0;
  259. enable_interrupt_key ();
  260. status = write (SUP.sock, str, status + 2);
  261. if (status < 0){
  262. code = 421;
  263. if (errno == EPIPE){ /* Remote server has closed connection */
  264. static int level = 0; /* login_server() use command() */
  265. if (level == 0){
  266. level = 1;
  267. status = reconnect (me, super);
  268. level = 0;
  269. if (status && write (SUP.sock, str, status + 2) > 0)
  270. goto ok;
  271. }
  272. got_sigpipe = 1;
  273. }
  274. g_free (str);
  275. disable_interrupt_key ();
  276. return TRANSIENT;
  277. }
  278. ok:
  279. g_free (str);
  280. disable_interrupt_key ();
  281. if (wait_reply)
  282. return get_reply (me, sock, (wait_reply & WANT_STRING) ? reply_str : NULL, sizeof (reply_str)-1);
  283. return COMPLETE;
  284. }
  285. static void
  286. free_archive (vfs *me, vfs_s_super *super)
  287. {
  288. if (SUP.sock != -1){
  289. print_vfs_message (_("ftpfs: Disconnecting from %s"), SUP.host);
  290. command(me, super, NONE, "QUIT");
  291. close(SUP.sock);
  292. }
  293. ifree (SUP.host);
  294. ifree (SUP.home);
  295. ifree (SUP.user);
  296. ifree (SUP.cwdir);
  297. ifree (SUP.password);
  298. }
  299. /* some defines only used by changetype */
  300. /* These two are valid values for the second parameter */
  301. #define TYPE_ASCII 0
  302. #define TYPE_BINARY 1
  303. /* This one is only used to initialize bucket->isbinary, don't use it as
  304. second parameter to changetype. */
  305. #define TYPE_UNKNOWN -1
  306. static int
  307. changetype (vfs *me, vfs_s_super *super, int binary)
  308. {
  309. if (binary != SUP.isbinary) {
  310. if (command (me, super, WAIT_REPLY, "TYPE %c", binary ? 'I' : 'A') != COMPLETE)
  311. ERRNOR (EIO, -1);
  312. SUP.isbinary = binary;
  313. }
  314. return binary;
  315. }
  316. /* This routine logs the user in */
  317. static int
  318. login_server (vfs *me, vfs_s_super *super, const char *netrcpass)
  319. {
  320. #if defined(HSC_PROXY)
  321. char *proxypass, *proxyname;
  322. #endif
  323. char *pass;
  324. char *op;
  325. char *name; /* login user name */
  326. int anon = 0;
  327. char reply_string[BUF_MEDIUM];
  328. SUP.isbinary = TYPE_UNKNOWN;
  329. if (netrcpass)
  330. op = g_strdup (netrcpass);
  331. else {
  332. if (!strcmp (SUP.user, "anonymous") ||
  333. !strcmp (SUP.user, "ftp")) {
  334. if (!ftpfs_anonymous_passwd)
  335. ftpfs_init_passwd();
  336. op = g_strdup (ftpfs_anonymous_passwd);
  337. anon = 1;
  338. } else {
  339. char *p;
  340. if (!SUP.password){
  341. p = g_strconcat (_(" FTP: Password required for "), SUP.user,
  342. " ", NULL);
  343. op = vfs_get_password (p);
  344. g_free (p);
  345. if (op == NULL)
  346. ERRNOR (EPERM, 0);
  347. SUP.password = g_strdup (op);
  348. } else
  349. op = g_strdup (SUP.password);
  350. }
  351. }
  352. if (!anon || logfile)
  353. pass = op;
  354. else {
  355. pass = g_strconcat ("-", op, NULL);
  356. wipe_password (op);
  357. }
  358. /* Proxy server accepts: username@host-we-want-to-connect*/
  359. if (SUP.proxy){
  360. #if defined(HSC_PROXY)
  361. char *p;
  362. int port;
  363. p = my_get_host_and_username (ftpfs_proxy_host, 0, &proxyname,
  364. &port, 0);
  365. if (p)
  366. g_free (p);
  367. p = g_strconcat (_(" Proxy: Password required for "), proxyname, " ",
  368. NULL);
  369. proxypass = vfs_get_password (p);
  370. g_free (p);
  371. if (proxypass == NULL) {
  372. wipe_password (pass);
  373. g_free (proxyname);
  374. ERRNOR (EPERM, 0);
  375. }
  376. name = g_strdup (SUP.user);
  377. #else
  378. name = g_strconcat (SUP.user, "@",
  379. SUP.host[0] == '!' ? SUP.host+1 : SUP.host, NULL);
  380. #endif
  381. } else
  382. name = g_strdup (SUP.user);
  383. if (get_reply (me, SUP.sock, reply_string, sizeof (reply_string) - 1) == COMPLETE) {
  384. g_strup (reply_string);
  385. SUP.remote_is_amiga = strstr (reply_string, "AMIGA") != 0;
  386. if (logfile) {
  387. fprintf (logfile, "MC -- remote_is_amiga = %d\n", SUP.remote_is_amiga);
  388. fflush (logfile);
  389. }
  390. #if defined(HSC_PROXY)
  391. if (SUP.proxy){
  392. print_vfs_message (_("ftpfs: sending proxy login name"));
  393. if (command (me, super, 1, "USER %s", proxyname) != CONTINUE)
  394. goto proxyfail;
  395. print_vfs_message (_("ftpfs: sending proxy user password"));
  396. if (command (me, super, 1, "PASS %s", proxypass) != COMPLETE)
  397. goto proxyfail;
  398. print_vfs_message (_("ftpfs: proxy authentication succeeded"));
  399. if (command (me, super, 1, "SITE %s", SUP.host+1) != COMPLETE)
  400. goto proxyfail;
  401. print_vfs_message (_("ftpfs: connected to %s"), SUP.host+1);
  402. if (0) {
  403. proxyfail:
  404. SUP.failed_on_login = 1;
  405. /* my_errno = E; */
  406. if (proxypass)
  407. wipe_password (proxypass);
  408. wipe_password (pass);
  409. g_free (proxyname);
  410. g_free (name);
  411. ERRNOR (EPERM, 0);
  412. }
  413. if (proxypass)
  414. wipe_password (proxypass);
  415. g_free (proxyname);
  416. }
  417. #endif
  418. print_vfs_message (_("ftpfs: sending login name"));
  419. code = command (me, super, WAIT_REPLY, "USER %s", name);
  420. switch (code){
  421. case CONTINUE:
  422. print_vfs_message (_("ftpfs: sending user password"));
  423. if (command (me, super, WAIT_REPLY, "PASS %s", pass) != COMPLETE)
  424. break;
  425. case COMPLETE:
  426. print_vfs_message (_("ftpfs: logged in"));
  427. wipe_password (pass);
  428. g_free (name);
  429. return 1;
  430. default:
  431. SUP.failed_on_login = 1;
  432. /* my_errno = E; */
  433. if (SUP.password)
  434. wipe_password (SUP.password);
  435. SUP.password = 0;
  436. goto login_fail;
  437. }
  438. }
  439. message_2s (1, MSG_ERROR, _("ftpfs: Login incorrect for user %s "), SUP.user);
  440. login_fail:
  441. wipe_password (pass);
  442. g_free (name);
  443. ERRNOR (EPERM, 0);
  444. }
  445. #ifdef HAVE_SETSOCKOPT
  446. static void
  447. setup_source_route (int socket, int dest)
  448. {
  449. char buffer [20];
  450. char *ptr = buffer;
  451. if (!source_route)
  452. return;
  453. bzero (buffer, sizeof (buffer));
  454. *ptr++ = IPOPT_LSRR;
  455. *ptr++ = 3 + 8;
  456. *ptr++ = 4; /* pointer */
  457. /* First hop */
  458. bcopy ((char *) &source_route, ptr, sizeof (int));
  459. ptr += 4;
  460. /* Second hop (ie, final destination) */
  461. bcopy ((char *) &dest, ptr, sizeof (int));
  462. ptr += 4;
  463. while ((ptr - buffer) & 3)
  464. ptr++;
  465. if (setsockopt (socket, IPPROTO_IP, IP_OPTIONS,
  466. buffer, ptr - buffer) < 0)
  467. message_2s (1, MSG_ERROR, _(" Could not set source routing (%s)"), unix_error_string (errno));
  468. }
  469. #else
  470. #define setup_source_route(x,y)
  471. #endif
  472. static struct no_proxy_entry {
  473. char *domain;
  474. void *next;
  475. } *no_proxy;
  476. static void
  477. load_no_proxy_list (void)
  478. {
  479. /* FixMe: shouldn't be hardcoded!!! */
  480. char s[BUF_LARGE]; /* provide for BUF_LARGE characters */
  481. struct no_proxy_entry *np, *current = 0;
  482. FILE *npf;
  483. int c;
  484. char *p;
  485. static char *mc_file;
  486. if (mc_file)
  487. return;
  488. mc_file = concat_dir_and_file (mc_home, "mc.no_proxy");
  489. if (exist_file (mc_file) &&
  490. (npf = fopen (mc_file, "r"))) {
  491. while (fgets (s, sizeof(s), npf) || !(feof (npf) || ferror (npf))) {
  492. if (!(p = strchr (s, '\n'))) { /* skip bogus entries */
  493. while ((c = fgetc (npf)) != EOF && c != '\n')
  494. ;
  495. continue;
  496. }
  497. if (p == s)
  498. continue;
  499. *p = '\0';
  500. np = g_new (struct no_proxy_entry, 1);
  501. np->domain = g_strdup (s);
  502. np->next = NULL;
  503. if (no_proxy)
  504. current->next = np;
  505. else
  506. no_proxy = np;
  507. current = np;
  508. }
  509. fclose (npf);
  510. }
  511. g_free (mc_file);
  512. }
  513. static int
  514. ftpfs_check_proxy (const char *host)
  515. {
  516. struct no_proxy_entry *npe;
  517. if (!ftpfs_proxy_host || !*ftpfs_proxy_host || !host || !*host)
  518. return 0; /* sanity check */
  519. if (*host == '!')
  520. return 1;
  521. if (!ftpfs_always_use_proxy)
  522. return 0;
  523. if (!strchr (host, '.'))
  524. return 0;
  525. load_no_proxy_list ();
  526. for (npe = no_proxy; npe; npe=npe->next) {
  527. char *domain = npe->domain;
  528. if (domain[0] == '.') {
  529. int ld = strlen (domain);
  530. int lh = strlen (host);
  531. while (ld && lh && host[lh - 1] == domain[ld - 1]) {
  532. ld--;
  533. lh--;
  534. }
  535. if (!ld)
  536. return 0;
  537. } else
  538. if (!g_strcasecmp (host, domain))
  539. return 0;
  540. }
  541. return 1;
  542. }
  543. static void
  544. ftpfs_get_proxy_host_and_port (char *proxy, char **host, int *port)
  545. {
  546. char *user, *dir;
  547. #if defined(HSC_PROXY)
  548. dir = vfs_split_url (proxy, host, &user, port, 0, HSC_PROXY_PORT, URL_DEFAULTANON);
  549. #else
  550. dir = vfs_split_url (proxy, host, &user, port, 0, FTP_COMMAND_PORT, URL_DEFAULTANON);
  551. #endif
  552. g_free (user);
  553. if (dir)
  554. g_free (dir);
  555. }
  556. static int
  557. ftpfs_open_socket (vfs *me, vfs_s_super *super)
  558. {
  559. struct sockaddr_in server_address;
  560. struct hostent *hp;
  561. int my_socket;
  562. char *host;
  563. int port = SUP.port;
  564. int free_host = 0;
  565. /* Use a proxy host? */
  566. host = SUP.host;
  567. if (!host || !*host){
  568. print_vfs_message (_("ftpfs: Invalid host name."));
  569. my_errno = EINVAL;
  570. return -1;
  571. }
  572. /* Hosts to connect to that start with a ! should use proxy */
  573. if (SUP.proxy){
  574. ftpfs_get_proxy_host_and_port (ftpfs_proxy_host, &host, &port);
  575. free_host = 1;
  576. }
  577. /* Get host address */
  578. bzero ((char *) &server_address, sizeof (server_address));
  579. server_address.sin_family = AF_INET;
  580. server_address.sin_addr.s_addr = inet_addr (host);
  581. if (server_address.sin_addr.s_addr != -1)
  582. server_address.sin_family = AF_INET;
  583. else {
  584. hp = gethostbyname (host);
  585. if (hp == NULL){
  586. print_vfs_message (_("ftpfs: Invalid host address."));
  587. my_errno = EINVAL;
  588. if (free_host)
  589. g_free (host);
  590. return -1;
  591. }
  592. server_address.sin_family = hp->h_addrtype;
  593. /* We copy only 4 bytes, we can not trust hp->h_length, as it comes from the DNS */
  594. bcopy ((char *) hp->h_addr, (char *) &server_address.sin_addr, 4);
  595. }
  596. server_address.sin_port = htons (port);
  597. /* Connect */
  598. if ((my_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
  599. my_errno = errno;
  600. if (free_host)
  601. g_free (host);
  602. return -1;
  603. }
  604. setup_source_route (my_socket, server_address.sin_addr.s_addr);
  605. print_vfs_message (_("ftpfs: making connection to %s"), host);
  606. if (free_host)
  607. g_free (host);
  608. enable_interrupt_key (); /* clear the interrupt flag */
  609. if (connect (my_socket, (struct sockaddr *) &server_address,
  610. sizeof (server_address)) < 0){
  611. my_errno = errno;
  612. if (errno == EINTR && got_interrupt ())
  613. print_vfs_message (_("ftpfs: connection interrupted by user"));
  614. else
  615. print_vfs_message (_("ftpfs: connection to server failed: %s"),
  616. unix_error_string(errno));
  617. disable_interrupt_key();
  618. close (my_socket);
  619. return -1;
  620. }
  621. disable_interrupt_key();
  622. return my_socket;
  623. }
  624. static int
  625. open_archive_int (vfs *me, vfs_s_super *super)
  626. {
  627. int retry_seconds, count_down;
  628. /* We do not want to use the passive if we are using proxies */
  629. if (SUP.use_proxy)
  630. SUP.use_passive_connection = 0;
  631. retry_seconds = 0;
  632. do {
  633. SUP.failed_on_login = 0;
  634. SUP.sock = ftpfs_open_socket (me, super);
  635. if (SUP.sock == -1)
  636. return -1;
  637. if (login_server (me, super, NULL)) {
  638. /* Logged in, no need to retry the connection */
  639. break;
  640. } else {
  641. if (SUP.failed_on_login){
  642. /* Close only the socket descriptor */
  643. close (SUP.sock);
  644. } else {
  645. return -1;
  646. }
  647. if (ftpfs_retry_seconds){
  648. retry_seconds = ftpfs_retry_seconds;
  649. enable_interrupt_key ();
  650. for (count_down = retry_seconds; count_down; count_down--){
  651. print_vfs_message (_("Waiting to retry... %d (Control-C to cancel)"), count_down);
  652. sleep (1);
  653. if (got_interrupt ()){
  654. /* my_errno = E; */
  655. disable_interrupt_key ();
  656. return 0;
  657. }
  658. }
  659. disable_interrupt_key ();
  660. }
  661. }
  662. } while (retry_seconds);
  663. SUP.home = ftpfs_get_current_directory (me, super);
  664. if (!SUP.home)
  665. SUP.home = g_strdup (PATH_SEP_STR);
  666. return 0;
  667. }
  668. static int
  669. open_archive (vfs *me, vfs_s_super *super, char *archive_name, char *op)
  670. {
  671. char *host, *user, *password;
  672. int port;
  673. op = vfs_split_url (strchr(op, ':')+1, &host, &user, &port, &password, FTP_COMMAND_PORT, URL_DEFAULTANON);
  674. if (op)
  675. g_free (op);
  676. SUP.host = host;
  677. SUP.user = user;
  678. SUP.port = port;
  679. SUP.home = NULL;
  680. SUP.proxy= 0;
  681. SUP.use_proxy = ftpfs_check_proxy (host);
  682. SUP.password = NULL;
  683. SUP.use_passive_connection = ftpfs_use_passive_connections | source_route;
  684. SUP.use_source_route = source_route;
  685. SUP.strict = ftpfs_use_unix_list_options?RFC_AUTODETECT:RFC_STRICT;
  686. SUP.isbinary = TYPE_UNKNOWN;
  687. SUP.remote_is_amiga = 0;
  688. super->name = g_strdup("/");
  689. #if 0
  690. super->name = g_strconcat( "/#ftp:", user, "@", host, "/", NULL );
  691. #endif
  692. super->root = vfs_s_new_inode (me, super, vfs_s_default_stat(me, S_IFDIR | 0755));
  693. if (password)
  694. SUP.password = password;
  695. /* try to get user and/or password from ~/.netrc */
  696. else if (use_netrc)
  697. lookup_netrc(SUP.host, &SUP.user, &SUP.password);
  698. return open_archive_int (me, super);
  699. }
  700. static int
  701. archive_same(vfs *me, vfs_s_super *super, char *archive_name, char *op, void *cookie)
  702. {
  703. char *host, *user;
  704. char *pass = NULL;
  705. int port;
  706. op = vfs_split_url (strchr(op, ':')+1, &host, &user, &port, 0, 21, URL_DEFAULTANON);
  707. if (op)
  708. g_free (op);
  709. /* replace the dummy user with the one from ~/.netrc */
  710. if (use_netrc && !strcmp(user, "*netrc*"))
  711. lookup_netrc(SUP.host, &user, &pass);
  712. port = ((strcmp (host, SUP.host) == 0) &&
  713. (strcmp (user, SUP.user) == 0) &&
  714. (port == SUP.port));
  715. g_free (host);
  716. g_free (user);
  717. return port;
  718. }
  719. void
  720. ftpfs_flushdir (void)
  721. {
  722. force_expiration = 1;
  723. }
  724. static int
  725. dir_uptodate(vfs *me, vfs_s_inode *ino)
  726. {
  727. struct timeval tim;
  728. if (force_expiration) {
  729. force_expiration = 0;
  730. return 0;
  731. }
  732. gettimeofday(&tim, NULL);
  733. if (tim.tv_sec < ino->u.ftp.timestamp.tv_sec)
  734. return 1;
  735. return 0;
  736. }
  737. /* The returned directory should always contain a trailing slash */
  738. static char *
  739. ftpfs_get_current_directory (vfs *me, vfs_s_super *super)
  740. {
  741. char buf[BUF_8K], *bufp, *bufq;
  742. if (command (me, super, NONE, "PWD") == COMPLETE &&
  743. get_reply(me, SUP.sock, buf, sizeof(buf)) == COMPLETE) {
  744. bufp = NULL;
  745. for (bufq = buf; *bufq; bufq++)
  746. if (*bufq == '"') {
  747. if (!bufp) {
  748. bufp = bufq + 1;
  749. } else {
  750. *bufq = 0;
  751. if (*bufp) {
  752. if (*(bufq - 1) != '/') {
  753. *bufq++ = '/';
  754. *bufq = 0;
  755. }
  756. if (*bufp == '/')
  757. return g_strdup (bufp);
  758. else {
  759. /* If the remote server is an Amiga a leading slash
  760. might be missing. MC needs it because it is used
  761. as seperator between hostname and path internally. */
  762. return g_strconcat( "/", bufp, 0);
  763. }
  764. } else {
  765. my_errno = EIO;
  766. return NULL;
  767. }
  768. }
  769. }
  770. }
  771. my_errno = EIO;
  772. return NULL;
  773. }
  774. /* Setup Passive ftp connection, we use it for source routed connections */
  775. static int
  776. setup_passive (vfs *me, vfs_s_super *super, int my_socket, struct sockaddr_in *sa)
  777. {
  778. int xa, xb, xc, xd, xe, xf;
  779. char n [6];
  780. char *c = reply_str;
  781. if (command (me, super, WAIT_REPLY | WANT_STRING, "PASV") != COMPLETE)
  782. return 0;
  783. /* Parse remote parameters */
  784. for (c = reply_str + 4; (*c) && (!isdigit ((unsigned char) *c)); c++)
  785. ;
  786. if (!*c)
  787. return 0;
  788. if (!isdigit ((unsigned char) *c))
  789. return 0;
  790. if (sscanf (c, "%d,%d,%d,%d,%d,%d", &xa, &xb, &xc, &xd, &xe, &xf) != 6)
  791. return 0;
  792. n [0] = (unsigned char) xa;
  793. n [1] = (unsigned char) xb;
  794. n [2] = (unsigned char) xc;
  795. n [3] = (unsigned char) xd;
  796. n [4] = (unsigned char) xe;
  797. n [5] = (unsigned char) xf;
  798. bcopy ((void *)n, &(sa->sin_addr.s_addr), 4);
  799. bcopy ((void *)&n[4], &(sa->sin_port), 2);
  800. setup_source_route (my_socket, sa->sin_addr.s_addr);
  801. if (connect (my_socket, (struct sockaddr *) sa, sizeof (struct sockaddr_in)) < 0)
  802. return 0;
  803. return 1;
  804. }
  805. static int
  806. initconn (vfs *me, vfs_s_super *super)
  807. {
  808. struct sockaddr_in data_addr;
  809. int data, len = sizeof(data_addr);
  810. struct protoent *pe;
  811. getsockname(SUP.sock, (struct sockaddr *) &data_addr, &len);
  812. data_addr.sin_port = 0;
  813. pe = getprotobyname("tcp");
  814. if (pe == NULL)
  815. ERRNOR (EIO, -1);
  816. data = socket (AF_INET, SOCK_STREAM, pe->p_proto);
  817. if (data < 0)
  818. ERRNOR (EIO, -1);
  819. if (SUP.use_passive_connection){
  820. if ((SUP.use_passive_connection = setup_passive (me, super, data, &data_addr)))
  821. return data;
  822. SUP.use_source_route = 0;
  823. SUP.use_passive_connection = 0;
  824. print_vfs_message (_("ftpfs: could not setup passive mode"));
  825. }
  826. /* If passive setup fails, fallback to active connections */
  827. /* Active FTP connection */
  828. if ((bind (data, (struct sockaddr *)&data_addr, len) == 0) &&
  829. (getsockname (data, (struct sockaddr *) &data_addr, &len) == 0) &&
  830. (listen (data, 1) == 0))
  831. {
  832. unsigned char *a = (unsigned char *)&data_addr.sin_addr;
  833. unsigned char *p = (unsigned char *)&data_addr.sin_port;
  834. if (command (me, super, WAIT_REPLY, "PORT %d,%d,%d,%d,%d,%d", a[0], a[1],
  835. a[2], a[3], p[0], p[1]) == COMPLETE)
  836. return data;
  837. }
  838. close(data);
  839. my_errno = EIO;
  840. return -1;
  841. }
  842. static int
  843. open_data_connection (vfs *me, vfs_s_super *super, char *cmd, char *remote,
  844. int isbinary, int reget)
  845. {
  846. struct sockaddr_in from;
  847. int s, j, data, fromlen = sizeof(from);
  848. if ((s = initconn (me, super)) == -1)
  849. return -1;
  850. if (changetype (me, super, isbinary) == -1)
  851. return -1;
  852. if (reget > 0){
  853. j = command (me, super, WAIT_REPLY, "REST %d", reget);
  854. if (j != CONTINUE)
  855. return -1;
  856. }
  857. if (remote) {
  858. char * remote_path = translate_path (me, super, remote);
  859. j = command (me, super, WAIT_REPLY, "%s /%s", cmd,
  860. /* WarFtpD can't STORE //filename */
  861. (*remote_path == '/') ? remote_path + 1 : remote_path);
  862. g_free (remote_path);
  863. } else
  864. j = command (me, super, WAIT_REPLY, "%s", cmd);
  865. if (j != PRELIM)
  866. ERRNOR (EPERM, -1);
  867. enable_interrupt_key();
  868. if (SUP.use_passive_connection)
  869. data = s;
  870. else {
  871. data = accept (s, (struct sockaddr *)&from, &fromlen);
  872. close(s);
  873. if (data < 0) {
  874. my_errno = errno;
  875. return -1;
  876. }
  877. }
  878. disable_interrupt_key();
  879. return data;
  880. }
  881. static void
  882. linear_abort (vfs *me, vfs_s_fh *fh)
  883. {
  884. vfs_s_super *super = FH_SUPER;
  885. static unsigned char const ipbuf[3] = { IAC, IP, IAC };
  886. fd_set mask;
  887. char buf[1024];
  888. int dsock = FH_SOCK;
  889. FH_SOCK = -1;
  890. SUP.control_connection_buzy = 0;
  891. print_vfs_message(_("ftpfs: aborting transfer."));
  892. if (send(SUP.sock, ipbuf, sizeof(ipbuf), MSG_OOB) != sizeof(ipbuf)) {
  893. print_vfs_message(_("ftpfs: abort error: %s"), unix_error_string(errno));
  894. return;
  895. }
  896. if (command(me, super, NONE, "%cABOR", DM) != COMPLETE){
  897. print_vfs_message (_("ftpfs: abort failed"));
  898. return;
  899. }
  900. if (dsock != -1) {
  901. FD_ZERO(&mask);
  902. FD_SET(dsock, &mask);
  903. if (select(dsock + 1, &mask, NULL, NULL, NULL) > 0)
  904. while (read(dsock, buf, sizeof(buf)) > 0);
  905. }
  906. if ((get_reply(me, SUP.sock, NULL, 0) == TRANSIENT) && (code == 426))
  907. get_reply(me, SUP.sock, NULL, 0);
  908. }
  909. #if 0
  910. static void
  911. resolve_symlink_without_ls_options(vfs *me, vfs_s_super *super, vfs_s_inode *dir)
  912. {
  913. struct linklist *flist;
  914. struct direntry *fe, *fel;
  915. char tmp[MC_MAXPATHLEN];
  916. int depth;
  917. dir->symlink_status = FTPFS_RESOLVING_SYMLINKS;
  918. for (flist = dir->file_list->next; flist != dir->file_list; flist = flist->next) {
  919. /* flist->data->l_stat is alread initialized with 0 */
  920. fel = flist->data;
  921. if (S_ISLNK(fel->s.st_mode) && fel->linkname) {
  922. if (fel->linkname[0] == '/') {
  923. if (strlen (fel->linkname) >= MC_MAXPATHLEN)
  924. continue;
  925. strcpy (tmp, fel->linkname);
  926. } else {
  927. if ((strlen (dir->remote_path) + strlen (fel->linkname)) >= MC_MAXPATHLEN)
  928. continue;
  929. strcpy (tmp, dir->remote_path);
  930. if (tmp[1] != '\0')
  931. strcat (tmp, "/");
  932. strcat (tmp + 1, fel->linkname);
  933. }
  934. for ( depth = 0; depth < 100; depth++) { /* depth protects against recursive symbolic links */
  935. canonicalize_pathname (tmp);
  936. fe = _get_file_entry(bucket, tmp, 0, 0);
  937. if (fe) {
  938. if (S_ISLNK (fe->s.st_mode) && fe->l_stat == 0) {
  939. /* Symlink points to link which isn't resolved, yet. */
  940. if (fe->linkname[0] == '/') {
  941. if (strlen (fe->linkname) >= MC_MAXPATHLEN)
  942. break;
  943. strcpy (tmp, fe->linkname);
  944. } else {
  945. /* at this point tmp looks always like this
  946. /directory/filename, i.e. no need to check
  947. strrchr's return value */
  948. *(strrchr (tmp, '/') + 1) = '\0'; /* dirname */
  949. if ((strlen (tmp) + strlen (fe->linkname)) >= MC_MAXPATHLEN)
  950. break;
  951. strcat (tmp, fe->linkname);
  952. }
  953. continue;
  954. } else {
  955. fel->l_stat = g_new (struct stat, 1);
  956. if ( S_ISLNK (fe->s.st_mode))
  957. *fel->l_stat = *fe->l_stat;
  958. else
  959. *fel->l_stat = fe->s;
  960. (*fel->l_stat).st_ino = bucket->__inode_counter++;
  961. }
  962. }
  963. break;
  964. }
  965. }
  966. }
  967. dir->symlink_status = FTPFS_RESOLVED_SYMLINKS;
  968. }
  969. static void
  970. resolve_symlink_with_ls_options(vfs *me, vfs_s_super *super, vfs_s_inode *dir)
  971. {
  972. char buffer[2048] = "", *filename;
  973. int sock;
  974. FILE *fp;
  975. struct stat s;
  976. struct linklist *flist;
  977. struct direntry *fe;
  978. int switch_method = 0;
  979. dir->symlink_status = FTPFS_RESOLVED_SYMLINKS;
  980. if (strchr (dir->remote_path, ' ')) {
  981. if (ftpfs_chdir_internal (bucket, dir->remote_path) != COMPLETE) {
  982. print_vfs_message(_("ftpfs: CWD failed."));
  983. return;
  984. }
  985. sock = open_data_connection (bucket, "LIST -lLa", ".", TYPE_ASCII, 0);
  986. }
  987. else
  988. sock = open_data_connection (bucket, "LIST -lLa",
  989. dir->remote_path, TYPE_ASCII, 0);
  990. if (sock == -1) {
  991. print_vfs_message(_("ftpfs: couldn't resolve symlink"));
  992. return;
  993. }
  994. fp = fdopen(sock, "r");
  995. if (fp == NULL) {
  996. close(sock);
  997. print_vfs_message(_("ftpfs: couldn't resolve symlink"));
  998. return;
  999. }
  1000. enable_interrupt_key();
  1001. flist = dir->file_list->next;
  1002. while (1) {
  1003. do {
  1004. if (flist == dir->file_list)
  1005. goto done;
  1006. fe = flist->data;
  1007. flist = flist->next;
  1008. } while (!S_ISLNK(fe->s.st_mode));
  1009. while (1) {
  1010. if (fgets (buffer, sizeof (buffer), fp) == NULL)
  1011. goto done;
  1012. if (logfile){
  1013. fputs (buffer, logfile);
  1014. fflush (logfile);
  1015. }
  1016. vfs_die("This code should be commented out\n");
  1017. if (vfs_parse_ls_lga (buffer, &s, &filename, NULL)) {
  1018. int r = strcmp(fe->name, filename);
  1019. g_free(filename);
  1020. if (r == 0) {
  1021. if (S_ISLNK (s.st_mode)) {
  1022. /* This server doesn't understand LIST -lLa */
  1023. switch_method = 1;
  1024. goto done;
  1025. }
  1026. fe->l_stat = g_new (struct stat, 1);
  1027. if (fe->l_stat == NULL)
  1028. goto done;
  1029. *fe->l_stat = s;
  1030. (*fe->l_stat).st_ino = bucket->__inode_counter++;
  1031. break;
  1032. }
  1033. if (r < 0)
  1034. break;
  1035. }
  1036. }
  1037. }
  1038. done:
  1039. while (fgets(buffer, sizeof(buffer), fp) != NULL);
  1040. disable_interrupt_key();
  1041. fclose(fp);
  1042. get_reply(me, SUP.sock, NULL, 0);
  1043. }
  1044. static void
  1045. resolve_symlink(vfs *me, vfs_s_super *super, vfs_s_inode *dir)
  1046. {
  1047. print_vfs_message(_("Resolving symlink..."));
  1048. if (SUP.strict_rfc959_list_cmd)
  1049. resolve_symlink_without_ls_options(me, super, dir);
  1050. else
  1051. resolve_symlink_with_ls_options(me, super, dir);
  1052. }
  1053. #endif
  1054. static int
  1055. dir_load(vfs *me, vfs_s_inode *dir, char *remote_path)
  1056. {
  1057. vfs_s_entry *ent;
  1058. vfs_s_super *super = dir->super;
  1059. int sock, num_entries = 0;
  1060. #ifdef FIXME_LATER
  1061. int has_symlinks = 0;
  1062. #endif
  1063. char buffer[BUF_8K];
  1064. int cd_first = ftpfs_first_cd_then_ls || (strchr (remote_path, ' ') != NULL) || (SUP.strict == RFC_STRICT);
  1065. again:
  1066. print_vfs_message(_("ftpfs: Reading FTP directory %s... %s%s"), remote_path,
  1067. SUP.strict == RFC_STRICT ? _("(strict rfc959)") : "",
  1068. cd_first ? _("(chdir first)") : "");
  1069. if (cd_first) {
  1070. char *p;
  1071. p = translate_path (me, super, remote_path);
  1072. if (ftpfs_chdir_internal (me, super, p) != COMPLETE) {
  1073. g_free (p);
  1074. my_errno = ENOENT;
  1075. print_vfs_message(_("ftpfs: CWD failed."));
  1076. return -1;
  1077. }
  1078. g_free (p);
  1079. }
  1080. gettimeofday(&dir->u.ftp.timestamp, NULL);
  1081. dir->u.ftp.timestamp.tv_sec += ftpfs_directory_timeout;
  1082. if (SUP.strict == RFC_STRICT)
  1083. sock = open_data_connection (me, super, "LIST", 0, TYPE_ASCII, 0);
  1084. else if (cd_first)
  1085. /* Dirty hack to avoid autoprepending / to . */
  1086. /* Wu-ftpd produces strange output for '/' if 'LIST -la .' used */
  1087. sock = open_data_connection (me, super, "LIST -la", 0, TYPE_ASCII, 0);
  1088. else {
  1089. /* Trailing "/." is necessary if remote_path is a symlink
  1090. but don't generate "//." */
  1091. char *path = (*remote_path) ? concat_dir_and_file (remote_path, ".")
  1092. : NULL;
  1093. sock = open_data_connection (me, super, "LIST -la", path, TYPE_ASCII, 0);
  1094. if (path)
  1095. g_free (path);
  1096. }
  1097. if (sock == -1)
  1098. goto fallback;
  1099. /* Clear the interrupt flag */
  1100. enable_interrupt_key ();
  1101. #if 1
  1102. {
  1103. /* added 20001006 by gisburn
  1104. * add dots '.' and '..'. This must be _executed_ before scanning the dir as the
  1105. * code below may jump directly into error handling code (without executing
  1106. * remaining code). And C doesn't have try {...} finally {}; :-)
  1107. */
  1108. vfs_s_inode *parent = dir->ent->dir;
  1109. if( parent==NULL )
  1110. parent = dir;
  1111. ent = vfs_s_generate_entry(me, ".", dir, 0);
  1112. ent->ino->st=dir->st;
  1113. num_entries++;
  1114. vfs_s_insert_entry(me, dir, ent);
  1115. ent = vfs_s_generate_entry(me, "..", parent, 0);
  1116. ent->ino->st=parent->st;
  1117. num_entries++;
  1118. vfs_s_insert_entry(me, dir, ent);
  1119. }
  1120. #endif
  1121. while (1) {
  1122. int i;
  1123. int res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), sock);
  1124. if (!res)
  1125. break;
  1126. if (res == EINTR) {
  1127. me->verrno = ECONNRESET;
  1128. close (sock);
  1129. disable_interrupt_key();
  1130. get_reply(me, SUP.sock, NULL, 0);
  1131. print_vfs_message(_("ftpfs: failed"));
  1132. return -1;
  1133. }
  1134. if (logfile){
  1135. fputs (buffer, logfile);
  1136. fputs ("\n", logfile);
  1137. fflush (logfile);
  1138. }
  1139. ent = vfs_s_generate_entry(me, NULL, dir, 0);
  1140. i = ent->ino->st.st_nlink;
  1141. if (!vfs_parse_ls_lga (buffer, &ent->ino->st, &ent->name, &ent->ino->linkname)) {
  1142. vfs_s_free_entry (me, ent);
  1143. continue;
  1144. }
  1145. ent->ino->st.st_nlink = i; /* Ouch, we need to preserve our counts :-( */
  1146. num_entries++;
  1147. if ((!strcmp(ent->name, ".")) || (!strcmp (ent->name, ".."))) {
  1148. g_free (ent->name);
  1149. ent->name = NULL; /* Ouch, vfs_s_free_entry "knows" about . and .. being special :-( */
  1150. vfs_s_free_entry (me, ent);
  1151. continue;
  1152. }
  1153. vfs_s_insert_entry(me, dir, ent);
  1154. }
  1155. /* vfs_s_add_dots(me, dir, NULL);
  1156. FIXME This really should be here; but we need to provide correct parent.
  1157. Disabled for now, please fix it. Pavel
  1158. */
  1159. close(sock);
  1160. me->verrno = E_REMOTE;
  1161. if ((get_reply (me, SUP.sock, NULL, 0) != COMPLETE) || !num_entries)
  1162. goto fallback;
  1163. if (SUP.strict == RFC_AUTODETECT)
  1164. SUP.strict = RFC_DARING;
  1165. #ifdef FIXME_LATER
  1166. if (has_symlinks) {
  1167. if (resolve_symlinks)
  1168. resolve_symlink(me, super, dcache);
  1169. else
  1170. dcache->symlink_status = FTPFS_UNRESOLVED_SYMLINKS;
  1171. }
  1172. #endif
  1173. return 0;
  1174. fallback:
  1175. if (SUP.strict == RFC_AUTODETECT) {
  1176. /* It's our first attempt to get a directory listing from this
  1177. server (UNIX style LIST command) */
  1178. SUP.strict = RFC_STRICT;
  1179. /* I hate goto, but recursive call needs another 8K on stack */
  1180. /* return dir_load (me, dir, remote_path); */
  1181. cd_first = 1;
  1182. goto again;
  1183. }
  1184. print_vfs_message(_("ftpfs: failed; nowhere to fallback to"));
  1185. ERRNOR(-1, EACCES);
  1186. }
  1187. static int
  1188. file_store(vfs *me, vfs_s_fh *fh, char *name, char *localname)
  1189. {
  1190. int h, sock, n;
  1191. off_t total;
  1192. #ifdef HAVE_STRUCT_LINGER
  1193. struct linger li;
  1194. #else
  1195. int flag_one = 1;
  1196. #endif
  1197. char buffer[8192];
  1198. struct stat s;
  1199. vfs_s_super *super = FH_SUPER;
  1200. h = open(localname, O_RDONLY);
  1201. if (h == -1)
  1202. ERRNOR (EIO, -1);
  1203. fstat(h, &s);
  1204. sock = open_data_connection(me, super, fh->u.ftp.append ? "APPE" : "STOR", name, TYPE_BINARY, 0);
  1205. if (sock < 0) {
  1206. close(h);
  1207. return -1;
  1208. }
  1209. #ifdef HAVE_STRUCT_LINGER
  1210. li.l_onoff = 1;
  1211. li.l_linger = 120;
  1212. setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
  1213. #else
  1214. setsockopt(sock, SOL_SOCKET, SO_LINGER, &flag_one, sizeof (flag_one));
  1215. #endif
  1216. total = 0;
  1217. enable_interrupt_key();
  1218. while (1) {
  1219. while ((n = read(h, buffer, sizeof(buffer))) < 0) {
  1220. if (errno == EINTR) {
  1221. if (got_interrupt()) {
  1222. my_errno = EINTR;
  1223. goto error_return;
  1224. }
  1225. else
  1226. continue;
  1227. }
  1228. my_errno = errno;
  1229. goto error_return;
  1230. }
  1231. if (n == 0)
  1232. break;
  1233. while (write(sock, buffer, n) < 0) {
  1234. if (errno == EINTR) {
  1235. if (got_interrupt()) {
  1236. my_errno = EINTR;
  1237. goto error_return;
  1238. }
  1239. else
  1240. continue;
  1241. }
  1242. my_errno = errno;
  1243. goto error_return;
  1244. }
  1245. total += n;
  1246. print_vfs_message(_("ftpfs: storing file %lu (%lu)"),
  1247. (unsigned long) total, (unsigned long) s.st_size);
  1248. }
  1249. disable_interrupt_key();
  1250. close(sock);
  1251. close(h);
  1252. if (get_reply (me, SUP.sock, NULL, 0) != COMPLETE)
  1253. ERRNOR (EIO, -1);
  1254. return 0;
  1255. error_return:
  1256. disable_interrupt_key();
  1257. close(sock);
  1258. close(h);
  1259. get_reply(me, SUP.sock, NULL, 0);
  1260. return -1;
  1261. }
  1262. //#define FH_SOCK fh->u.ftp.sock
  1263. static int
  1264. linear_start(vfs *me, vfs_s_fh *fh, int offset)
  1265. {
  1266. char *name = vfs_s_fullpath (me, fh->ino);
  1267. if (!name)
  1268. return 0;
  1269. FH_SOCK = open_data_connection(me, FH_SUPER, "RETR", name, TYPE_BINARY, offset);
  1270. g_free (name);
  1271. if (FH_SOCK == -1)
  1272. ERRNOR (EACCES, 0);
  1273. fh->linear = LS_LINEAR_OPEN;
  1274. FH_SUPER->u.ftp.control_connection_buzy = 1;
  1275. fh->u.ftp.append = 0;
  1276. return 1;
  1277. }
  1278. static int
  1279. linear_read (vfs *me, vfs_s_fh *fh, void *buf, int len)
  1280. {
  1281. int n;
  1282. vfs_s_super *super = FH_SUPER;
  1283. while ((n = read (FH_SOCK, buf, len))<0) {
  1284. if ((errno == EINTR) && !got_interrupt())
  1285. continue;
  1286. break;
  1287. }
  1288. if (n<0)
  1289. linear_abort(me, fh);
  1290. if (!n) {
  1291. SUP.control_connection_buzy = 0;
  1292. close (FH_SOCK);
  1293. FH_SOCK = -1;
  1294. if ((get_reply (me, SUP.sock, NULL, 0) != COMPLETE))
  1295. ERRNOR (E_REMOTE, -1);
  1296. return 0;
  1297. }
  1298. ERRNOR (errno, n);
  1299. }
  1300. static void
  1301. linear_close (vfs *me, vfs_s_fh *fh)
  1302. {
  1303. if (FH_SOCK != -1)
  1304. linear_abort(me, fh);
  1305. }
  1306. static int ftpfs_ctl (void *fh, int ctlop, int arg)
  1307. {
  1308. switch (ctlop) {
  1309. case MCCTL_IS_NOTREADY:
  1310. {
  1311. int v;
  1312. if (!FH->linear)
  1313. vfs_die ("You may not do this");
  1314. if (FH->linear == LS_LINEAR_CLOSED)
  1315. return 0;
  1316. v = vfs_s_select_on_two (FH->u.ftp.sock, 0);
  1317. if (((v < 0) && (errno == EINTR)) || v == 0)
  1318. return 1;
  1319. return 0;
  1320. }
  1321. default:
  1322. return 0;
  1323. }
  1324. }
  1325. /* Warning: filename passed to this command is damaged */
  1326. static int
  1327. send_ftp_command(vfs *me, char *filename, char *cmd, int flags)
  1328. {
  1329. char *rpath, *p;
  1330. vfs_s_super *super;
  1331. int r;
  1332. int flush_directory_cache = (flags & OPT_FLUSH);
  1333. if (!(rpath = vfs_s_get_path_mangle(me, filename, &super, 0)))
  1334. return -1;
  1335. p = translate_path (me, super, rpath);
  1336. r = command (me, super, WAIT_REPLY, cmd, p);
  1337. g_free (p);
  1338. vfs_add_noncurrent_stamps (&vfs_ftpfs_ops, (vfsid) super, NULL);
  1339. if (flags & OPT_IGNORE_ERROR)
  1340. r = COMPLETE;
  1341. if (r != COMPLETE)
  1342. ERRNOR (EPERM, -1);
  1343. if (flush_directory_cache)
  1344. vfs_s_invalidate(me, super);
  1345. return 0;
  1346. }
  1347. /* This routine is called as the last step in load_setup */
  1348. void
  1349. ftpfs_init_passwd(void)
  1350. {
  1351. ftpfs_anonymous_passwd = load_anon_passwd ();
  1352. if (ftpfs_anonymous_passwd)
  1353. return;
  1354. /* If there is no anonymous ftp password specified
  1355. * then we'll just use anonymous@
  1356. * We don't send any other thing because:
  1357. * - We want to remain anonymous
  1358. * - We want to stop SPAM
  1359. * - We don't want to let ftp sites to discriminate by the user,
  1360. * host or country.
  1361. */
  1362. ftpfs_anonymous_passwd = g_strdup ("anonymous@");
  1363. }
  1364. static int ftpfs_chmod (vfs *me, char *path, int mode)
  1365. {
  1366. char buf[BUF_SMALL];
  1367. g_snprintf(buf, sizeof(buf), "SITE CHMOD %4.4o /%%s", mode & 07777);
  1368. return send_ftp_command(me, path, buf, OPT_FLUSH);
  1369. }
  1370. static int ftpfs_chown (vfs *me, char *path, int owner, int group)
  1371. {
  1372. #if 0
  1373. my_errno = EPERM;
  1374. return -1;
  1375. #else
  1376. /* Everyone knows it is not possible to chown remotely, so why bother them.
  1377. If someone's root, then copy/move will always try to chown it... */
  1378. return 0;
  1379. #endif
  1380. }
  1381. static int ftpfs_unlink (vfs *me, char *path)
  1382. {
  1383. return send_ftp_command(me, path, "DELE /%s", OPT_FLUSH);
  1384. }
  1385. /* Return true if path is the same directoy as the one we are on now */
  1386. static int
  1387. is_same_dir (vfs *me, vfs_s_super *super, const char *path)
  1388. {
  1389. if (!SUP.cwdir)
  1390. return 0;
  1391. if (strcmp (path, SUP.cwdir) == 0)
  1392. return 1;
  1393. return 0;
  1394. }
  1395. static int
  1396. ftpfs_chdir_internal (vfs *me, vfs_s_super *super, char *remote_path)
  1397. {
  1398. int r;
  1399. char *p;
  1400. if (!SUP.cwd_defered && is_same_dir (me, super, remote_path))
  1401. return COMPLETE;
  1402. p = translate_path (me, super, remote_path);
  1403. r = command (me, super, WAIT_REPLY, "CWD /%s", p);
  1404. g_free (p);
  1405. if (r != COMPLETE) {
  1406. my_errno = EIO;
  1407. } else {
  1408. if (SUP.cwdir)
  1409. g_free(SUP.cwdir);
  1410. SUP.cwdir = g_strdup (remote_path);
  1411. SUP.cwd_defered = 0;
  1412. }
  1413. return r;
  1414. }
  1415. static int ftpfs_rename (vfs *me, char *path1, char *path2)
  1416. {
  1417. send_ftp_command(me, path1, "RNFR /%s", OPT_FLUSH);
  1418. return send_ftp_command(me, path2, "RNTO /%s", OPT_FLUSH);
  1419. }
  1420. static int ftpfs_mkdir (vfs *me, char *path, mode_t mode)
  1421. {
  1422. return send_ftp_command(me, path, "MKD /%s", OPT_FLUSH);
  1423. }
  1424. static int ftpfs_rmdir (vfs *me, char *path)
  1425. {
  1426. return send_ftp_command(me, path, "RMD /%s", OPT_FLUSH);
  1427. }
  1428. #ifdef FIXME_LATER_ALIGATOR
  1429. static void my_forget (char *file)
  1430. {
  1431. struct linklist *l;
  1432. char *host, *user, *pass, *rp;
  1433. int port;
  1434. #ifndef BROKEN_PATHS
  1435. if (strncmp (file, "/#ftp:", 6))
  1436. return; /* Normal: consider cd /bla/#ftp */
  1437. #else
  1438. if (!(file = strstr (file, "/#ftp:")))
  1439. return;
  1440. #endif
  1441. file += 6;
  1442. if (!(rp = my_get_host_and_username (file, &host, &user, &port, &pass))) {
  1443. g_free (host);
  1444. g_free (user);
  1445. if (pass)
  1446. wipe_password (pass);
  1447. return;
  1448. }
  1449. /* we do not care about the path actually */
  1450. g_free (rp);
  1451. for (l = connections_list->next; l != connections_list; l = l->next){
  1452. struct connection *bucket = l->data;
  1453. if ((strcmp (host, SUP.host) == 0) &&
  1454. (strcmp (user, SUP.user) == 0) &&
  1455. (port == SUP.port)){
  1456. /* close socket: the child owns it now */
  1457. close (bucket->sock);
  1458. bucket->sock = -1;
  1459. /* reopen the connection */
  1460. bucket->sock = ftpfs_open_socket (bucket);
  1461. if (bucket->sock != -1)
  1462. login_server (bucket, pass);
  1463. break;
  1464. }
  1465. }
  1466. g_free (host);
  1467. g_free (user);
  1468. if (pass)
  1469. wipe_password (pass);
  1470. }
  1471. #endif
  1472. static int ftpfs_fh_open (vfs *me, vfs_s_fh *fh, int flags, int mode)
  1473. {
  1474. fh->u.ftp.append = 0;
  1475. /* File will be written only, so no need to retrieve it from ftp server */
  1476. if (((flags & O_WRONLY) == O_WRONLY) && !(flags & (O_RDONLY|O_RDWR))){
  1477. #ifdef HAVE_STRUCT_LINGER
  1478. struct linger li;
  1479. #else
  1480. int li = 1;
  1481. #endif
  1482. char * name;
  1483. /* linear_start() called, so data will be written
  1484. * to local temporary file and stored to ftp server
  1485. * by vfs_s_close later
  1486. */
  1487. if (FH_SUPER->u.ftp.control_connection_buzy){
  1488. if (!fh->ino->localname){
  1489. int handle = mc_mkstemps (&fh->ino->localname, me->name, NULL);
  1490. if (handle == -1)
  1491. return -1;
  1492. close (handle);
  1493. fh->u.ftp.append = flags & O_APPEND;
  1494. }
  1495. return 0;
  1496. }
  1497. name = vfs_s_fullpath (me, fh->ino);
  1498. if (!name)
  1499. return -1;
  1500. fh->handle = open_data_connection(me, fh->ino->super,
  1501. (flags & O_APPEND) ? "APPE" : "STOR", name, TYPE_BINARY, 0);
  1502. g_free (name);
  1503. if (fh->handle < 0)
  1504. return -1;
  1505. #ifdef HAVE_STRUCT_LINGER
  1506. li.l_onoff = 1;
  1507. li.l_linger = 120;
  1508. #endif
  1509. setsockopt(fh->handle, SOL_SOCKET, SO_LINGER, &li, sizeof(li));
  1510. if (fh->ino->localname){
  1511. unlink (fh->ino->localname);
  1512. g_free (fh->ino->localname);
  1513. fh->ino->localname = NULL;
  1514. }
  1515. return 0;
  1516. }
  1517. if (!fh->ino->localname)
  1518. if (vfs_s_retrieve_file (me, fh->ino)==-1)
  1519. return -1;
  1520. if (!fh->ino->localname)
  1521. vfs_die( "retrieve_file failed to fill in localname" );
  1522. return 0;
  1523. }
  1524. static int ftpfs_fh_close (vfs *me, vfs_s_fh *fh)
  1525. {
  1526. if (fh->handle != -1 && !fh->ino->localname){
  1527. close (fh->handle);
  1528. fh->handle = -1;
  1529. /* File is stored to destination already, so
  1530. * we prevent MEDATA->file_store() call from vfs_s_close ()
  1531. */
  1532. fh->changed = 0;
  1533. if (get_reply (me, fh->ino->SUP.sock, NULL, 0) != COMPLETE)
  1534. ERRNOR (EIO, -1);
  1535. vfs_s_invalidate (me, FH_SUPER);
  1536. }
  1537. return 0;
  1538. }
  1539. static struct vfs_s_data ftp_data = {
  1540. NULL,
  1541. 0,
  1542. 0,
  1543. NULL, /* logfile */
  1544. NULL, /* init_inode */
  1545. NULL, /* free_inode */
  1546. NULL, /* init_entry */
  1547. NULL, /* archive_check */
  1548. archive_same,
  1549. open_archive,
  1550. free_archive,
  1551. ftpfs_fh_open, /* fh_open */
  1552. ftpfs_fh_close, /* fh_close */
  1553. vfs_s_find_entry_linear,
  1554. dir_load,
  1555. dir_uptodate,
  1556. file_store,
  1557. linear_start,
  1558. linear_read,
  1559. linear_close
  1560. };
  1561. static void
  1562. ftpfs_fill_names (vfs *me, void (*func)(char *))
  1563. {
  1564. struct vfs_s_super * super = ftp_data.supers;
  1565. char *name;
  1566. while (super){
  1567. name = g_strconcat ("/#ftp:", SUP.user, "@", SUP.host, "/", SUP.cwdir, NULL);
  1568. (*func)(name);
  1569. g_free (name);
  1570. super = super->next;
  1571. }
  1572. }
  1573. vfs vfs_ftpfs_ops = {
  1574. NULL, /* This is place of next pointer */
  1575. "ftpfs",
  1576. F_NET, /* flags */
  1577. "ftp:", /* prefix */
  1578. &ftp_data, /* data */
  1579. 0, /* errno */
  1580. NULL, /* init */
  1581. NULL, /* done */
  1582. ftpfs_fill_names,
  1583. NULL,
  1584. vfs_s_open,
  1585. vfs_s_close,
  1586. vfs_s_read,
  1587. vfs_s_write,
  1588. vfs_s_opendir,
  1589. vfs_s_readdir,
  1590. vfs_s_closedir,
  1591. vfs_s_telldir,
  1592. vfs_s_seekdir,
  1593. vfs_s_stat,
  1594. vfs_s_lstat,
  1595. vfs_s_fstat,
  1596. ftpfs_chmod,
  1597. ftpfs_chown, /* not really implemented but returns success */
  1598. NULL,
  1599. vfs_s_readlink,
  1600. NULL,
  1601. NULL,
  1602. ftpfs_unlink,
  1603. ftpfs_rename,
  1604. vfs_s_chdir,
  1605. vfs_s_ferrno,
  1606. vfs_s_lseek,
  1607. NULL,
  1608. vfs_s_getid,
  1609. vfs_s_nothingisopen,
  1610. vfs_s_free,
  1611. NULL,
  1612. NULL,
  1613. ftpfs_mkdir,
  1614. ftpfs_rmdir,
  1615. ftpfs_ctl,
  1616. vfs_s_setctl
  1617. MMAPNULL
  1618. };
  1619. void ftpfs_set_debug (const char *file)
  1620. {
  1621. logfile = fopen (file, "w+");
  1622. if (logfile)
  1623. ftp_data.logfile = logfile;
  1624. }
  1625. static char buffer[BUF_MEDIUM];
  1626. static char *netrc, *netrcp;
  1627. static int netrc_next (void)
  1628. {
  1629. char *p;
  1630. int i;
  1631. static const char * const keywords [] = { "default", "machine",
  1632. "login", "password", "passwd", "account", "macdef" };
  1633. while (1) {
  1634. netrcp = skip_separators (netrcp);
  1635. if (*netrcp != '\n')
  1636. break;
  1637. netrcp++;
  1638. }
  1639. if (!*netrcp)
  1640. return 0;
  1641. p = buffer;
  1642. if (*netrcp == '"') {
  1643. for (netrcp++; *netrcp != '"' && *netrcp; netrcp++) {
  1644. if (*netrcp == '\\')
  1645. netrcp++;
  1646. *p++ = *netrcp;
  1647. }
  1648. } else {
  1649. for (;*netrcp != '\n' && *netrcp != '\t' && *netrcp != ' ' &&
  1650. *netrcp != ',' && *netrcp; netrcp++) {
  1651. if (*netrcp == '\\')
  1652. netrcp++;
  1653. *p++ = *netrcp;
  1654. }
  1655. }
  1656. *p = 0;
  1657. if (!*buffer)
  1658. return 0;
  1659. for (i = 0; i < sizeof (keywords) / sizeof (keywords [0]); i++)
  1660. if (!strcmp (keywords [i], buffer))
  1661. break;
  1662. return i + 1;
  1663. }
  1664. static int netrc_has_incorrect_mode (char * netrcname, char * netrc)
  1665. {
  1666. static int be_angry = 1;
  1667. struct stat mystat;
  1668. if (stat (netrcname, &mystat) >= 0 && (mystat.st_mode & 077)) {
  1669. if (be_angry) {
  1670. message_1s (1, MSG_ERROR, _("~/.netrc file has not correct mode.\n"
  1671. "Remove password or correct mode."));
  1672. be_angry = 0;
  1673. }
  1674. g_free (netrc);
  1675. g_free (netrcname);
  1676. return 1;
  1677. }
  1678. return 0;
  1679. }
  1680. static int lookup_netrc (char *host, char **login, char **pass)
  1681. {
  1682. char *netrcname, *tmp;
  1683. char hostname[MAXHOSTNAMELEN], *domain;
  1684. int keyword;
  1685. static struct rupcache {
  1686. struct rupcache *next;
  1687. char *host;
  1688. char *login;
  1689. char *pass;
  1690. } *rup_cache = NULL, *rupp;
  1691. for (rupp = rup_cache; rupp != NULL; rupp = rupp->next)
  1692. /* return from cache only if host AND user match! */
  1693. if ((!strcmp (host, rupp->host)) &&
  1694. (rupp->login != NULL) &&
  1695. (*login != NULL) &&
  1696. (!strcmp(rupp->login, *login))) {
  1697. *login = g_strdup (rupp->login);
  1698. if (rupp->pass != NULL)
  1699. *pass = g_strdup (rupp->pass);
  1700. return 0;
  1701. }
  1702. netrcname = concat_dir_and_file (home_dir, ".netrc");
  1703. netrcp = netrc = load_file (netrcname);
  1704. if (netrc == NULL) {
  1705. g_free (netrcname);
  1706. return 0;
  1707. }
  1708. if (gethostname (hostname, sizeof (hostname)) < 0)
  1709. *hostname = 0;
  1710. if (!(domain = strchr (hostname, '.')))
  1711. domain = "";
  1712. while ((keyword = netrc_next ())) {
  1713. if (keyword == 2) {
  1714. if (netrc_next () != 8)
  1715. continue;
  1716. if (g_strcasecmp (host, buffer) &&
  1717. ((tmp = strchr (host, '.')) == NULL ||
  1718. g_strcasecmp (tmp, domain) ||
  1719. g_strncasecmp (host, buffer, tmp - host) ||
  1720. buffer [tmp - host]))
  1721. continue;
  1722. } else if (keyword != 1)
  1723. continue;
  1724. while ((keyword = netrc_next ()) > 2) {
  1725. switch (keyword) {
  1726. case 3:
  1727. if (netrc_next ()) {
  1728. /* replace the dummy user with the one from ~/.netrc */
  1729. if ((*login == NULL) || !strcmp(*login, "*netrc*"))
  1730. *login = g_strdup (buffer);
  1731. else if (strcmp (*login, buffer))
  1732. keyword = 20;
  1733. }
  1734. break;
  1735. case 4:
  1736. case 5:
  1737. if (strcmp (*login, "anonymous") && strcmp (*login, "ftp") &&
  1738. netrc_has_incorrect_mode (netrcname, netrc)) {
  1739. return -1;
  1740. }
  1741. if (netrc_next () && *pass == NULL)
  1742. *pass = g_strdup (buffer);
  1743. break;
  1744. case 6:
  1745. if (netrc_has_incorrect_mode (netrcname, netrc)) {
  1746. return -1;
  1747. }
  1748. netrc_next ();
  1749. break;
  1750. case 7: /* macdef: skip it */
  1751. do {
  1752. while (*netrcp && *netrcp != '\n')
  1753. netrcp++;
  1754. if (*netrcp != '\n')
  1755. break;
  1756. netrcp++;
  1757. } while (*netrcp && *netrcp != '\n');
  1758. break;
  1759. }
  1760. if (keyword == 20)
  1761. break;
  1762. }
  1763. if (keyword != 20)
  1764. break;
  1765. }
  1766. g_free (netrc);
  1767. g_free (netrcname);
  1768. rupp = g_new (struct rupcache, 1);
  1769. rupp->host = g_strdup (host);
  1770. rupp->login = rupp->pass = 0;
  1771. if (*login != NULL) {
  1772. if (!strcmp(*login, "*netrc*"))
  1773. /* no match in ~/.netrc, try anonymous */
  1774. *login = g_strdup("anonymous");
  1775. rupp->login = g_strdup (*login);
  1776. }
  1777. if (*pass != NULL)
  1778. rupp->pass = g_strdup (*pass);
  1779. rupp->next = rup_cache;
  1780. rup_cache = rupp;
  1781. return 0;
  1782. }