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