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