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