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