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