1 #ifndef lint 2 static char sccsid[] = "@(#)ftpd.c 4.11 (Berkeley) 01/21/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 extern int errno; 26 extern char *sys_errlist[]; 27 extern char *crypt(); 28 extern char version[]; 29 extern char *home; /* pointer to home directory for glob */ 30 extern FILE *popen(), *fopen(); 31 extern int pclose(), fclose(); 32 33 struct sockaddr_in ctrl_addr; 34 struct sockaddr_in data_source; 35 struct sockaddr_in data_dest; 36 struct sockaddr_in his_addr; 37 38 struct hostent *hp; 39 40 int data; 41 jmp_buf errcatch; 42 int logged_in; 43 struct passwd *pw; 44 int debug; 45 int logging = 1; 46 int guest; 47 int type; 48 int form; 49 int stru; /* avoid C keyword */ 50 int mode; 51 int usedefault = 1; /* for data transfers */ 52 char hostname[32]; 53 char *remotehost; 54 struct servent *sp; 55 56 int lostconn(); 57 int reapchild(); 58 FILE *getdatasock(), *dataconn(); 59 char *ntoa(); 60 61 main(argc, argv) 62 int argc; 63 char *argv[]; 64 { 65 int ctrl, s, options = 0; 66 char *cp; 67 68 sp = getservbyname("ftp", "tcp"); 69 if (sp == 0) { 70 fprintf(stderr, "ftpd: fpt/tcp: unknown service\n"); 71 exit(1); 72 } 73 ctrl_addr.sin_port = sp->s_port; 74 data_source.sin_port = htons(ntohs(sp->s_port) - 1); 75 signal(SIGPIPE, lostconn); 76 debug = 0; 77 argc--, argv++; 78 while (argc > 0 && *argv[0] == '-') { 79 for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { 80 81 case 'd': 82 debug = 1; 83 options |= SO_DEBUG; 84 break; 85 86 default: 87 fprintf(stderr, "Unknown flag -%c ignored.\n", cp); 88 break; 89 } 90 argc--, argv++; 91 } 92 #ifndef DEBUG 93 if (fork()) 94 exit(0); 95 for (s = 0; s < 10; s++) 96 (void) close(s); 97 (void) open("/dev/null", 0); 98 (void) dup2(0, 1); 99 { int tt = open("/dev/tty", 2); 100 if (tt > 0) { 101 ioctl(tt, TIOCNOTTY, 0); 102 close(tt); 103 } 104 } 105 #endif 106 while ((s = socket(AF_INET, SOCK_STREAM, 0, 0)) < 0) { 107 perror("ftpd: socket"); 108 sleep(5); 109 } 110 if (options & SO_DEBUG) 111 if (setsockopt(s, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 112 perror("ftpd: setsockopt (SO_DEBUG)"); 113 #ifdef notdef 114 if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0) 115 perror("ftpd: setsockopt (SO_KEEPALIVE)"); 116 #endif 117 while (bind(s, &ctrl_addr, sizeof (ctrl_addr), 0) < 0) { 118 perror("ftpd: bind"); 119 sleep(5); 120 } 121 signal(SIGCHLD, reapchild); 122 listen(s, 10); 123 for (;;) { 124 int hisaddrlen = sizeof (his_addr); 125 126 ctrl = accept(s, &his_addr, &hisaddrlen, 0); 127 if (ctrl < 0) { 128 if (errno == EINTR) 129 continue; 130 perror("ftpd: accept"); 131 continue; 132 } 133 if (fork() == 0) { 134 if (logging) 135 dolog(&his_addr); 136 close(s); 137 dup2(ctrl, 0), close(ctrl), dup2(0, 1); 138 /* do telnet option negotiation here */ 139 /* 140 * Set up default state 141 */ 142 logged_in = 0; 143 data = -1; 144 type = TYPE_A; 145 form = FORM_N; 146 stru = STRU_F; 147 mode = MODE_S; 148 gethostname(hostname, sizeof (hostname)); 149 reply(220, "%s FTP server (%s) ready.", 150 hostname, version); 151 for (;;) { 152 setjmp(errcatch); 153 yyparse(); 154 } 155 } 156 close(ctrl); 157 } 158 } 159 160 reapchild() 161 { 162 union wait status; 163 164 while (wait3(&status, WNOHANG, 0) > 0) 165 ; 166 } 167 168 lostconn() 169 { 170 171 fatal("Connection closed."); 172 } 173 174 pass(passwd) 175 char *passwd; 176 { 177 char *xpasswd, *savestr(); 178 static struct passwd save; 179 180 if (logged_in || pw == NULL) { 181 reply(503, "Login with USER first."); 182 return; 183 } 184 if (!guest) { /* "ftp" is only account allowed no password */ 185 xpasswd = crypt(passwd, pw->pw_passwd); 186 if (strcmp(xpasswd, pw->pw_passwd) != 0) { 187 reply(530, "Login incorrect."); 188 pw = NULL; 189 return; 190 } 191 } 192 setegid(pw->pw_gid); 193 initgroups(pw->pw_name, pw->pw_gid); 194 if (chdir(pw->pw_dir)) { 195 reply(550, "User %s: can't change directory to $s.", 196 pw->pw_name, pw->pw_dir); 197 goto bad; 198 } 199 if (guest && chroot(pw->pw_dir) < 0) { 200 reply(550, "Can't set guest privileges."); 201 goto bad; 202 } 203 if (!guest) 204 reply(230, "User %s logged in.", pw->pw_name); 205 else 206 reply(230, "Guest login ok, access restrictions apply."); 207 logged_in = 1; 208 seteuid(pw->pw_uid); 209 /* 210 * Save everything so globbing doesn't 211 * clobber the fields. 212 */ 213 save = *pw; 214 save.pw_name = savestr(pw->pw_name); 215 save.pw_passwd = savestr(pw->pw_passwd); 216 save.pw_comment = savestr(pw->pw_comment); 217 save.pw_gecos = savestr(pw->pw_gecos, &save.pw_gecos); 218 save.pw_dir = savestr(pw->pw_dir); 219 save.pw_shell = savestr(pw->pw_shell); 220 pw = &save; 221 home = pw->pw_dir; /* home dir for globbing */ 222 return; 223 bad: 224 seteuid(0); 225 pw = NULL; 226 } 227 228 char * 229 savestr(s) 230 char *s; 231 { 232 char *malloc(); 233 char *new = malloc(strlen(s) + 1); 234 235 if (new != NULL) 236 strcpy(new, s); 237 return(new); 238 } 239 240 retrieve(cmd, name) 241 char *cmd, *name; 242 { 243 FILE *fin, *dout; 244 struct stat st; 245 int (*closefunc)(); 246 247 if (cmd == 0) { 248 #ifdef notdef 249 /* no remote command execution -- it's a security hole */ 250 if (*name == '!') 251 fin = popen(name + 1, "r"), closefunc = pclose; 252 else 253 #endif 254 fin = fopen(name, "r"), closefunc = fclose; 255 } else { 256 char line[BUFSIZ]; 257 258 sprintf(line, cmd, name), name = line; 259 fin = popen(line, "r"), closefunc = pclose; 260 } 261 if (fin == NULL) { 262 reply(550, "%s: %s.", name, sys_errlist[errno]); 263 return; 264 } 265 st.st_size = 0; 266 if (cmd == 0 && 267 (stat(name, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) { 268 reply(550, "%s: not a plain file.", name); 269 goto done; 270 } 271 dout = dataconn(name, st.st_size, "w"); 272 if (dout == NULL) 273 goto done; 274 if (send_data(fin, dout) || ferror(dout)) 275 reply(550, "%s: %s.", name, sys_errlist[errno]); 276 else 277 reply(226, "Transfer complete."); 278 fclose(dout), data = -1; 279 done: 280 (*closefunc)(fin); 281 } 282 283 store(name, mode) 284 char *name, *mode; 285 { 286 FILE *fout, *din; 287 int (*closefunc)(), dochown = 0; 288 289 #ifdef notdef 290 /* no remote command execution -- it's a security hole */ 291 if (name[0] == '!') 292 fout = popen(&name[1], "w"), closefunc = pclose; 293 else 294 #endif 295 { 296 struct stat st; 297 298 if (stat(name, &st) < 0) 299 dochown++; 300 fout = fopen(name, mode), closefunc = fclose; 301 } 302 if (fout == NULL) { 303 reply(550, "%s: %s.", name, sys_errlist[errno]); 304 return; 305 } 306 din = dataconn(name, -1, "r"); 307 if (din == NULL) 308 goto done; 309 if (receive_data(din, fout) || ferror(fout)) 310 reply(550, "%s: %s.", name, sys_errlist[errno]); 311 else 312 reply(226, "Transfer complete."); 313 fclose(din), data = -1; 314 done: 315 if (dochown) 316 (void) chown(name, pw->pw_uid, -1); 317 (*closefunc)(fout); 318 } 319 320 FILE * 321 getdatasock(mode) 322 char *mode; 323 { 324 int retrytime, s; 325 326 if (data >= 0) 327 return (fdopen(data, mode)); 328 retrytime = 1; 329 while ((s = socket(AF_INET, SOCK_STREAM, 0, 0)) < 0) { 330 if (retrytime < 5) { 331 sleep(retrytime); 332 retrytime <<= 1; 333 continue; 334 } 335 return (NULL); 336 } 337 retrytime = 1; 338 seteuid(0); 339 while (bind(s, &data_source, sizeof (data_source), 0) < 0) { 340 if (retrytime < 5) { 341 sleep(retrytime); 342 retrytime <<= 1; 343 continue; 344 } 345 seteuid(pw->pw_uid); 346 close(s); 347 return (NULL); 348 } 349 seteuid(pw->pw_uid); 350 return (fdopen(s, mode)); 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 reply(150, "Opening data connection for %s (%s,%d)%s.", 376 name, ntoa(data_dest.sin_addr.s_addr), 377 ntohs(data_dest.sin_port), sizebuf); 378 file = getdatasock(mode); 379 if (file == NULL) { 380 reply(425, "Can't create data socket (%s,%d): %s.", 381 ntoa(data_source.sin_addr), 382 ntohs(data_source.sin_port), 383 sys_errlist[errno]); 384 return (NULL); 385 } 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 putc('\r', outstr); 418 if (putc(c, outstr) == EOF) 419 return (1); 420 } 421 return (0); 422 423 case TYPE_I: 424 case TYPE_L: 425 netfd = fileno(outstr); 426 filefd = fileno(instr); 427 428 while ((cnt = read(filefd, buf, sizeof (buf))) > 0) 429 if (write(netfd, buf, cnt) < 0) 430 return (1); 431 return (cnt < 0); 432 } 433 reply(504,"Unimplemented TYPE %d in send_data", type); 434 return (1); 435 } 436 437 /* 438 * Transfer data from peer to 439 * "outstr" using the appropriate 440 * encapulation of the data subject 441 * to Mode, Structure, and Type. 442 * 443 * N.B.: Form isn't handled. 444 */ 445 receive_data(instr, outstr) 446 FILE *instr, *outstr; 447 { 448 register int c; 449 int cr, escape, eof; 450 int netfd, filefd, cnt; 451 char buf[BUFSIZ]; 452 453 454 switch (type) { 455 456 case TYPE_I: 457 case TYPE_L: 458 netfd = fileno(instr); 459 netfd = fileno(outstr); 460 while ((cnt = read(netfd, buf, sizeof buf)) > 0) 461 if (write(filefd, buf, cnt) < 0) 462 return (1); 463 return (cnt < 0); 464 465 case TYPE_E: 466 reply(504, "TYPE E not implemented."); 467 return (1); 468 469 case TYPE_A: 470 cr = 0; 471 while ((c = getc(instr)) != EOF) { 472 if (cr) { 473 if (c != '\r' && c != '\n') 474 putc('\r', outstr); 475 putc(c, outstr); 476 cr = c == '\r'; 477 continue; 478 } 479 if (c == '\r') { 480 cr = 1; 481 continue; 482 } 483 putc(c, outstr); 484 } 485 if (cr) 486 putc('\r', outstr); 487 return (0); 488 } 489 fatal("Unknown type in receive_data."); 490 /*NOTREACHED*/ 491 } 492 493 fatal(s) 494 char *s; 495 { 496 reply(451, "Error in server: %s\n", s); 497 reply(221, "Closing connection due to server error."); 498 exit(0); 499 } 500 501 reply(n, s, args) 502 int n; 503 char *s; 504 { 505 506 printf("%d ", n); 507 _doprnt(s, &args, stdout); 508 printf("\r\n"); 509 fflush(stdout); 510 if (debug) { 511 fprintf(stderr, "<--- %d ", n); 512 _doprnt(s, &args, stderr); 513 fprintf(stderr, "\n"); 514 fflush(stderr); 515 } 516 } 517 518 lreply(n, s, args) 519 int n; 520 char *s; 521 { 522 printf("%d-", n); 523 _doprnt(s, &args, stdout); 524 printf("\r\n"); 525 fflush(stdout); 526 if (debug) { 527 fprintf(stderr, "<--- %d-", n); 528 _doprnt(s, &args, stderr); 529 fprintf(stderr, "\n"); 530 } 531 } 532 533 replystr(s) 534 char *s; 535 { 536 printf("%s\r\n", s); 537 fflush(stdout); 538 if (debug) 539 fprintf(stderr, "<--- %s\n", s); 540 } 541 542 ack(s) 543 char *s; 544 { 545 reply(200, "%s command okay.", s); 546 } 547 548 nack(s) 549 char *s; 550 { 551 reply(502, "%s command not implemented.", s); 552 } 553 554 yyerror() 555 { 556 reply(500, "Command not understood."); 557 } 558 559 delete(name) 560 char *name; 561 { 562 struct stat st; 563 564 if (stat(name, &st) < 0) { 565 reply(550, "%s: %s.", name, sys_errlist[errno]); 566 return; 567 } 568 if ((st.st_mode&S_IFMT) == S_IFDIR) { 569 if (rmdir(name) < 0) { 570 reply(550, "%s: %s.", name, sys_errlist[errno]); 571 return; 572 } 573 goto done; 574 } 575 if (unlink(name) < 0) { 576 reply(550, "%s: %s.", name, sys_errlist[errno]); 577 return; 578 } 579 done: 580 ack("DELE"); 581 } 582 583 cwd(path) 584 char *path; 585 { 586 587 if (chdir(path) < 0) { 588 reply(550, "%s: %s.", path, sys_errlist[errno]); 589 return; 590 } 591 ack("CWD"); 592 } 593 594 makedir(name) 595 char *name; 596 { 597 struct stat st; 598 int dochown = stat(name, &st) < 0; 599 600 if (mkdir(name, 0777) < 0) { 601 reply(550, "%s: %s.", name, sys_errlist[errno]); 602 return; 603 } 604 if (dochown) 605 (void) chown(name, pw->pw_uid, -1); 606 ack("MKDIR"); 607 } 608 609 removedir(name) 610 char *name; 611 { 612 613 if (rmdir(name) < 0) { 614 reply(550, "%s: %s.", name, sys_errlist[errno]); 615 return; 616 } 617 ack("RMDIR"); 618 } 619 620 pwd() 621 { 622 char path[MAXPATHLEN + 1]; 623 char *p; 624 625 if (getwd(path) == NULL) { 626 reply(451, "%s.", path); 627 return; 628 } 629 reply(251, "\"%s\" is current directory.", path); 630 } 631 632 char * 633 renamefrom(name) 634 char *name; 635 { 636 struct stat st; 637 638 if (stat(name, &st) < 0) { 639 reply(550, "%s: %s.", name, sys_errlist[errno]); 640 return ((char *)0); 641 } 642 reply(350, "File exists, ready for destination name"); 643 return (name); 644 } 645 646 renamecmd(from, to) 647 char *from, *to; 648 { 649 650 if (rename(from, to) < 0) { 651 reply(550, "rename: %s.", sys_errlist[errno]); 652 return; 653 } 654 ack("RNTO"); 655 } 656 657 int guest; 658 /* 659 * Test pathname for guest-user safety. 660 */ 661 inappropriate_request(name) 662 char *name; 663 { 664 int bogus = 0, depth = 0, length = strlen(name); 665 char *p, *s; 666 667 if (!guest) 668 return (0); 669 if (name[0] == '/' || name[0] == '|') 670 bogus = 1; 671 for (p = name; p < name+length;) { 672 s = p; /* start of token */ 673 while ( *p && *p!= '/') 674 p++; 675 *p = 0; 676 if (strcmp(s, "..") == 0) 677 depth -= 1; /* backing up */ 678 else if (strcmp(s, ".") == 0) 679 depth += 0; /* no change */ 680 else 681 depth += 1; /* descending */ 682 if (depth < 0) { 683 bogus = 1; 684 break; 685 } 686 } 687 if (bogus) 688 reply(553, "%s: pathname disallowed guest users", name); 689 return (bogus); 690 } 691 692 /* 693 * Convert network-format internet address 694 * to base 256 d.d.d.d representation. 695 */ 696 char * 697 ntoa(in) 698 struct in_addr in; 699 { 700 static char b[18]; 701 register char *p; 702 703 in.s_addr = ntohl(in.s_addr); 704 p = (char *)∈ 705 #define UC(b) (((int)b)&0xff) 706 sprintf(b, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3])); 707 return (b); 708 } 709 710 dolog(sin) 711 struct sockaddr_in *sin; 712 { 713 struct hostent *hp = gethostbyaddr(&sin->sin_addr, 714 sizeof (struct in_addr), AF_INET); 715 char *remotehost; 716 time_t t; 717 718 if (hp) 719 remotehost = hp->h_name; 720 else 721 remotehost = "UNKNOWNHOST"; 722 t = time(0); 723 fprintf(stderr,"FTP: connection from %s at %s", remotehost, ctime(&t)); 724 fflush(stderr); 725 } 726