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