Deleted Added
full compact
ftp.c (93150) ftp.c (97856)
1/*-
2 * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 13 unchanged lines hidden (view full) ---

22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 13 unchanged lines hidden (view full) ---

22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/lib/libfetch/ftp.c 93150 2002-03-25 13:53:46Z phk $");
30__FBSDID("$FreeBSD: head/lib/libfetch/ftp.c 97856 2002-06-05 10:05:03Z des $");
31
32/*
33 * Portions of this code were taken from or based on ftpio.c:
34 *
35 * ----------------------------------------------------------------------------
36 * "THE BEER-WARE LICENSE" (Revision 42):
37 * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
38 * can do whatever you want with this stuff. If we meet some day, and you think

--- 22 unchanged lines hidden (view full) ---

61#include <netinet/in.h>
62
63#include <ctype.h>
64#include <err.h>
65#include <errno.h>
66#include <fcntl.h>
67#include <netdb.h>
68#include <stdarg.h>
31
32/*
33 * Portions of this code were taken from or based on ftpio.c:
34 *
35 * ----------------------------------------------------------------------------
36 * "THE BEER-WARE LICENSE" (Revision 42):
37 * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
38 * can do whatever you want with this stuff. If we meet some day, and you think

--- 22 unchanged lines hidden (view full) ---

61#include <netinet/in.h>
62
63#include <ctype.h>
64#include <err.h>
65#include <errno.h>
66#include <fcntl.h>
67#include <netdb.h>
68#include <stdarg.h>
69#include <stdint.h>
69#include <stdio.h>
70#include <stdlib.h>
71#include <string.h>
72#include <time.h>
73#include <unistd.h>
74
75#include "fetch.h"
76#include "common.h"

--- 14 unchanged lines hidden (view full) ---

91#define FTP_FILE_ACTION_OK 250
92#define FTP_NEED_PASSWORD 331
93#define FTP_NEED_ACCOUNT 332
94#define FTP_FILE_OK 350
95#define FTP_SYNTAX_ERROR 500
96#define FTP_PROTOCOL_ERROR 999
97
98static struct url cached_host;
70#include <stdio.h>
71#include <stdlib.h>
72#include <string.h>
73#include <time.h>
74#include <unistd.h>
75
76#include "fetch.h"
77#include "common.h"

--- 14 unchanged lines hidden (view full) ---

92#define FTP_FILE_ACTION_OK 250
93#define FTP_NEED_PASSWORD 331
94#define FTP_NEED_ACCOUNT 332
95#define FTP_FILE_OK 350
96#define FTP_SYNTAX_ERROR 500
97#define FTP_PROTOCOL_ERROR 999
98
99static struct url cached_host;
99static int cached_socket;
100static conn_t *cached_connection;
100
101
101static char *last_reply;
102static size_t lr_size;
103static size_t lr_length;
104static int last_code;
105
106#define isftpreply(foo) (isdigit(foo[0]) && isdigit(foo[1]) \
107 && isdigit(foo[2]) \
108 && (foo[3] == ' ' || foo[3] == '\0'))
109#define isftpinfo(foo) (isdigit(foo[0]) && isdigit(foo[1]) \
110 && isdigit(foo[2]) && foo[3] == '-')
111
112/*
113 * Translate IPv4 mapped IPv6 address to IPv4 address

--- 17 unchanged lines hidden (view full) ---

131 sin4->sin_family = AF_INET;
132 sin4->sin_len = sizeof(struct sockaddr_in);
133}
134
135/*
136 * Get server response
137 */
138static int
102#define isftpreply(foo) (isdigit(foo[0]) && isdigit(foo[1]) \
103 && isdigit(foo[2]) \
104 && (foo[3] == ' ' || foo[3] == '\0'))
105#define isftpinfo(foo) (isdigit(foo[0]) && isdigit(foo[1]) \
106 && isdigit(foo[2]) && foo[3] == '-')
107
108/*
109 * Translate IPv4 mapped IPv6 address to IPv4 address

--- 17 unchanged lines hidden (view full) ---

127 sin4->sin_family = AF_INET;
128 sin4->sin_len = sizeof(struct sockaddr_in);
129}
130
131/*
132 * Get server response
133 */
134static int
139_ftp_chkerr(int cd)
135_ftp_chkerr(conn_t *conn)
140{
136{
141 if (_fetch_getln(cd, &last_reply, &lr_size, &lr_length) == -1) {
137 if (_fetch_getln(conn) == -1) {
142 _fetch_syserr();
143 return (-1);
144 }
138 _fetch_syserr();
139 return (-1);
140 }
145 if (isftpinfo(last_reply)) {
146 while (lr_length && !isftpreply(last_reply)) {
147 if (_fetch_getln(cd, &last_reply,
148 &lr_size, &lr_length) == -1) {
141 if (isftpinfo(conn->buf)) {
142 while (conn->buflen && !isftpreply(conn->buf)) {
143 if (_fetch_getln(conn) == -1) {
149 _fetch_syserr();
150 return (-1);
151 }
152 }
153 }
154
144 _fetch_syserr();
145 return (-1);
146 }
147 }
148 }
149
155 while (lr_length && isspace(last_reply[lr_length-1]))
156 lr_length--;
157 last_reply[lr_length] = 0;
150 while (conn->buflen && isspace(conn->buf[conn->buflen - 1]))
151 conn->buflen--;
152 conn->buf[conn->buflen] = '\0';
158
153
159 if (!isftpreply(last_reply)) {
154 if (!isftpreply(conn->buf)) {
160 _ftp_seterr(FTP_PROTOCOL_ERROR);
161 return (-1);
162 }
163
155 _ftp_seterr(FTP_PROTOCOL_ERROR);
156 return (-1);
157 }
158
164 last_code = (last_reply[0] - '0') * 100
165 + (last_reply[1] - '0') * 10
166 + (last_reply[2] - '0');
159 conn->err = (conn->buf[0] - '0') * 100
160 + (conn->buf[1] - '0') * 10
161 + (conn->buf[2] - '0');
167
162
168 return (last_code);
163 return (conn->err);
169}
170
171/*
172 * Send a command and check reply
173 */
174static int
164}
165
166/*
167 * Send a command and check reply
168 */
169static int
175_ftp_cmd(int cd, const char *fmt, ...)
170_ftp_cmd(conn_t *conn, const char *fmt, ...)
176{
177 va_list ap;
178 size_t len;
179 char *msg;
180 int r;
181
182 va_start(ap, fmt);
183 len = vasprintf(&msg, fmt, ap);
184 va_end(ap);
185
186 if (msg == NULL) {
187 errno = ENOMEM;
188 _fetch_syserr();
189 return (-1);
190 }
191
171{
172 va_list ap;
173 size_t len;
174 char *msg;
175 int r;
176
177 va_start(ap, fmt);
178 len = vasprintf(&msg, fmt, ap);
179 va_end(ap);
180
181 if (msg == NULL) {
182 errno = ENOMEM;
183 _fetch_syserr();
184 return (-1);
185 }
186
192 r = _fetch_putln(cd, msg, len);
187 r = _fetch_putln(conn, msg, len);
193 free(msg);
194
195 if (r == -1) {
196 _fetch_syserr();
197 return (-1);
198 }
199
188 free(msg);
189
190 if (r == -1) {
191 _fetch_syserr();
192 return (-1);
193 }
194
200 return (_ftp_chkerr(cd));
195 return (_ftp_chkerr(conn));
201}
202
203/*
204 * Return a pointer to the filename part of a path
205 */
206static const char *
207_ftp_filename(const char *file)
208{

--- 5 unchanged lines hidden (view full) ---

214 return (s + 1);
215}
216
217/*
218 * Change working directory to the directory that contains the specified
219 * file.
220 */
221static int
196}
197
198/*
199 * Return a pointer to the filename part of a path
200 */
201static const char *
202_ftp_filename(const char *file)
203{

--- 5 unchanged lines hidden (view full) ---

209 return (s + 1);
210}
211
212/*
213 * Change working directory to the directory that contains the specified
214 * file.
215 */
216static int
222_ftp_cwd(int cd, const char *file)
217_ftp_cwd(conn_t *conn, const char *file)
223{
224 char *s;
225 int e;
226
227 if ((s = strrchr(file, '/')) == NULL || s == file) {
218{
219 char *s;
220 int e;
221
222 if ((s = strrchr(file, '/')) == NULL || s == file) {
228 e = _ftp_cmd(cd, "CWD /");
223 e = _ftp_cmd(conn, "CWD /");
229 } else {
224 } else {
230 e = _ftp_cmd(cd, "CWD %.*s", s - file, file);
225 e = _ftp_cmd(conn, "CWD %.*s", s - file, file);
231 }
232 if (e != FTP_FILE_ACTION_OK) {
233 _ftp_seterr(e);
234 return (-1);
235 }
236 return (0);
237}
238
239/*
240 * Request and parse file stats
241 */
242static int
226 }
227 if (e != FTP_FILE_ACTION_OK) {
228 _ftp_seterr(e);
229 return (-1);
230 }
231 return (0);
232}
233
234/*
235 * Request and parse file stats
236 */
237static int
243_ftp_stat(int cd, const char *file, struct url_stat *us)
238_ftp_stat(conn_t *conn, const char *file, struct url_stat *us)
244{
245 char *ln;
246 const char *s;
247 struct tm tm;
248 time_t t;
249 int e;
250
251 us->size = -1;
252 us->atime = us->mtime = 0;
253
254 if ((s = strrchr(file, '/')) == NULL)
255 s = file;
256 else
257 ++s;
258
239{
240 char *ln;
241 const char *s;
242 struct tm tm;
243 time_t t;
244 int e;
245
246 us->size = -1;
247 us->atime = us->mtime = 0;
248
249 if ((s = strrchr(file, '/')) == NULL)
250 s = file;
251 else
252 ++s;
253
259 if ((e = _ftp_cmd(cd, "SIZE %s", s)) != FTP_FILE_STATUS) {
254 if ((e = _ftp_cmd(conn, "SIZE %s", s)) != FTP_FILE_STATUS) {
260 _ftp_seterr(e);
261 return (-1);
262 }
255 _ftp_seterr(e);
256 return (-1);
257 }
263 for (ln = last_reply + 4; *ln && isspace(*ln); ln++)
258 for (ln = conn->buf + 4; *ln && isspace(*ln); ln++)
264 /* nothing */ ;
265 for (us->size = 0; *ln && isdigit(*ln); ln++)
266 us->size = us->size * 10 + *ln - '0';
267 if (*ln && !isspace(*ln)) {
268 _ftp_seterr(FTP_PROTOCOL_ERROR);
269 us->size = -1;
270 return (-1);
271 }
272 if (us->size == 0)
273 us->size = -1;
274 DEBUG(fprintf(stderr, "size: [%lld]\n", (long long)us->size));
275
259 /* nothing */ ;
260 for (us->size = 0; *ln && isdigit(*ln); ln++)
261 us->size = us->size * 10 + *ln - '0';
262 if (*ln && !isspace(*ln)) {
263 _ftp_seterr(FTP_PROTOCOL_ERROR);
264 us->size = -1;
265 return (-1);
266 }
267 if (us->size == 0)
268 us->size = -1;
269 DEBUG(fprintf(stderr, "size: [%lld]\n", (long long)us->size));
270
276 if ((e = _ftp_cmd(cd, "MDTM %s", s)) != FTP_FILE_STATUS) {
271 if ((e = _ftp_cmd(conn, "MDTM %s", s)) != FTP_FILE_STATUS) {
277 _ftp_seterr(e);
278 return (-1);
279 }
272 _ftp_seterr(e);
273 return (-1);
274 }
280 for (ln = last_reply + 4; *ln && isspace(*ln); ln++)
275 for (ln = conn->buf + 4; *ln && isspace(*ln); ln++)
281 /* nothing */ ;
282 switch (strspn(ln, "0123456789")) {
283 case 14:
284 break;
285 case 15:
286 ln++;
287 ln[0] = '2';
288 ln[1] = '0';

--- 22 unchanged lines hidden (view full) ---

311 tm.tm_hour, tm.tm_min, tm.tm_sec));
312 return (0);
313}
314
315/*
316 * I/O functions for FTP
317 */
318struct ftpio {
276 /* nothing */ ;
277 switch (strspn(ln, "0123456789")) {
278 case 14:
279 break;
280 case 15:
281 ln++;
282 ln[0] = '2';
283 ln[1] = '0';

--- 22 unchanged lines hidden (view full) ---

306 tm.tm_hour, tm.tm_min, tm.tm_sec));
307 return (0);
308}
309
310/*
311 * I/O functions for FTP
312 */
313struct ftpio {
319 int csd; /* Control socket descriptor */
314 conn_t *conn; /* Control connection */
320 int dsd; /* Data socket descriptor */
321 int dir; /* Direction */
322 int eof; /* EOF reached */
323 int err; /* Error code */
324};
325
326static int _ftp_readfn(void *, char *, int);
327static int _ftp_writefn(void *, const char *, int);

--- 6 unchanged lines hidden (view full) ---

334 struct ftpio *io;
335 int r;
336
337 io = (struct ftpio *)v;
338 if (io == NULL) {
339 errno = EBADF;
340 return (-1);
341 }
315 int dsd; /* Data socket descriptor */
316 int dir; /* Direction */
317 int eof; /* EOF reached */
318 int err; /* Error code */
319};
320
321static int _ftp_readfn(void *, char *, int);
322static int _ftp_writefn(void *, const char *, int);

--- 6 unchanged lines hidden (view full) ---

329 struct ftpio *io;
330 int r;
331
332 io = (struct ftpio *)v;
333 if (io == NULL) {
334 errno = EBADF;
335 return (-1);
336 }
342 if (io->csd == -1 || io->dsd == -1 || io->dir == O_WRONLY) {
337 if (io->conn == NULL || io->dsd == -1 || io->dir == O_WRONLY) {
343 errno = EBADF;
344 return (-1);
345 }
346 if (io->err) {
347 errno = io->err;
348 return (-1);
349 }
350 if (io->eof)

--- 16 unchanged lines hidden (view full) ---

367 struct ftpio *io;
368 int w;
369
370 io = (struct ftpio *)v;
371 if (io == NULL) {
372 errno = EBADF;
373 return (-1);
374 }
338 errno = EBADF;
339 return (-1);
340 }
341 if (io->err) {
342 errno = io->err;
343 return (-1);
344 }
345 if (io->eof)

--- 16 unchanged lines hidden (view full) ---

362 struct ftpio *io;
363 int w;
364
365 io = (struct ftpio *)v;
366 if (io == NULL) {
367 errno = EBADF;
368 return (-1);
369 }
375 if (io->csd == -1 || io->dsd == -1 || io->dir == O_RDONLY) {
370 if (io->conn == NULL || io->dsd == -1 || io->dir == O_RDONLY) {
376 errno = EBADF;
377 return (-1);
378 }
379 if (io->err) {
380 errno = io->err;
381 return (-1);
382 }
383 w = write(io->dsd, buf, len);

--- 26 unchanged lines hidden (view full) ---

410
411 io = (struct ftpio *)v;
412 if (io == NULL) {
413 errno = EBADF;
414 return (-1);
415 }
416 if (io->dir == -1)
417 return (0);
371 errno = EBADF;
372 return (-1);
373 }
374 if (io->err) {
375 errno = io->err;
376 return (-1);
377 }
378 w = write(io->dsd, buf, len);

--- 26 unchanged lines hidden (view full) ---

405
406 io = (struct ftpio *)v;
407 if (io == NULL) {
408 errno = EBADF;
409 return (-1);
410 }
411 if (io->dir == -1)
412 return (0);
418 if (io->csd == -1 || io->dsd == -1) {
413 if (io->conn == NULL || io->dsd == -1) {
419 errno = EBADF;
420 return (-1);
421 }
422 close(io->dsd);
423 io->dir = -1;
424 io->dsd = -1;
425 DEBUG(fprintf(stderr, "Waiting for final status\n"));
414 errno = EBADF;
415 return (-1);
416 }
417 close(io->dsd);
418 io->dir = -1;
419 io->dsd = -1;
420 DEBUG(fprintf(stderr, "Waiting for final status\n"));
426 r = _ftp_chkerr(io->csd);
427 close(io->csd);
421 r = _ftp_chkerr(io->conn);
422 _fetch_close(io->conn);
428 free(io);
429 return (r == FTP_TRANSFER_COMPLETE) ? 0 : -1;
430}
431
432static FILE *
423 free(io);
424 return (r == FTP_TRANSFER_COMPLETE) ? 0 : -1;
425}
426
427static FILE *
433_ftp_setup(int csd, int dsd, int mode)
428_ftp_setup(conn_t *conn, int dsd, int mode)
434{
435 struct ftpio *io;
436 FILE *f;
437
438 if ((io = malloc(sizeof *io)) == NULL)
439 return (NULL);
429{
430 struct ftpio *io;
431 FILE *f;
432
433 if ((io = malloc(sizeof *io)) == NULL)
434 return (NULL);
440 io->csd = dup(csd);
435 io->conn = conn;
441 io->dsd = dsd;
442 io->dir = mode;
443 io->eof = io->err = 0;
444 f = funopen(io, _ftp_readfn, _ftp_writefn, _ftp_seekfn, _ftp_closefn);
445 if (f == NULL)
446 free(io);
447 return (f);
448}
449
450/*
451 * Transfer file
452 */
453static FILE *
436 io->dsd = dsd;
437 io->dir = mode;
438 io->eof = io->err = 0;
439 f = funopen(io, _ftp_readfn, _ftp_writefn, _ftp_seekfn, _ftp_closefn);
440 if (f == NULL)
441 free(io);
442 return (f);
443}
444
445/*
446 * Transfer file
447 */
448static FILE *
454_ftp_transfer(int cd, const char *oper, const char *file,
449_ftp_transfer(conn_t *conn, const char *oper, const char *file,
455 int mode, off_t offset, const char *flags)
456{
457 struct sockaddr_storage sa;
458 struct sockaddr_in6 *sin6;
459 struct sockaddr_in *sin4;
460 int low, pasv, verbose;
461 int e, sd = -1;
462 socklen_t l;

--- 7 unchanged lines hidden (view full) ---

470
471 /* passive mode */
472 if (!pasv)
473 pasv = ((s = getenv("FTP_PASSIVE_MODE")) != NULL &&
474 strncasecmp(s, "no", 2) != 0);
475
476 /* find our own address, bind, and listen */
477 l = sizeof sa;
450 int mode, off_t offset, const char *flags)
451{
452 struct sockaddr_storage sa;
453 struct sockaddr_in6 *sin6;
454 struct sockaddr_in *sin4;
455 int low, pasv, verbose;
456 int e, sd = -1;
457 socklen_t l;

--- 7 unchanged lines hidden (view full) ---

465
466 /* passive mode */
467 if (!pasv)
468 pasv = ((s = getenv("FTP_PASSIVE_MODE")) != NULL &&
469 strncasecmp(s, "no", 2) != 0);
470
471 /* find our own address, bind, and listen */
472 l = sizeof sa;
478 if (getsockname(cd, (struct sockaddr *)&sa, &l) == -1)
473 if (getsockname(conn->sd, (struct sockaddr *)&sa, &l) == -1)
479 goto sysouch;
480 if (sa.ss_family == AF_INET6)
481 unmappedaddr((struct sockaddr_in6 *)&sa);
482
483 /* open data socket */
484 if ((sd = socket(sa.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
485 _fetch_syserr();
486 return (NULL);

--- 5 unchanged lines hidden (view full) ---

492 unsigned int i;
493 int port;
494
495 /* send PASV command */
496 if (verbose)
497 _fetch_info("setting passive mode");
498 switch (sa.ss_family) {
499 case AF_INET:
474 goto sysouch;
475 if (sa.ss_family == AF_INET6)
476 unmappedaddr((struct sockaddr_in6 *)&sa);
477
478 /* open data socket */
479 if ((sd = socket(sa.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
480 _fetch_syserr();
481 return (NULL);

--- 5 unchanged lines hidden (view full) ---

487 unsigned int i;
488 int port;
489
490 /* send PASV command */
491 if (verbose)
492 _fetch_info("setting passive mode");
493 switch (sa.ss_family) {
494 case AF_INET:
500 if ((e = _ftp_cmd(cd, "PASV")) != FTP_PASSIVE_MODE)
495 if ((e = _ftp_cmd(conn, "PASV")) != FTP_PASSIVE_MODE)
501 goto ouch;
502 break;
503 case AF_INET6:
496 goto ouch;
497 break;
498 case AF_INET6:
504 if ((e = _ftp_cmd(cd, "EPSV")) != FTP_EPASSIVE_MODE) {
499 if ((e = _ftp_cmd(conn, "EPSV")) != FTP_EPASSIVE_MODE) {
505 if (e == -1)
506 goto ouch;
500 if (e == -1)
501 goto ouch;
507 if ((e = _ftp_cmd(cd, "LPSV")) != FTP_LPASSIVE_MODE)
502 if ((e = _ftp_cmd(conn, "LPSV")) !=
503 FTP_LPASSIVE_MODE)
508 goto ouch;
509 }
510 break;
511 default:
512 e = FTP_PROTOCOL_ERROR; /* XXX: error code should be prepared */
513 goto ouch;
514 }
515
516 /*
517 * Find address and port number. The reply to the PASV command
518 * is IMHO the one and only weak point in the FTP protocol.
519 */
504 goto ouch;
505 }
506 break;
507 default:
508 e = FTP_PROTOCOL_ERROR; /* XXX: error code should be prepared */
509 goto ouch;
510 }
511
512 /*
513 * Find address and port number. The reply to the PASV command
514 * is IMHO the one and only weak point in the FTP protocol.
515 */
520 ln = last_reply;
516 ln = conn->buf;
521 switch (e) {
522 case FTP_PASSIVE_MODE:
523 case FTP_LPASSIVE_MODE:
524 for (p = ln + 3; *p && !isdigit(*p); p++)
525 /* nothing */ ;
526 if (!*p) {
527 e = FTP_PROTOCOL_ERROR;
528 goto ouch;

--- 21 unchanged lines hidden (view full) ---

550 e = FTP_PROTOCOL_ERROR;
551 goto ouch;
552 }
553 break;
554 }
555
556 /* seek to required offset */
557 if (offset)
517 switch (e) {
518 case FTP_PASSIVE_MODE:
519 case FTP_LPASSIVE_MODE:
520 for (p = ln + 3; *p && !isdigit(*p); p++)
521 /* nothing */ ;
522 if (!*p) {
523 e = FTP_PROTOCOL_ERROR;
524 goto ouch;

--- 21 unchanged lines hidden (view full) ---

546 e = FTP_PROTOCOL_ERROR;
547 goto ouch;
548 }
549 break;
550 }
551
552 /* seek to required offset */
553 if (offset)
558 if (_ftp_cmd(cd, "REST %lu", (u_long)offset) != FTP_FILE_OK)
554 if (_ftp_cmd(conn, "REST %lu", (u_long)offset) != FTP_FILE_OK)
559 goto sysouch;
560
561 /* construct sockaddr for data socket */
562 l = sizeof sa;
555 goto sysouch;
556
557 /* construct sockaddr for data socket */
558 l = sizeof sa;
563 if (getpeername(cd, (struct sockaddr *)&sa, &l) == -1)
559 if (getpeername(conn->sd, (struct sockaddr *)&sa, &l) == -1)
564 goto sysouch;
565 if (sa.ss_family == AF_INET6)
566 unmappedaddr((struct sockaddr_in6 *)&sa);
567 switch (sa.ss_family) {
568 case AF_INET6:
569 sin6 = (struct sockaddr_in6 *)&sa;
570 if (e == FTP_EPASSIVE_MODE)
571 sin6->sin6_port = htons(port);

--- 20 unchanged lines hidden (view full) ---

592 if (verbose)
593 _fetch_info("opening data connection");
594 if (connect(sd, (struct sockaddr *)&sa, sa.ss_len) == -1)
595 goto sysouch;
596
597 /* make the server initiate the transfer */
598 if (verbose)
599 _fetch_info("initiating transfer");
560 goto sysouch;
561 if (sa.ss_family == AF_INET6)
562 unmappedaddr((struct sockaddr_in6 *)&sa);
563 switch (sa.ss_family) {
564 case AF_INET6:
565 sin6 = (struct sockaddr_in6 *)&sa;
566 if (e == FTP_EPASSIVE_MODE)
567 sin6->sin6_port = htons(port);

--- 20 unchanged lines hidden (view full) ---

588 if (verbose)
589 _fetch_info("opening data connection");
590 if (connect(sd, (struct sockaddr *)&sa, sa.ss_len) == -1)
591 goto sysouch;
592
593 /* make the server initiate the transfer */
594 if (verbose)
595 _fetch_info("initiating transfer");
600 e = _ftp_cmd(cd, "%s %s", oper, _ftp_filename(file));
596 e = _ftp_cmd(conn, "%s %s", oper, _ftp_filename(file));
601 if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION)
602 goto ouch;
603
604 } else {
605 u_int32_t a;
606 u_short p;
607 int arg, d;
608 char *ap;

--- 27 unchanged lines hidden (view full) ---

636 /* find what port we're on and tell the server */
637 if (getsockname(sd, (struct sockaddr *)&sa, &l) == -1)
638 goto sysouch;
639 switch (sa.ss_family) {
640 case AF_INET:
641 sin4 = (struct sockaddr_in *)&sa;
642 a = ntohl(sin4->sin_addr.s_addr);
643 p = ntohs(sin4->sin_port);
597 if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION)
598 goto ouch;
599
600 } else {
601 u_int32_t a;
602 u_short p;
603 int arg, d;
604 char *ap;

--- 27 unchanged lines hidden (view full) ---

632 /* find what port we're on and tell the server */
633 if (getsockname(sd, (struct sockaddr *)&sa, &l) == -1)
634 goto sysouch;
635 switch (sa.ss_family) {
636 case AF_INET:
637 sin4 = (struct sockaddr_in *)&sa;
638 a = ntohl(sin4->sin_addr.s_addr);
639 p = ntohs(sin4->sin_port);
644 e = _ftp_cmd(cd, "PORT %d,%d,%d,%d,%d,%d",
640 e = _ftp_cmd(conn, "PORT %d,%d,%d,%d,%d,%d",
645 (a >> 24) & 0xff, (a >> 16) & 0xff,
646 (a >> 8) & 0xff, a & 0xff,
647 (p >> 8) & 0xff, p & 0xff);
648 break;
649 case AF_INET6:
650#define UC(b) (((int)b)&0xff)
651 e = -1;
652 sin6 = (struct sockaddr_in6 *)&sa;
653 if (getnameinfo((struct sockaddr *)&sa, sa.ss_len,
654 hname, sizeof(hname),
655 NULL, 0, NI_NUMERICHOST) == 0) {
641 (a >> 24) & 0xff, (a >> 16) & 0xff,
642 (a >> 8) & 0xff, a & 0xff,
643 (p >> 8) & 0xff, p & 0xff);
644 break;
645 case AF_INET6:
646#define UC(b) (((int)b)&0xff)
647 e = -1;
648 sin6 = (struct sockaddr_in6 *)&sa;
649 if (getnameinfo((struct sockaddr *)&sa, sa.ss_len,
650 hname, sizeof(hname),
651 NULL, 0, NI_NUMERICHOST) == 0) {
656 e = _ftp_cmd(cd, "EPRT |%d|%s|%d|", 2, hname,
652 e = _ftp_cmd(conn, "EPRT |%d|%s|%d|", 2, hname,
657 htons(sin6->sin6_port));
658 if (e == -1)
659 goto ouch;
660 }
661 if (e != FTP_OK) {
662 ap = (char *)&sin6->sin6_addr;
653 htons(sin6->sin6_port));
654 if (e == -1)
655 goto ouch;
656 }
657 if (e != FTP_OK) {
658 ap = (char *)&sin6->sin6_addr;
663 e = _ftp_cmd(cd,
659 e = _ftp_cmd(conn,
664 "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
665 6, 16,
666 UC(ap[0]), UC(ap[1]), UC(ap[2]), UC(ap[3]),
667 UC(ap[4]), UC(ap[5]), UC(ap[6]), UC(ap[7]),
668 UC(ap[8]), UC(ap[9]), UC(ap[10]), UC(ap[11]),
669 UC(ap[12]), UC(ap[13]), UC(ap[14]), UC(ap[15]),
670 2,
671 (ntohs(sin6->sin6_port) >> 8) & 0xff,

--- 4 unchanged lines hidden (view full) ---

676 e = FTP_PROTOCOL_ERROR; /* XXX: error code should be prepared */
677 goto ouch;
678 }
679 if (e != FTP_OK)
680 goto ouch;
681
682 /* seek to required offset */
683 if (offset)
660 "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
661 6, 16,
662 UC(ap[0]), UC(ap[1]), UC(ap[2]), UC(ap[3]),
663 UC(ap[4]), UC(ap[5]), UC(ap[6]), UC(ap[7]),
664 UC(ap[8]), UC(ap[9]), UC(ap[10]), UC(ap[11]),
665 UC(ap[12]), UC(ap[13]), UC(ap[14]), UC(ap[15]),
666 2,
667 (ntohs(sin6->sin6_port) >> 8) & 0xff,

--- 4 unchanged lines hidden (view full) ---

672 e = FTP_PROTOCOL_ERROR; /* XXX: error code should be prepared */
673 goto ouch;
674 }
675 if (e != FTP_OK)
676 goto ouch;
677
678 /* seek to required offset */
679 if (offset)
684 if (_ftp_cmd(cd, "REST %lu", (u_long)offset) != FTP_FILE_OK)
680 if (_ftp_cmd(conn, "REST %ju", (uintmax_t)offset) != FTP_FILE_OK)
685 goto sysouch;
686
687 /* make the server initiate the transfer */
688 if (verbose)
689 _fetch_info("initiating transfer");
681 goto sysouch;
682
683 /* make the server initiate the transfer */
684 if (verbose)
685 _fetch_info("initiating transfer");
690 e = _ftp_cmd(cd, "%s %s", oper, _ftp_filename(file));
686 e = _ftp_cmd(conn, "%s %s", oper, _ftp_filename(file));
691 if (e != FTP_OPEN_DATA_CONNECTION)
692 goto ouch;
693
694 /* accept the incoming connection and go to town */
695 if ((d = accept(sd, NULL, NULL)) == -1)
696 goto sysouch;
697 close(sd);
698 sd = d;
699 }
700
687 if (e != FTP_OPEN_DATA_CONNECTION)
688 goto ouch;
689
690 /* accept the incoming connection and go to town */
691 if ((d = accept(sd, NULL, NULL)) == -1)
692 goto sysouch;
693 close(sd);
694 sd = d;
695 }
696
701 if ((df = _ftp_setup(cd, sd, mode)) == NULL)
697 if ((df = _ftp_setup(conn, sd, mode)) == NULL)
702 goto sysouch;
703 return (df);
704
705sysouch:
706 _fetch_syserr();
707 if (sd >= 0)
708 close(sd);
709 return (NULL);

--- 5 unchanged lines hidden (view full) ---

715 close(sd);
716 return (NULL);
717}
718
719/*
720 * Authenticate
721 */
722static int
698 goto sysouch;
699 return (df);
700
701sysouch:
702 _fetch_syserr();
703 if (sd >= 0)
704 close(sd);
705 return (NULL);

--- 5 unchanged lines hidden (view full) ---

711 close(sd);
712 return (NULL);
713}
714
715/*
716 * Authenticate
717 */
718static int
723_ftp_authenticate(int cd, struct url *url, struct url *purl)
719_ftp_authenticate(conn_t *conn, struct url *url, struct url *purl)
724{
725 const char *user, *pwd, *logname;
726 char pbuf[MAXHOSTNAMELEN + MAXLOGNAME + 1];
727 int e, len;
728
729 /* XXX FTP_AUTH, and maybe .netrc */
730
731 /* send user name and password */
732 user = url->user;
733 if (!user || !*user)
734 user = getenv("FTP_LOGIN");
735 if (!user || !*user)
736 user = FTP_ANONYMOUS_USER;
737 if (purl && url->port == _fetch_default_port(url->scheme))
720{
721 const char *user, *pwd, *logname;
722 char pbuf[MAXHOSTNAMELEN + MAXLOGNAME + 1];
723 int e, len;
724
725 /* XXX FTP_AUTH, and maybe .netrc */
726
727 /* send user name and password */
728 user = url->user;
729 if (!user || !*user)
730 user = getenv("FTP_LOGIN");
731 if (!user || !*user)
732 user = FTP_ANONYMOUS_USER;
733 if (purl && url->port == _fetch_default_port(url->scheme))
738 e = _ftp_cmd(cd, "USER %s@%s", user, url->host);
734 e = _ftp_cmd(conn, "USER %s@%s", user, url->host);
739 else if (purl)
735 else if (purl)
740 e = _ftp_cmd(cd, "USER %s@%s@%d", user, url->host, url->port);
736 e = _ftp_cmd(conn, "USER %s@%s@%d", user, url->host, url->port);
741 else
737 else
742 e = _ftp_cmd(cd, "USER %s", user);
738 e = _ftp_cmd(conn, "USER %s", user);
743
744 /* did the server request a password? */
745 if (e == FTP_NEED_PASSWORD) {
746 pwd = url->pwd;
747 if (!pwd || !*pwd)
748 pwd = getenv("FTP_PASSWORD");
749 if (!pwd || !*pwd) {
750 if ((logname = getlogin()) == 0)
751 logname = FTP_ANONYMOUS_USER;
752 if ((len = snprintf(pbuf, MAXLOGNAME + 1, "%s@", logname)) < 0)
753 len = 0;
754 else if (len > MAXLOGNAME)
755 len = MAXLOGNAME;
756 gethostname(pbuf + len, sizeof pbuf - len);
757 pwd = pbuf;
758 }
739
740 /* did the server request a password? */
741 if (e == FTP_NEED_PASSWORD) {
742 pwd = url->pwd;
743 if (!pwd || !*pwd)
744 pwd = getenv("FTP_PASSWORD");
745 if (!pwd || !*pwd) {
746 if ((logname = getlogin()) == 0)
747 logname = FTP_ANONYMOUS_USER;
748 if ((len = snprintf(pbuf, MAXLOGNAME + 1, "%s@", logname)) < 0)
749 len = 0;
750 else if (len > MAXLOGNAME)
751 len = MAXLOGNAME;
752 gethostname(pbuf + len, sizeof pbuf - len);
753 pwd = pbuf;
754 }
759 e = _ftp_cmd(cd, "PASS %s", pwd);
755 e = _ftp_cmd(conn, "PASS %s", pwd);
760 }
761
762 return (e);
763}
764
765/*
766 * Log on to FTP server
767 */
756 }
757
758 return (e);
759}
760
761/*
762 * Log on to FTP server
763 */
768static int
764static conn_t *
769_ftp_connect(struct url *url, struct url *purl, const char *flags)
770{
765_ftp_connect(struct url *url, struct url *purl, const char *flags)
766{
771 int cd, e, direct, verbose;
767 conn_t *conn;
768 int e, direct, verbose;
772#ifdef INET6
773 int af = AF_UNSPEC;
774#else
775 int af = AF_INET;
776#endif
777
778 direct = CHECK_FLAG('d');
779 verbose = CHECK_FLAG('v');
780 if (CHECK_FLAG('4'))
781 af = AF_INET;
782 else if (CHECK_FLAG('6'))
783 af = AF_INET6;
784
785 if (direct)
786 purl = NULL;
787
788 /* check for proxy */
789 if (purl) {
790 /* XXX proxy authentication! */
769#ifdef INET6
770 int af = AF_UNSPEC;
771#else
772 int af = AF_INET;
773#endif
774
775 direct = CHECK_FLAG('d');
776 verbose = CHECK_FLAG('v');
777 if (CHECK_FLAG('4'))
778 af = AF_INET;
779 else if (CHECK_FLAG('6'))
780 af = AF_INET6;
781
782 if (direct)
783 purl = NULL;
784
785 /* check for proxy */
786 if (purl) {
787 /* XXX proxy authentication! */
791 cd = _fetch_connect(purl->host, purl->port, af, verbose);
788 conn = _fetch_connect(purl->host, purl->port, af, verbose);
792 } else {
793 /* no proxy, go straight to target */
789 } else {
790 /* no proxy, go straight to target */
794 cd = _fetch_connect(url->host, url->port, af, verbose);
791 conn = _fetch_connect(url->host, url->port, af, verbose);
795 purl = NULL;
796 }
797
798 /* check connection */
792 purl = NULL;
793 }
794
795 /* check connection */
799 if (cd == -1) {
796 if (conn == NULL) {
800 _fetch_syserr();
801 return (NULL);
802 }
803
804 /* expect welcome message */
797 _fetch_syserr();
798 return (NULL);
799 }
800
801 /* expect welcome message */
805 if ((e = _ftp_chkerr(cd)) != FTP_SERVICE_READY)
802 if ((e = _ftp_chkerr(conn)) != FTP_SERVICE_READY)
806 goto fouch;
807
808 /* authenticate */
803 goto fouch;
804
805 /* authenticate */
809 if ((e = _ftp_authenticate(cd, url, purl)) != FTP_LOGGED_IN)
806 if ((e = _ftp_authenticate(conn, url, purl)) != FTP_LOGGED_IN)
810 goto fouch;
811
812 /* might as well select mode and type at once */
813#ifdef FTP_FORCE_STREAM_MODE
807 goto fouch;
808
809 /* might as well select mode and type at once */
810#ifdef FTP_FORCE_STREAM_MODE
814 if ((e = _ftp_cmd(cd, "MODE S")) != FTP_OK) /* default is S */
811 if ((e = _ftp_cmd(conn, "MODE S")) != FTP_OK) /* default is S */
815 goto fouch;
816#endif
812 goto fouch;
813#endif
817 if ((e = _ftp_cmd(cd, "TYPE I")) != FTP_OK) /* default is A */
814 if ((e = _ftp_cmd(conn, "TYPE I")) != FTP_OK) /* default is A */
818 goto fouch;
819
820 /* done */
815 goto fouch;
816
817 /* done */
821 return (cd);
818 return (conn);
822
823fouch:
824 if (e != -1)
825 _ftp_seterr(e);
819
820fouch:
821 if (e != -1)
822 _ftp_seterr(e);
826 close(cd);
823 _fetch_close(conn);
827 return (NULL);
828}
829
830/*
831 * Disconnect from server
832 */
833static void
824 return (NULL);
825}
826
827/*
828 * Disconnect from server
829 */
830static void
834_ftp_disconnect(int cd)
831_ftp_disconnect(conn_t *conn)
835{
832{
836 (void)_ftp_cmd(cd, "QUIT");
837 close(cd);
833 (void)_ftp_cmd(conn, "QUIT");
834 _fetch_close(conn);
838}
839
840/*
841 * Check if we're already connected
842 */
843static int
844_ftp_isconnected(struct url *url)
845{
835}
836
837/*
838 * Check if we're already connected
839 */
840static int
841_ftp_isconnected(struct url *url)
842{
846 return (cached_socket
843 return (cached_connection
847 && (strcmp(url->host, cached_host.host) == 0)
848 && (strcmp(url->user, cached_host.user) == 0)
849 && (strcmp(url->pwd, cached_host.pwd) == 0)
850 && (url->port == cached_host.port));
851}
852
853/*
854 * Check the cache, reconnect if no luck
855 */
844 && (strcmp(url->host, cached_host.host) == 0)
845 && (strcmp(url->user, cached_host.user) == 0)
846 && (strcmp(url->pwd, cached_host.pwd) == 0)
847 && (url->port == cached_host.port));
848}
849
850/*
851 * Check the cache, reconnect if no luck
852 */
856static int
853static conn_t *
857_ftp_cached_connect(struct url *url, struct url *purl, const char *flags)
858{
854_ftp_cached_connect(struct url *url, struct url *purl, const char *flags)
855{
859 int e, cd;
856 conn_t *conn;
857 int e;
860
858
861 cd = -1;
862
863 /* set default port */
864 if (!url->port)
865 url->port = _fetch_default_port(url->scheme);
866
867 /* try to use previously cached connection */
868 if (_ftp_isconnected(url)) {
859 /* set default port */
860 if (!url->port)
861 url->port = _fetch_default_port(url->scheme);
862
863 /* try to use previously cached connection */
864 if (_ftp_isconnected(url)) {
869 e = _ftp_cmd(cached_socket, "NOOP");
865 e = _ftp_cmd(cached_connection, "NOOP");
870 if (e == FTP_OK || e == FTP_SYNTAX_ERROR)
866 if (e == FTP_OK || e == FTP_SYNTAX_ERROR)
871 return (cached_socket);
867 return (cached_connection);
872 }
873
874 /* connect to server */
868 }
869
870 /* connect to server */
875 if ((cd = _ftp_connect(url, purl, flags)) == -1)
876 return (-1);
877 if (cached_socket)
878 _ftp_disconnect(cached_socket);
879 cached_socket = cd;
871 if ((conn = _ftp_connect(url, purl, flags)) == NULL)
872 return (NULL);
873 if (cached_connection)
874 _ftp_disconnect(cached_connection);
875 cached_connection = conn;
880 memcpy(&cached_host, url, sizeof *url);
876 memcpy(&cached_host, url, sizeof *url);
881 return (cd);
877 return (conn);
882}
883
884/*
885 * Check the proxy settings
886 */
887static struct url *
888_ftp_get_proxy(void)
889{

--- 21 unchanged lines hidden (view full) ---

911
912/*
913 * Process an FTP request
914 */
915FILE *
916_ftp_request(struct url *url, const char *op, struct url_stat *us,
917 struct url *purl, const char *flags)
918{
878}
879
880/*
881 * Check the proxy settings
882 */
883static struct url *
884_ftp_get_proxy(void)
885{

--- 21 unchanged lines hidden (view full) ---

907
908/*
909 * Process an FTP request
910 */
911FILE *
912_ftp_request(struct url *url, const char *op, struct url_stat *us,
913 struct url *purl, const char *flags)
914{
919 int cd, oflag;
915 conn_t *conn;
916 int oflag;
920
921 /* check if we should use HTTP instead */
922 if (purl && strcasecmp(purl->scheme, SCHEME_HTTP) == 0) {
923 if (strcmp(op, "STAT") == 0)
924 return (_http_request(url, "HEAD", us, purl, flags));
925 else if (strcmp(op, "RETR") == 0)
926 return (_http_request(url, "GET", us, purl, flags));
927 /*
928 * Our HTTP code doesn't support PUT requests yet, so try
929 * a direct connection.
930 */
931 }
932
933 /* connect to server */
917
918 /* check if we should use HTTP instead */
919 if (purl && strcasecmp(purl->scheme, SCHEME_HTTP) == 0) {
920 if (strcmp(op, "STAT") == 0)
921 return (_http_request(url, "HEAD", us, purl, flags));
922 else if (strcmp(op, "RETR") == 0)
923 return (_http_request(url, "GET", us, purl, flags));
924 /*
925 * Our HTTP code doesn't support PUT requests yet, so try
926 * a direct connection.
927 */
928 }
929
930 /* connect to server */
934 cd = _ftp_cached_connect(url, purl, flags);
931 conn = _ftp_cached_connect(url, purl, flags);
935 if (purl)
936 fetchFreeURL(purl);
932 if (purl)
933 fetchFreeURL(purl);
937 if (cd == NULL)
934 if (conn == NULL)
938 return (NULL);
939
940 /* change directory */
935 return (NULL);
936
937 /* change directory */
941 if (_ftp_cwd(cd, url->doc) == -1)
938 if (_ftp_cwd(conn, url->doc) == -1)
942 return (NULL);
943
944 /* stat file */
939 return (NULL);
940
941 /* stat file */
945 if (us && _ftp_stat(cd, url->doc, us) == -1
942 if (us && _ftp_stat(conn, url->doc, us) == -1
946 && fetchLastErrCode != FETCH_PROTO
947 && fetchLastErrCode != FETCH_UNAVAIL)
948 return (NULL);
949
950 /* just a stat */
951 if (strcmp(op, "STAT") == 0)
952 return (FILE *)1; /* bogus return value */
953 if (strcmp(op, "STOR") == 0 || strcmp(op, "APPE") == 0)
954 oflag = O_WRONLY;
955 else
956 oflag = O_RDONLY;
957
958 /* initiate the transfer */
943 && fetchLastErrCode != FETCH_PROTO
944 && fetchLastErrCode != FETCH_UNAVAIL)
945 return (NULL);
946
947 /* just a stat */
948 if (strcmp(op, "STAT") == 0)
949 return (FILE *)1; /* bogus return value */
950 if (strcmp(op, "STOR") == 0 || strcmp(op, "APPE") == 0)
951 oflag = O_WRONLY;
952 else
953 oflag = O_RDONLY;
954
955 /* initiate the transfer */
959 return (_ftp_transfer(cd, op, url->doc, oflag, url->offset, flags));
956 return (_ftp_transfer(conn, op, url->doc, oflag, url->offset, flags));
960}
961
962/*
963 * Get and stat file
964 */
965FILE *
966fetchXGetFTP(struct url *url, struct url_stat *us, const char *flags)
967{

--- 44 unchanged lines hidden ---
957}
958
959/*
960 * Get and stat file
961 */
962FILE *
963fetchXGetFTP(struct url *url, struct url_stat *us, const char *flags)
964{

--- 44 unchanged lines hidden ---