1 #ifndef lint 2 static char sccsid[] = "@(#)ftpd.c 4.18 (Berkeley) 03/23/83"; 3 #endif 4 5 /* 6 * FTP server. 7 */ 8 #include <sys/param.h> 9 #include <sys/stat.h> 10 #include <sys/ioctl.h> 11 #include <sys/socket.h> 12 13 #include <netinet/in.h> 14 15 #include <stdio.h> 16 #include <signal.h> 17 #include <wait.h> 18 #include <pwd.h> 19 #include <setjmp.h> 20 #include <netdb.h> 21 #include <errno.h> 22 23 #include "ftp.h" 24 25 /* 26 * File containing login names 27 * NOT to be used on this machine. 28 * Commonly used to disallow uucp. 29 */ 30 #define FTPUSERS "/etc/ftpusers" 31 32 extern int errno; 33 extern char *sys_errlist[]; 34 extern char *crypt(); 35 extern char version[]; 36 extern char *home; /* pointer to home directory for glob */ 37 extern FILE *popen(), *fopen(); 38 extern int pclose(), fclose(); 39 40 struct sockaddr_in ctrl_addr; 41 struct sockaddr_in data_source; 42 struct sockaddr_in data_dest; 43 struct sockaddr_in his_addr; 44 45 struct hostent *hp; 46 47 int data; 48 jmp_buf errcatch; 49 int logged_in; 50 struct passwd *pw; 51 int debug; 52 int timeout; 53 int logging = 1; 54 int guest; 55 int type; 56 int form; 57 int stru; /* avoid C keyword */ 58 int mode; 59 int usedefault = 1; /* for data transfers */ 60 char hostname[32]; 61 char *remotehost; 62 struct servent *sp; 63 64 /* 65 * Timeout intervals for retrying connections 66 * to hosts that don't accept PORT cmds. This 67 * is a kludge, but given the problems with TCP... 68 */ 69 #define SWAITMAX 90 /* wait at most 90 seconds */ 70 #define SWAITINT 5 /* interval between retries */ 71 72 int swaitmax = SWAITMAX; 73 int swaitint = SWAITINT; 74 75 int lostconn(); 76 int reapchild(); 77 FILE *getdatasock(), *dataconn(); 78 char *ntoa(); 79 80 main(argc, argv) 81 int argc; 82 char *argv[]; 83 { 84 int ctrl, s, options = 0; 85 char *cp; 86 87 sp = getservbyname("ftp", "tcp"); 88 if (sp == 0) { 89 fprintf(stderr, "ftpd: ftp/tcp: unknown service\n"); 90 exit(1); 91 } 92 ctrl_addr.sin_port = sp->s_port; 93 data_source.sin_port = htons(ntohs(sp->s_port) - 1); 94 signal(SIGPIPE, lostconn); 95 debug = 0; 96 argc--, argv++; 97 while (argc > 0 && *argv[0] == '-') { 98 for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { 99 100 case 'v': 101 debug = 1; 102 break; 103 104 case 'd': 105 debug = 1; 106 options |= SO_DEBUG; 107 break; 108 109 case 't': 110 timeout = atoi(++cp); 111 goto nextopt; 112 break; 113 114 default: 115 fprintf(stderr, "Unknown flag -%c ignored.\n", *cp); 116 break; 117 } 118 nextopt: 119 argc--, argv++; 120 } 121 #ifndef DEBUG 122 if (fork()) 123 exit(0); 124 for (s = 0; s < 10; s++) 125 if (!logging || (s != 2)) 126 (void) close(s); 127 (void) close(s); 128 (void) open("/", 0); 129 (void) dup2(0, 1); 130 if (!logging) 131 (void) dup2(0, 2); 132 { int tt = open("/dev/tty", 2); 133 if (tt > 0) { 134 ioctl(tt, TIOCNOTTY, 0); 135 close(tt); 136 } 137 } 138 #endif 139 while ((s = socket(AF_INET, SOCK_STREAM, 0, 0)) < 0) { 140 perror("ftpd: socket"); 141 sleep(5); 142 } 143 if (options & SO_DEBUG) 144 if (setsockopt(s, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 145 perror("ftpd: setsockopt (SO_DEBUG)"); 146 #ifdef notdef 147 if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0) 148 perror("ftpd: setsockopt (SO_KEEPALIVE)"); 149 #endif 150 while (bind(s, &ctrl_addr, sizeof (ctrl_addr), 0) < 0) { 151 perror("ftpd: bind"); 152 sleep(5); 153 } 154 sigset(SIGCHLD, reapchild); 155 listen(s, 10); 156 for (;;) { 157 int hisaddrlen = sizeof (his_addr); 158 159 ctrl = accept(s, &his_addr, &hisaddrlen, 0); 160 if (ctrl < 0) { 161 if (errno == EINTR) 162 continue; 163 perror("ftpd: accept"); 164 continue; 165 } 166 if (fork() == 0) { 167 signal (SIGCHLD, SIG_IGN); 168 if (logging) 169 dolog(&his_addr); 170 close(s); 171 dup2(ctrl, 0), close(ctrl), dup2(0, 1); 172 /* do telnet option negotiation here */ 173 /* 174 * Set up default state 175 */ 176 logged_in = 0; 177 data = -1; 178 type = TYPE_A; 179 form = FORM_N; 180 stru = STRU_F; 181 mode = MODE_S; 182 gethostname(hostname, sizeof (hostname)); 183 reply(220, "%s FTP server (%s) ready.", 184 hostname, version); 185 for (;;) { 186 setjmp(errcatch); 187 yyparse(); 188 } 189 } 190 close(ctrl); 191 } 192 } 193 194 reapchild() 195 { 196 union wait status; 197 198 while (wait3(&status, WNOHANG, 0) > 0) 199 ; 200 } 201 202 lostconn() 203 { 204 205 fatal("Connection closed."); 206 } 207 208 pass(passwd) 209 char *passwd; 210 { 211 char *xpasswd, *savestr(); 212 static struct passwd save; 213 214 if (logged_in || pw == NULL) { 215 reply(503, "Login with USER first."); 216 return; 217 } 218 if (!guest) { /* "ftp" is only account allowed no password */ 219 xpasswd = crypt(passwd, pw->pw_passwd); 220 if (strcmp(xpasswd, pw->pw_passwd) != 0) { 221 reply(530, "Login incorrect."); 222 pw = NULL; 223 return; 224 } 225 } 226 setegid(pw->pw_gid); 227 initgroups(pw->pw_name, pw->pw_gid); 228 if (chdir(pw->pw_dir)) { 229 reply(550, "User %s: can't change directory to $s.", 230 pw->pw_name, pw->pw_dir); 231 goto bad; 232 } 233 if (guest && chroot(pw->pw_dir) < 0) { 234 reply(550, "Can't set guest privileges."); 235 goto bad; 236 } 237 if (!guest) 238 reply(230, "User %s logged in.", pw->pw_name); 239 else 240 reply(230, "Guest login ok, access restrictions apply."); 241 logged_in = 1; 242 seteuid(pw->pw_uid); 243 /* 244 * Save everything so globbing doesn't 245 * clobber the fields. 246 */ 247 save = *pw; 248 save.pw_name = savestr(pw->pw_name); 249 save.pw_passwd = savestr(pw->pw_passwd); 250 save.pw_comment = savestr(pw->pw_comment); 251 save.pw_gecos = savestr(pw->pw_gecos, &save.pw_gecos); 252 save.pw_dir = savestr(pw->pw_dir); 253 save.pw_shell = savestr(pw->pw_shell); 254 pw = &save; 255 home = pw->pw_dir; /* home dir for globbing */ 256 return; 257 bad: 258 seteuid(0); 259 pw = NULL; 260 } 261 262 char * 263 savestr(s) 264 char *s; 265 { 266 char *malloc(); 267 char *new = malloc(strlen(s) + 1); 268 269 if (new != NULL) 270 strcpy(new, s); 271 return (new); 272 } 273 274 retrieve(cmd, name) 275 char *cmd, *name; 276 { 277 FILE *fin, *dout; 278 struct stat st; 279 int (*closefunc)(); 280 281 if (cmd == 0) { 282 #ifdef notdef 283 /* no remote command execution -- it's a security hole */ 284 if (*name == '|') 285 fin = popen(name + 1, "r"), closefunc = pclose; 286 else 287 #endif 288 fin = fopen(name, "r"), closefunc = fclose; 289 } else { 290 char line[BUFSIZ]; 291 292 sprintf(line, cmd, name), name = line; 293 fin = popen(line, "r"), closefunc = pclose; 294 } 295 if (fin == NULL) { 296 reply(550, "%s: %s.", name, sys_errlist[errno]); 297 return; 298 } 299 st.st_size = 0; 300 if (cmd == 0 && 301 (stat(name, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) { 302 reply(550, "%s: not a plain file.", name); 303 goto done; 304 } 305 dout = dataconn(name, st.st_size, "w"); 306 if (dout == NULL) 307 goto done; 308 if (send_data(fin, dout) || ferror(dout)) 309 reply(550, "%s: %s.", name, sys_errlist[errno]); 310 else 311 reply(226, "Transfer complete."); 312 fclose(dout), data = -1; 313 done: 314 (*closefunc)(fin); 315 } 316 317 store(name, mode) 318 char *name, *mode; 319 { 320 FILE *fout, *din; 321 int (*closefunc)(), dochown = 0; 322 323 #ifdef notdef 324 /* no remote command execution -- it's a security hole */ 325 if (name[0] == '|') 326 fout = popen(&name[1], "w"), closefunc = pclose; 327 else 328 #endif 329 { 330 struct stat st; 331 332 if (stat(name, &st) < 0) 333 dochown++; 334 fout = fopen(name, mode), closefunc = fclose; 335 } 336 if (fout == NULL) { 337 reply(550, "%s: %s.", name, sys_errlist[errno]); 338 return; 339 } 340 din = dataconn(name, (off_t)-1, "r"); 341 if (din == NULL) 342 goto done; 343 if (receive_data(din, fout) || ferror(fout)) 344 reply(550, "%s: %s.", name, sys_errlist[errno]); 345 else 346 reply(226, "Transfer complete."); 347 fclose(din), data = -1; 348 done: 349 if (dochown) 350 (void) chown(name, pw->pw_uid, -1); 351 (*closefunc)(fout); 352 } 353 354 FILE * 355 getdatasock(mode) 356 char *mode; 357 { 358 int s; 359 360 if (data >= 0) 361 return (fdopen(data, mode)); 362 s = socket(AF_INET, SOCK_STREAM, 0, 0); 363 if (s < 0) 364 return (NULL); 365 seteuid(0); 366 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0) 367 goto bad; 368 if (bind(s, &data_source, sizeof (data_source), 0) < 0) 369 goto bad; 370 seteuid(pw->pw_uid); 371 return (fdopen(s, mode)); 372 bad: 373 seteuid(pw->pw_uid); 374 close(s); 375 return (NULL); 376 } 377 378 FILE * 379 dataconn(name, size, mode) 380 char *name; 381 off_t size; 382 char *mode; 383 { 384 char sizebuf[32]; 385 FILE *file; 386 int retry = 0; 387 388 if (size >= 0) 389 sprintf (sizebuf, " (%ld bytes)", size); 390 else 391 (void) strcpy(sizebuf, ""); 392 if (data >= 0) { 393 reply(125, "Using existing data connection for %s%s.", 394 name, sizebuf); 395 usedefault = 1; 396 return (fdopen(data, mode)); 397 } 398 if (usedefault) 399 data_dest = his_addr; 400 usedefault = 1; 401 file = getdatasock(mode); 402 if (file == NULL) { 403 reply(425, "Can't create data socket (%s,%d): %s.", 404 ntoa(data_source.sin_addr), 405 ntohs(data_source.sin_port), 406 sys_errlist[errno]); 407 return (NULL); 408 } 409 reply(150, "Opening data connection for %s (%s,%d)%s.", 410 name, ntoa(data_dest.sin_addr.s_addr), 411 ntohs(data_dest.sin_port), sizebuf); 412 data = fileno(file); 413 while (connect(data, &data_dest, sizeof (data_dest), 0) < 0) { 414 if (errno == EADDRINUSE && retry < swaitmax) { 415 sleep(swaitint); 416 retry += swaitint; 417 continue; 418 } 419 reply(425, "Can't build data connection: %s.", 420 sys_errlist[errno]); 421 (void) fclose(file); 422 data = -1; 423 return (NULL); 424 } 425 return (file); 426 } 427 428 /* 429 * Tranfer the contents of "instr" to 430 * "outstr" peer using the appropriate 431 * encapulation of the date subject 432 * to Mode, Structure, and Type. 433 * 434 * NB: Form isn't handled. 435 */ 436 send_data(instr, outstr) 437 FILE *instr, *outstr; 438 { 439 register int c; 440 int netfd, filefd, cnt; 441 char buf[BUFSIZ]; 442 443 switch (type) { 444 445 case TYPE_A: 446 while ((c = getc(instr)) != EOF) { 447 if (c == '\n') { 448 if (ferror (outstr)) 449 return (1); 450 putc('\r', outstr); 451 } 452 putc(c, outstr); 453 if (c == '\r') 454 putc ('\0', outstr); 455 } 456 if (ferror (instr) || ferror (outstr)) 457 return (1); 458 return (0); 459 460 case TYPE_I: 461 case TYPE_L: 462 netfd = fileno(outstr); 463 filefd = fileno(instr); 464 465 while ((cnt = read(filefd, buf, sizeof (buf))) > 0) 466 if (write(netfd, buf, cnt) < 0) 467 return (1); 468 return (cnt < 0); 469 } 470 reply(504,"Unimplemented TYPE %d in send_data", type); 471 return (1); 472 } 473 474 /* 475 * Transfer data from peer to 476 * "outstr" using the appropriate 477 * encapulation of the data subject 478 * to Mode, Structure, and Type. 479 * 480 * N.B.: Form isn't handled. 481 */ 482 receive_data(instr, outstr) 483 FILE *instr, *outstr; 484 { 485 register int c; 486 int cnt; 487 char buf[BUFSIZ]; 488 489 490 switch (type) { 491 492 case TYPE_I: 493 case TYPE_L: 494 while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) 495 if (write(fileno(outstr), buf, cnt) < 0) 496 return (1); 497 return (cnt < 0); 498 499 case TYPE_E: 500 reply(504, "TYPE E not implemented."); 501 return (1); 502 503 case TYPE_A: 504 while ((c = getc(instr)) != EOF) { 505 if (c == '\r') { 506 if (ferror (outstr)) 507 return (1); 508 if ((c = getc(instr)) != '\n') 509 putc ('\r', outstr); 510 if (c == '\0') 511 continue; 512 } 513 putc (c, outstr); 514 } 515 if (ferror (instr) || ferror (outstr)) 516 return (1); 517 return (0); 518 } 519 fatal("Unknown type in receive_data."); 520 /*NOTREACHED*/ 521 } 522 523 fatal(s) 524 char *s; 525 { 526 reply(451, "Error in server: %s\n", s); 527 reply(221, "Closing connection due to server error."); 528 exit(0); 529 } 530 531 reply(n, s, args) 532 int n; 533 char *s; 534 { 535 536 printf("%d ", n); 537 _doprnt(s, &args, stdout); 538 printf("\r\n"); 539 fflush(stdout); 540 if (debug) { 541 fprintf(stderr, "<--- %d ", n); 542 _doprnt(s, &args, stderr); 543 fprintf(stderr, "\n"); 544 fflush(stderr); 545 } 546 } 547 548 lreply(n, s, args) 549 int n; 550 char *s; 551 { 552 printf("%d-", n); 553 _doprnt(s, &args, stdout); 554 printf("\r\n"); 555 fflush(stdout); 556 if (debug) { 557 fprintf(stderr, "<--- %d-", n); 558 _doprnt(s, &args, stderr); 559 fprintf(stderr, "\n"); 560 } 561 } 562 563 replystr(s) 564 char *s; 565 { 566 printf("%s\r\n", s); 567 fflush(stdout); 568 if (debug) 569 fprintf(stderr, "<--- %s\n", s); 570 } 571 572 ack(s) 573 char *s; 574 { 575 reply(200, "%s command okay.", s); 576 } 577 578 nack(s) 579 char *s; 580 { 581 reply(502, "%s command not implemented.", s); 582 } 583 584 yyerror() 585 { 586 reply(500, "Command not understood."); 587 } 588 589 delete(name) 590 char *name; 591 { 592 struct stat st; 593 594 if (stat(name, &st) < 0) { 595 reply(550, "%s: %s.", name, sys_errlist[errno]); 596 return; 597 } 598 if ((st.st_mode&S_IFMT) == S_IFDIR) { 599 if (rmdir(name) < 0) { 600 reply(550, "%s: %s.", name, sys_errlist[errno]); 601 return; 602 } 603 goto done; 604 } 605 if (unlink(name) < 0) { 606 reply(550, "%s: %s.", name, sys_errlist[errno]); 607 return; 608 } 609 done: 610 ack("DELE"); 611 } 612 613 cwd(path) 614 char *path; 615 { 616 617 if (chdir(path) < 0) { 618 reply(550, "%s: %s.", path, sys_errlist[errno]); 619 return; 620 } 621 ack("CWD"); 622 } 623 624 makedir(name) 625 char *name; 626 { 627 struct stat st; 628 int dochown = stat(name, &st) < 0; 629 630 if (mkdir(name, 0777) < 0) { 631 reply(550, "%s: %s.", name, sys_errlist[errno]); 632 return; 633 } 634 if (dochown) 635 (void) chown(name, pw->pw_uid, -1); 636 ack("MKDIR"); 637 } 638 639 removedir(name) 640 char *name; 641 { 642 643 if (rmdir(name) < 0) { 644 reply(550, "%s: %s.", name, sys_errlist[errno]); 645 return; 646 } 647 ack("RMDIR"); 648 } 649 650 pwd() 651 { 652 char path[MAXPATHLEN + 1]; 653 654 if (getwd(path) == NULL) { 655 reply(451, "%s.", path); 656 return; 657 } 658 reply(251, "\"%s\" is current directory.", path); 659 } 660 661 char * 662 renamefrom(name) 663 char *name; 664 { 665 struct stat st; 666 667 if (stat(name, &st) < 0) { 668 reply(550, "%s: %s.", name, sys_errlist[errno]); 669 return ((char *)0); 670 } 671 reply(350, "File exists, ready for destination name"); 672 return (name); 673 } 674 675 renamecmd(from, to) 676 char *from, *to; 677 { 678 679 if (rename(from, to) < 0) { 680 reply(550, "rename: %s.", sys_errlist[errno]); 681 return; 682 } 683 ack("RNTO"); 684 } 685 686 /* 687 * Convert network-format internet address 688 * to base 256 d.d.d.d representation. 689 */ 690 char * 691 ntoa(in) 692 struct in_addr in; 693 { 694 static char b[18]; 695 register char *p; 696 697 p = (char *)∈ 698 #define UC(b) (((int)b)&0xff) 699 sprintf(b, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3])); 700 return (b); 701 } 702 703 dolog(sin) 704 struct sockaddr_in *sin; 705 { 706 struct hostent *hp = gethostbyaddr(&sin->sin_addr, 707 sizeof (struct in_addr), AF_INET); 708 char *remotehost; 709 time_t t; 710 711 if (hp) 712 remotehost = hp->h_name; 713 else 714 remotehost = "UNKNOWNHOST"; 715 t = time(0); 716 fprintf(stderr,"FTP: connection from %s at %s", remotehost, ctime(&t)); 717 fflush(stderr); 718 } 719 720 /* 721 * Special version of popen which avoids 722 * call to shell. This insures noone may 723 * create a pipe to a hidden program as a side 724 * effect of a list or dir command. 725 */ 726 #define tst(a,b) (*mode == 'r'? (b) : (a)) 727 #define RDR 0 728 #define WTR 1 729 static int popen_pid[5]; 730 731 static char * 732 nextarg(cpp) 733 char *cpp; 734 { 735 register char *cp = cpp; 736 737 if (cp == 0) 738 return (cp); 739 while (*cp && *cp != ' ' && *cp != '\t') 740 cp++; 741 if (*cp == ' ' || *cp == '\t') { 742 *cp++ = '\0'; 743 while (*cp == ' ' || *cp == '\t') 744 cp++; 745 } 746 if (cp == cpp) 747 return ((char *)0); 748 return (cp); 749 } 750 751 FILE * 752 popen(cmd, mode) 753 char *cmd, *mode; 754 { 755 int p[2], ac; 756 register myside, hisside, pid; 757 char *av[10]; 758 register char *cp; 759 760 if (pipe(p) < 0) 761 return (NULL); 762 cp = cmd, ac = 0; 763 do { 764 av[ac++] = cp; 765 cp = nextarg(cp); 766 } while (cp && *cp); 767 av[ac] = (char *)0; 768 myside = tst(p[WTR], p[RDR]); 769 hisside = tst(p[RDR], p[WTR]); 770 if ((pid = fork()) == 0) { 771 /* myside and hisside reverse roles in child */ 772 close(myside); 773 dup2(hisside, tst(0, 1)); 774 close(hisside); 775 execv(av[0], av); 776 _exit(1); 777 } 778 if (pid == -1) 779 return (NULL); 780 popen_pid[myside] = pid; 781 close(hisside); 782 return (fdopen(myside, mode)); 783 } 784 785 pclose(ptr) 786 FILE *ptr; 787 { 788 register f, r, (*hstat)(), (*istat)(), (*qstat)(); 789 int status; 790 791 f = fileno(ptr); 792 fclose(ptr); 793 istat = signal(SIGINT, SIG_IGN); 794 qstat = signal(SIGQUIT, SIG_IGN); 795 hstat = signal(SIGHUP, SIG_IGN); 796 while ((r = wait(&status)) != popen_pid[f] && r != -1) 797 ; 798 if (r == -1) 799 status = -1; 800 signal(SIGINT, istat); 801 signal(SIGQUIT, qstat); 802 signal(SIGHUP, hstat); 803 return (status); 804 } 805 806 /* 807 * Check user requesting login priviledges. 808 * Disallow anyone mentioned in the file FTPUSERS 809 * to allow people such as uucp to be avoided. 810 */ 811 checkuser(name) 812 register char *name; 813 { 814 char line[BUFSIZ], *index(); 815 FILE *fd; 816 int found = 0; 817 818 fd = fopen(FTPUSERS, "r"); 819 if (fd == NULL) 820 return (1); 821 while (fgets(line, sizeof (line), fd) != NULL) { 822 register char *cp = index(line, '\n'); 823 824 if (cp) 825 *cp = '\0'; 826 if (strcmp(line, name) == 0) { 827 found++; 828 break; 829 } 830 } 831 fclose(fd); 832 return (!found); 833 } 834