|
1 // |
|
2 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved. |
|
3 // |
|
4 /* |
|
5 * zftp.c - builtin FTP client |
|
6 * |
|
7 * This file is part of zsh, the Z shell. |
|
8 * |
|
9 * Copyright (c) 1998 Peter Stephenson |
|
10 * All rights reserved. |
|
11 * |
|
12 * Permission is hereby granted, without written agreement and without |
|
13 * license or royalty fees, to use, copy, modify, and distribute this |
|
14 * software and to distribute modified versions of this software for any |
|
15 * purpose, provided that the above copyright notice and the following |
|
16 * two paragraphs appear in all copies of this software. |
|
17 * |
|
18 * In no event shall Peter Stephenson or the Zsh Development Group be liable |
|
19 * to any party for direct, indirect, special, incidental, or consequential |
|
20 * damages arising out of the use of this software and its documentation, |
|
21 * even if Peter Stephenson and the Zsh Development Group have been advised of |
|
22 * the possibility of such damage. |
|
23 * |
|
24 * Peter Stephenson and the Zsh Development Group specifically disclaim any |
|
25 * warranties, including, but not limited to, the implied warranties of |
|
26 * merchantability and fitness for a particular purpose. The software |
|
27 * provided hereunder is on an "as is" basis, and Peter Stephenson and the |
|
28 * Zsh Development Group have no obligation to provide maintenance, |
|
29 * support, updates, enhancements, or modifications. |
|
30 * |
|
31 */ |
|
32 |
|
33 /* |
|
34 * TODO: |
|
35 * should be eight-bit clean, but isn't. |
|
36 * tracking of logical rather than physical directories, like nochaselinks |
|
37 * (usually PWD returns physical directory). |
|
38 * can signal handling be improved? |
|
39 * maybe we should block CTRL-c on some more operations, |
|
40 * otherwise you can get the connection closed prematurely. |
|
41 * some way of turning off progress reports when backgrounded |
|
42 * would be nice, but the shell doesn't make it easy to find that out. |
|
43 * proxy/gateway connections if i knew what to do |
|
44 * options to specify e.g. a non-standard port |
|
45 */ |
|
46 |
|
47 /* needed in prototypes for statics */ |
|
48 |
|
49 struct hostent; |
|
50 struct in_addr; |
|
51 struct sockaddr_in; |
|
52 struct sockaddr_in6; |
|
53 struct zftp_session; |
|
54 typedef struct zftp_session *Zftp_session; |
|
55 |
|
56 #include "tcp.h" |
|
57 #include "zftp.mdh" |
|
58 #include "zftp.pro" |
|
59 |
|
60 /* it's a TELNET based protocol, but don't think I like doing this */ |
|
61 #ifndef __SYMBIAN32__ |
|
62 #include <arpa/telnet.h> |
|
63 #else |
|
64 #include "telnet.h" |
|
65 #include "dummy.h" |
|
66 #endif //__SYMBIAN32__ |
|
67 |
|
68 /* |
|
69 * We use poll() in preference to select because some subset of manuals says |
|
70 * that's the thing to do, plus it's a bit less fiddly. I don't actually |
|
71 * have access to a system with poll but not select, however, though |
|
72 * both bits of the code have been tested on a machine with both. |
|
73 */ |
|
74 #ifdef HAVE_POLL_H |
|
75 #ifndef __SYMBIAN32__ |
|
76 # include <sys/poll.h> |
|
77 #else |
|
78 # include "poll.h" |
|
79 #endif |
|
80 #endif |
|
81 #if defined(HAVE_POLL) && !defined(POLLIN) && !defined(POLLNORM) |
|
82 # undef HAVE_POLL |
|
83 #endif |
|
84 |
|
85 #ifdef __SYMBIAN32__ |
|
86 #ifdef __WINSCW__ |
|
87 #pragma warn_unusedarg off |
|
88 #endif//__WINSCW__ |
|
89 #endif//__SYMBIAN32__ |
|
90 |
|
91 #ifdef USE_LOCAL_H_ERRNO |
|
92 int h_errno; |
|
93 #endif |
|
94 |
|
95 union zftp_sockaddr { |
|
96 struct sockaddr a; |
|
97 struct sockaddr_in in; |
|
98 #ifdef SUPPORT_IPV6 |
|
99 struct sockaddr_in6 in6; |
|
100 #endif |
|
101 }; |
|
102 |
|
103 #ifdef USE_LOCAL_H_ERRNO |
|
104 int h_errno; |
|
105 #endif |
|
106 |
|
107 /* |
|
108 * For FTP block mode |
|
109 * |
|
110 * The server on our AIX machine here happily accepts block mode, takes the |
|
111 * first connection, then at the second complains that it's got nowhere |
|
112 * to send data. The same problem happens with ncftp, it's not just |
|
113 * me. And a lot of servers don't even support block mode. So I'm not sure |
|
114 * how widespread the supposed ability to leave open the data fd between |
|
115 * transfers. Therefore, I've closed all connections after the transfer. |
|
116 * But then what's the point in block mode? I only implemented it because |
|
117 * it says in RFC959 that you need it to be able to restart transfers |
|
118 * later in the file. However, it turns out that's not true for |
|
119 * most servers --- but our AIX machine happily accepts the REST |
|
120 * command and then dumps the whole file onto you. Sigh. |
|
121 * |
|
122 * Note on block sizes: |
|
123 * Not quite sure how to optimize this: in principle |
|
124 * we should handle blocks up to 65535 bytes, which |
|
125 * is pretty big, and should presumably send blocks |
|
126 * which are smaller to be on the safe side. |
|
127 * Currently we send 32768 and use that also as |
|
128 * the maximum to receive. No-one's complained yet. Of course, |
|
129 * no-one's *used* it yet apart from me, but even so. |
|
130 */ |
|
131 |
|
132 struct zfheader { |
|
133 char flags; |
|
134 unsigned char bytes[2]; |
|
135 }; |
|
136 |
|
137 enum { |
|
138 ZFHD_MARK = 16, /* restart marker */ |
|
139 ZFHD_ERRS = 32, /* suspected errors in block */ |
|
140 ZFHD_EOFB = 64, /* block is end of record */ |
|
141 ZFHD_EORB = 128 /* block is end of file */ |
|
142 }; |
|
143 |
|
144 typedef int (*readwrite_t)(int, char *, off_t, int); |
|
145 |
|
146 struct zftpcmd { |
|
147 const char *nam; |
|
148 int (*fun) _((char *, char **, int)); |
|
149 int min, max, flags; |
|
150 }; |
|
151 |
|
152 enum { |
|
153 ZFTP_CONN = 0x0001, /* must be connected */ |
|
154 ZFTP_LOGI = 0x0002, /* must be logged in */ |
|
155 ZFTP_TBIN = 0x0004, /* set transfer type image */ |
|
156 ZFTP_TASC = 0x0008, /* set transfer type ASCII */ |
|
157 ZFTP_NLST = 0x0010, /* use NLST rather than LIST */ |
|
158 ZFTP_DELE = 0x0020, /* a delete rather than a make */ |
|
159 ZFTP_SITE = 0x0040, /* a site rather than a quote */ |
|
160 ZFTP_APPE = 0x0080, /* append rather than overwrite */ |
|
161 ZFTP_HERE = 0x0100, /* here rather than over there */ |
|
162 ZFTP_CDUP = 0x0200, /* CDUP rather than CWD */ |
|
163 ZFTP_REST = 0x0400, /* restart: set point in remote file */ |
|
164 ZFTP_RECV = 0x0800, /* receive rather than send */ |
|
165 ZFTP_TEST = 0x1000, /* test command, don't test */ |
|
166 ZFTP_SESS = 0x2000 /* session command, don't need status */ |
|
167 }; |
|
168 |
|
169 typedef struct zftpcmd *Zftpcmd; |
|
170 |
|
171 static struct zftpcmd zftpcmdtab[] = { |
|
172 { "open", zftp_open, 0, 4, 0 }, |
|
173 { "params", zftp_params, 0, 4, 0 }, |
|
174 { "login", zftp_login, 0, 3, ZFTP_CONN }, |
|
175 { "user", zftp_login, 0, 3, ZFTP_CONN }, |
|
176 { "test", zftp_test, 0, 0, ZFTP_TEST }, |
|
177 { "cd", zftp_cd, 1, 1, ZFTP_CONN|ZFTP_LOGI }, |
|
178 { "cdup", zftp_cd, 0, 0, ZFTP_CONN|ZFTP_LOGI|ZFTP_CDUP }, |
|
179 { "dir", zftp_dir, 0, -1, ZFTP_CONN|ZFTP_LOGI }, |
|
180 { "ls", zftp_dir, 0, -1, ZFTP_CONN|ZFTP_LOGI|ZFTP_NLST }, |
|
181 { "type", zftp_type, 0, 1, ZFTP_CONN|ZFTP_LOGI }, |
|
182 { "ascii", zftp_type, 0, 0, ZFTP_CONN|ZFTP_LOGI|ZFTP_TASC }, |
|
183 { "binary", zftp_type, 0, 0, ZFTP_CONN|ZFTP_LOGI|ZFTP_TBIN }, |
|
184 { "mode", zftp_mode, 0, 1, ZFTP_CONN|ZFTP_LOGI }, |
|
185 { "local", zftp_local, 0, -1, ZFTP_HERE }, |
|
186 { "remote", zftp_local, 1, -1, ZFTP_CONN|ZFTP_LOGI }, |
|
187 { "get", zftp_getput, 1, -1, ZFTP_CONN|ZFTP_LOGI|ZFTP_RECV }, |
|
188 { "getat", zftp_getput, 2, 2, ZFTP_CONN|ZFTP_LOGI|ZFTP_RECV|ZFTP_REST }, |
|
189 { "put", zftp_getput, 1, -1, ZFTP_CONN|ZFTP_LOGI }, |
|
190 { "putat", zftp_getput, 2, 2, ZFTP_CONN|ZFTP_LOGI|ZFTP_REST }, |
|
191 { "append", zftp_getput, 1, -1, ZFTP_CONN|ZFTP_LOGI|ZFTP_APPE }, |
|
192 { "appendat", zftp_getput, 2, 2, ZFTP_CONN|ZFTP_LOGI|ZFTP_APPE|ZFTP_REST }, |
|
193 { "delete", zftp_delete, 1, -1, ZFTP_CONN|ZFTP_LOGI }, |
|
194 { "mkdir", zftp_mkdir, 1, 1, ZFTP_CONN|ZFTP_LOGI }, |
|
195 { "rmdir", zftp_mkdir, 1, 1, ZFTP_CONN|ZFTP_LOGI|ZFTP_DELE }, |
|
196 { "rename", zftp_rename, 2, 2, ZFTP_CONN|ZFTP_LOGI }, |
|
197 { "quote", zftp_quote, 1, -1, ZFTP_CONN }, |
|
198 { "site", zftp_quote, 1, -1, ZFTP_CONN|ZFTP_SITE }, |
|
199 { "close", zftp_close, 0, 0, ZFTP_CONN }, |
|
200 { "quit", zftp_close, 0, 0, ZFTP_CONN }, |
|
201 { "session", zftp_session, 0, 1, ZFTP_SESS }, |
|
202 { "rmsession", zftp_rmsession, 0, 1, ZFTP_SESS }, |
|
203 { 0, 0, 0, 0, 0 } |
|
204 }; |
|
205 |
|
206 static struct builtin bintab[] = { |
|
207 BUILTIN("zftp", 0, bin_zftp, 1, -1, 0, NULL, NULL), |
|
208 }; |
|
209 |
|
210 /* |
|
211 * these are the non-special params to unset when a connection |
|
212 * closes. any special params are handled, well, specially. |
|
213 * currently there aren't any, which is the way I like it. |
|
214 */ |
|
215 static char *zfparams[] = { |
|
216 "ZFTP_HOST", "ZFTP_PORT", "ZFTP_IP", "ZFTP_SYSTEM", "ZFTP_USER", |
|
217 "ZFTP_ACCOUNT", "ZFTP_PWD", "ZFTP_TYPE", "ZFTP_MODE", NULL |
|
218 }; |
|
219 |
|
220 /* flags for zfsetparam */ |
|
221 |
|
222 enum { |
|
223 ZFPM_READONLY = 0x01, /* make parameter readonly */ |
|
224 ZFPM_IFUNSET = 0x02, /* only set if not already set */ |
|
225 ZFPM_INTEGER = 0x04 /* passed pointer to off_t */ |
|
226 }; |
|
227 |
|
228 /* Number of connections actually open */ |
|
229 static int zfnopen; |
|
230 |
|
231 /* |
|
232 * zcfinish = 0 keep going |
|
233 * 1 line finished, alles klar |
|
234 * 2 EOF |
|
235 */ |
|
236 static int zcfinish; |
|
237 /* zfclosing is set if zftp_close() is active */ |
|
238 static int zfclosing; |
|
239 |
|
240 /* |
|
241 * Stuff about last message: last line of message and status code. |
|
242 * The reply is also stored in $ZFTP_REPLY; we keep these separate |
|
243 * for convenience. |
|
244 */ |
|
245 static char *lastmsg, lastcodestr[4]; |
|
246 static int lastcode; |
|
247 |
|
248 /* remote system has size, mdtm commands */ |
|
249 enum { |
|
250 ZFCP_UNKN = 0, /* dunno if it works on this server */ |
|
251 ZFCP_YUPP = 1, /* it does */ |
|
252 ZFCP_NOPE = 2 /* it doesn't */ |
|
253 }; |
|
254 |
|
255 /* |
|
256 * We keep an fd open for communication between the main shell |
|
257 * and forked off bits and pieces. This allows us to know |
|
258 * if something happend in a subshell: mode changed, type changed, |
|
259 * connection was closed. If something too substantial happened |
|
260 * in a subshell --- connection opened, ZFTP_USER and ZFTP_PWD changed |
|
261 * --- we don't try to track it because it's too complicated. |
|
262 */ |
|
263 enum { |
|
264 ZFST_ASCI = 0x0000, /* type for next transfer is ASCII */ |
|
265 ZFST_IMAG = 0x0001, /* type for next transfer is image */ |
|
266 |
|
267 ZFST_TMSK = 0x0001, /* mask for type flags */ |
|
268 ZFST_TBIT = 0x0001, /* number of bits in type flags */ |
|
269 |
|
270 ZFST_CASC = 0x0000, /* current type is ASCII - default */ |
|
271 ZFST_CIMA = 0x0002, /* current type is image */ |
|
272 |
|
273 ZFST_STRE = 0x0000, /* stream mode - default */ |
|
274 ZFST_BLOC = 0x0004, /* block mode */ |
|
275 |
|
276 ZFST_MMSK = 0x0004, /* mask for mode flags */ |
|
277 |
|
278 ZFST_LOGI = 0x0008, /* user logged in */ |
|
279 ZFST_SYST = 0x0010, /* done system type check */ |
|
280 ZFST_NOPS = 0x0020, /* server doesn't understand PASV */ |
|
281 ZFST_NOSZ = 0x0040, /* server doesn't send `(XXXX bytes)' reply */ |
|
282 ZFST_TRSZ = 0x0080, /* tried getting 'size' from reply */ |
|
283 ZFST_CLOS = 0x0100 /* connection closed */ |
|
284 }; |
|
285 #define ZFST_TYPE(x) (x & ZFST_TMSK) |
|
286 /* |
|
287 * shift current type flags to match type flags: should be by |
|
288 * the number of bits in the type flags |
|
289 */ |
|
290 #define ZFST_CTYP(x) ((x >> ZFST_TBIT) & ZFST_TMSK) |
|
291 #define ZFST_MODE(x) (x & ZFST_MMSK) |
|
292 |
|
293 /* fd containing status for all sessions and array for internal use */ |
|
294 static int zfstatfd = -1, *zfstatusp; |
|
295 |
|
296 /* Preferences, read in from the `zftp_prefs' array variable */ |
|
297 enum { |
|
298 ZFPF_SNDP = 0x01, /* Use send port mode */ |
|
299 ZFPF_PASV = 0x02, /* Try using passive mode */ |
|
300 ZFPF_DUMB = 0x04 /* Don't do clever things with variables */ |
|
301 }; |
|
302 |
|
303 /* The flags as stored internally. */ |
|
304 static int zfprefs; |
|
305 |
|
306 /* |
|
307 * Data node for linked list of sessions. |
|
308 * |
|
309 * Memory management notes: |
|
310 * name is permanently allocated and remains for the life of the node. |
|
311 * userparams is set directly by zftp_params and also freed with the node. |
|
312 * params and its data are allocated when we need |
|
313 * to save an existing session, and are freed when we switch back |
|
314 * to that session. |
|
315 * The node itself is deleted when we remove it from the list. |
|
316 */ |
|
317 struct zftp_session { |
|
318 char *name; /* name of session */ |
|
319 char **params; /* parameters ordered as in zfparams */ |
|
320 char **userparams; /* user parameters set by zftp_params */ |
|
321 FILE *cin; /* control input file */ |
|
322 Tcp_session control; /* the control connection */ |
|
323 int dfd; /* data connection */ |
|
324 int has_size; /* understands SIZE? */ |
|
325 int has_mdtm; /* understands MDTM? */ |
|
326 }; |
|
327 |
|
328 /* List of active sessions */ |
|
329 static LinkList zfsessions; |
|
330 |
|
331 /* Current session */ |
|
332 static Zftp_session zfsess; |
|
333 |
|
334 /* Number of current session, corresponding to position in list */ |
|
335 static int zfsessno; |
|
336 |
|
337 /* Total number of sessions */ |
|
338 static int zfsesscnt; |
|
339 |
|
340 /* |
|
341 * Bits and pieces for dealing with SIGALRM (and SIGPIPE, but that's |
|
342 * easier). The complication is that SIGALRM may already be handled |
|
343 * by the user setting TMOUT and possibly setting their own trap --- in |
|
344 * fact, it's always handled by the shell when it's interactive. It's |
|
345 * too difficult to use zsh's own signal handler --- either it would |
|
346 * need rewriting to use a C function as a trap, or we would need a |
|
347 * hack to make it callback via a hidden builtin from a function --- so |
|
348 * just install our own, and use settrap() to restore the behaviour |
|
349 * afterwards if necessary. However, the more that could be done by |
|
350 * the main shell code, the better I would like it. |
|
351 * |
|
352 * Since we don't want to go through the palaver of changing between |
|
353 * the main zsh signal handler and ours every time we start or stop the |
|
354 * alarm, we keep the flag zfalarmed set to 1 while zftp is rigged to |
|
355 * handle alarms. This is tested at the end of bin_zftp(), which is |
|
356 * the entry point for all functions, and that restores the original |
|
357 * handler for SIGALRM. To turn off the alarm temporarily in the zftp |
|
358 * code we then just call alarm(0). |
|
359 * |
|
360 * If we could rely on having select() or some replacement, we would |
|
361 * only need the alarm during zftp_open(). |
|
362 */ |
|
363 |
|
364 /* flags for alarm set, alarm gone off */ |
|
365 int zfalarmed, zfdrrrring; |
|
366 /* remember old alarm status */ |
|
367 time_t oaltime; |
|
368 unsigned int oalremain; |
|
369 |
|
370 /* |
|
371 * Where to jump to when the alarm goes off. This is much |
|
372 * easier than fiddling with error flags at every turn. |
|
373 * Since we don't expect too many alarm's, the simple setjmp() |
|
374 * mechanism should be good enough. |
|
375 * |
|
376 * gcc -O gives apparently spurious `may be clobbered by longjmp' warnings. |
|
377 */ |
|
378 jmp_buf zfalrmbuf; |
|
379 |
|
380 /* The signal handler itself */ |
|
381 |
|
382 /**/ |
|
383 static RETSIGTYPE |
|
384 zfhandler(int sig) |
|
385 { |
|
386 if (sig == SIGALRM) { |
|
387 zfdrrrring = 1; |
|
388 #ifdef ETIMEDOUT /* just in case */ |
|
389 errno = ETIMEDOUT; |
|
390 #else |
|
391 errno = EIO; |
|
392 #endif |
|
393 longjmp(zfalrmbuf, 1); |
|
394 } |
|
395 DPUTS(1, "zfhandler caught incorrect signal"); |
|
396 } |
|
397 |
|
398 /* Set up for an alarm call */ |
|
399 |
|
400 /**/ |
|
401 static void |
|
402 zfalarm(int tmout) |
|
403 { |
|
404 zfdrrrring = 0; |
|
405 /* |
|
406 * We need to do this even if tmout is zero, since there may |
|
407 * be a non-zero timeout set in the main shell which we don't |
|
408 * want to go off. This could be argued the other way, since |
|
409 * if we don't get that it's probably harmless. But this looks safer. |
|
410 */ |
|
411 if (zfalarmed) { |
|
412 alarm(tmout); |
|
413 return; |
|
414 } |
|
415 #ifndef __SYMBIAN32__ |
|
416 signal(SIGALRM, zfhandler); |
|
417 #endif |
|
418 oalremain = alarm(tmout); |
|
419 if (oalremain) |
|
420 oaltime = time(NULL); |
|
421 /* |
|
422 * We'll leave sigtrapped, sigfuncs and TRAPXXX as they are; since the |
|
423 * shell's handler doesn't get the signal, they don't matter. |
|
424 */ |
|
425 zfalarmed = 1; |
|
426 } |
|
427 |
|
428 /* Set up for a broken pipe */ |
|
429 |
|
430 /**/ |
|
431 static void |
|
432 zfpipe() |
|
433 { |
|
434 /* Just ignore SIGPIPE and rely on getting EPIPE from the write. */ |
|
435 #ifndef __SYMBIAN32__ |
|
436 signal(SIGPIPE, SIG_IGN); |
|
437 #endif |
|
438 } |
|
439 |
|
440 /* Unset the alarm, see above */ |
|
441 |
|
442 /**/ |
|
443 static void |
|
444 zfunalarm(void) |
|
445 { |
|
446 if (oalremain) { |
|
447 /* |
|
448 * The alarm was previously set, so set it back, adjusting |
|
449 * for the time used. Mostly the alarm was set to zero |
|
450 * beforehand, so it would probably be best to reinstall |
|
451 * the proper signal handler before resetting the alarm. |
|
452 * |
|
453 * I love the way alarm() uses unsigned int while time_t |
|
454 * is probably something completely different. |
|
455 */ |
|
456 unsigned int tdiff = time(NULL) - oaltime; |
|
457 alarm(oalremain < tdiff ? 1 : oalremain - tdiff); |
|
458 } else |
|
459 alarm(0); |
|
460 if (sigtrapped[SIGALRM] || interact) { |
|
461 if (sigfuncs[SIGALRM] || !sigtrapped[SIGALRM]) |
|
462 install_handler(SIGALRM); |
|
463 else |
|
464 signal_ignore(SIGALRM); |
|
465 } else |
|
466 signal_default(SIGALRM); |
|
467 zfalarmed = 0; |
|
468 } |
|
469 |
|
470 /* Restore SIGPIPE handling to its usual status */ |
|
471 |
|
472 /**/ |
|
473 static void |
|
474 zfunpipe() |
|
475 { |
|
476 if (sigtrapped[SIGPIPE]) { |
|
477 if (sigfuncs[SIGPIPE]) |
|
478 install_handler(SIGPIPE); |
|
479 else |
|
480 signal_ignore(SIGPIPE); |
|
481 } else |
|
482 signal_default(SIGPIPE); |
|
483 } |
|
484 |
|
485 /* |
|
486 * Same as movefd(), but don't mark the fd in the zsh tables, |
|
487 * because we only want it closed by zftp. However, we still |
|
488 * need to shift the fd's out of the way of the user-visible 0-9. |
|
489 */ |
|
490 |
|
491 /**/ |
|
492 static int |
|
493 zfmovefd(int fd) |
|
494 { |
|
495 if (fd != -1 && fd < 10) { |
|
496 #ifdef F_DUPFD |
|
497 int fe = fcntl(fd, F_DUPFD, 10); |
|
498 #else |
|
499 int fe = zfmovefd(dup(fd)); |
|
500 #endif |
|
501 close(fd); |
|
502 fd = fe; |
|
503 } |
|
504 return fd; |
|
505 } |
|
506 |
|
507 /* |
|
508 * set a non-special parameter. |
|
509 * if ZFPM_IFUNSET, don't set if it already exists. |
|
510 * if ZFPM_READONLY, make it readonly, but only when creating it. |
|
511 * if ZFPM_INTEGER, val pointer is to off_t (NB not int), don't free. |
|
512 */ |
|
513 /**/ |
|
514 static void |
|
515 zfsetparam(char *name, void *val, int flags) |
|
516 { |
|
517 Param pm = NULL; |
|
518 int type = (flags & ZFPM_INTEGER) ? PM_INTEGER : PM_SCALAR; |
|
519 |
|
520 if (!(pm = (Param) paramtab->getnode(paramtab, name)) |
|
521 || (pm->flags & PM_UNSET)) { |
|
522 /* |
|
523 * just make it readonly when creating, in case user |
|
524 * *really* knows what they're doing |
|
525 */ |
|
526 if ((pm = createparam(name, type)) && (flags & ZFPM_READONLY)) |
|
527 pm->flags |= PM_READONLY; |
|
528 } else if (flags & ZFPM_IFUNSET) { |
|
529 pm = NULL; |
|
530 } |
|
531 if (!pm || PM_TYPE(pm->flags) != type) { |
|
532 /* parameters are funny, you just never know */ |
|
533 if (type == PM_SCALAR) |
|
534 zsfree((char *)val); |
|
535 return; |
|
536 } |
|
537 if (type == PM_INTEGER) |
|
538 pm->gsu.i->setfn(pm, *(off_t *)val); |
|
539 else |
|
540 pm->gsu.s->setfn(pm, (char *)val); |
|
541 } |
|
542 |
|
543 /* |
|
544 * Unset a ZFTP parameter when the connection is closed. |
|
545 * We only do this with connection-specific parameters. |
|
546 */ |
|
547 |
|
548 /**/ |
|
549 static void |
|
550 zfunsetparam(char *name) |
|
551 { |
|
552 Param pm; |
|
553 |
|
554 if ((pm = (Param) paramtab->getnode(paramtab, name))) { |
|
555 pm->flags &= ~PM_READONLY; |
|
556 unsetparam_pm(pm, 0, 1); |
|
557 } |
|
558 } |
|
559 |
|
560 /* |
|
561 * Join command and arguments to make a proper TELNET command line. |
|
562 * New line is in permanent storage. |
|
563 */ |
|
564 |
|
565 /**/ |
|
566 static char * |
|
567 zfargstring(char *cmd, char **args) |
|
568 { |
|
569 int clen = strlen(cmd) + 3; |
|
570 char *line, **aptr; |
|
571 |
|
572 for (aptr = args; *aptr; aptr++) |
|
573 clen += strlen(*aptr) + 1; |
|
574 line = zalloc(clen); |
|
575 strcpy(line, cmd); |
|
576 for (aptr = args; *aptr; aptr++) { |
|
577 strcat(line, " "); |
|
578 strcat(line, *aptr); |
|
579 } |
|
580 strcat(line, "\r\n"); |
|
581 |
|
582 return line; |
|
583 } |
|
584 |
|
585 /* |
|
586 * get a line on the control connection according to TELNET rules |
|
587 * Return status is first digit of FTP reply code |
|
588 */ |
|
589 |
|
590 /**/ |
|
591 static int |
|
592 zfgetline(char *ln, int lnsize, int tmout) |
|
593 { |
|
594 int ch, added = 0; |
|
595 /* current line point */ |
|
596 char *pcur = ln, cmdbuf[3]; |
|
597 |
|
598 zcfinish = 0; |
|
599 /* leave room for null byte */ |
|
600 lnsize--; |
|
601 /* in case we return unexpectedly before getting anything */ |
|
602 ln[0] = '\0'; |
|
603 |
|
604 if (setjmp(zfalrmbuf)) { |
|
605 alarm(0); |
|
606 zwarnnam("zftp", "timeout getting response", NULL, 0); |
|
607 return 6; |
|
608 } |
|
609 zfalarm(tmout); |
|
610 |
|
611 /* |
|
612 * We need to be more careful about errors here; we |
|
613 * should do the stuff with errflag and so forth. |
|
614 * We should probably holdintr() here, since if we don't |
|
615 * get the message, the connection is going to be messed up. |
|
616 * But then we get `frustrated user syndrome'. |
|
617 */ |
|
618 for (;;) { |
|
619 ch = fgetc(zfsess->cin); |
|
620 |
|
621 switch(ch) { |
|
622 case EOF: |
|
623 if (ferror(zfsess->cin) && errno == EINTR) { |
|
624 clearerr(zfsess->cin); |
|
625 continue; |
|
626 } |
|
627 zcfinish = 2; |
|
628 break; |
|
629 |
|
630 case '\r': |
|
631 /* always precedes something else */ |
|
632 ch = fgetc(zfsess->cin); |
|
633 if (ch == EOF) { |
|
634 zcfinish = 2; |
|
635 break; |
|
636 } |
|
637 if (ch == '\n') { |
|
638 zcfinish = 1; |
|
639 break; |
|
640 } |
|
641 if (ch == '\0') { |
|
642 ch = '\r'; |
|
643 break; |
|
644 } |
|
645 /* not supposed to get here */ |
|
646 ch = '\r'; |
|
647 break; |
|
648 |
|
649 case '\n': |
|
650 /* not supposed to get here */ |
|
651 zcfinish = 1; |
|
652 break; |
|
653 |
|
654 case IAC: |
|
655 /* |
|
656 * oh great, now it's sending TELNET commands. try |
|
657 * to persuade it not to. |
|
658 */ |
|
659 ch = fgetc(zfsess->cin); |
|
660 switch (ch) { |
|
661 case WILL: |
|
662 case WONT: |
|
663 ch = fgetc(zfsess->cin); |
|
664 /* whatever it wants to do, stop it. */ |
|
665 cmdbuf[0] = (char)IAC; |
|
666 cmdbuf[1] = (char)DONT; |
|
667 cmdbuf[2] = ch; |
|
668 write(zfsess->control->fd, cmdbuf, 3); |
|
669 continue; |
|
670 |
|
671 case DO: |
|
672 case DONT: |
|
673 ch = fgetc(zfsess->cin); |
|
674 /* well, tough, we're not going to. */ |
|
675 cmdbuf[0] = (char)IAC; |
|
676 cmdbuf[1] = (char)WONT; |
|
677 cmdbuf[2] = ch; |
|
678 write(zfsess->control->fd, cmdbuf, 3); |
|
679 continue; |
|
680 |
|
681 case EOF: |
|
682 /* strange machine. */ |
|
683 zcfinish = 2; |
|
684 break; |
|
685 |
|
686 default: |
|
687 break; |
|
688 } |
|
689 break; |
|
690 } |
|
691 |
|
692 if (zcfinish) |
|
693 break; |
|
694 if (added < lnsize) { |
|
695 *pcur++ = ch; |
|
696 added++; |
|
697 } |
|
698 /* junk it if we don't have room, but go on reading */ |
|
699 } |
|
700 |
|
701 alarm(0); |
|
702 |
|
703 *pcur = '\0'; |
|
704 /* if zcfinish == 2, at EOF, return that, else 0 */ |
|
705 return (zcfinish & 2); |
|
706 } |
|
707 |
|
708 /* |
|
709 * Get a whole message from the server. A dash after |
|
710 * the first line code means keep reading until we get |
|
711 * a line with the same code followed by a space. |
|
712 * |
|
713 * Note that this returns an FTP status code, the first |
|
714 * digit of the reply. There is also a pseudocode, 6, which |
|
715 * means `there's no point trying anything, just yet'. |
|
716 * We return it either if the connection is closed, or if |
|
717 * we got a 530 (user not logged in), in which case whatever |
|
718 * you're trying to do isn't going to work. |
|
719 */ |
|
720 |
|
721 /**/ |
|
722 static int |
|
723 zfgetmsg(void) |
|
724 { |
|
725 char line[256], *ptr, *verbose; |
|
726 int stopit, printing = 0, tmout; |
|
727 |
|
728 if (!zfsess->control) |
|
729 return 6; |
|
730 zsfree(lastmsg); |
|
731 lastmsg = NULL; |
|
732 |
|
733 tmout = getiparam("ZFTP_TMOUT"); |
|
734 |
|
735 zfgetline(line, 256, tmout); |
|
736 ptr = line; |
|
737 if (zfdrrrring || !isdigit(STOUC(*ptr)) || !isdigit(STOUC(ptr[1])) || |
|
738 !isdigit(STOUC(ptr[2]))) { |
|
739 /* timeout, or not talking FTP. not really interested. */ |
|
740 zcfinish = 2; |
|
741 if (!zfclosing) |
|
742 zfclose(0); |
|
743 lastmsg = ztrdup(""); |
|
744 strcpy(lastcodestr, "000"); |
|
745 zfsetparam("ZFTP_REPLY", ztrdup(lastmsg), ZFPM_READONLY); |
|
746 return 6; |
|
747 } |
|
748 strncpy(lastcodestr, ptr, 3); |
|
749 ptr += 3; |
|
750 lastcodestr[3] = '\0'; |
|
751 lastcode = atoi(lastcodestr); |
|
752 zfsetparam("ZFTP_CODE", ztrdup(lastcodestr), ZFPM_READONLY); |
|
753 stopit = (*ptr++ != '-'); |
|
754 |
|
755 queue_signals(); |
|
756 if (!(verbose = getsparam("ZFTP_VERBOSE"))) |
|
757 verbose = ""; |
|
758 if (strchr(verbose, lastcodestr[0])) { |
|
759 /* print the whole thing verbatim */ |
|
760 printing = 1; |
|
761 fputs(line, stderr); |
|
762 } else if (strchr(verbose, '0') && !stopit) { |
|
763 /* print multiline parts with the code stripped */ |
|
764 printing = 2; |
|
765 fputs(ptr, stderr); |
|
766 } |
|
767 unqueue_signals(); |
|
768 if (printing) |
|
769 fputc('\n', stderr); |
|
770 |
|
771 while (zcfinish != 2 && !stopit) { |
|
772 zfgetline(line, 256, tmout); |
|
773 ptr = line; |
|
774 if (zfdrrrring) { |
|
775 line[0] = '\0'; |
|
776 break; |
|
777 } |
|
778 |
|
779 if (!strncmp(lastcodestr, line, 3)) { |
|
780 if (line[3] == ' ') { |
|
781 stopit = 1; |
|
782 ptr += 4; |
|
783 } else if (line[3] == '-') |
|
784 ptr += 4; |
|
785 } else if (!strncmp(" ", line, 4)) |
|
786 ptr += 4; |
|
787 |
|
788 if (printing == 2) { |
|
789 if (!stopit) { |
|
790 fputs(ptr, stderr); |
|
791 fputc('\n', stderr); |
|
792 } |
|
793 } else if (printing) { |
|
794 fputs(line, stderr); |
|
795 fputc('\n', stderr); |
|
796 } |
|
797 } |
|
798 |
|
799 if (printing) |
|
800 fflush(stderr); |
|
801 |
|
802 /* The internal message is just the text. */ |
|
803 lastmsg = ztrdup(ptr); |
|
804 /* |
|
805 * The parameter is the whole thing, including the code. |
|
806 */ |
|
807 zfsetparam("ZFTP_REPLY", ztrdup(line), ZFPM_READONLY); |
|
808 /* |
|
809 * close the connection here if zcfinish == 2, i.e. EOF, |
|
810 * or if we get a 421 (service not available, closing connection), |
|
811 * but don't do it if it's expected (zfclosing set). |
|
812 */ |
|
813 if ((zcfinish == 2 || lastcode == 421) && !zfclosing) { |
|
814 zcfinish = 2; /* don't need to tell server */ |
|
815 zfclose(0); |
|
816 /* unexpected, so tell user */ |
|
817 zwarnnam("zftp", "remote server has closed connection", NULL, 0); |
|
818 return 6; |
|
819 } |
|
820 if (lastcode == 530) { |
|
821 /* user not logged in */ |
|
822 return 6; |
|
823 } |
|
824 /* |
|
825 * May as well handle this here, though it's pretty uncommon. |
|
826 * A 120 is something like "service ready in nnn minutes". |
|
827 * It means we just hang around waiting for another reply. |
|
828 */ |
|
829 if (lastcode == 120) { |
|
830 zwarnnam("zftp", "delay expected, waiting: %s", lastmsg, 0); |
|
831 return zfgetmsg(); |
|
832 } |
|
833 |
|
834 /* first digit of code determines success, failure, not in the mood... */ |
|
835 return lastcodestr[0] - '0'; |
|
836 } |
|
837 |
|
838 |
|
839 /* |
|
840 * Send a command and get the reply. |
|
841 * The command is expected to have the \r\n already tacked on. |
|
842 * Returns the status code for the reply. |
|
843 */ |
|
844 |
|
845 /**/ |
|
846 static int |
|
847 zfsendcmd(char *cmd) |
|
848 { |
|
849 /* |
|
850 * We use the fd directly; there's no point even using |
|
851 * stdio with line buffering, since we always send the |
|
852 * complete line in one string anyway. |
|
853 */ |
|
854 int ret, tmout; |
|
855 |
|
856 if (!zfsess->control) |
|
857 return 6; |
|
858 tmout = getiparam("ZFTP_TMOUT"); |
|
859 if (setjmp(zfalrmbuf)) { |
|
860 alarm(0); |
|
861 zwarnnam("zftp", "timeout sending message", NULL, 0); |
|
862 return 6; |
|
863 } |
|
864 zfalarm(tmout); |
|
865 ret = write(zfsess->control->fd, cmd, strlen(cmd)); |
|
866 alarm(0); |
|
867 |
|
868 if (ret <= 0) { |
|
869 zwarnnam("zftp send", "failure sending control message: %e", |
|
870 NULL, errno); |
|
871 return 6; |
|
872 } |
|
873 |
|
874 return zfgetmsg(); |
|
875 } |
|
876 |
|
877 |
|
878 /* Set up a data connection, return 1 for failure, 0 for success */ |
|
879 |
|
880 /**/ |
|
881 static int |
|
882 zfopendata(char *name, union tcp_sockaddr *zdsockp, int *is_passivep) |
|
883 { |
|
884 if (!(zfprefs & (ZFPF_SNDP|ZFPF_PASV))) { |
|
885 zwarnnam(name, "Must set preference S or P to transfer data", NULL, 0); |
|
886 return 1; |
|
887 } |
|
888 zfsess->dfd = socket(zfsess->control->peer.a.sa_family, SOCK_STREAM, 0); |
|
889 if (zfsess->dfd < 0) { |
|
890 zwarnnam(name, "can't get data socket: %e", NULL, errno); |
|
891 return 1; |
|
892 } |
|
893 |
|
894 if (!(zfstatusp[zfsessno] & ZFST_NOPS) && (zfprefs & ZFPF_PASV)) { |
|
895 char *psv_cmd; |
|
896 int err, salen; |
|
897 |
|
898 #ifdef SUPPORT_IPV6 |
|
899 if(zfsess->control->peer.a.sa_family == AF_INET6) |
|
900 psv_cmd = "EPSV\r\n"; |
|
901 else |
|
902 #endif /* SUPPORT_IPV6 */ |
|
903 psv_cmd = "PASV\r\n"; |
|
904 if (zfsendcmd(psv_cmd) == 6) |
|
905 return 1; |
|
906 else if (lastcode >= 500 && lastcode <= 504) { |
|
907 /* |
|
908 * Fall back to send port mode. That will |
|
909 * test the preferences for whether that's OK. |
|
910 */ |
|
911 zfstatusp[zfsessno] |= ZFST_NOPS; |
|
912 zfclosedata(); |
|
913 return zfopendata(name, zdsockp, is_passivep); |
|
914 } |
|
915 zdsockp->a.sa_family = zfsess->control->peer.a.sa_family; |
|
916 #ifdef SUPPORT_IPV6 |
|
917 if(zfsess->control->peer.a.sa_family == AF_INET6) { |
|
918 /* see RFC 2428 for explanation */ |
|
919 char const *ptr, *end; |
|
920 char delim, portbuf[6], *pbp; |
|
921 unsigned long portnum; |
|
922 ptr = strchr(lastmsg, '('); |
|
923 if(!ptr) { |
|
924 bad_epsv: |
|
925 zwarnnam(name, "bad response to EPSV: %s", lastmsg, 0); |
|
926 zfclosedata(); |
|
927 return 1; |
|
928 } |
|
929 delim = ptr[1]; |
|
930 if(delim < 33 || delim > 126 || ptr[2] != delim || ptr[3] != delim) |
|
931 goto bad_epsv; |
|
932 ptr += 4; |
|
933 end = strchr(ptr, delim); |
|
934 if(!end || end[1] != ')') |
|
935 goto bad_epsv; |
|
936 while(ptr != end && *ptr == '0') |
|
937 ptr++; |
|
938 if(ptr == end || (end-ptr) > 5 || !isdigit(STOUC(*ptr))) |
|
939 goto bad_epsv; |
|
940 memcpy(portbuf, ptr, (end-ptr)); |
|
941 portbuf[end-ptr] = 0; |
|
942 portnum = strtoul(portbuf, &pbp, 10); |
|
943 if(*pbp || portnum > 65535UL) |
|
944 goto bad_epsv; |
|
945 *zdsockp = zfsess->control->peer; |
|
946 zdsockp->in6.sin6_port = htons((unsigned)portnum); |
|
947 salen = sizeof(struct sockaddr_in6); |
|
948 } else |
|
949 #endif /* SUPPORT_IPV6 */ |
|
950 { |
|
951 char *ptr; |
|
952 int i, nums[6]; |
|
953 unsigned char iaddr[4], iport[2]; |
|
954 |
|
955 /* |
|
956 * OK, now we need to know what port we're looking at, |
|
957 * which is cunningly concealed in the reply. |
|
958 * lastmsg already has the reply code expunged. |
|
959 */ |
|
960 for (ptr = lastmsg; *ptr; ptr++) |
|
961 if (isdigit(STOUC(*ptr))) |
|
962 break; |
|
963 if (sscanf(ptr, "%d,%d,%d,%d,%d,%d", |
|
964 nums, nums+1, nums+2, nums+3, nums+4, nums+5) != 6) { |
|
965 zwarnnam(name, "bad response to PASV: %s", lastmsg, 0); |
|
966 zfclosedata(); |
|
967 return 1; |
|
968 } |
|
969 for (i = 0; i < 4; i++) |
|
970 iaddr[i] = STOUC(nums[i]); |
|
971 iport[0] = STOUC(nums[4]); |
|
972 iport[1] = STOUC(nums[5]); |
|
973 |
|
974 memcpy(&zdsockp->in.sin_addr, iaddr, sizeof(iaddr)); |
|
975 memcpy(&zdsockp->in.sin_port, iport, sizeof(iport)); |
|
976 salen = sizeof(struct sockaddr_in); |
|
977 } |
|
978 |
|
979 /* we should timeout this connect */ |
|
980 do { |
|
981 err = connect(zfsess->dfd, (struct sockaddr *)zdsockp, salen); |
|
982 } while (err && errno == EINTR && !errflag); |
|
983 |
|
984 if (err) { |
|
985 zwarnnam(name, "connect failed: %e", NULL, errno); |
|
986 zfclosedata(); |
|
987 return 1; |
|
988 } |
|
989 |
|
990 *is_passivep = 1; |
|
991 } else { |
|
992 #ifdef SUPPORT_IPV6 |
|
993 char portcmd[8+INET6_ADDRSTRLEN+9]; |
|
994 #else |
|
995 char portcmd[40]; |
|
996 #endif |
|
997 ZSOCKLEN_T len; |
|
998 int ret; |
|
999 |
|
1000 if (!(zfprefs & ZFPF_SNDP)) { |
|
1001 zwarnnam(name, "only sendport mode available for data", NULL, 0); |
|
1002 return 1; |
|
1003 } |
|
1004 |
|
1005 *zdsockp = zfsess->control->sock; |
|
1006 #ifdef SUPPORT_IPV6 |
|
1007 if(zdsockp->a.sa_family == AF_INET6) { |
|
1008 zdsockp->in6.sin6_port = 0; /* to be set by bind() */ |
|
1009 len = sizeof(struct sockaddr_in6); |
|
1010 } else |
|
1011 #endif /* SUPPORT_IPV6 */ |
|
1012 { |
|
1013 zdsockp->in.sin_port = 0; /* to be set by bind() */ |
|
1014 len = sizeof(struct sockaddr_in); |
|
1015 } |
|
1016 /* need to do timeout stuff and probably handle EINTR here */ |
|
1017 if (bind(zfsess->dfd, (struct sockaddr *)zdsockp, len) < 0) |
|
1018 ret = 1; |
|
1019 else if (getsockname(zfsess->dfd, (struct sockaddr *)zdsockp, |
|
1020 &len) < 0) |
|
1021 ret = 2; |
|
1022 else if (listen(zfsess->dfd, 1) < 0) |
|
1023 ret = 3; |
|
1024 else |
|
1025 ret = 0; |
|
1026 |
|
1027 if (ret) { |
|
1028 zwarnnam(name, "failure on data socket: %s: %e", |
|
1029 ret == 3 ? "listen" : ret == 2 ? "getsockname" : "bind", |
|
1030 errno); |
|
1031 zfclosedata(); |
|
1032 return 1; |
|
1033 } |
|
1034 |
|
1035 #ifdef SUPPORT_IPV6 |
|
1036 if(zdsockp->a.sa_family == AF_INET6) { |
|
1037 /* see RFC 2428 for explanation */ |
|
1038 strcpy(portcmd, "EPRT |2|"); |
|
1039 zsh_inet_ntop(AF_INET6, &zdsockp->in6.sin6_addr, |
|
1040 portcmd+8, INET6_ADDRSTRLEN); |
|
1041 sprintf(strchr(portcmd, 0), "|%u|\r\n", |
|
1042 (unsigned)ntohs(zdsockp->in6.sin6_port)); |
|
1043 } else |
|
1044 #endif /* SUPPORT_IPV6 */ |
|
1045 { |
|
1046 unsigned char *addr = (unsigned char *) &zdsockp->in.sin_addr; |
|
1047 unsigned char *port = (unsigned char *) &zdsockp->in.sin_port; |
|
1048 sprintf(portcmd, "PORT %d,%d,%d,%d,%d,%d\r\n", |
|
1049 addr[0],addr[1],addr[2],addr[3],port[0],port[1]); |
|
1050 } |
|
1051 if (zfsendcmd(portcmd) >= 5) { |
|
1052 zwarnnam(name, "port command failed", NULL, 0); |
|
1053 zfclosedata(); |
|
1054 return 1; |
|
1055 } |
|
1056 *is_passivep = 0; |
|
1057 } |
|
1058 |
|
1059 return 0; |
|
1060 } |
|
1061 |
|
1062 /* Close the data connection. */ |
|
1063 |
|
1064 /**/ |
|
1065 static void |
|
1066 zfclosedata(void) |
|
1067 { |
|
1068 if (zfsess->dfd == -1) |
|
1069 return; |
|
1070 close(zfsess->dfd); |
|
1071 zfsess->dfd = -1; |
|
1072 } |
|
1073 |
|
1074 /* |
|
1075 * Set up a data connection and use cmd to initiate a transfer. |
|
1076 * The actual data fd will be zfsess->dfd; the calling routine |
|
1077 * must handle the data itself. |
|
1078 * rest is a REST command to specify starting somewhere other |
|
1079 * then the start of the remote file. |
|
1080 * getsize is non-zero if we want to try to find the number |
|
1081 * of bytes in the reply to a RETR command. |
|
1082 * |
|
1083 * Return 0 on success, 1 on failure. |
|
1084 */ |
|
1085 |
|
1086 /**/ |
|
1087 static int |
|
1088 zfgetdata(char *name, char *rest, char *cmd, int getsize) |
|
1089 { |
|
1090 ZSOCKLEN_T len; |
|
1091 int newfd, is_passive; |
|
1092 union tcp_sockaddr zdsock; |
|
1093 |
|
1094 if (zfopendata(name, &zdsock, &is_passive)) |
|
1095 return 1; |
|
1096 |
|
1097 /* |
|
1098 * Set position in remote file for get/put. |
|
1099 * According to RFC959, the restart command needs something |
|
1100 * called a marker which has previously been put into the data. |
|
1101 * Luckily for the real world, UNIX machines just interpret this |
|
1102 * as an offset into the byte stream. |
|
1103 * |
|
1104 * This has to be sent immediately before the data transfer, i.e. |
|
1105 * after all mucking around with types and sizes and so on. |
|
1106 */ |
|
1107 if (rest && zfsendcmd(rest) > 3) { |
|
1108 zfclosedata(); |
|
1109 return 1; |
|
1110 } |
|
1111 |
|
1112 if (zfsendcmd(cmd) > 2) { |
|
1113 zfclosedata(); |
|
1114 return 1; |
|
1115 } |
|
1116 if (getsize || (!(zfstatusp[zfsessno] & ZFST_TRSZ) && |
|
1117 !strncmp(cmd, "RETR", 4))) { |
|
1118 /* |
|
1119 * See if we got something like: |
|
1120 * Opening data connection for nortypix.gif (1234567 bytes). |
|
1121 * On the first RETR, always see if this works, Then we |
|
1122 * can avoid sending a special SIZE command beforehand. |
|
1123 */ |
|
1124 char *ptr = strstr(lastmsg, "bytes"); |
|
1125 zfstatusp[zfsessno] |= ZFST_NOSZ|ZFST_TRSZ; |
|
1126 if (ptr) { |
|
1127 while (ptr > lastmsg && !isdigit(STOUC(*ptr))) |
|
1128 ptr--; |
|
1129 while (ptr > lastmsg && isdigit(STOUC(ptr[-1]))) |
|
1130 ptr--; |
|
1131 if (isdigit(STOUC(*ptr))) { |
|
1132 zfstatusp[zfsessno] &= ~ZFST_NOSZ; |
|
1133 if (getsize) { |
|
1134 off_t sz = zstrtol(ptr, NULL, 10); |
|
1135 zfsetparam("ZFTP_SIZE", &sz, ZFPM_READONLY|ZFPM_INTEGER); |
|
1136 } |
|
1137 } |
|
1138 } |
|
1139 } |
|
1140 |
|
1141 if (!is_passive) { |
|
1142 /* |
|
1143 * the current zfsess->dfd is the socket we opened, but we need |
|
1144 * to let the server set up a different fd for reading/writing. |
|
1145 * then we can close the fd we were listening for a connection on. |
|
1146 * don't expect me to understand this, i'm only the programmer. |
|
1147 */ |
|
1148 |
|
1149 /* accept the connection */ |
|
1150 len = sizeof(zdsock); |
|
1151 newfd = zfmovefd(accept(zfsess->dfd, (struct sockaddr *)&zdsock, |
|
1152 &len)); |
|
1153 if (newfd < 0) |
|
1154 zwarnnam(name, "unable to accept data: %e", NULL, errno); |
|
1155 zfclosedata(); |
|
1156 if (newfd < 0) |
|
1157 return 1; |
|
1158 zfsess->dfd = newfd; /* this is now the actual data fd */ |
|
1159 } else { |
|
1160 /* |
|
1161 * We avoided dup'ing zfsess->dfd up to this point, to try to keep |
|
1162 * things simple, so we now need to move it out of the way |
|
1163 * of the user-visible fd's. |
|
1164 */ |
|
1165 zfsess->dfd = zfmovefd(zfsess->dfd); |
|
1166 } |
|
1167 |
|
1168 |
|
1169 /* more options, just to look professional */ |
|
1170 #ifdef SO_LINGER |
|
1171 /* |
|
1172 * Since data can take arbitrary amounts of time to arrive, |
|
1173 * the socket can be made to hang around until it doesn't think |
|
1174 * anything is arriving. |
|
1175 * |
|
1176 * In BSD 4.3, you could only linger for infinity. Don't |
|
1177 * know if this has changed. |
|
1178 */ |
|
1179 { |
|
1180 struct linger li; |
|
1181 |
|
1182 li.l_onoff = 1; |
|
1183 li.l_linger = 120; |
|
1184 setsockopt(zfsess->dfd, SOL_SOCKET, SO_LINGER, |
|
1185 (char *)&li, sizeof(li)); |
|
1186 } |
|
1187 #endif |
|
1188 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT) |
|
1189 /* try to get high throughput, snigger */ |
|
1190 { |
|
1191 int arg = IPTOS_THROUGHPUT; |
|
1192 setsockopt(zfsess->dfd, IPPROTO_IP, IP_TOS, (char *)&arg, sizeof(arg)); |
|
1193 } |
|
1194 #endif |
|
1195 #if defined(F_SETFD) && defined(FD_CLOEXEC) |
|
1196 /* If the shell execs a program, we don't want this fd left open. */ |
|
1197 fcntl(zfsess->dfd, F_SETFD, FD_CLOEXEC); |
|
1198 #endif |
|
1199 |
|
1200 return 0; |
|
1201 } |
|
1202 |
|
1203 /* |
|
1204 * Find out about a local or remote file and pass back the information. |
|
1205 * |
|
1206 * We could jigger this to use ls like ncftp does as a backup. |
|
1207 * But if the server is non-standard enough not to have SIZE and MDTM, |
|
1208 * there's a very good chance ls -l isn't going to do great things. |
|
1209 * |
|
1210 * if fd is >= 0, it is used for an fstat when remote is zero: |
|
1211 * this is because on a put we are taking input from fd 0. |
|
1212 */ |
|
1213 |
|
1214 /**/ |
|
1215 static int |
|
1216 zfstats(char *fnam, int remote, off_t *retsize, char **retmdtm, int fd) |
|
1217 { |
|
1218 off_t sz = -1; |
|
1219 char *mt = NULL; |
|
1220 int ret; |
|
1221 |
|
1222 if (retsize) |
|
1223 *retsize = -1; |
|
1224 if (retmdtm) |
|
1225 *retmdtm = NULL; |
|
1226 if (remote) { |
|
1227 char *cmd; |
|
1228 if ((zfsess->has_size == ZFCP_NOPE && retsize) || |
|
1229 (zfsess->has_mdtm == ZFCP_NOPE && retmdtm)) |
|
1230 return 2; |
|
1231 |
|
1232 /* |
|
1233 * File is coming from over there. |
|
1234 * Make sure we get the type right. |
|
1235 */ |
|
1236 zfsettype(ZFST_TYPE(zfstatusp[zfsessno])); |
|
1237 if (retsize) { |
|
1238 cmd = tricat("SIZE ", fnam, "\r\n"); |
|
1239 ret = zfsendcmd(cmd); |
|
1240 zsfree(cmd); |
|
1241 if (ret == 6) |
|
1242 return 1; |
|
1243 else if (lastcode < 300) { |
|
1244 sz = zstrtol(lastmsg, 0, 10); |
|
1245 zfsess->has_size = ZFCP_YUPP; |
|
1246 } else if (lastcode >= 500 && lastcode <= 504) { |
|
1247 zfsess->has_size = ZFCP_NOPE; |
|
1248 return 2; |
|
1249 } else if (lastcode == 550) |
|
1250 return 1; |
|
1251 /* if we got a 550 from SIZE, the file doesn't exist */ |
|
1252 } |
|
1253 |
|
1254 if (retmdtm) { |
|
1255 cmd = tricat("MDTM ", fnam, "\r\n"); |
|
1256 ret = zfsendcmd(cmd); |
|
1257 zsfree(cmd); |
|
1258 if (ret == 6) |
|
1259 return 1; |
|
1260 else if (lastcode < 300) { |
|
1261 mt = ztrdup(lastmsg); |
|
1262 zfsess->has_mdtm = ZFCP_YUPP; |
|
1263 } else if (lastcode >= 500 && lastcode <= 504) { |
|
1264 zfsess->has_mdtm = ZFCP_NOPE; |
|
1265 return 2; |
|
1266 } else if (lastcode == 550) |
|
1267 return 1; |
|
1268 } |
|
1269 } else { |
|
1270 /* File is over here */ |
|
1271 struct stat statbuf; |
|
1272 struct tm *tm; |
|
1273 char tmbuf[20]; |
|
1274 |
|
1275 if ((fd == -1 ? stat(fnam, &statbuf) : fstat(fd, &statbuf)) < 0) |
|
1276 return 1; |
|
1277 /* make sure it's off_t, since this has to be a pointer */ |
|
1278 sz = statbuf.st_size; |
|
1279 |
|
1280 if (retmdtm) { |
|
1281 /* use gmtime() rather than localtime() for consistency */ |
|
1282 tm = gmtime(&statbuf.st_mtime); |
|
1283 /* |
|
1284 * FTP format for data is YYYYMMDDHHMMSS |
|
1285 * Using tm directly is easier than worrying about |
|
1286 * incompatible strftime()'s. |
|
1287 */ |
|
1288 sprintf(tmbuf, "%04d%02d%02d%02d%02d%02d", |
|
1289 tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, |
|
1290 tm->tm_hour, tm->tm_min, tm->tm_sec); |
|
1291 mt = ztrdup(tmbuf); |
|
1292 } |
|
1293 } |
|
1294 if (retsize) |
|
1295 *retsize = sz; |
|
1296 if (retmdtm) |
|
1297 *retmdtm = mt; |
|
1298 return 0; |
|
1299 } |
|
1300 |
|
1301 /* Set parameters to say what's coming */ |
|
1302 |
|
1303 /**/ |
|
1304 static void |
|
1305 zfstarttrans(char *nam, int recv, off_t sz) |
|
1306 { |
|
1307 off_t cnt = 0; |
|
1308 /* |
|
1309 * sz = -1 signifies error getting size. don't set ZFTP_SIZE if sz is |
|
1310 * zero, either: it probably came from an fstat() on a pipe, so it |
|
1311 * means we don't know and shouldn't tell the user porkies. |
|
1312 */ |
|
1313 if (sz > 0) |
|
1314 zfsetparam("ZFTP_SIZE", &sz, ZFPM_READONLY|ZFPM_INTEGER); |
|
1315 zfsetparam("ZFTP_FILE", ztrdup(nam), ZFPM_READONLY); |
|
1316 zfsetparam("ZFTP_TRANSFER", ztrdup(recv ? "G" : "P"), ZFPM_READONLY); |
|
1317 zfsetparam("ZFTP_COUNT", &cnt, ZFPM_READONLY|ZFPM_INTEGER); |
|
1318 } |
|
1319 |
|
1320 /* Tidy up afterwards */ |
|
1321 |
|
1322 /**/ |
|
1323 static void |
|
1324 zfendtrans() |
|
1325 { |
|
1326 zfunsetparam("ZFTP_SIZE"); |
|
1327 zfunsetparam("ZFTP_FILE"); |
|
1328 zfunsetparam("ZFTP_TRANSFER"); |
|
1329 zfunsetparam("ZFTP_COUNT"); |
|
1330 } |
|
1331 |
|
1332 /* Read with timeout if recv is set. */ |
|
1333 |
|
1334 /**/ |
|
1335 static int |
|
1336 zfread(int fd, char *bf, off_t sz, int tmout) |
|
1337 { |
|
1338 int ret; |
|
1339 |
|
1340 if (!tmout) |
|
1341 return read(fd, bf, sz); |
|
1342 |
|
1343 if (setjmp(zfalrmbuf)) { |
|
1344 alarm(0); |
|
1345 zwarnnam("zftp", "timeout on network read", NULL, 0); |
|
1346 return -1; |
|
1347 } |
|
1348 zfalarm(tmout); |
|
1349 |
|
1350 ret = read(fd, bf, sz); |
|
1351 |
|
1352 /* we don't bother turning off the whole alarm mechanism here */ |
|
1353 alarm(0); |
|
1354 return ret; |
|
1355 } |
|
1356 |
|
1357 /* Write with timeout if recv is not set. */ |
|
1358 |
|
1359 /**/ |
|
1360 static int |
|
1361 zfwrite(int fd, char *bf, off_t sz, int tmout) |
|
1362 { |
|
1363 int ret; |
|
1364 |
|
1365 if (!tmout) |
|
1366 return write(fd, bf, sz); |
|
1367 |
|
1368 if (setjmp(zfalrmbuf)) { |
|
1369 alarm(0); |
|
1370 zwarnnam("zftp", "timeout on network write", NULL, 0); |
|
1371 return -1; |
|
1372 } |
|
1373 zfalarm(tmout); |
|
1374 |
|
1375 ret = write(fd, bf, sz); |
|
1376 |
|
1377 /* we don't bother turning off the whole alarm mechanism here */ |
|
1378 alarm(0); |
|
1379 return ret; |
|
1380 } |
|
1381 |
|
1382 static int zfread_eof; |
|
1383 |
|
1384 /* Version of zfread when we need to read in block mode. */ |
|
1385 |
|
1386 /**/ |
|
1387 static int |
|
1388 zfread_block(int fd, char *bf, off_t sz, int tmout) |
|
1389 { |
|
1390 int n; |
|
1391 struct zfheader hdr; |
|
1392 off_t blksz, cnt; |
|
1393 char *bfptr; |
|
1394 do { |
|
1395 /* we need the header */ |
|
1396 do { |
|
1397 n = zfread(fd, (char *)&hdr, sizeof(hdr), tmout); |
|
1398 } while (n < 0 && errno == EINTR); |
|
1399 if (n != 3 && !zfdrrrring) { |
|
1400 zwarnnam("zftp", "failure reading FTP block header", NULL, 0); |
|
1401 return n; |
|
1402 } |
|
1403 /* size is stored in network byte order */ |
|
1404 if (hdr.flags & ZFHD_EOFB) |
|
1405 zfread_eof = 1; |
|
1406 blksz = (hdr.bytes[0] << 8) | hdr.bytes[1]; |
|
1407 if (blksz > sz) { |
|
1408 /* |
|
1409 * See comments in file headers |
|
1410 */ |
|
1411 zwarnnam("zftp", "block too large to handle", NULL, 0); |
|
1412 errno = EIO; |
|
1413 return -1; |
|
1414 } |
|
1415 bfptr = bf; |
|
1416 cnt = blksz; |
|
1417 while (cnt) { |
|
1418 n = zfread(fd, bfptr, cnt, tmout); |
|
1419 if (n > 0) { |
|
1420 bfptr += n; |
|
1421 cnt -= n; |
|
1422 } else if (n < 0 && (errflag || zfdrrrring || errno != EINTR)) |
|
1423 return n; |
|
1424 else |
|
1425 break; |
|
1426 } |
|
1427 if (cnt) { |
|
1428 zwarnnam("zftp", "short data block", NULL, 0); |
|
1429 errno = EIO; |
|
1430 return -1; |
|
1431 } |
|
1432 } while ((hdr.flags & ZFHD_MARK) && !zfread_eof); |
|
1433 return (hdr.flags & ZFHD_MARK) ? 0 : blksz; |
|
1434 } |
|
1435 |
|
1436 /* Version of zfwrite when we need to write in block mode. */ |
|
1437 |
|
1438 /**/ |
|
1439 static int |
|
1440 zfwrite_block(int fd, char *bf, off_t sz, int tmout) |
|
1441 { |
|
1442 int n; |
|
1443 struct zfheader hdr; |
|
1444 off_t cnt; |
|
1445 char *bfptr; |
|
1446 /* we need the header */ |
|
1447 do { |
|
1448 hdr.bytes[0] = (sz & 0xff00) >> 8; |
|
1449 hdr.bytes[1] = sz & 0xff; |
|
1450 hdr.flags = sz ? 0 : ZFHD_EOFB; |
|
1451 n = zfwrite(fd, (char *)&hdr, sizeof(hdr), tmout); |
|
1452 } while (n < 0 && errno == EINTR); |
|
1453 if (n != 3 && !zfdrrrring) { |
|
1454 zwarnnam("zftp", "failure writing FTP block header", NULL, 0); |
|
1455 return n; |
|
1456 } |
|
1457 bfptr = bf; |
|
1458 cnt = sz; |
|
1459 while (cnt) { |
|
1460 n = zfwrite(fd, bfptr, cnt, tmout); |
|
1461 if (n > 0) { |
|
1462 bfptr += n; |
|
1463 cnt -= n; |
|
1464 } else if (n < 0 && (errflag || zfdrrrring || errno != EINTR)) |
|
1465 return n; |
|
1466 } |
|
1467 |
|
1468 return sz; |
|
1469 } |
|
1470 |
|
1471 /* |
|
1472 * Move stuff from fdin to fdout, tidying up the data connection |
|
1473 * when finished. The data connection could be either input or output: |
|
1474 * recv is 1 for receiving a file, 0 for sending. |
|
1475 * |
|
1476 * progress is 1 to use a progress meter. |
|
1477 * startat says how far in we're starting with a REST command. |
|
1478 * |
|
1479 * Since we're doing some buffering here anyway, we don't bother |
|
1480 * with a stdio layer. |
|
1481 */ |
|
1482 |
|
1483 /**/ |
|
1484 static int |
|
1485 zfsenddata(char *name, int recv, int progress, off_t startat) |
|
1486 { |
|
1487 #define ZF_BUFSIZE 32768 |
|
1488 #define ZF_ASCSIZE (ZF_BUFSIZE/2) |
|
1489 /* ret = 2 signals the local read/write failed, so send abort */ |
|
1490 int n, ret = 0, gotack = 0, fdin, fdout, fromasc = 0, toasc = 0; |
|
1491 int rtmout = 0, wtmout = 0; |
|
1492 char lsbuf[ZF_BUFSIZE], *ascbuf = NULL, *optr; |
|
1493 off_t sofar = 0, last_sofar = 0; |
|
1494 readwrite_t read_ptr = zfread, write_ptr = zfwrite; |
|
1495 Eprog prog; |
|
1496 |
|
1497 if (progress && (prog = getshfunc("zftp_progress")) != &dummy_eprog) { |
|
1498 /* |
|
1499 * progress to set up: ZFTP_COUNT is zero. |
|
1500 * We do this here in case we needed to wait for a RETR |
|
1501 * command to tell us how many bytes are coming. |
|
1502 */ |
|
1503 int osc = sfcontext; |
|
1504 |
|
1505 sfcontext = SFC_HOOK; |
|
1506 doshfunc("zftp_progress", prog, NULL, 0, 1); |
|
1507 sfcontext = osc; |
|
1508 /* Now add in the bit of the file we've got/sent already */ |
|
1509 sofar = last_sofar = startat; |
|
1510 } |
|
1511 if (recv) { |
|
1512 fdin = zfsess->dfd; |
|
1513 fdout = 1; |
|
1514 rtmout = getiparam("ZFTP_TMOUT"); |
|
1515 if (ZFST_CTYP(zfstatusp[zfsessno]) == ZFST_ASCI) |
|
1516 fromasc = 1; |
|
1517 if (ZFST_MODE(zfstatusp[zfsessno]) == ZFST_BLOC) |
|
1518 read_ptr = zfread_block; |
|
1519 } else { |
|
1520 fdin = 0; |
|
1521 fdout = zfsess->dfd; |
|
1522 wtmout = getiparam("ZFTP_TMOUT"); |
|
1523 if (ZFST_CTYP(zfstatusp[zfsessno]) == ZFST_ASCI) |
|
1524 toasc = 1; |
|
1525 if (ZFST_MODE(zfstatusp[zfsessno]) == ZFST_BLOC) |
|
1526 write_ptr = zfwrite_block; |
|
1527 } |
|
1528 |
|
1529 if (toasc) |
|
1530 ascbuf = zalloc(ZF_ASCSIZE); |
|
1531 zfpipe(); |
|
1532 zfread_eof = 0; |
|
1533 while (!ret && !zfread_eof) { |
|
1534 n = (toasc) ? read_ptr(fdin, ascbuf, ZF_ASCSIZE, rtmout) |
|
1535 : read_ptr(fdin, lsbuf, ZF_BUFSIZE, rtmout); |
|
1536 if (n > 0) { |
|
1537 char *iptr; |
|
1538 if (toasc) { |
|
1539 /* \n -> \r\n it shouldn't happen to a dog. */ |
|
1540 char *iptr = ascbuf, *optr = lsbuf; |
|
1541 int cnt = n; |
|
1542 while (cnt--) { |
|
1543 if (*iptr == '\n') { |
|
1544 *optr++ = '\r'; |
|
1545 n++; |
|
1546 } |
|
1547 *optr++ = *iptr++; |
|
1548 } |
|
1549 } |
|
1550 if (fromasc && (iptr = memchr(lsbuf, '\r', n))) { |
|
1551 /* \r\n -> \n */ |
|
1552 char *optr = iptr; |
|
1553 int cnt = n - (iptr - lsbuf); |
|
1554 while (cnt--) { |
|
1555 if (*iptr != '\r' || iptr[1] != '\n') { |
|
1556 *optr++ = *iptr; |
|
1557 } else |
|
1558 n--; |
|
1559 iptr++; |
|
1560 } |
|
1561 } |
|
1562 optr = lsbuf; |
|
1563 |
|
1564 sofar += n; |
|
1565 |
|
1566 for (;;) { |
|
1567 /* |
|
1568 * in principle, write can be interrupted after |
|
1569 * safely writing some bytes, and will return the |
|
1570 * number already written, which may not be the |
|
1571 * complete buffer. so make this robust. they call me |
|
1572 * `robustness stephenson'. in my dreams. |
|
1573 */ |
|
1574 int newn = write_ptr(fdout, optr, n, wtmout); |
|
1575 if (newn == n) |
|
1576 break; |
|
1577 if (newn < 0) { |
|
1578 /* |
|
1579 * The somewhat contorted test here (for write) |
|
1580 * and below (for read) means: |
|
1581 * real error if |
|
1582 * - errno is set and it's not just an interrupt, or |
|
1583 * - errflag is set, probably due to CTRL-c, or |
|
1584 * - zfdrrrring is set, due to the alarm going off. |
|
1585 * print an error message if |
|
1586 * - not a timeout, since that was reported, and |
|
1587 * either |
|
1588 * - a non-interactive shell, where we don't |
|
1589 * know what happened otherwise |
|
1590 * - or both of |
|
1591 * - not errflag, i.e. CTRL-c or what have you, |
|
1592 * since the user probably knows about that, and |
|
1593 * - not a SIGPIPE, since usually people are |
|
1594 * silent about those when going to pagers |
|
1595 * (if you quit less or more in the middle |
|
1596 * and see an error message you think `I |
|
1597 * shouldn't have done that'). |
|
1598 * |
|
1599 * If we didn't print an error message here, |
|
1600 * and were going to do an abort (ret == 2) |
|
1601 * because the error happened on the local end |
|
1602 * of the connection, set ret to 3 and don't print |
|
1603 * the 'aborting...' either. |
|
1604 * |
|
1605 * There must be a better way of doing this. |
|
1606 */ |
|
1607 if (errno != EINTR || errflag || zfdrrrring) { |
|
1608 if (!zfdrrrring && |
|
1609 (!interact || (!errflag && errno != EPIPE))) { |
|
1610 ret = recv ? 2 : 1; |
|
1611 zwarnnam(name, "write failed: %e", NULL, errno); |
|
1612 } else |
|
1613 ret = recv ? 3 : 1; |
|
1614 break; |
|
1615 } |
|
1616 continue; |
|
1617 } |
|
1618 optr += newn; |
|
1619 n -= newn; |
|
1620 } |
|
1621 } else if (n < 0) { |
|
1622 if (errno != EINTR || errflag || zfdrrrring) { |
|
1623 if (!zfdrrrring && |
|
1624 (!interact || (!errflag && errno != EPIPE))) { |
|
1625 ret = recv ? 1 : 2; |
|
1626 zwarnnam(name, "read failed: %e", NULL, errno); |
|
1627 } else |
|
1628 ret = recv ? 1 : 3; |
|
1629 break; |
|
1630 } |
|
1631 } else |
|
1632 break; |
|
1633 if (!ret && sofar != last_sofar && progress && |
|
1634 (prog = getshfunc("zftp_progress")) != &dummy_eprog) { |
|
1635 int osc = sfcontext; |
|
1636 |
|
1637 zfsetparam("ZFTP_COUNT", &sofar, ZFPM_READONLY|ZFPM_INTEGER); |
|
1638 sfcontext = SFC_HOOK; |
|
1639 doshfunc("zftp_progress", prog, NULL, 0, 1); |
|
1640 sfcontext = osc; |
|
1641 last_sofar = sofar; |
|
1642 } |
|
1643 } |
|
1644 zfunpipe(); |
|
1645 /* |
|
1646 * At this point any timeout was on the data connection, |
|
1647 * so we don't need to force the control connection to close. |
|
1648 */ |
|
1649 zfdrrrring = 0; |
|
1650 if (!errflag && !ret && !recv && |
|
1651 ZFST_MODE(zfstatusp[zfsessno]) == ZFST_BLOC) { |
|
1652 /* send an end-of-file marker block */ |
|
1653 ret = (zfwrite_block(fdout, lsbuf, 0, wtmout) < 0); |
|
1654 } |
|
1655 if (errflag || ret > 1) { |
|
1656 /* |
|
1657 * some error occurred, maybe a keyboard interrupt, or |
|
1658 * a local file/pipe handling problem. |
|
1659 * send an abort. |
|
1660 * |
|
1661 * safest to block all signals here? can get frustrating if |
|
1662 * we're waiting for an abort. don't I know. let's start |
|
1663 * off just by blocking SIGINT's. |
|
1664 * |
|
1665 * maybe the timeout for the abort should be shorter than |
|
1666 * for normal commands. and what about aborting after |
|
1667 * we had a timeout on the data connection, is that |
|
1668 * really a good idea? |
|
1669 */ |
|
1670 /* RFC 959 says this is what to send */ |
|
1671 unsigned char msg[4] = { IAC, IP, IAC, SYNCH }; |
|
1672 |
|
1673 if (ret == 2) |
|
1674 zwarnnam(name, "aborting data transfer...", NULL, 0); |
|
1675 |
|
1676 holdintr(); |
|
1677 |
|
1678 /* the following is black magic, as far as I'm concerned. */ |
|
1679 /* what are we going to do if it fails? not a lot, actually. */ |
|
1680 send(zfsess->control->fd, (char *)msg, 3, 0); |
|
1681 send(zfsess->control->fd, (char *)msg+3, 1, MSG_OOB); |
|
1682 |
|
1683 zfsendcmd("ABOR\r\n"); |
|
1684 if (lastcode == 226) { |
|
1685 /* |
|
1686 * 226 is supposed to mean the transfer got sent OK after |
|
1687 * all, and the abort got ignored, at least that's what |
|
1688 * rfc959 seems to be saying. but in fact what can happen |
|
1689 * is the transfer finishes (at least as far as the |
|
1690 * server's concerned) and it's response is waiting, then |
|
1691 * the abort gets sent, and we need to mop up a response to |
|
1692 * that. so actually in most cases we get two replies |
|
1693 * anyway. we could test if we had select() on all hosts. |
|
1694 */ |
|
1695 /* gotack = 1; */ |
|
1696 /* |
|
1697 * we'd better leave errflag, since we don't know |
|
1698 * where it came from. maybe the user wants to abort |
|
1699 * a whole script or function. |
|
1700 */ |
|
1701 } else |
|
1702 ret = 1; |
|
1703 |
|
1704 noholdintr(); |
|
1705 } |
|
1706 |
|
1707 if (toasc) |
|
1708 zfree(ascbuf, ZF_ASCSIZE); |
|
1709 zfclosedata(); |
|
1710 if (!gotack && zfgetmsg() > 2) |
|
1711 ret = 1; |
|
1712 return ret != 0; |
|
1713 } |
|
1714 |
|
1715 /* Open a new control connection, i.e. start a new FTP session */ |
|
1716 |
|
1717 /**/ |
|
1718 static int |
|
1719 zftp_open(char *name, char **args, int flags) |
|
1720 { |
|
1721 struct protoent *zprotop; |
|
1722 struct servent *zservp; |
|
1723 struct hostent *zhostp = NULL; |
|
1724 char **addrp, *fname, *tmpptr, *portnam = "ftp"; |
|
1725 char *hostnam, *hostsuffix; |
|
1726 int err, tmout, port = -1; |
|
1727 ZSOCKLEN_T len; |
|
1728 int herrno, af, hlen; |
|
1729 |
|
1730 if (!*args) { |
|
1731 if (zfsess->userparams) |
|
1732 args = zfsess->userparams; |
|
1733 else { |
|
1734 zwarnnam(name, "no host specified", NULL, 0); |
|
1735 return 1; |
|
1736 } |
|
1737 } |
|
1738 |
|
1739 /* |
|
1740 * Close the existing connection if any. |
|
1741 * Probably this is the safest thing to do. It's possible |
|
1742 * a `QUIT' will hang, though. |
|
1743 */ |
|
1744 if (zfsess->control) |
|
1745 zfclose(0); |
|
1746 |
|
1747 hostnam = dupstring(args[0]); |
|
1748 /* |
|
1749 * Check for IPv6 address in square brackets (RFC2732). |
|
1750 * We are more lenient and allow any form for the host here. |
|
1751 */ |
|
1752 if (hostnam[0] == '[') { |
|
1753 hostnam++; |
|
1754 hostsuffix = strchr(hostnam, ']'); |
|
1755 if (!hostsuffix || (hostsuffix[1] && hostsuffix[1] != ':')) { |
|
1756 zwarnnam(name, "Invalid host format: %s", hostnam, 0); |
|
1757 return 1; |
|
1758 } |
|
1759 *hostsuffix++ = '\0'; |
|
1760 } |
|
1761 else |
|
1762 hostsuffix = hostnam; |
|
1763 |
|
1764 if ((tmpptr = strchr(hostsuffix, ':'))) { |
|
1765 char *endptr; |
|
1766 |
|
1767 *tmpptr++ = '\0'; |
|
1768 port = (int)zstrtol(tmpptr, &endptr, 10); |
|
1769 /* |
|
1770 * If the port is not numeric, look it up by name below. |
|
1771 */ |
|
1772 if (*endptr) { |
|
1773 portnam = tmpptr; |
|
1774 port = -1; |
|
1775 } |
|
1776 #if defined(HAVE_NTOHS) && defined(HAVE_HTONS) |
|
1777 else { |
|
1778 port = (int)htons((unsigned short)port); |
|
1779 } |
|
1780 #endif |
|
1781 } |
|
1782 |
|
1783 /* this is going to give 0. why bother? */ |
|
1784 zprotop = getprotobyname("tcp"); |
|
1785 if (!zprotop) { |
|
1786 zwarnnam(name, "Can't find protocol TCP (is your network functional)?", |
|
1787 NULL, 0); |
|
1788 return 1; |
|
1789 } |
|
1790 if (port < 0) |
|
1791 zservp = getservbyname(portnam, "tcp"); |
|
1792 else |
|
1793 zservp = getservbyport(port, "tcp"); |
|
1794 |
|
1795 if (!zprotop || !zservp) { |
|
1796 zwarnnam(name, "Can't find port for service `%s'", portnam, 0); |
|
1797 return 1; |
|
1798 } |
|
1799 |
|
1800 /* don't try talking to server yet */ |
|
1801 zcfinish = 2; |
|
1802 |
|
1803 /* |
|
1804 * This sets an alarm for the whole process, getting the host name |
|
1805 * as well as connecting. Arguably you could time them out separately. |
|
1806 */ |
|
1807 tmout = getiparam("ZFTP_TMOUT"); |
|
1808 if (setjmp(zfalrmbuf)) { |
|
1809 char *hname; |
|
1810 alarm(0); |
|
1811 queue_signals(); |
|
1812 if ((hname = getsparam("ZFTP_HOST")) && *hname) |
|
1813 zwarnnam(name, "timeout connecting to %s", hname, 0); |
|
1814 else |
|
1815 zwarnnam(name, "timeout on host name lookup", NULL, 0); |
|
1816 unqueue_signals(); |
|
1817 zfclose(0); |
|
1818 return 1; |
|
1819 } |
|
1820 zfalarm(tmout); |
|
1821 |
|
1822 #ifdef SUPPORT_IPV6 |
|
1823 for(af=AF_INET6; 1; af = AF_INET) |
|
1824 # define SUCCEEDED() break |
|
1825 # define FAILED() if(af == AF_INET) { } else continue |
|
1826 #else |
|
1827 af = AF_INET; |
|
1828 # define SUCCEEDED() do { } while(0) |
|
1829 # define FAILED() do { } while(0) |
|
1830 #endif |
|
1831 { |
|
1832 off_t tcp_port; |
|
1833 |
|
1834 zhostp = zsh_getipnodebyname(hostnam, af, 0, &herrno); |
|
1835 if (!zhostp || errflag) { |
|
1836 /* should use herror() here if available, but maybe |
|
1837 * needs configure test. on AIX it's present but not |
|
1838 * in headers. |
|
1839 * |
|
1840 * on the other hand, herror() is obsolete |
|
1841 */ |
|
1842 FAILED(); |
|
1843 zwarnnam(name, "host not found: %s", hostnam, 0); |
|
1844 alarm(0); |
|
1845 return 1; |
|
1846 } |
|
1847 zfsetparam("ZFTP_HOST", ztrdup(zhostp->h_name), ZFPM_READONLY); |
|
1848 /* careful with pointer types */ |
|
1849 #if defined(HAVE_NTOHS) && defined(HAVE_HTONS) |
|
1850 tcp_port = (off_t)ntohs((unsigned short)zservp->s_port); |
|
1851 #else |
|
1852 tcp_port = (off_t)zservp->s_port; |
|
1853 #endif |
|
1854 zfsetparam("ZFTP_PORT", &tcp_port, ZFPM_READONLY|ZFPM_INTEGER); |
|
1855 |
|
1856 #ifdef SUPPORT_IPV6 |
|
1857 if(af == AF_INET6) { |
|
1858 hlen = 16; |
|
1859 } else |
|
1860 #endif /* SUPPORT_IPV6 */ |
|
1861 { |
|
1862 hlen = 4; |
|
1863 } |
|
1864 |
|
1865 zfsess->control = tcp_socket(af, SOCK_STREAM, 0, ZTCP_ZFTP); |
|
1866 |
|
1867 if (!(zfsess->control) || (zfsess->control->fd < 0)) { |
|
1868 if (zfsess->control) { |
|
1869 tcp_close(zfsess->control); |
|
1870 zfsess->control = NULL; |
|
1871 } |
|
1872 freehostent(zhostp); |
|
1873 zfunsetparam("ZFTP_HOST"); |
|
1874 zfunsetparam("ZFTP_PORT"); |
|
1875 FAILED(); |
|
1876 zwarnnam(name, "socket failed: %e", NULL, errno); |
|
1877 alarm(0); |
|
1878 return 1; |
|
1879 } |
|
1880 /* counts as `open' so long as it's not negative */ |
|
1881 zfnopen++; |
|
1882 |
|
1883 /* |
|
1884 * now connect the socket. manual pages all say things like `this is |
|
1885 * all explained oh-so-wonderfully in some other manual page'. not. |
|
1886 */ |
|
1887 |
|
1888 err = 1; |
|
1889 |
|
1890 /* try all possible IP's */ |
|
1891 for (addrp = zhostp->h_addr_list; err && *addrp; addrp++) { |
|
1892 if(hlen != zhostp->h_length) |
|
1893 zwarnnam(name, "address length mismatch", NULL, 0); |
|
1894 do { |
|
1895 err = tcp_connect(zfsess->control, *addrp, zhostp, zservp->s_port); } while (err && errno == EINTR && !errflag); |
|
1896 /* you can check whether it's worth retrying here */ |
|
1897 } |
|
1898 |
|
1899 if (err) { |
|
1900 freehostent(zhostp); |
|
1901 zfclose(0); |
|
1902 FAILED(); |
|
1903 zwarnnam(name, "connect failed: %e", NULL, errno); |
|
1904 alarm(0); |
|
1905 return 1; |
|
1906 } |
|
1907 |
|
1908 SUCCEEDED(); |
|
1909 } |
|
1910 alarm(0); |
|
1911 { |
|
1912 #ifdef SUPPORT_IPV6 |
|
1913 char pbuf[INET6_ADDRSTRLEN]; |
|
1914 #else |
|
1915 char pbuf[INET_ADDRSTRLEN]; |
|
1916 #endif |
|
1917 addrp--; |
|
1918 zsh_inet_ntop(af, *addrp, pbuf, sizeof(pbuf)); |
|
1919 zfsetparam("ZFTP_IP", ztrdup(pbuf), ZFPM_READONLY); |
|
1920 } |
|
1921 freehostent(zhostp); |
|
1922 /* now we can talk to the control connection */ |
|
1923 zcfinish = 0; |
|
1924 |
|
1925 /* |
|
1926 * Move the fd out of the user-visible range. We need to do |
|
1927 * this after the connect() on some systems. |
|
1928 */ |
|
1929 zfsess->control->fd = zfmovefd(zfsess->control->fd); |
|
1930 |
|
1931 #if defined(F_SETFD) && defined(FD_CLOEXEC) |
|
1932 /* If the shell execs a program, we don't want this fd left open. */ |
|
1933 fcntl(zfsess->control->fd, F_SETFD, FD_CLOEXEC); |
|
1934 #endif |
|
1935 |
|
1936 len = sizeof(zfsess->control->sock); |
|
1937 if (getsockname(zfsess->control->fd, (struct sockaddr *)&zfsess->control->sock, &len) < 0) { |
|
1938 zwarnnam(name, "getsockname failed: %e", NULL, errno); |
|
1939 zfclose(0); |
|
1940 return 1; |
|
1941 } |
|
1942 /* nice to get some options right, ignore if they don't work */ |
|
1943 #ifdef SO_OOBINLINE |
|
1944 /* |
|
1945 * this says we want messages in line. maybe sophisticated people |
|
1946 * do clever things with SIGURG. |
|
1947 */ |
|
1948 len = 1; |
|
1949 setsockopt(zfsess->control->fd, SOL_SOCKET, SO_OOBINLINE, |
|
1950 (char *)&len, sizeof(len)); |
|
1951 #endif |
|
1952 #if defined(IP_TOS) && defined(IPTOS_LOWDELAY) |
|
1953 /* for control connection we want low delay. please don't laugh. */ |
|
1954 len = IPTOS_LOWDELAY; |
|
1955 setsockopt(zfsess->control->fd, IPPROTO_IP, IP_TOS, (char *)&len, sizeof(len)); |
|
1956 #endif |
|
1957 |
|
1958 /* |
|
1959 * We use stdio with line buffering for convenience on input. |
|
1960 * On output, we can just dump a complete message to the fd via write(). |
|
1961 */ |
|
1962 zfsess->cin = fdopen(zfsess->control->fd, "r"); |
|
1963 |
|
1964 if (!zfsess->cin) { |
|
1965 zwarnnam(name, "file handling error", NULL, 0); |
|
1966 zfclose(0); |
|
1967 return 1; |
|
1968 } |
|
1969 |
|
1970 #ifdef _IONBF |
|
1971 setvbuf(zfsess->cin, NULL, _IONBF, 0); |
|
1972 #else |
|
1973 setlinebuf(zfsess->cin); |
|
1974 #endif |
|
1975 |
|
1976 /* |
|
1977 * now see what the remote server has to say about that. |
|
1978 */ |
|
1979 if (zfgetmsg() >= 4) { |
|
1980 zfclose(0); |
|
1981 return 1; |
|
1982 } |
|
1983 |
|
1984 zfsess->has_size = zfsess->has_mdtm = ZFCP_UNKN; |
|
1985 zfsess->dfd = -1; |
|
1986 /* initial status: open, ASCII data, stream mode 'n' stuff */ |
|
1987 zfstatusp[zfsessno] = 0; |
|
1988 |
|
1989 /* |
|
1990 * Open file for saving the current status. |
|
1991 * We keep this open at the end of the session because |
|
1992 * it is used to store the status for all sessions. |
|
1993 * However, it is closed whenever there are no connections open. |
|
1994 */ |
|
1995 if (zfstatfd == -1) { |
|
1996 zfstatfd = gettempfile(NULL, 1, &fname); |
|
1997 DPUTS(zfstatfd == -1, "zfstatfd not created"); |
|
1998 #if defined(F_SETFD) && defined(FD_CLOEXEC) |
|
1999 /* If the shell execs a program, we don't want this fd left open. */ |
|
2000 fcntl(zfstatfd, F_SETFD, FD_CLOEXEC); |
|
2001 #endif |
|
2002 unlink(fname); |
|
2003 } |
|
2004 |
|
2005 if (zfsess->control->fd == -1) { |
|
2006 /* final paranoid check */ |
|
2007 tcp_close(zfsess->control); |
|
2008 zfsess->control = NULL; |
|
2009 zfnopen--; |
|
2010 } else { |
|
2011 zfsetparam("ZFTP_MODE", ztrdup("S"), ZFPM_READONLY); |
|
2012 /* if remaining arguments, use them to log in. */ |
|
2013 if (*++args) |
|
2014 return zftp_login(name, args, flags); |
|
2015 } |
|
2016 /* if something wayward happened, connection was already closed */ |
|
2017 return !zfsess->control; |
|
2018 } |
|
2019 |
|
2020 /* |
|
2021 * Read a parameter string, with a prompt if reading from stdin. |
|
2022 * The returned string is on the heap. |
|
2023 * If noecho, turn off ECHO mode while reading. |
|
2024 */ |
|
2025 |
|
2026 /**/ |
|
2027 static char * |
|
2028 zfgetinfo(char *prompt, int noecho) |
|
2029 { |
|
2030 int resettty = 0; |
|
2031 /* 256 characters should be enough, hardly worth allocating |
|
2032 * a password string byte by byte |
|
2033 */ |
|
2034 char instr[256], *strret; |
|
2035 int len; |
|
2036 |
|
2037 /* |
|
2038 * Only print the prompt if getting info from a tty. Of |
|
2039 * course, we don't know if stderr has been redirected, but |
|
2040 * that seems a minor point. |
|
2041 */ |
|
2042 if (isatty(0)) { |
|
2043 if (noecho) { |
|
2044 /* hmmm... all this great big shell and we have to read |
|
2045 * something with no echo by ourselves. |
|
2046 * bin_read() is far to complicated for our needs. |
|
2047 * we could use zread(), but that relies on static |
|
2048 * variables, so someone doesn't want that to happen. |
|
2049 * |
|
2050 * this is modified from setcbreak() in utils.c, |
|
2051 * except I don't see any point in using cbreak mode |
|
2052 */ |
|
2053 struct ttyinfo ti; |
|
2054 |
|
2055 ti = shttyinfo; |
|
2056 #ifdef HAS_TIO |
|
2057 ti.tio.c_lflag &= ~ECHO; |
|
2058 #else |
|
2059 ti.sgttyb.sg_flags &= ~ECHO; |
|
2060 #endif |
|
2061 settyinfo(&ti); |
|
2062 resettty = 1; |
|
2063 } |
|
2064 fflush(stdin); |
|
2065 fputs(prompt, stderr); |
|
2066 fflush(stderr); |
|
2067 } |
|
2068 |
|
2069 fgets(instr, 256, stdin); |
|
2070 if (instr[len = strlen(instr)-1] == '\n') |
|
2071 instr[len] = '\0'; |
|
2072 |
|
2073 strret = dupstring(instr); |
|
2074 |
|
2075 if (resettty) { |
|
2076 /* '\n' didn't get echoed */ |
|
2077 fputc('\n', stdout); |
|
2078 fflush(stdout); |
|
2079 settyinfo(&shttyinfo); |
|
2080 } |
|
2081 |
|
2082 return strret; |
|
2083 } |
|
2084 |
|
2085 /* |
|
2086 * set params for an open with no arguments. |
|
2087 * this allows easy re-opens. |
|
2088 */ |
|
2089 |
|
2090 /**/ |
|
2091 static int |
|
2092 zftp_params(UNUSED(char *name), char **args, UNUSED(int flags)) |
|
2093 { |
|
2094 char *prompts[] = { "Host: ", "User: ", "Password: ", "Account: " }; |
|
2095 char **aptr, **newarr; |
|
2096 int i, j, len; |
|
2097 |
|
2098 if (!*args) { |
|
2099 if (zfsess->userparams) { |
|
2100 for (aptr = zfsess->userparams, i = 0; *aptr; aptr++, i++) { |
|
2101 if (i == 2) { |
|
2102 len = strlen(*aptr); |
|
2103 for (j = 0; j < len; j++) |
|
2104 fputc('*', stdout); |
|
2105 fputc('\n', stdout); |
|
2106 } else |
|
2107 fprintf(stdout, "%s\n", *aptr); |
|
2108 } |
|
2109 return 0; |
|
2110 } else |
|
2111 return 1; |
|
2112 } |
|
2113 if (!strcmp(*args, "-")) { |
|
2114 if (zfsess->userparams) |
|
2115 freearray(zfsess->userparams); |
|
2116 zfsess->userparams = 0; |
|
2117 return 0; |
|
2118 } |
|
2119 len = arrlen(args); |
|
2120 newarr = (char **)zshcalloc((len+1)*sizeof(char *)); |
|
2121 for (aptr = args, i = 0; *aptr && !errflag; aptr++, i++) { |
|
2122 char *str; |
|
2123 if (**aptr == '?') |
|
2124 str = zfgetinfo((*aptr)[1] ? (*aptr+1) : prompts[i], i == 2); |
|
2125 else |
|
2126 str = (**aptr == '\\') ? *aptr+1 : *aptr; |
|
2127 newarr[i] = ztrdup(str); |
|
2128 } |
|
2129 if (errflag) { |
|
2130 /* maybe user CTRL-c'd in the middle somewhere */ |
|
2131 for (aptr = newarr; *aptr; aptr++) |
|
2132 zsfree(*aptr); |
|
2133 zfree(newarr, len+1); |
|
2134 return 1; |
|
2135 } |
|
2136 if (zfsess->userparams) |
|
2137 freearray(zfsess->userparams); |
|
2138 zfsess->userparams = newarr; |
|
2139 return 0; |
|
2140 } |
|
2141 |
|
2142 /* login a user: often called as part of the open sequence */ |
|
2143 |
|
2144 /**/ |
|
2145 static int |
|
2146 zftp_login(char *name, char **args, UNUSED(int flags)) |
|
2147 { |
|
2148 char *ucmd, *passwd = NULL, *acct = NULL; |
|
2149 char *user, tbuf[2] = "X"; |
|
2150 int stopit; |
|
2151 |
|
2152 if ((zfstatusp[zfsessno] & ZFST_LOGI) && zfsendcmd("REIN\r\n") >= 4) |
|
2153 return 1; |
|
2154 |
|
2155 zfstatusp[zfsessno] &= ~ZFST_LOGI; |
|
2156 if (*args) { |
|
2157 user = *args++; |
|
2158 } else { |
|
2159 user = zfgetinfo("User: ", 0); |
|
2160 } |
|
2161 |
|
2162 ucmd = tricat("USER ", user, "\r\n"); |
|
2163 stopit = 0; |
|
2164 |
|
2165 if (zfsendcmd(ucmd) == 6) |
|
2166 stopit = 2; |
|
2167 |
|
2168 while (!stopit && !errflag) { |
|
2169 switch (lastcode) { |
|
2170 case 230: /* user logged in */ |
|
2171 case 202: /* command not implemented, don't care */ |
|
2172 stopit = 1; |
|
2173 break; |
|
2174 |
|
2175 case 331: /* need password */ |
|
2176 if (*args) |
|
2177 passwd = *args++; |
|
2178 else |
|
2179 passwd = zfgetinfo("Password: ", 1); |
|
2180 zsfree(ucmd); |
|
2181 ucmd = tricat("PASS ", passwd, "\r\n"); |
|
2182 if (zfsendcmd(ucmd) == 6) |
|
2183 stopit = 2; |
|
2184 break; |
|
2185 |
|
2186 case 332: /* need account */ |
|
2187 case 532: |
|
2188 if (*args) |
|
2189 acct = *args++; |
|
2190 else |
|
2191 acct = zfgetinfo("Account: ", 0); |
|
2192 zsfree(ucmd); |
|
2193 ucmd = tricat("ACCT ", passwd, "\r\n"); |
|
2194 if (zfsendcmd(ucmd) == 6) |
|
2195 stopit = 2; |
|
2196 break; |
|
2197 |
|
2198 case 421: /* service not available, so closed anyway */ |
|
2199 case 501: /* syntax error */ |
|
2200 case 503: /* bad commands */ |
|
2201 case 530: /* not logged in */ |
|
2202 case 550: /* random can't-do-that */ |
|
2203 default: /* whatever, should flag this as bad karma */ |
|
2204 /* need more diagnostics here */ |
|
2205 stopit = 2; |
|
2206 break; |
|
2207 } |
|
2208 } |
|
2209 |
|
2210 zsfree(ucmd); |
|
2211 if (!zfsess->control) |
|
2212 return 1; |
|
2213 if (stopit == 2 || (lastcode != 230 && lastcode != 202)) { |
|
2214 zwarnnam(name, "login failed", NULL, 0); |
|
2215 return 1; |
|
2216 } |
|
2217 |
|
2218 if (*args) { |
|
2219 int cnt; |
|
2220 for (cnt = 0; *args; args++) |
|
2221 cnt++; |
|
2222 zwarnnam(name, "warning: %d comand arguments not used\n", NULL, cnt); |
|
2223 } |
|
2224 zfstatusp[zfsessno] |= ZFST_LOGI; |
|
2225 zfsetparam("ZFTP_USER", ztrdup(user), ZFPM_READONLY); |
|
2226 if (acct) |
|
2227 zfsetparam("ZFTP_ACCOUNT", ztrdup(acct), ZFPM_READONLY); |
|
2228 |
|
2229 /* |
|
2230 * Now find out what system we're connected to. Some systems |
|
2231 * won't let us do this until we're logged in; it's fairly safe |
|
2232 * to delay it here for all systems. |
|
2233 */ |
|
2234 if (!(zfprefs & ZFPF_DUMB) && !(zfstatusp[zfsessno] & ZFST_SYST)) { |
|
2235 if (zfsendcmd("SYST\r\n") == 2) { |
|
2236 char *ptr = lastmsg, *eptr, *systype; |
|
2237 for (eptr = ptr; *eptr; eptr++) |
|
2238 ; |
|
2239 systype = ztrduppfx(ptr, eptr-ptr); |
|
2240 if (!strncmp(systype, "UNIX Type: L8", 13)) { |
|
2241 /* |
|
2242 * Use binary for transfers. This simple test saves much |
|
2243 * hassle for all concerned, particularly me. |
|
2244 * |
|
2245 * We could set this based just on the UNIX part, |
|
2246 * but I don't really know the consequences of that. |
|
2247 */ |
|
2248 zfstatusp[zfsessno] |= ZFST_IMAG; |
|
2249 } |
|
2250 zfsetparam("ZFTP_SYSTEM", systype, ZFPM_READONLY); |
|
2251 } |
|
2252 zfstatusp[zfsessno] |= ZFST_SYST; |
|
2253 } |
|
2254 tbuf[0] = (ZFST_TYPE(zfstatusp[zfsessno]) == ZFST_ASCI) ? 'A' : 'I'; |
|
2255 zfsetparam("ZFTP_TYPE", ztrdup(tbuf), ZFPM_READONLY); |
|
2256 |
|
2257 /* |
|
2258 * Get the directory. This is possibly an unnecessary overhead, of |
|
2259 * course, but when you're being driven by shell functions there's |
|
2260 * just no way of telling. |
|
2261 */ |
|
2262 return zfgetcwd(); |
|
2263 } |
|
2264 |
|
2265 /* |
|
2266 * See if the server wants to tell us something. On a timeout, we usually |
|
2267 * have a `421 Timeout' or something such waiting for us, so we read |
|
2268 * it here. As well as being called explicitly by the user |
|
2269 * (precmd is a very good place for this, it's cheap since it has |
|
2270 * no network overhead), we call it in the bin_zftp front end if we |
|
2271 * have a connection and weren't going to call it anyway. |
|
2272 * |
|
2273 * Poll-free and select-free systems are few and far between these days, |
|
2274 * but I'm willing to consider suggestions. |
|
2275 */ |
|
2276 |
|
2277 /**/ |
|
2278 static int |
|
2279 zftp_test(UNUSED(char *name), UNUSED(char **args), UNUSED(int flags)) |
|
2280 { |
|
2281 #if defined(HAVE_POLL) || defined(HAVE_SELECT) |
|
2282 int ret; |
|
2283 # ifdef HAVE_POLL |
|
2284 struct pollfd pfd; |
|
2285 # else |
|
2286 fd_set f; |
|
2287 struct timeval tv; |
|
2288 # endif /* HAVE_POLL */ |
|
2289 |
|
2290 if (!zfsess->control) |
|
2291 return 1; |
|
2292 |
|
2293 # ifdef HAVE_POLL |
|
2294 # ifndef POLLIN |
|
2295 /* safety first, though I think POLLIN is more common */ |
|
2296 # define POLLIN POLLNORM |
|
2297 # endif /* HAVE_POLL */ |
|
2298 pfd.fd = zfsess->control->fd; |
|
2299 pfd.events = POLLIN; |
|
2300 if ((ret = poll(&pfd, 1, 0)) < 0 && errno != EINTR && errno != EAGAIN) |
|
2301 zfclose(0); |
|
2302 else if (ret > 0 && pfd.revents) { |
|
2303 /* handles 421 (maybe a bit noisily?) */ |
|
2304 zfgetmsg(); |
|
2305 } |
|
2306 # else |
|
2307 FD_ZERO(&f); |
|
2308 FD_SET(zfsess->control->fd, &f); |
|
2309 tv.tv_sec = 0; |
|
2310 tv.tv_usec = 0; |
|
2311 if ((ret = select(zfsess->control->fd +1, (SELECT_ARG_2_T) &f, |
|
2312 NULL, NULL, &tv)) < 0 |
|
2313 && errno != EINTR) |
|
2314 zfclose(0); |
|
2315 else if (ret > 0) { |
|
2316 /* handles 421 */ |
|
2317 zfgetmsg(); |
|
2318 } |
|
2319 # endif /* HAVE_POLL */ |
|
2320 /* if we have no zfsess->control, then we've just been dumped out. */ |
|
2321 return zfsess->control ? 0 : 2; |
|
2322 #else |
|
2323 zfwarnnam(name, "not supported on this system.", NULL, 0); |
|
2324 return 3; |
|
2325 #endif /* defined(HAVE_POLL) || defined(HAVE_SELECT) */ |
|
2326 } |
|
2327 |
|
2328 |
|
2329 /* do ls or dir on the remote directory */ |
|
2330 |
|
2331 /**/ |
|
2332 static int |
|
2333 zftp_dir(char *name, char **args, int flags) |
|
2334 { |
|
2335 /* maybe should be cleverer about handling arguments */ |
|
2336 char *cmd; |
|
2337 int ret; |
|
2338 |
|
2339 /* |
|
2340 * RFC959 says this must be ASCII or EBCDIC, not image format. |
|
2341 * I rather suspect on a UNIX server we get away handsomely |
|
2342 * with doing everything, including this, as image. |
|
2343 */ |
|
2344 zfsettype(ZFST_ASCI); |
|
2345 |
|
2346 cmd = zfargstring((flags & ZFTP_NLST) ? "NLST" : "LIST", args); |
|
2347 ret = zfgetdata(name, NULL, cmd, 0); |
|
2348 zsfree(cmd); |
|
2349 if (ret) |
|
2350 return 1; |
|
2351 |
|
2352 fflush(stdout); /* since we're now using fd 1 */ |
|
2353 return zfsenddata(name, 1, 0, 0); |
|
2354 } |
|
2355 |
|
2356 /* change the remote directory */ |
|
2357 |
|
2358 /**/ |
|
2359 static int |
|
2360 zftp_cd(UNUSED(char *name), char **args, int flags) |
|
2361 { |
|
2362 /* change directory --- enhance to allow 'zftp cdup' */ |
|
2363 int ret; |
|
2364 |
|
2365 if ((flags & ZFTP_CDUP) || !strcmp(*args, "..") || |
|
2366 !strcmp(*args, "../")) { |
|
2367 ret = zfsendcmd("CDUP\r\n"); |
|
2368 } else { |
|
2369 char *cmd = tricat("CWD ", *args, "\r\n"); |
|
2370 ret = zfsendcmd(cmd); |
|
2371 zsfree(cmd); |
|
2372 } |
|
2373 if (ret > 2) |
|
2374 return 1; |
|
2375 /* sometimes the directory may be in the response. usually not. */ |
|
2376 if (zfgetcwd()) |
|
2377 return 1; |
|
2378 |
|
2379 return 0; |
|
2380 } |
|
2381 |
|
2382 /* get the remote directory */ |
|
2383 |
|
2384 /**/ |
|
2385 static int |
|
2386 zfgetcwd(void) |
|
2387 { |
|
2388 char *ptr, *eptr; |
|
2389 int endc; |
|
2390 Eprog prog; |
|
2391 |
|
2392 if (zfprefs & ZFPF_DUMB) |
|
2393 return 1; |
|
2394 if (zfsendcmd("PWD\r\n") > 2) { |
|
2395 zfunsetparam("ZFTP_PWD"); |
|
2396 return 1; |
|
2397 } |
|
2398 ptr = lastmsg; |
|
2399 while (*ptr == ' ') |
|
2400 ptr++; |
|
2401 if (!*ptr) /* ultra safe */ |
|
2402 return 1; |
|
2403 if (*ptr == '"') { |
|
2404 ptr++; |
|
2405 endc = '"'; |
|
2406 } else |
|
2407 endc = ' '; |
|
2408 for (eptr = ptr; *eptr && *eptr != endc; eptr++) |
|
2409 ; |
|
2410 zfsetparam("ZFTP_PWD", ztrduppfx(ptr, eptr-ptr), ZFPM_READONLY); |
|
2411 |
|
2412 /* |
|
2413 * This isn't so necessary if we're going to have a shell function |
|
2414 * front end. By putting it here, and in close when ZFTP_PWD is unset, |
|
2415 * we at least cover the bases. |
|
2416 */ |
|
2417 if ((prog = getshfunc("zftp_chpwd")) != &dummy_eprog) { |
|
2418 int osc = sfcontext; |
|
2419 |
|
2420 sfcontext = SFC_HOOK; |
|
2421 doshfunc("zftp_chpwd", prog, NULL, 0, 1); |
|
2422 sfcontext = osc; |
|
2423 } |
|
2424 return 0; |
|
2425 } |
|
2426 |
|
2427 /* |
|
2428 * Set the type for the next transfer, usually image (binary) or ASCII. |
|
2429 */ |
|
2430 |
|
2431 /**/ |
|
2432 static int |
|
2433 zfsettype(int type) |
|
2434 { |
|
2435 char buf[] = "TYPE X\r\n"; |
|
2436 if (ZFST_TYPE(type) == ZFST_CTYP(zfstatusp[zfsessno])) |
|
2437 return 0; |
|
2438 buf[5] = (ZFST_TYPE(type) == ZFST_ASCI) ? 'A' : 'I'; |
|
2439 if (zfsendcmd(buf) > 2) |
|
2440 return 1; |
|
2441 zfstatusp[zfsessno] &= ~(ZFST_TMSK << ZFST_TBIT); |
|
2442 /* shift the type left to set the current type bits */; |
|
2443 zfstatusp[zfsessno] |= type << ZFST_TBIT; |
|
2444 return 0; |
|
2445 } |
|
2446 |
|
2447 /* |
|
2448 * Print or get a new type for the transfer. |
|
2449 * We don't actually set the type at this point. |
|
2450 */ |
|
2451 |
|
2452 /**/ |
|
2453 static int |
|
2454 zftp_type(char *name, char **args, int flags) |
|
2455 { |
|
2456 char *str, nt, tbuf[2] = "A"; |
|
2457 if (flags & (ZFTP_TBIN|ZFTP_TASC)) { |
|
2458 nt = (flags & ZFTP_TBIN) ? 'I' : 'A'; |
|
2459 } else if (!(str = *args)) { |
|
2460 /* |
|
2461 * Since this is supposed to be a low-level basis for |
|
2462 * an FTP system, just print the single code letter. |
|
2463 */ |
|
2464 printf("%c\n", (ZFST_TYPE(zfstatusp[zfsessno]) == ZFST_ASCI) ? |
|
2465 'A' : 'I'); |
|
2466 fflush(stdout); |
|
2467 return 0; |
|
2468 } else { |
|
2469 nt = toupper(STOUC(*str)); |
|
2470 /* |
|
2471 * RFC959 specifies other types, but these are the only |
|
2472 * ones we know what to do with. |
|
2473 */ |
|
2474 if (str[1] || (nt != 'A' && nt != 'B' && nt != 'I')) { |
|
2475 zwarnnam(name, "transfer type %s not recognised", str, 0); |
|
2476 return 1; |
|
2477 } |
|
2478 |
|
2479 if (nt == 'B') /* binary = image */ |
|
2480 nt = 'I'; |
|
2481 } |
|
2482 |
|
2483 zfstatusp[zfsessno] &= ~ZFST_TMSK; |
|
2484 zfstatusp[zfsessno] |= (nt == 'I') ? ZFST_IMAG : ZFST_ASCI; |
|
2485 tbuf[0] = nt; |
|
2486 zfsetparam("ZFTP_TYPE", ztrdup(tbuf), ZFPM_READONLY); |
|
2487 return 0; |
|
2488 } |
|
2489 |
|
2490 /**/ |
|
2491 static int |
|
2492 zftp_mode(char *name, char **args, UNUSED(int flags)) |
|
2493 { |
|
2494 char *str, cmd[] = "MODE X\r\n"; |
|
2495 int nt; |
|
2496 |
|
2497 if (!(str = *args)) { |
|
2498 printf("%c\n", (ZFST_MODE(zfstatusp[zfsessno]) == ZFST_STRE) ? |
|
2499 'S' : 'B'); |
|
2500 fflush(stdout); |
|
2501 return 0; |
|
2502 } |
|
2503 nt = str[0] = toupper(STOUC(*str)); |
|
2504 if (str[1] || (nt != 'S' && nt != 'B')) { |
|
2505 zwarnnam(name, "transfer mode %s not recognised", str, 0); |
|
2506 return 1; |
|
2507 } |
|
2508 cmd[5] = (char) nt; |
|
2509 if (zfsendcmd(cmd) > 2) |
|
2510 return 1; |
|
2511 zfstatusp[zfsessno] &= ZFST_MMSK; |
|
2512 zfstatusp[zfsessno] |= (nt == 'S') ? ZFST_STRE : ZFST_BLOC; |
|
2513 zfsetparam("ZFTP_MODE", ztrdup(str), ZFPM_READONLY); |
|
2514 return 0; |
|
2515 } |
|
2516 |
|
2517 /**/ |
|
2518 static int |
|
2519 zftp_local(UNUSED(char *name), char **args, int flags) |
|
2520 { |
|
2521 int more = !!args[1], ret = 0, dofd = !*args; |
|
2522 while (*args || dofd) { |
|
2523 off_t sz; |
|
2524 char *mt; |
|
2525 int newret = zfstats(*args, !(flags & ZFTP_HERE), &sz, &mt, |
|
2526 dofd ? 0 : -1); |
|
2527 if (newret == 2) /* at least one is not implemented */ |
|
2528 return 2; |
|
2529 else if (newret) { |
|
2530 ret = 1; |
|
2531 if (mt) |
|
2532 zsfree(mt); |
|
2533 args++; |
|
2534 continue; |
|
2535 } |
|
2536 if (more) { |
|
2537 fputs(*args, stdout); |
|
2538 fputc(' ', stdout); |
|
2539 } |
|
2540 #ifdef OFF_T_IS_64_BIT |
|
2541 printf("%s %s\n", output64(sz), mt); |
|
2542 #else |
|
2543 DPUTS(sizeof(sz) > 4, "Shell compiled with wrong off_t size"); |
|
2544 printf("%ld %s\n", sz, mt); |
|
2545 #endif |
|
2546 zsfree(mt); |
|
2547 if (dofd) |
|
2548 break; |
|
2549 args++; |
|
2550 } |
|
2551 fflush(stdout); |
|
2552 |
|
2553 return ret; |
|
2554 } |
|
2555 |
|
2556 /* |
|
2557 * Generic transfer for get, put and append. |
|
2558 * |
|
2559 * Get sends all files to stdout, i.e. this is basically cat. It's up to a |
|
2560 * shell function driver to turn this into standard FTP-like commands. |
|
2561 * |
|
2562 * Put/append sends everything from stdin down the drai^H^H^Hata connection. |
|
2563 * Slightly weird with multiple files in that it tries to read |
|
2564 * a separate complete file from stdin each time, which is |
|
2565 * only even potentially useful interactively. But the only |
|
2566 * real alternative is just to allow one file at a time. |
|
2567 */ |
|
2568 |
|
2569 /**/ |
|
2570 static int |
|
2571 zftp_getput(char *name, char **args, int flags) |
|
2572 { |
|
2573 int ret = 0, recv = (flags & ZFTP_RECV), getsize = 0, progress = 1; |
|
2574 char *cmd = recv ? "RETR " : (flags & ZFTP_APPE) ? "APPE " : "STOR "; |
|
2575 Eprog prog; |
|
2576 |
|
2577 /* |
|
2578 * At this point I'd like to set progress to 0 if we're |
|
2579 * backgrounded, since it's hard for the user to find out. |
|
2580 * It turns out it's hard enough for us to find out. |
|
2581 * The problem is that zsh clears it's job table, so we |
|
2582 * just don't know if we're some forked shell in a pipeline |
|
2583 * somewhere or in the background. This seems to me a problem. |
|
2584 */ |
|
2585 |
|
2586 zfsettype(ZFST_TYPE(zfstatusp[zfsessno])); |
|
2587 |
|
2588 if (recv) |
|
2589 fflush(stdout); /* since we may be using fd 1 */ |
|
2590 for (; *args; args++) { |
|
2591 char *ln, *rest = NULL; |
|
2592 off_t startat = 0; |
|
2593 if (progress && (prog = getshfunc("zftp_progress")) != &dummy_eprog) { |
|
2594 off_t sz; |
|
2595 /* |
|
2596 * This calls the SIZE command to get the size for remote |
|
2597 * files. Some servers send the size with the reply to |
|
2598 * the transfer command (i.e. RETR), in which |
|
2599 * case we note the fact and don't call this |
|
2600 * next time. For that reason, the first call |
|
2601 * of zftp_progress is delayed until zfsenddata(). |
|
2602 */ |
|
2603 if ((!(zfprefs & ZFPF_DUMB) && |
|
2604 (zfstatusp[zfsessno] & (ZFST_NOSZ|ZFST_TRSZ)) != ZFST_TRSZ) |
|
2605 || !recv) { |
|
2606 /* the final 0 is a local fd to fstat if recv is zero */ |
|
2607 zfstats(*args, recv, &sz, NULL, 0); |
|
2608 /* even if it doesn't support SIZE, it may tell us */ |
|
2609 if (recv && sz == -1) |
|
2610 getsize = 1; |
|
2611 } else |
|
2612 getsize = 1; |
|
2613 zfstarttrans(*args, recv, sz); |
|
2614 } |
|
2615 |
|
2616 if (flags & ZFTP_REST) { |
|
2617 startat = zstrtol(args[1], NULL, 10); |
|
2618 rest = tricat("REST ", args[1], "\r\n"); |
|
2619 } |
|
2620 |
|
2621 ln = tricat(cmd, *args, "\r\n"); |
|
2622 /* note zfsess->dfd doesn't exist till zfgetdata() creates it */ |
|
2623 if (zfgetdata(name, rest, ln, getsize)) |
|
2624 ret = 2; |
|
2625 else if (zfsenddata(name, recv, progress, startat)) |
|
2626 ret = 1; |
|
2627 zsfree(ln); |
|
2628 /* |
|
2629 * The progress report isn't started till zfsenddata(), where |
|
2630 * it's the first item. Hence we send a final progress report |
|
2631 * if and only if we called zfsenddata(); |
|
2632 */ |
|
2633 if (progress && ret != 2 && |
|
2634 (prog = getshfunc("zftp_progress")) != &dummy_eprog) { |
|
2635 /* progress to finish: ZFTP_TRANSFER set to GF or PF */ |
|
2636 int osc = sfcontext; |
|
2637 |
|
2638 zfsetparam("ZFTP_TRANSFER", ztrdup(recv ? "GF" : "PF"), |
|
2639 ZFPM_READONLY); |
|
2640 sfcontext = SFC_HOOK; |
|
2641 doshfunc("zftp_progress", prog, NULL, 0, 1); |
|
2642 sfcontext = osc; |
|
2643 } |
|
2644 if (rest) { |
|
2645 zsfree(rest); |
|
2646 args++; |
|
2647 } |
|
2648 if (errflag) |
|
2649 break; |
|
2650 } |
|
2651 zfendtrans(); |
|
2652 return ret != 0; |
|
2653 } |
|
2654 |
|
2655 /* |
|
2656 * Delete a list of files on the server. We allow a list by analogy with |
|
2657 * `rm'. |
|
2658 */ |
|
2659 |
|
2660 /**/ |
|
2661 static int |
|
2662 zftp_delete(UNUSED(char *name), char **args, UNUSED(int flags)) |
|
2663 { |
|
2664 int ret = 0; |
|
2665 char *cmd, **aptr; |
|
2666 for (aptr = args; *aptr; aptr++) { |
|
2667 cmd = tricat("DELE ", *aptr, "\r\n"); |
|
2668 if (zfsendcmd(cmd) > 2) |
|
2669 ret = 1; |
|
2670 zsfree(cmd); |
|
2671 } |
|
2672 return ret; |
|
2673 } |
|
2674 |
|
2675 /* Create or remove a directory on the server */ |
|
2676 |
|
2677 /**/ |
|
2678 static int |
|
2679 zftp_mkdir(UNUSED(char *name), char **args, int flags) |
|
2680 { |
|
2681 int ret; |
|
2682 char *cmd = tricat((flags & ZFTP_DELE) ? "RMD " : "MKD ", |
|
2683 *args, "\r\n"); |
|
2684 ret = (zfsendcmd(cmd) > 2); |
|
2685 zsfree(cmd); |
|
2686 return ret; |
|
2687 } |
|
2688 |
|
2689 /* Rename a file on the server */ |
|
2690 |
|
2691 /**/ |
|
2692 static int |
|
2693 zftp_rename(UNUSED(char *name), char **args, UNUSED(int flags)) |
|
2694 { |
|
2695 int ret; |
|
2696 char *cmd; |
|
2697 |
|
2698 cmd = tricat("RNFR ", args[0], "\r\n"); |
|
2699 ret = 1; |
|
2700 if (zfsendcmd(cmd) == 3) { |
|
2701 zsfree(cmd); |
|
2702 cmd = tricat("RNTO ", args[1], "\r\n"); |
|
2703 if (zfsendcmd(cmd) == 2) |
|
2704 ret = 0; |
|
2705 } |
|
2706 zsfree(cmd); |
|
2707 return ret; |
|
2708 } |
|
2709 |
|
2710 /* |
|
2711 * Send random commands, either with SITE or literal. |
|
2712 * In the second case, the user better know what they're doing. |
|
2713 */ |
|
2714 |
|
2715 /**/ |
|
2716 static int |
|
2717 zftp_quote(UNUSED(char *name), char **args, int flags) |
|
2718 { |
|
2719 int ret = 0; |
|
2720 char *cmd; |
|
2721 |
|
2722 cmd = (flags & ZFTP_SITE) ? zfargstring("SITE", args) |
|
2723 : zfargstring(args[0], args+1); |
|
2724 ret = (zfsendcmd(cmd) > 2); |
|
2725 zsfree(cmd); |
|
2726 |
|
2727 return ret; |
|
2728 } |
|
2729 |
|
2730 /* |
|
2731 * Close the connection, ending the session. With leaveparams, |
|
2732 * don't do anything to the external status (parameters, zftp_chpwd), |
|
2733 * probably because this isn't the current session. |
|
2734 */ |
|
2735 |
|
2736 /**/ |
|
2737 static void |
|
2738 zfclose(int leaveparams) |
|
2739 { |
|
2740 char **aptr; |
|
2741 Eprog prog; |
|
2742 |
|
2743 if (!zfsess->control) |
|
2744 return; |
|
2745 |
|
2746 zfclosing = 1; |
|
2747 if (zcfinish != 2) { |
|
2748 /* |
|
2749 * haven't had EOF from server, so send a QUIT and get the response. |
|
2750 * maybe we should set a shorter timeout for this to avoid |
|
2751 * CTRL-c rage. |
|
2752 */ |
|
2753 zfsendcmd("QUIT\r\n"); |
|
2754 } |
|
2755 if (zfsess->cin) { |
|
2756 /* |
|
2757 * We fdopen'd the TCP control fd; since we can't fdclose it, |
|
2758 * we need to perform a full fclose, which invalidates the |
|
2759 * TCP fd. We need to do this before closing the FILE, since |
|
2760 * it's not usable afterwards. |
|
2761 */ |
|
2762 if (fileno(zfsess->cin) == zfsess->control->fd) |
|
2763 zfsess->control->fd = -1; |
|
2764 fclose(zfsess->cin); |
|
2765 zfsess->cin = NULL; |
|
2766 } |
|
2767 if (zfsess->control) { |
|
2768 zfnopen--; |
|
2769 tcp_close(zfsess->control); |
|
2770 /* We leak if the above failed */ |
|
2771 zfsess->control = NULL; |
|
2772 } |
|
2773 |
|
2774 if (zfstatfd != -1) { |
|
2775 zfstatusp[zfsessno] |= ZFST_CLOS; |
|
2776 if (!zfnopen) { |
|
2777 /* Write the final status in case this is a subshell */ |
|
2778 lseek(zfstatfd, zfsessno*sizeof(int), 0); |
|
2779 write(zfstatfd, (char *)zfstatusp+zfsessno, sizeof(int)); |
|
2780 |
|
2781 close(zfstatfd); |
|
2782 zfstatfd = -1; |
|
2783 } |
|
2784 } |
|
2785 |
|
2786 if (!leaveparams) { |
|
2787 /* Unset the non-special parameters */ |
|
2788 for (aptr = zfparams; *aptr; aptr++) |
|
2789 zfunsetparam(*aptr); |
|
2790 |
|
2791 /* Now ZFTP_PWD is unset. It's up to zftp_chpwd to notice. */ |
|
2792 if ((prog = getshfunc("zftp_chpwd")) != &dummy_eprog) { |
|
2793 int osc = sfcontext; |
|
2794 |
|
2795 sfcontext = SFC_HOOK; |
|
2796 doshfunc("zftp_chpwd", prog, NULL, 0, 1); |
|
2797 sfcontext = osc; |
|
2798 } |
|
2799 } |
|
2800 |
|
2801 /* tidy up status variables, because mess is bad */ |
|
2802 zfclosing = zfdrrrring = 0; |
|
2803 } |
|
2804 |
|
2805 /* Safe front end to zftp_close() from within the package */ |
|
2806 |
|
2807 /**/ |
|
2808 static int |
|
2809 zftp_close(UNUSED(char *name), UNUSED(char **args), UNUSED(int flags)) |
|
2810 { |
|
2811 zfclose(0); |
|
2812 return 0; |
|
2813 } |
|
2814 |
|
2815 |
|
2816 /* |
|
2817 * Session management routines. A session consists of various |
|
2818 * internal variables describing the connection, the set of shell |
|
2819 * parameters --- the same set which is unset by closing a connection --- |
|
2820 * and the set of host/user parameters if set by zftp params. |
|
2821 */ |
|
2822 |
|
2823 /* |
|
2824 * Switch to a new session, creating it if necessary. |
|
2825 * Sets zfsessno, zfsess and $ZFTP_SESSION; updates zfsesscnt and zfstatusp. |
|
2826 */ |
|
2827 |
|
2828 /**/ |
|
2829 static void |
|
2830 newsession(char *nm) |
|
2831 { |
|
2832 LinkNode nptr; |
|
2833 |
|
2834 for (zfsessno = 0, nptr = firstnode(zfsessions); |
|
2835 nptr; zfsessno++, incnode(nptr)) { |
|
2836 zfsess = (Zftp_session) nptr->dat; |
|
2837 if (!strcmp(zfsess->name, nm)) |
|
2838 break; |
|
2839 } |
|
2840 |
|
2841 if (!nptr) { |
|
2842 zfsess = (Zftp_session) zshcalloc(sizeof(struct zftp_session)); |
|
2843 zfsess->name = ztrdup(nm); |
|
2844 zfsess->dfd = -1; |
|
2845 zfsess->params = (char **) zshcalloc(sizeof(zfparams)); |
|
2846 zaddlinknode(zfsessions, zfsess); |
|
2847 |
|
2848 zfsesscnt++; |
|
2849 zfstatusp = (int *)zrealloc(zfstatusp, sizeof(int)*zfsesscnt); |
|
2850 zfstatusp[zfsessno] = 0; |
|
2851 } |
|
2852 |
|
2853 zfsetparam("ZFTP_SESSION", ztrdup(zfsess->name), ZFPM_READONLY); |
|
2854 } |
|
2855 |
|
2856 /* Save the existing session: this just means saving the parameters. */ |
|
2857 |
|
2858 static void |
|
2859 savesession() |
|
2860 { |
|
2861 char **ps, **pd, *val; |
|
2862 |
|
2863 for (ps = zfparams, pd = zfsess->params; *ps; ps++, pd++) { |
|
2864 if (*pd) |
|
2865 zsfree(*pd); |
|
2866 queue_signals(); |
|
2867 if ((val = getsparam(*ps))) |
|
2868 *pd = ztrdup(val); |
|
2869 else |
|
2870 *pd = NULL; |
|
2871 unqueue_signals(); |
|
2872 } |
|
2873 *pd = NULL; |
|
2874 } |
|
2875 |
|
2876 /* |
|
2877 * Switch to session nm, creating it if necessary. |
|
2878 * Just call newsession, then set up the session-specific parameters. |
|
2879 */ |
|
2880 |
|
2881 /**/ |
|
2882 static void |
|
2883 switchsession(char *nm) |
|
2884 { |
|
2885 char **ps, **pd; |
|
2886 |
|
2887 newsession(nm); |
|
2888 |
|
2889 for (ps = zfparams, pd = zfsess->params; *ps; ps++, pd++) { |
|
2890 if (*pd) { |
|
2891 /* Use the permanently allocated string for the parameter */ |
|
2892 zfsetparam(*ps, *pd, ZFPM_READONLY); |
|
2893 *pd = NULL; |
|
2894 } else |
|
2895 zfunsetparam(*ps); |
|
2896 } |
|
2897 } |
|
2898 |
|
2899 /**/ |
|
2900 static void |
|
2901 freesession(Zftp_session sptr) |
|
2902 { |
|
2903 char **ps, **pd; |
|
2904 zsfree(sptr->name); |
|
2905 for (ps = zfparams, pd = zfsess->params; *ps; ps++, pd++) |
|
2906 if (*pd) |
|
2907 zsfree(*pd); |
|
2908 zfree(zfsess->params, sizeof(zfparams)); |
|
2909 if (sptr->userparams) |
|
2910 freearray(sptr->userparams); |
|
2911 zfree(sptr, sizeof(struct zftp_session)); |
|
2912 } |
|
2913 |
|
2914 /**/ |
|
2915 static int |
|
2916 zftp_session(UNUSED(char *name), char **args, UNUSED(int flags)) |
|
2917 { |
|
2918 if (!*args) { |
|
2919 LinkNode nptr; |
|
2920 |
|
2921 for (nptr = firstnode(zfsessions); nptr; incnode(nptr)) |
|
2922 printf("%s\n", ((Zftp_session)nptr->dat)->name); |
|
2923 return 0; |
|
2924 } |
|
2925 |
|
2926 /* |
|
2927 * Check if we are already in the required session: if so, |
|
2928 * it's a no-op, not an error. |
|
2929 */ |
|
2930 if (!strcmp(*args, zfsess->name)) |
|
2931 return 0; |
|
2932 |
|
2933 savesession(); |
|
2934 switchsession(*args); |
|
2935 return 0; |
|
2936 } |
|
2937 |
|
2938 /* Remove a session and free it */ |
|
2939 |
|
2940 /**/ |
|
2941 static int |
|
2942 zftp_rmsession(UNUSED(char *name), char **args, UNUSED(int flags)) |
|
2943 { |
|
2944 int no; |
|
2945 LinkNode nptr; |
|
2946 Zftp_session sptr = NULL; |
|
2947 char *newsess = NULL; |
|
2948 |
|
2949 /* Find the session in the list: either the current one, or by name */ |
|
2950 for (no = 0, nptr = firstnode(zfsessions); nptr; no++, incnode(nptr)) { |
|
2951 sptr = (Zftp_session) nptr->dat; |
|
2952 if ((!*args && sptr == zfsess) || |
|
2953 (*args && !strcmp(sptr->name, *args))) |
|
2954 break; |
|
2955 } |
|
2956 if (!nptr) |
|
2957 return 1; |
|
2958 |
|
2959 if (sptr == zfsess) { |
|
2960 /* Freeing current session: make sure it's closed */ |
|
2961 zfclosedata(); |
|
2962 zfclose(0); |
|
2963 |
|
2964 /* |
|
2965 * Choose new session to switch to if any: first in list |
|
2966 * excluding the one just freed. |
|
2967 */ |
|
2968 if (zfsesscnt > 1) { |
|
2969 LinkNode newn = firstnode(zfsessions); |
|
2970 if (newn == nptr) |
|
2971 incnode(newn); |
|
2972 newsess = ((Zftp_session)newn->dat)->name; |
|
2973 } |
|
2974 } else { |
|
2975 Zftp_session oldsess = zfsess; |
|
2976 zfsess = sptr; |
|
2977 /* |
|
2978 * Freeing another session: don't need to switch, just |
|
2979 * tell zfclose() not to delete parameters etc. |
|
2980 */ |
|
2981 zfclosedata(); |
|
2982 zfclose(1); |
|
2983 zfsess = oldsess; |
|
2984 } |
|
2985 remnode(zfsessions, nptr); |
|
2986 freesession(sptr); |
|
2987 |
|
2988 /* |
|
2989 * Fix up array of status pointers. |
|
2990 */ |
|
2991 if (--zfsesscnt) { |
|
2992 /* |
|
2993 * Some remaining, so just shift up |
|
2994 */ |
|
2995 int *newstatusp = (int *)zalloc(sizeof(int)*zfsesscnt); |
|
2996 int *src, *dst, i; |
|
2997 for (i = 0, src = zfstatusp, dst = newstatusp; i < zfsesscnt; |
|
2998 i++, src++, dst++) { |
|
2999 if (i == no) |
|
3000 src++; |
|
3001 *dst = *src; |
|
3002 } |
|
3003 zfree(zfstatusp, sizeof(int)*(zfsesscnt+1)); |
|
3004 zfstatusp = newstatusp; |
|
3005 |
|
3006 /* |
|
3007 * Maybe we need to switch to one of the remaining sessions. |
|
3008 */ |
|
3009 if (newsess) |
|
3010 switchsession(newsess); |
|
3011 } else { |
|
3012 zfree(zfstatusp, sizeof(int)); |
|
3013 zfstatusp = NULL; |
|
3014 |
|
3015 /* |
|
3016 * We've just deleted the last session, so we need to |
|
3017 * start again from scratch. |
|
3018 */ |
|
3019 newsession("default"); |
|
3020 } |
|
3021 |
|
3022 return 0; |
|
3023 } |
|
3024 |
|
3025 /* The builtin command frontend to the rest of the package */ |
|
3026 |
|
3027 /**/ |
|
3028 static int |
|
3029 bin_zftp(char *name, char **args, UNUSED(Options ops), UNUSED(int func)) |
|
3030 { |
|
3031 char fullname[20] = "zftp "; |
|
3032 char *cnam = *args++, *prefs, *ptr; |
|
3033 Zftpcmd zptr; |
|
3034 int n, ret = 0; |
|
3035 |
|
3036 for (zptr = zftpcmdtab; zptr->nam; zptr++) |
|
3037 if (!strcmp(zptr->nam, cnam)) |
|
3038 break; |
|
3039 |
|
3040 if (!zptr->nam) { |
|
3041 zwarnnam(name, "no such subcommand: %s", cnam, 0); |
|
3042 return 1; |
|
3043 } |
|
3044 |
|
3045 /* check number of arguments */ |
|
3046 for (n = 0; args[n]; n++) |
|
3047 ; |
|
3048 if (n < zptr->min || (zptr->max != -1 && n > zptr->max)) { |
|
3049 zwarnnam(name, "wrong no. of arguments for %s", cnam, 0); |
|
3050 return 1; |
|
3051 } |
|
3052 |
|
3053 strcat(fullname, cnam); |
|
3054 if (zfstatfd != -1 && !(zptr->flags & ZFTP_SESS)) { |
|
3055 /* Get the status in case it was set by a forked process */ |
|
3056 int oldstatus = zfstatusp[zfsessno]; |
|
3057 lseek(zfstatfd, 0, 0); |
|
3058 read(zfstatfd, (char *)zfstatusp, sizeof(int)*zfsesscnt); |
|
3059 if (zfsess->control && (zfstatusp[zfsessno] & ZFST_CLOS)) { |
|
3060 /* got closed in subshell without us knowing */ |
|
3061 zcfinish = 2; |
|
3062 zfclose(0); |
|
3063 } else { |
|
3064 /* |
|
3065 * fix up status types: unfortunately they may already |
|
3066 * have been looked at between being changed in the subshell |
|
3067 * and now, but we can't help that. |
|
3068 */ |
|
3069 if (ZFST_TYPE(oldstatus) != ZFST_TYPE(zfstatusp[zfsessno])) |
|
3070 zfsetparam("ZFTP_TYPE", |
|
3071 ztrdup(ZFST_TYPE(zfstatusp[zfsessno]) == ZFST_ASCI ? |
|
3072 "A" : "I"), ZFPM_READONLY); |
|
3073 if (ZFST_MODE(oldstatus) != ZFST_MODE(zfstatusp[zfsessno])) |
|
3074 zfsetparam("ZFTP_MODE", |
|
3075 ztrdup(ZFST_MODE(zfstatusp[zfsessno]) == ZFST_BLOC ? |
|
3076 "B" : "S"), ZFPM_READONLY); |
|
3077 } |
|
3078 } |
|
3079 #if defined(HAVE_SELECT) || defined (HAVE_POLL) |
|
3080 if (zfsess->control && !(zptr->flags & (ZFTP_TEST|ZFTP_SESS))) { |
|
3081 /* |
|
3082 * Test the connection for a bad fd or incoming message, but |
|
3083 * only if the connection was last heard of open, and |
|
3084 * if we are not about to call the test command anyway. |
|
3085 * Not worth it unless we have select() or poll(). |
|
3086 */ |
|
3087 ret = zftp_test("zftp test", NULL, 0); |
|
3088 } |
|
3089 #endif |
|
3090 if ((zptr->flags & ZFTP_CONN) && !zfsess->control) { |
|
3091 if (ret != 2) { |
|
3092 /* |
|
3093 * with ret == 2, we just got dumped out in the test, |
|
3094 * so enough messages already. |
|
3095 */ |
|
3096 zwarnnam(fullname, "not connected.", NULL, 0); |
|
3097 } |
|
3098 return 1; |
|
3099 } |
|
3100 |
|
3101 queue_signals(); |
|
3102 if ((prefs = getsparam("ZFTP_PREFS"))) { |
|
3103 zfprefs = 0; |
|
3104 for (ptr = prefs; *ptr; ptr++) { |
|
3105 switch (toupper(STOUC(*ptr))) { |
|
3106 case 'S': |
|
3107 /* sendport */ |
|
3108 zfprefs |= ZFPF_SNDP; |
|
3109 break; |
|
3110 |
|
3111 case 'P': |
|
3112 /* |
|
3113 * passive |
|
3114 * If we have already been told to use sendport mode, |
|
3115 * we're never going to use passive mode. |
|
3116 */ |
|
3117 if (!(zfprefs & ZFPF_SNDP)) |
|
3118 zfprefs |= ZFPF_PASV; |
|
3119 break; |
|
3120 |
|
3121 case 'D': |
|
3122 /* dumb */ |
|
3123 zfprefs |= ZFPF_DUMB; |
|
3124 break; |
|
3125 |
|
3126 default: |
|
3127 zwarnnam(name, "preference %c not recognized", NULL, *ptr); |
|
3128 break; |
|
3129 } |
|
3130 } |
|
3131 } |
|
3132 unqueue_signals(); |
|
3133 |
|
3134 ret = (*zptr->fun)(fullname, args, zptr->flags); |
|
3135 |
|
3136 if (zfalarmed) |
|
3137 zfunalarm(); |
|
3138 if (zfdrrrring) { |
|
3139 /* had a timeout, close the connection */ |
|
3140 zcfinish = 2; /* don't try sending QUIT */ |
|
3141 zfclose(0); |
|
3142 } |
|
3143 if (zfstatfd != -1) { |
|
3144 /* |
|
3145 * Set the status in case another process needs to know, |
|
3146 * but only for the active session. |
|
3147 */ |
|
3148 lseek(zfstatfd, zfsessno*sizeof(int), 0); |
|
3149 write(zfstatfd, (char *)zfstatusp+zfsessno, sizeof(int)); |
|
3150 } |
|
3151 return ret; |
|
3152 } |
|
3153 |
|
3154 static void |
|
3155 zftp_cleanup(void) |
|
3156 { |
|
3157 /* |
|
3158 * There are various parameters hanging around, but they're |
|
3159 * all non-special so are entirely non-life-threatening. |
|
3160 */ |
|
3161 LinkNode nptr; |
|
3162 Zftp_session cursess = zfsess; |
|
3163 for (zfsessno = 0, nptr = firstnode(zfsessions); nptr; |
|
3164 zfsessno++, incnode(nptr)) { |
|
3165 zfsess = (Zftp_session)nptr->dat; |
|
3166 zfclosedata(); |
|
3167 /* |
|
3168 * When closing the current session, do the usual unsetting, |
|
3169 * otherwise don't. |
|
3170 */ |
|
3171 zfclose(zfsess != cursess); |
|
3172 } |
|
3173 zsfree(lastmsg); |
|
3174 zfunsetparam("ZFTP_SESSION"); |
|
3175 freelinklist(zfsessions, (FreeFunc) freesession); |
|
3176 zfree(zfstatusp, sizeof(int)*zfsesscnt); |
|
3177 deletebuiltins("zftp", bintab, sizeof(bintab)/sizeof(*bintab)); |
|
3178 } |
|
3179 |
|
3180 static int |
|
3181 zftpexithook(UNUSED(Hookdef d), UNUSED(void *dummy)) |
|
3182 { |
|
3183 zftp_cleanup(); |
|
3184 return 0; |
|
3185 } |
|
3186 |
|
3187 /* The load/unload routines required by the zsh library interface */ |
|
3188 |
|
3189 /**/ |
|
3190 int |
|
3191 setup_(UNUSED(Module m)) |
|
3192 { |
|
3193 /* setup_ returns 0 for success. require_module returns 1 for success. */ |
|
3194 return !require_module("", "zsh/net/tcp", 0, 0); |
|
3195 } |
|
3196 |
|
3197 /**/ |
|
3198 int |
|
3199 boot_(UNUSED(Module m)) |
|
3200 { |
|
3201 int ret; |
|
3202 if ((ret = addbuiltins("zftp", bintab, |
|
3203 sizeof(bintab)/sizeof(*bintab))) == 1) { |
|
3204 /* if successful, set some default parameters */ |
|
3205 off_t tmout_def = 60; |
|
3206 zfsetparam("ZFTP_VERBOSE", ztrdup("450"), ZFPM_IFUNSET); |
|
3207 zfsetparam("ZFTP_TMOUT", &tmout_def, ZFPM_IFUNSET|ZFPM_INTEGER); |
|
3208 zfsetparam("ZFTP_PREFS", ztrdup("PS"), ZFPM_IFUNSET); |
|
3209 /* default preferences if user deletes variable */ |
|
3210 zfprefs = ZFPF_SNDP|ZFPF_PASV; |
|
3211 |
|
3212 zfsessions = znewlinklist(); |
|
3213 newsession("default"); |
|
3214 |
|
3215 addhookfunc("exit", zftpexithook); |
|
3216 } |
|
3217 |
|
3218 return !ret; |
|
3219 } |
|
3220 |
|
3221 /**/ |
|
3222 int |
|
3223 cleanup_(UNUSED(Module m)) |
|
3224 { |
|
3225 deletehookfunc("exit", zftpexithook); |
|
3226 zftp_cleanup(); |
|
3227 return 0; |
|
3228 } |
|
3229 |
|
3230 /**/ |
|
3231 int |
|
3232 finish_(UNUSED(Module m)) |
|
3233 { |
|
3234 return 0; |
|
3235 } |