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