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 --- |