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