1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 static char sccsid[] = "@(#)ftp.c 5.5 (Berkeley) 01/13/86"; 9 #endif not lint 10 11 #include <sys/param.h> 12 #include <sys/stat.h> 13 #include <sys/ioctl.h> 14 #include <sys/socket.h> 15 #include <sys/time.h> 16 17 #include <netinet/in.h> 18 #include <arpa/ftp.h> 19 20 #include <stdio.h> 21 #include <signal.h> 22 #include <errno.h> 23 #include <netdb.h> 24 25 #include "ftp_var.h" 26 27 struct sockaddr_in hisctladdr; 28 struct sockaddr_in data_addr; 29 int data = -1; 30 int connected; 31 struct sockaddr_in myctladdr; 32 33 FILE *cin, *cout; 34 FILE *dataconn(); 35 36 char * 37 hookup(host, port) 38 char *host; 39 int port; 40 { 41 register struct hostent *hp = 0; 42 static char hostnamebuf[80]; 43 int s, len; 44 45 bzero((char *)&hisctladdr, sizeof (hisctladdr)); 46 hisctladdr.sin_addr.s_addr = inet_addr(host); 47 if (hisctladdr.sin_addr.s_addr != -1) { 48 hisctladdr.sin_family = AF_INET; 49 (void) strcpy(hostnamebuf, host); 50 } else { 51 hp = gethostbyname(host); 52 if (hp == NULL) { 53 printf("%s: unknown host\n", host); 54 return (0); 55 } 56 hisctladdr.sin_family = hp->h_addrtype; 57 bcopy(hp->h_addr_list[0], 58 (caddr_t)&hisctladdr.sin_addr, hp->h_length); 59 (void) strcpy(hostnamebuf, hp->h_name); 60 } 61 hostname = hostnamebuf; 62 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); 63 if (s < 0) { 64 perror("ftp: socket"); 65 return (0); 66 } 67 hisctladdr.sin_port = port; 68 while (connect(s, (caddr_t)&hisctladdr, sizeof (hisctladdr)) < 0) { 69 if (hp && hp->h_addr_list[1]) { 70 int oerrno = errno; 71 72 fprintf(stderr, "ftp: connect to address %s: ", 73 inet_ntoa(hisctladdr.sin_addr)); 74 errno = oerrno; 75 perror(0); 76 hp->h_addr_list++; 77 bcopy(hp->h_addr_list[0], 78 (caddr_t)&hisctladdr.sin_addr, hp->h_length); 79 fprintf(stderr, "Trying %s...\n", 80 inet_ntoa(hisctladdr.sin_addr)); 81 continue; 82 } 83 perror("ftp: connect"); 84 goto bad; 85 } 86 len = sizeof (myctladdr); 87 if (getsockname(s, (char *)&myctladdr, &len) < 0) { 88 perror("ftp: getsockname"); 89 goto bad; 90 } 91 cin = fdopen(s, "r"); 92 cout = fdopen(s, "w"); 93 if (cin == NULL || cout == NULL) { 94 fprintf(stderr, "ftp: fdopen failed.\n"); 95 if (cin) 96 fclose(cin); 97 if (cout) 98 fclose(cout); 99 goto bad; 100 } 101 if (verbose) 102 printf("Connected to %s.\n", hostname); 103 (void) getreply(0); /* read startup message from server */ 104 return (hostname); 105 bad: 106 close(s); 107 return ((char *)0); 108 } 109 110 login(host) 111 char *host; 112 { 113 char acct[80]; 114 char *user, *pass; 115 int n; 116 117 user = pass = 0; 118 ruserpass(host, &user, &pass); 119 n = command("USER %s", user); 120 if (n == CONTINUE) 121 n = command("PASS %s", pass); 122 if (n == CONTINUE) { 123 printf("Account: "); (void) fflush(stdout); 124 (void) fgets(acct, sizeof(acct) - 1, stdin); 125 acct[strlen(acct) - 1] = '\0'; 126 n = command("ACCT %s", acct); 127 } 128 if (n != COMPLETE) { 129 fprintf(stderr, "Login failed.\n"); 130 return (0); 131 } 132 return (1); 133 } 134 135 /*VARARGS 1*/ 136 command(fmt, args) 137 char *fmt; 138 { 139 140 if (debug) { 141 printf("---> "); 142 _doprnt(fmt, &args, stdout); 143 printf("\n"); 144 (void) fflush(stdout); 145 } 146 if (cout == NULL) { 147 perror ("No control connection for command"); 148 return (0); 149 } 150 _doprnt(fmt, &args, cout); 151 fprintf(cout, "\r\n"); 152 (void) fflush(cout); 153 return (getreply(!strcmp(fmt, "QUIT"))); 154 } 155 156 #include <ctype.h> 157 158 getreply(expecteof) 159 int expecteof; 160 { 161 register int c, n; 162 register int code, dig; 163 int originalcode = 0, continuation = 0; 164 165 for (;;) { 166 dig = n = code = 0; 167 while ((c = getc(cin)) != '\n') { 168 dig++; 169 if (c == EOF) { 170 if (expecteof) 171 return (0); 172 lostpeer(); 173 exit(1); 174 } 175 if (verbose && c != '\r' || 176 (n == '5' && dig > 4)) 177 putchar(c); 178 if (dig < 4 && isdigit(c)) 179 code = code * 10 + (c - '0'); 180 if (dig == 4 && c == '-') 181 continuation++; 182 if (n == 0) 183 n = c; 184 } 185 if (verbose || n == '5') { 186 putchar(c); 187 (void) fflush (stdout); 188 } 189 if (continuation && code != originalcode) { 190 if (originalcode == 0) 191 originalcode = code; 192 continue; 193 } 194 return (n - '0'); 195 } 196 } 197 198 jmp_buf sendabort; 199 200 abortsend() 201 { 202 203 longjmp(sendabort, 1); 204 } 205 206 sendrequest(cmd, local, remote) 207 char *cmd, *local, *remote; 208 { 209 FILE *fin, *dout, *popen(); 210 int (*closefunc)(), pclose(), fclose(), (*oldintr)(); 211 char buf[BUFSIZ]; 212 int expectingreply = 0; 213 long bytes = 0, hashbytes = sizeof (buf); 214 register int c, d; 215 struct stat st; 216 struct timeval start, stop; 217 218 closefunc = NULL; 219 if (setjmp(sendabort)) 220 goto bad; 221 oldintr = signal(SIGINT, abortsend); 222 if (strcmp(local, "-") == 0) 223 fin = stdin; 224 else if (*local == '|') { 225 /* 226 * Advance local so further uses just yield file name 227 * thus later references for error messages need not check 228 * for '|' special case. 229 */ 230 local += 1; 231 fin = popen(local, "r"); 232 if (fin == NULL) { 233 perror(local); 234 goto bad; 235 } 236 closefunc = pclose; 237 } else { 238 fin = fopen(local, "r"); 239 if (fin == NULL) { 240 perror(local); 241 goto bad; 242 } 243 closefunc = fclose; 244 if (fstat(fileno(fin), &st) < 0 || 245 (st.st_mode&S_IFMT) != S_IFREG) { 246 fprintf(stderr, "%s: not a plain file.\n", local); 247 goto bad; 248 } 249 } 250 if (initconn()) 251 goto bad; 252 if (remote) { 253 if (command("%s %s", cmd, remote) != PRELIM) 254 goto bad; 255 } else 256 if (command("%s", cmd) != PRELIM) 257 goto bad; 258 expectingreply++; /* got preliminary reply, expecting final reply */ 259 dout = dataconn("w"); 260 if (dout == NULL) 261 goto bad; 262 gettimeofday(&start, (struct timezone *)0); 263 switch (type) { 264 265 case TYPE_I: 266 case TYPE_L: 267 errno = d = 0; 268 while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) { 269 if ((d = write(fileno (dout), buf, c)) < 0) 270 break; 271 bytes += c; 272 if (hash) { 273 putchar('#'); 274 fflush(stdout); 275 } 276 } 277 if (hash && bytes > 0) { 278 putchar('\n'); 279 fflush(stdout); 280 } 281 if (c < 0) 282 perror(local); 283 if (d < 0) 284 perror("netout"); 285 break; 286 287 case TYPE_A: 288 while ((c = getc(fin)) != EOF) { 289 if (c == '\n') { 290 while (hash && (bytes >= hashbytes)) { 291 putchar('#'); 292 fflush(stdout); 293 hashbytes += sizeof (buf); 294 } 295 if (ferror(dout)) 296 break; 297 putc('\r', dout); 298 bytes++; 299 } 300 putc(c, dout); 301 bytes++; 302 if (c == '\r') { 303 putc('\0', dout); 304 bytes++; 305 } 306 } 307 if (hash) { 308 if (bytes < hashbytes) 309 putchar('#'); 310 putchar('\n'); 311 fflush(stdout); 312 } 313 if (ferror(fin)) 314 perror(local); 315 if (ferror(dout)) 316 perror("netout"); 317 break; 318 } 319 gettimeofday(&stop, (struct timezone *)0); 320 if (closefunc != NULL) 321 (*closefunc)(fin), closefunc = NULL; 322 (void) fclose(dout); 323 done: 324 if (expectingreply) { 325 (void) getreply(0); 326 expectingreply = 0; 327 } 328 signal(SIGINT, oldintr); 329 if (bytes > 0 && verbose) 330 ptransfer("sent", bytes, &start, &stop); 331 return; 332 bad: 333 if (data >= 0) 334 (void) close(data), data = -1; 335 if (closefunc != NULL && fin != NULL) 336 (*closefunc)(fin), closefunc = NULL; 337 bytes = 0; /* so we don't print a message if the transfer was aborted */ 338 goto done; 339 } 340 341 jmp_buf recvabort; 342 343 abortrecv() 344 { 345 346 longjmp(recvabort, 1); 347 } 348 349 recvrequest(cmd, local, remote, mode) 350 char *cmd, *local, *remote, *mode; 351 { 352 FILE *fout, *din, *popen(); 353 int (*closefunc)(), pclose(), fclose(), (*oldintr)(); 354 char buf[BUFSIZ]; 355 int expectingreply = 0; 356 long bytes = 0, hashbytes = sizeof (buf); 357 register int c, d; 358 struct timeval start, stop; 359 360 closefunc = NULL; 361 if (setjmp(recvabort)) 362 goto bad; 363 oldintr = signal(SIGINT, abortrecv); 364 if (strcmp(local, "-") && *local != '|') 365 if (access(local, 2) < 0) { 366 if (errno == ENOENT) { 367 char *dir = rindex(local, '/'); 368 369 if (dir != NULL) 370 *dir = 0; 371 d = access(dir ? local : ".", 2); 372 if (dir != NULL) 373 *dir = '/'; 374 if (d < 0) { 375 perror(local); 376 goto bad; 377 } 378 } else { 379 perror(local); 380 goto bad; 381 } 382 } 383 if (initconn()) 384 goto bad; 385 if (remote) { 386 if (command("%s %s", cmd, remote) != PRELIM) 387 goto bad; 388 } else 389 if (command("%s", cmd) != PRELIM) 390 goto bad; 391 expectingreply++; /* got preliminary reply, expecting final reply */ 392 if (strcmp(local, "-") == 0) 393 fout = stdout; 394 else if (*local == '|') { 395 /* 396 * Advance local over '|' so don't need to check for 397 * '|' special case any further. 398 */ 399 local += 1; 400 fout = popen(local, "w"); 401 closefunc = pclose; 402 } else { 403 fout = fopen(local, mode); 404 closefunc = fclose; 405 } 406 if (fout == NULL) { 407 perror(local); 408 goto bad; 409 } 410 din = dataconn("r"); 411 if (din == NULL) 412 goto bad; 413 gettimeofday(&start, (struct timezone *)0); 414 switch (type) { 415 416 case TYPE_I: 417 case TYPE_L: 418 errno = d = 0; 419 while ((c = read(fileno(din), buf, sizeof (buf))) > 0) { 420 if ((d = write(fileno(fout), buf, c)) < 0) 421 break; 422 bytes += c; 423 if (hash) { 424 putchar('#'); 425 fflush(stdout); 426 } 427 } 428 if (hash && bytes > 0) { 429 putchar('\n'); 430 fflush(stdout); 431 } 432 if (c < 0) 433 perror("netin"); 434 if (d < 0) 435 perror(local); 436 break; 437 438 case TYPE_A: 439 while ((c = getc(din)) != EOF) { 440 if (c == '\r') { 441 while (hash && (bytes >= hashbytes)) { 442 putchar('#'); 443 fflush(stdout); 444 hashbytes += sizeof (buf); 445 } 446 bytes++; 447 if ((c = getc(din)) != '\n') { 448 if (ferror (fout)) 449 break; 450 putc ('\r', fout); 451 } 452 if (c == '\0') { 453 bytes++; 454 continue; 455 } 456 } 457 putc (c, fout); 458 bytes++; 459 } 460 if (hash) { 461 if (bytes < hashbytes) 462 putchar('#'); 463 putchar('\n'); 464 fflush(stdout); 465 } 466 if (ferror (din)) 467 perror ("netin"); 468 if (ferror (fout)) 469 perror (local); 470 break; 471 } 472 gettimeofday(&stop, (struct timezone *)0); 473 (void) fclose(din); 474 if (closefunc != NULL) 475 (*closefunc)(fout), closefunc = NULL; 476 done: 477 if (expectingreply) { 478 (void) getreply(0); 479 expectingreply = 0; 480 } 481 signal(SIGINT, oldintr); 482 if (bytes > 0 && verbose) 483 ptransfer("received", bytes, &start, &stop); 484 return; 485 bad: 486 if (data >= 0) 487 (void) close(data), data = -1; 488 if (closefunc != NULL && fout != NULL) 489 (*closefunc)(fout); 490 bytes = 0; /* so we don't print a message if the transfer was aborted */ 491 goto done; 492 } 493 494 /* 495 * Need to start a listen on the data channel 496 * before we send the command, otherwise the 497 * server's connect may fail. 498 */ 499 static int sendport = -1; 500 501 initconn() 502 { 503 register char *p, *a; 504 int result, len; 505 int on = 1; 506 507 noport: 508 data_addr = myctladdr; 509 if (sendport) 510 data_addr.sin_port = 0; /* let system pick one */ 511 if (data != -1) 512 (void) close (data); 513 data = socket(AF_INET, SOCK_STREAM, 0); 514 if (data < 0) { 515 perror("ftp: socket"); 516 return (1); 517 } 518 if (!sendport) 519 if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) { 520 perror("ftp: setsockopt (reuse address)"); 521 goto bad; 522 } 523 if (bind(data, (char *)&data_addr, sizeof (data_addr), 0) < 0) { 524 perror("ftp: bind"); 525 goto bad; 526 } 527 if (options & SO_DEBUG && 528 setsockopt(data, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) 529 perror("ftp: setsockopt (ignored)"); 530 len = sizeof (data_addr); 531 if (getsockname(data, (char *)&data_addr, &len) < 0) { 532 perror("ftp: getsockname"); 533 goto bad; 534 } 535 if (listen(data, 1) < 0) { 536 perror("ftp: listen"); 537 goto bad; 538 } 539 if (sendport) { 540 a = (char *)&data_addr.sin_addr; 541 p = (char *)&data_addr.sin_port; 542 #define UC(b) (((int)b)&0xff) 543 result = 544 command("PORT %d,%d,%d,%d,%d,%d", 545 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 546 UC(p[0]), UC(p[1])); 547 if (result == ERROR && sendport == -1) { 548 sendport = 0; 549 goto noport; 550 } 551 return (result != COMPLETE); 552 } 553 return (0); 554 bad: 555 (void) close(data), data = -1; 556 return (1); 557 } 558 559 FILE * 560 dataconn(mode) 561 char *mode; 562 { 563 struct sockaddr_in from; 564 int s, fromlen = sizeof (from); 565 566 s = accept(data, &from, &fromlen, 0); 567 if (s < 0) { 568 perror("ftp: accept"); 569 (void) close(data), data = -1; 570 return (NULL); 571 } 572 (void) close(data); 573 data = s; 574 return (fdopen(data, mode)); 575 } 576 577 ptransfer(direction, bytes, t0, t1) 578 char *direction; 579 long bytes; 580 struct timeval *t0, *t1; 581 { 582 struct timeval td; 583 float s, bs; 584 585 tvsub(&td, t1, t0); 586 s = td.tv_sec + (td.tv_usec / 1000000.); 587 #define nz(x) ((x) == 0 ? 1 : (x)) 588 bs = bytes / nz(s); 589 printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n", 590 bytes, direction, s, bs / 1024.); 591 } 592 593 tvadd(tsum, t0) 594 struct timeval *tsum, *t0; 595 { 596 597 tsum->tv_sec += t0->tv_sec; 598 tsum->tv_usec += t0->tv_usec; 599 if (tsum->tv_usec > 1000000) 600 tsum->tv_sec++, tsum->tv_usec -= 1000000; 601 } 602 603 tvsub(tdiff, t1, t0) 604 struct timeval *tdiff, *t1, *t0; 605 { 606 607 tdiff->tv_sec = t1->tv_sec - t0->tv_sec; 608 tdiff->tv_usec = t1->tv_usec - t0->tv_usec; 609 if (tdiff->tv_usec < 0) 610 tdiff->tv_sec--, tdiff->tv_usec += 1000000; 611 } 612