1 /* 2 * Copyright (c) 1985, 1988, 1990 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1985, 1988, 1990 Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)ftpd.c 5.37 (Berkeley) 06/27/90"; 16 #endif /* not lint */ 17 18 /* 19 * FTP server. 20 */ 21 #include <sys/param.h> 22 #include <sys/stat.h> 23 #include <sys/ioctl.h> 24 #include <sys/socket.h> 25 #include <sys/file.h> 26 #include <sys/wait.h> 27 #include <sys/dir.h> 28 29 #include <netinet/in.h> 30 #include <netinet/in_systm.h> 31 #include <netinet/ip.h> 32 33 #define FTP_NAMES 34 #include <arpa/ftp.h> 35 #include <arpa/inet.h> 36 #include <arpa/telnet.h> 37 38 #include <ctype.h> 39 #include <stdio.h> 40 #include <signal.h> 41 #include <pwd.h> 42 #include <setjmp.h> 43 #include <netdb.h> 44 #include <errno.h> 45 #include <string.h> 46 #include <syslog.h> 47 #include <varargs.h> 48 #include "pathnames.h" 49 50 /* 51 * File containing login names 52 * NOT to be used on this machine. 53 * Commonly used to disallow uucp. 54 */ 55 extern int errno; 56 extern char *crypt(); 57 extern char version[]; 58 extern char *home; /* pointer to home directory for glob */ 59 extern FILE *ftpd_popen(), *fopen(), *freopen(); 60 extern int ftpd_pclose(), fclose(); 61 extern char *getline(); 62 extern char cbuf[]; 63 extern off_t restart_point; 64 65 struct sockaddr_in ctrl_addr; 66 struct sockaddr_in data_source; 67 struct sockaddr_in data_dest; 68 struct sockaddr_in his_addr; 69 struct sockaddr_in pasv_addr; 70 71 int data; 72 jmp_buf errcatch, urgcatch; 73 int logged_in; 74 struct passwd *pw; 75 int debug; 76 int timeout = 900; /* timeout after 15 minutes of inactivity */ 77 int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ 78 int logging; 79 int guest; 80 int type; 81 int form; 82 int stru; /* avoid C keyword */ 83 int mode; 84 int usedefault = 1; /* for data transfers */ 85 int pdata = -1; /* for passive mode */ 86 int transflag; 87 off_t file_size; 88 off_t byte_count; 89 #if !defined(CMASK) || CMASK == 0 90 #undef CMASK 91 #define CMASK 027 92 #endif 93 int defumask = CMASK; /* default umask value */ 94 char tmpline[7]; 95 char hostname[MAXHOSTNAMELEN]; 96 char remotehost[MAXHOSTNAMELEN]; 97 98 /* 99 * Timeout intervals for retrying connections 100 * to hosts that don't accept PORT cmds. This 101 * is a kludge, but given the problems with TCP... 102 */ 103 #define SWAITMAX 90 /* wait at most 90 seconds */ 104 #define SWAITINT 5 /* interval between retries */ 105 106 int swaitmax = SWAITMAX; 107 int swaitint = SWAITINT; 108 109 int lostconn(); 110 int myoob(); 111 FILE *getdatasock(), *dataconn(); 112 113 #ifdef SETPROCTITLE 114 char **Argv = NULL; /* pointer to argument vector */ 115 char *LastArgv = NULL; /* end of argv */ 116 char proctitle[BUFSIZ]; /* initial part of title */ 117 #endif /* SETPROCTITLE */ 118 119 main(argc, argv, envp) 120 int argc; 121 char *argv[]; 122 char **envp; 123 { 124 int addrlen, on = 1, tos; 125 char *cp; 126 127 addrlen = sizeof (his_addr); 128 if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { 129 syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); 130 exit(1); 131 } 132 addrlen = sizeof (ctrl_addr); 133 if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { 134 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); 135 exit(1); 136 } 137 #ifdef IP_TOS 138 tos = IPTOS_LOWDELAY; 139 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) 140 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 141 #endif 142 data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); 143 debug = 0; 144 openlog("ftpd", LOG_PID, LOG_DAEMON); 145 #ifdef SETPROCTITLE 146 /* 147 * Save start and extent of argv for setproctitle. 148 */ 149 Argv = argv; 150 while (*envp) 151 envp++; 152 LastArgv = envp[-1] + strlen(envp[-1]); 153 #endif /* SETPROCTITLE */ 154 155 argc--, argv++; 156 while (argc > 0 && *argv[0] == '-') { 157 for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { 158 159 case 'v': 160 debug = 1; 161 break; 162 163 case 'd': 164 debug = 1; 165 break; 166 167 case 'l': 168 logging = 1; 169 break; 170 171 case 't': 172 timeout = atoi(++cp); 173 if (maxtimeout < timeout) 174 maxtimeout = timeout; 175 goto nextopt; 176 177 case 'T': 178 maxtimeout = atoi(++cp); 179 if (timeout > maxtimeout) 180 timeout = maxtimeout; 181 goto nextopt; 182 183 case 'u': 184 { 185 int val = 0; 186 187 while (*++cp && *cp >= '0' && *cp <= '9') 188 val = val*8 + *cp - '0'; 189 if (*cp) 190 fprintf(stderr, "ftpd: Bad value for -u\n"); 191 else 192 defumask = val; 193 goto nextopt; 194 } 195 196 default: 197 fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n", 198 *cp); 199 break; 200 } 201 nextopt: 202 argc--, argv++; 203 } 204 (void) freopen(_PATH_DEVNULL, "w", stderr); 205 (void) signal(SIGPIPE, lostconn); 206 (void) signal(SIGCHLD, SIG_IGN); 207 if ((int)signal(SIGURG, myoob) < 0) 208 syslog(LOG_ERR, "signal: %m"); 209 210 /* Try to handle urgent data inline */ 211 #ifdef SO_OOBINLINE 212 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) 213 syslog(LOG_ERR, "setsockopt: %m"); 214 #endif 215 216 #ifdef F_SETOWN 217 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) 218 syslog(LOG_ERR, "fcntl F_SETOWN: %m"); 219 #endif 220 dolog(&his_addr); 221 /* 222 * Set up default state 223 */ 224 data = -1; 225 type = TYPE_A; 226 form = FORM_N; 227 stru = STRU_F; 228 mode = MODE_S; 229 tmpline[0] = '\0'; 230 (void) gethostname(hostname, sizeof (hostname)); 231 reply(220, "%s FTP server (%s) ready.", hostname, version); 232 (void) setjmp(errcatch); 233 for (;;) 234 (void) yyparse(); 235 /* NOTREACHED */ 236 } 237 238 lostconn() 239 { 240 241 if (debug) 242 syslog(LOG_DEBUG, "lost connection"); 243 dologout(-1); 244 } 245 246 static char ttyline[20]; 247 248 /* 249 * Helper function for sgetpwnam(). 250 */ 251 char * 252 sgetsave(s) 253 char *s; 254 { 255 char *malloc(); 256 char *new = malloc((unsigned) strlen(s) + 1); 257 258 if (new == NULL) { 259 perror_reply(421, "Local resource failure: malloc"); 260 dologout(1); 261 /* NOTREACHED */ 262 } 263 (void) strcpy(new, s); 264 return (new); 265 } 266 267 /* 268 * Save the result of a getpwnam. Used for USER command, since 269 * the data returned must not be clobbered by any other command 270 * (e.g., globbing). 271 */ 272 struct passwd * 273 sgetpwnam(name) 274 char *name; 275 { 276 static struct passwd save; 277 register struct passwd *p; 278 char *sgetsave(); 279 280 if ((p = getpwnam(name)) == NULL) 281 return (p); 282 if (save.pw_name) { 283 free(save.pw_name); 284 free(save.pw_passwd); 285 free(save.pw_gecos); 286 free(save.pw_dir); 287 free(save.pw_shell); 288 } 289 save = *p; 290 save.pw_name = sgetsave(p->pw_name); 291 save.pw_passwd = sgetsave(p->pw_passwd); 292 save.pw_gecos = sgetsave(p->pw_gecos); 293 save.pw_dir = sgetsave(p->pw_dir); 294 save.pw_shell = sgetsave(p->pw_shell); 295 return (&save); 296 } 297 298 int login_attempts; /* number of failed login attempts */ 299 int askpasswd; /* had user command, ask for passwd */ 300 301 /* 302 * USER command. 303 * Sets global passwd pointer pw if named account exists and is acceptable; 304 * sets askpasswd if a PASS command is expected. If logged in previously, 305 * need to reset state. If name is "ftp" or "anonymous", the name is not in 306 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return. 307 * If account doesn't exist, ask for passwd anyway. Otherwise, check user 308 * requesting login privileges. Disallow anyone who does not have a standard 309 * shell as returned by getusershell(). Disallow anyone mentioned in the file 310 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. 311 */ 312 user(name) 313 char *name; 314 { 315 register char *cp; 316 char *shell; 317 char *getusershell(); 318 319 if (logged_in) { 320 if (guest) { 321 reply(530, "Can't change user from guest login."); 322 return; 323 } 324 end_login(); 325 } 326 327 guest = 0; 328 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { 329 if (checkuser("ftp") || checkuser("anonymous")) 330 reply(530, "User %s access denied.", name); 331 else if ((pw = sgetpwnam("ftp")) != NULL) { 332 guest = 1; 333 askpasswd = 1; 334 reply(331, "Guest login ok, send ident as password."); 335 } else 336 reply(530, "User %s unknown.", name); 337 return; 338 } 339 if (pw = sgetpwnam(name)) { 340 if ((shell = pw->pw_shell) == NULL || *shell == 0) 341 shell = _PATH_BSHELL; 342 while ((cp = getusershell()) != NULL) 343 if (strcmp(cp, shell) == 0) 344 break; 345 endusershell(); 346 if (cp == NULL || checkuser(name)) { 347 reply(530, "User %s access denied.", name); 348 if (logging) 349 syslog(LOG_NOTICE, 350 "FTP LOGIN REFUSED FROM %s, %s", 351 remotehost, name); 352 pw = (struct passwd *) NULL; 353 return; 354 } 355 } 356 reply(331, "Password required for %s.", name); 357 askpasswd = 1; 358 /* 359 * Delay before reading passwd after first failed 360 * attempt to slow down passwd-guessing programs. 361 */ 362 if (login_attempts) 363 sleep((unsigned) login_attempts); 364 } 365 366 /* 367 * Check if a user is in the file _PATH_FTPUSERS 368 */ 369 checkuser(name) 370 char *name; 371 { 372 register FILE *fd; 373 register char *p; 374 char line[BUFSIZ]; 375 376 if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) { 377 while (fgets(line, sizeof(line), fd) != NULL) 378 if ((p = index(line, '\n')) != NULL) { 379 *p = '\0'; 380 if (line[0] == '#') 381 continue; 382 if (strcmp(line, name) == 0) 383 return (1); 384 } 385 (void) fclose(fd); 386 } 387 return (0); 388 } 389 390 /* 391 * Terminate login as previous user, if any, resetting state; 392 * used when USER command is given or login fails. 393 */ 394 end_login() 395 { 396 397 (void) seteuid((uid_t)0); 398 if (logged_in) 399 logwtmp(ttyline, "", ""); 400 pw = NULL; 401 logged_in = 0; 402 guest = 0; 403 } 404 405 pass(passwd) 406 char *passwd; 407 { 408 char *xpasswd, *salt; 409 410 if (logged_in || askpasswd == 0) { 411 reply(503, "Login with USER first."); 412 return; 413 } 414 askpasswd = 0; 415 if (!guest) { /* "ftp" is only account allowed no password */ 416 if (pw == NULL) 417 salt = "xx"; 418 else 419 salt = pw->pw_passwd; 420 xpasswd = crypt(passwd, salt); 421 /* The strcmp does not catch null passwords! */ 422 if (pw == NULL || *pw->pw_passwd == '\0' || 423 strcmp(xpasswd, pw->pw_passwd)) { 424 reply(530, "Login incorrect."); 425 pw = NULL; 426 if (login_attempts++ >= 5) { 427 syslog(LOG_NOTICE, 428 "repeated login failures from %s", 429 remotehost); 430 exit(0); 431 } 432 return; 433 } 434 } 435 login_attempts = 0; /* this time successful */ 436 (void) setegid((gid_t)pw->pw_gid); 437 (void) initgroups(pw->pw_name, pw->pw_gid); 438 439 /* open wtmp before chroot */ 440 (void)sprintf(ttyline, "ftp%d", getpid()); 441 logwtmp(ttyline, pw->pw_name, remotehost); 442 logged_in = 1; 443 444 if (guest) { 445 /* 446 * We MUST do a chdir() after the chroot. Otherwise 447 * the old current directory will be accessible as "." 448 * outside the new root! 449 */ 450 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { 451 reply(550, "Can't set guest privileges."); 452 goto bad; 453 } 454 } else if (chdir(pw->pw_dir) < 0) { 455 if (chdir("/") < 0) { 456 reply(530, "User %s: can't change directory to %s.", 457 pw->pw_name, pw->pw_dir); 458 goto bad; 459 } else 460 lreply(230, "No directory! Logging in with home=/"); 461 } 462 if (seteuid((uid_t)pw->pw_uid) < 0) { 463 reply(550, "Can't set uid."); 464 goto bad; 465 } 466 if (guest) { 467 reply(230, "Guest login ok, access restrictions apply."); 468 #ifdef SETPROCTITLE 469 sprintf(proctitle, "%s: anonymous/%.*s", remotehost, 470 sizeof(proctitle) - sizeof(remotehost) - 471 sizeof(": anonymous/"), passwd); 472 setproctitle(proctitle); 473 #endif /* SETPROCTITLE */ 474 if (logging) 475 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s", 476 remotehost, passwd); 477 } else { 478 reply(230, "User %s logged in.", pw->pw_name); 479 #ifdef SETPROCTITLE 480 sprintf(proctitle, "%s: %s", remotehost, pw->pw_name); 481 setproctitle(proctitle); 482 #endif /* SETPROCTITLE */ 483 if (logging) 484 syslog(LOG_INFO, "FTP LOGIN FROM %s, %s", 485 remotehost, pw->pw_name); 486 } 487 home = pw->pw_dir; /* home dir for globbing */ 488 (void) umask(defumask); 489 return; 490 bad: 491 /* Forget all about it... */ 492 end_login(); 493 } 494 495 retrieve(cmd, name) 496 char *cmd, *name; 497 { 498 FILE *fin, *dout; 499 struct stat st; 500 int (*closefunc)(); 501 502 if (cmd == 0) { 503 fin = fopen(name, "r"), closefunc = fclose; 504 st.st_size = 0; 505 } else { 506 char line[BUFSIZ]; 507 508 (void) sprintf(line, cmd, name), name = line; 509 fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose; 510 st.st_size = -1; 511 st.st_blksize = BUFSIZ; 512 } 513 if (fin == NULL) { 514 if (errno != 0) 515 perror_reply(550, name); 516 return; 517 } 518 if (cmd == 0 && 519 (fstat(fileno(fin), &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) { 520 reply(550, "%s: not a plain file.", name); 521 goto done; 522 } 523 if (restart_point) { 524 if (type == TYPE_A) { 525 register int i, n, c; 526 527 n = restart_point; 528 i = 0; 529 while (i++ < n) { 530 if ((c=getc(fin)) == EOF) { 531 perror_reply(550, name); 532 goto done; 533 } 534 if (c == '\n') 535 i++; 536 } 537 } else if (lseek(fileno(fin), restart_point, L_SET) < 0) { 538 perror_reply(550, name); 539 goto done; 540 } 541 } 542 dout = dataconn(name, st.st_size, "w"); 543 if (dout == NULL) 544 goto done; 545 send_data(fin, dout, st.st_blksize); 546 (void) fclose(dout); 547 data = -1; 548 pdata = -1; 549 done: 550 (*closefunc)(fin); 551 } 552 553 store(name, mode, unique) 554 char *name, *mode; 555 int unique; 556 { 557 FILE *fout, *din; 558 struct stat st; 559 int (*closefunc)(); 560 char *gunique(); 561 562 if (unique && stat(name, &st) == 0 && 563 (name = gunique(name)) == NULL) 564 return; 565 566 if (restart_point) 567 mode = "r+w"; 568 fout = fopen(name, mode); 569 closefunc = fclose; 570 if (fout == NULL) { 571 perror_reply(553, name); 572 return; 573 } 574 if (restart_point) { 575 if (type == TYPE_A) { 576 register int i, n, c; 577 578 n = restart_point; 579 i = 0; 580 while (i++ < n) { 581 if ((c=getc(fout)) == EOF) { 582 perror_reply(550, name); 583 goto done; 584 } 585 if (c == '\n') 586 i++; 587 } 588 /* 589 * We must do this seek to "current" position 590 * because we are changing from reading to 591 * writing. 592 */ 593 if (fseek(fout, 0L, L_INCR) < 0) { 594 perror_reply(550, name); 595 goto done; 596 } 597 } else if (lseek(fileno(fout), restart_point, L_SET) < 0) { 598 perror_reply(550, name); 599 goto done; 600 } 601 } 602 din = dataconn(name, (off_t)-1, "r"); 603 if (din == NULL) 604 goto done; 605 if (receive_data(din, fout) == 0) { 606 if (unique) 607 reply(226, "Transfer complete (unique file name:%s).", 608 name); 609 else 610 reply(226, "Transfer complete."); 611 } 612 (void) fclose(din); 613 data = -1; 614 pdata = -1; 615 done: 616 (*closefunc)(fout); 617 } 618 619 FILE * 620 getdatasock(mode) 621 char *mode; 622 { 623 int s, on = 1, tries; 624 625 if (data >= 0) 626 return (fdopen(data, mode)); 627 s = socket(AF_INET, SOCK_STREAM, 0); 628 if (s < 0) 629 return (NULL); 630 (void) seteuid((uid_t)0); 631 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 632 (char *) &on, sizeof (on)) < 0) 633 goto bad; 634 /* anchor socket to avoid multi-homing problems */ 635 data_source.sin_family = AF_INET; 636 data_source.sin_addr = ctrl_addr.sin_addr; 637 for (tries = 1; ; tries++) { 638 if (bind(s, (struct sockaddr *)&data_source, 639 sizeof (data_source)) >= 0) 640 break; 641 if (errno != EADDRINUSE || tries > 10) 642 goto bad; 643 sleep(tries); 644 } 645 (void) seteuid((uid_t)pw->pw_uid); 646 #ifdef IP_TOS 647 on = IPTOS_THROUGHPUT; 648 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 649 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 650 #endif 651 return (fdopen(s, mode)); 652 bad: 653 (void) seteuid((uid_t)pw->pw_uid); 654 (void) close(s); 655 return (NULL); 656 } 657 658 FILE * 659 dataconn(name, size, mode) 660 char *name; 661 off_t size; 662 char *mode; 663 { 664 char sizebuf[32]; 665 FILE *file; 666 int retry = 0, tos; 667 668 file_size = size; 669 byte_count = 0; 670 if (size != (off_t) -1) 671 (void) sprintf (sizebuf, " (%ld bytes)", size); 672 else 673 (void) strcpy(sizebuf, ""); 674 if (pdata >= 0) { 675 struct sockaddr_in from; 676 int s, fromlen = sizeof(from); 677 678 s = accept(pdata, (struct sockaddr *)&from, &fromlen); 679 if (s < 0) { 680 reply(425, "Can't open data connection."); 681 (void) close(pdata); 682 pdata = -1; 683 return(NULL); 684 } 685 (void) close(pdata); 686 pdata = s; 687 #ifdef IP_TOS 688 tos = IPTOS_LOWDELAY; 689 (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, 690 sizeof(int)); 691 #endif 692 reply(150, "Opening %s mode data connection for %s%s.", 693 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 694 return(fdopen(pdata, mode)); 695 } 696 if (data >= 0) { 697 reply(125, "Using existing data connection for %s%s.", 698 name, sizebuf); 699 usedefault = 1; 700 return (fdopen(data, mode)); 701 } 702 if (usedefault) 703 data_dest = his_addr; 704 usedefault = 1; 705 file = getdatasock(mode); 706 if (file == NULL) { 707 reply(425, "Can't create data socket (%s,%d): %s.", 708 inet_ntoa(data_source.sin_addr), 709 ntohs(data_source.sin_port), strerror(errno)); 710 return (NULL); 711 } 712 data = fileno(file); 713 while (connect(data, (struct sockaddr *)&data_dest, 714 sizeof (data_dest)) < 0) { 715 if (errno == EADDRINUSE && retry < swaitmax) { 716 sleep((unsigned) swaitint); 717 retry += swaitint; 718 continue; 719 } 720 perror_reply(425, "Can't build data connection"); 721 (void) fclose(file); 722 data = -1; 723 return (NULL); 724 } 725 reply(150, "Opening %s mode data connection for %s%s.", 726 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 727 return (file); 728 } 729 730 /* 731 * Tranfer the contents of "instr" to 732 * "outstr" peer using the appropriate 733 * encapsulation of the data subject 734 * to Mode, Structure, and Type. 735 * 736 * NB: Form isn't handled. 737 */ 738 send_data(instr, outstr, blksize) 739 FILE *instr, *outstr; 740 off_t blksize; 741 { 742 register int c, cnt; 743 register char *buf; 744 int netfd, filefd; 745 746 transflag++; 747 if (setjmp(urgcatch)) { 748 transflag = 0; 749 return; 750 } 751 switch (type) { 752 753 case TYPE_A: 754 while ((c = getc(instr)) != EOF) { 755 byte_count++; 756 if (c == '\n') { 757 if (ferror(outstr)) 758 goto data_err; 759 (void) putc('\r', outstr); 760 } 761 (void) putc(c, outstr); 762 } 763 fflush(outstr); 764 transflag = 0; 765 if (ferror(instr)) 766 goto file_err; 767 if (ferror(outstr)) 768 goto data_err; 769 reply(226, "Transfer complete."); 770 return; 771 772 case TYPE_I: 773 case TYPE_L: 774 if ((buf = malloc((u_int)blksize)) == NULL) { 775 transflag = 0; 776 perror_reply(451, "Local resource failure: malloc"); 777 return; 778 } 779 netfd = fileno(outstr); 780 filefd = fileno(instr); 781 while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 && 782 write(netfd, buf, cnt) == cnt) 783 byte_count += cnt; 784 transflag = 0; 785 (void)free(buf); 786 if (cnt != 0) { 787 if (cnt < 0) 788 goto file_err; 789 goto data_err; 790 } 791 reply(226, "Transfer complete."); 792 return; 793 default: 794 transflag = 0; 795 reply(550, "Unimplemented TYPE %d in send_data", type); 796 return; 797 } 798 799 data_err: 800 transflag = 0; 801 perror_reply(426, "Data connection"); 802 return; 803 804 file_err: 805 transflag = 0; 806 perror_reply(551, "Error on input file"); 807 } 808 809 /* 810 * Transfer data from peer to 811 * "outstr" using the appropriate 812 * encapulation of the data subject 813 * to Mode, Structure, and Type. 814 * 815 * N.B.: Form isn't handled. 816 */ 817 receive_data(instr, outstr) 818 FILE *instr, *outstr; 819 { 820 register int c; 821 int cnt, bare_lfs = 0; 822 char buf[BUFSIZ]; 823 824 transflag++; 825 if (setjmp(urgcatch)) { 826 transflag = 0; 827 return (-1); 828 } 829 switch (type) { 830 831 case TYPE_I: 832 case TYPE_L: 833 while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) { 834 if (write(fileno(outstr), buf, cnt) != cnt) 835 goto file_err; 836 byte_count += cnt; 837 } 838 if (cnt < 0) 839 goto data_err; 840 transflag = 0; 841 return (0); 842 843 case TYPE_E: 844 reply(553, "TYPE E not implemented."); 845 transflag = 0; 846 return (-1); 847 848 case TYPE_A: 849 while ((c = getc(instr)) != EOF) { 850 byte_count++; 851 if (c == '\n') 852 bare_lfs++; 853 while (c == '\r') { 854 if (ferror(outstr)) 855 goto data_err; 856 if ((c = getc(instr)) != '\n') { 857 (void) putc ('\r', outstr); 858 if (c == '\0' || c == EOF) 859 goto contin2; 860 } 861 } 862 (void) putc(c, outstr); 863 contin2: ; 864 } 865 fflush(outstr); 866 if (ferror(instr)) 867 goto data_err; 868 if (ferror(outstr)) 869 goto file_err; 870 transflag = 0; 871 if (bare_lfs) { 872 lreply(230, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs); 873 printf(" File may not have transferred correctly.\r\n"); 874 } 875 return (0); 876 default: 877 reply(550, "Unimplemented TYPE %d in receive_data", type); 878 transflag = 0; 879 return (-1); 880 } 881 882 data_err: 883 transflag = 0; 884 perror_reply(426, "Data Connection"); 885 return (-1); 886 887 file_err: 888 transflag = 0; 889 perror_reply(452, "Error writing file"); 890 return (-1); 891 } 892 893 statfilecmd(filename) 894 char *filename; 895 { 896 char line[BUFSIZ]; 897 FILE *fin; 898 int c; 899 900 (void) sprintf(line, "/bin/ls -lgA %s", filename); 901 fin = ftpd_popen(line, "r"); 902 lreply(211, "status of %s:", filename); 903 while ((c = getc(fin)) != EOF) { 904 if (c == '\n') { 905 if (ferror(stdout)){ 906 perror_reply(421, "control connection"); 907 (void) ftpd_pclose(fin); 908 dologout(1); 909 /* NOTREACHED */ 910 } 911 if (ferror(fin)) { 912 perror_reply(551, filename); 913 (void) ftpd_pclose(fin); 914 return; 915 } 916 (void) putc('\r', stdout); 917 } 918 (void) putc(c, stdout); 919 } 920 (void) ftpd_pclose(fin); 921 reply(211, "End of Status"); 922 } 923 924 statcmd() 925 { 926 struct sockaddr_in *sin; 927 u_char *a, *p; 928 929 lreply(211, "%s FTP server status:", hostname, version); 930 printf(" %s\r\n", version); 931 printf(" Connected to %s", remotehost); 932 if (!isdigit(remotehost[0])) 933 printf(" (%s)", inet_ntoa(his_addr.sin_addr)); 934 printf("\r\n"); 935 if (logged_in) { 936 if (guest) 937 printf(" Logged in anonymously\r\n"); 938 else 939 printf(" Logged in as %s\r\n", pw->pw_name); 940 } else if (askpasswd) 941 printf(" Waiting for password\r\n"); 942 else 943 printf(" Waiting for user name\r\n"); 944 printf(" TYPE: %s", typenames[type]); 945 if (type == TYPE_A || type == TYPE_E) 946 printf(", FORM: %s", formnames[form]); 947 if (type == TYPE_L) 948 #if NBBY == 8 949 printf(" %d", NBBY); 950 #else 951 printf(" %d", bytesize); /* need definition! */ 952 #endif 953 printf("; STRUcture: %s; transfer MODE: %s\r\n", 954 strunames[stru], modenames[mode]); 955 if (data != -1) 956 printf(" Data connection open\r\n"); 957 else if (pdata != -1) { 958 printf(" in Passive mode"); 959 sin = &pasv_addr; 960 goto printaddr; 961 } else if (usedefault == 0) { 962 printf(" PORT"); 963 sin = &data_dest; 964 printaddr: 965 a = (u_char *) &sin->sin_addr; 966 p = (u_char *) &sin->sin_port; 967 #define UC(b) (((int) b) & 0xff) 968 printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]), 969 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 970 #undef UC 971 } else 972 printf(" No data connection\r\n"); 973 reply(211, "End of status"); 974 } 975 976 fatal(s) 977 char *s; 978 { 979 reply(451, "Error in server: %s\n", s); 980 reply(221, "Closing connection due to server error."); 981 dologout(0); 982 /* NOTREACHED */ 983 } 984 985 /* VARARGS2 */ 986 reply(n, fmt, p0, p1, p2, p3, p4, p5) 987 int n; 988 char *fmt; 989 { 990 printf("%d ", n); 991 printf(fmt, p0, p1, p2, p3, p4, p5); 992 printf("\r\n"); 993 (void)fflush(stdout); 994 if (debug) { 995 syslog(LOG_DEBUG, "<--- %d ", n); 996 syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5); 997 } 998 } 999 1000 /* VARARGS2 */ 1001 lreply(n, fmt, p0, p1, p2, p3, p4, p5) 1002 int n; 1003 char *fmt; 1004 { 1005 printf("%d- ", n); 1006 printf(fmt, p0, p1, p2, p3, p4, p5); 1007 printf("\r\n"); 1008 (void)fflush(stdout); 1009 if (debug) { 1010 syslog(LOG_DEBUG, "<--- %d- ", n); 1011 syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5); 1012 } 1013 } 1014 1015 ack(s) 1016 char *s; 1017 { 1018 reply(250, "%s command successful.", s); 1019 } 1020 1021 nack(s) 1022 char *s; 1023 { 1024 reply(502, "%s command not implemented.", s); 1025 } 1026 1027 /* ARGSUSED */ 1028 yyerror(s) 1029 char *s; 1030 { 1031 char *cp; 1032 1033 if (cp = index(cbuf,'\n')) 1034 *cp = '\0'; 1035 reply(500, "'%s': command not understood.", cbuf); 1036 } 1037 1038 delete(name) 1039 char *name; 1040 { 1041 struct stat st; 1042 1043 if (stat(name, &st) < 0) { 1044 perror_reply(550, name); 1045 return; 1046 } 1047 if ((st.st_mode&S_IFMT) == S_IFDIR) { 1048 if (rmdir(name) < 0) { 1049 perror_reply(550, name); 1050 return; 1051 } 1052 goto done; 1053 } 1054 if (unlink(name) < 0) { 1055 perror_reply(550, name); 1056 return; 1057 } 1058 done: 1059 ack("DELE"); 1060 } 1061 1062 cwd(path) 1063 char *path; 1064 { 1065 if (chdir(path) < 0) 1066 perror_reply(550, path); 1067 else 1068 ack("CWD"); 1069 } 1070 1071 makedir(name) 1072 char *name; 1073 { 1074 if (mkdir(name, 0777) < 0) 1075 perror_reply(550, name); 1076 else 1077 reply(257, "MKD command successful."); 1078 } 1079 1080 removedir(name) 1081 char *name; 1082 { 1083 if (rmdir(name) < 0) 1084 perror_reply(550, name); 1085 else 1086 ack("RMD"); 1087 } 1088 1089 pwd() 1090 { 1091 char path[MAXPATHLEN + 1]; 1092 extern char *getwd(); 1093 1094 if (getwd(path) == (char *)NULL) 1095 reply(550, "%s.", path); 1096 else 1097 reply(257, "\"%s\" is current directory.", path); 1098 } 1099 1100 char * 1101 renamefrom(name) 1102 char *name; 1103 { 1104 struct stat st; 1105 1106 if (stat(name, &st) < 0) { 1107 perror_reply(550, name); 1108 return ((char *)0); 1109 } 1110 reply(350, "File exists, ready for destination name"); 1111 return (name); 1112 } 1113 1114 renamecmd(from, to) 1115 char *from, *to; 1116 { 1117 if (rename(from, to) < 0) 1118 perror_reply(550, "rename"); 1119 else 1120 ack("RNTO"); 1121 } 1122 1123 dolog(sin) 1124 struct sockaddr_in *sin; 1125 { 1126 struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr, 1127 sizeof (struct in_addr), AF_INET); 1128 time_t t, time(); 1129 extern char *ctime(); 1130 1131 if (hp) 1132 (void) strncpy(remotehost, hp->h_name, sizeof (remotehost)); 1133 else 1134 (void) strncpy(remotehost, inet_ntoa(sin->sin_addr), 1135 sizeof (remotehost)); 1136 #ifdef SETPROCTITLE 1137 sprintf(proctitle, "%s: connected", remotehost); 1138 setproctitle(proctitle); 1139 #endif /* SETPROCTITLE */ 1140 1141 if (logging) { 1142 t = time((time_t *) 0); 1143 syslog(LOG_INFO, "connection from %s at %s", 1144 remotehost, ctime(&t)); 1145 } 1146 } 1147 1148 /* 1149 * Record logout in wtmp file 1150 * and exit with supplied status. 1151 */ 1152 dologout(status) 1153 int status; 1154 { 1155 if (logged_in) { 1156 (void) seteuid((uid_t)0); 1157 logwtmp(ttyline, "", ""); 1158 } 1159 /* beware of flushing buffers after a SIGPIPE */ 1160 _exit(status); 1161 } 1162 1163 myoob() 1164 { 1165 char *cp; 1166 1167 /* only process if transfer occurring */ 1168 if (!transflag) 1169 return; 1170 cp = tmpline; 1171 if (getline(cp, 7, stdin) == NULL) { 1172 reply(221, "You could at least say goodbye."); 1173 dologout(0); 1174 } 1175 upper(cp); 1176 if (strcmp(cp, "ABOR\r\n") == 0) { 1177 tmpline[0] = '\0'; 1178 reply(426, "Transfer aborted. Data connection closed."); 1179 reply(226, "Abort successful"); 1180 longjmp(urgcatch, 1); 1181 } 1182 if (strcmp(cp, "STAT\r\n") == 0) { 1183 if (file_size != (off_t) -1) 1184 reply(213, "Status: %lu of %lu bytes transferred", 1185 byte_count, file_size); 1186 else 1187 reply(213, "Status: %lu bytes transferred", byte_count); 1188 } 1189 } 1190 1191 /* 1192 * Note: a response of 425 is not mentioned as a possible response to 1193 * the PASV command in RFC959. However, it has been blessed as 1194 * a legitimate response by Jon Postel in a telephone conversation 1195 * with Rick Adams on 25 Jan 89. 1196 */ 1197 passive() 1198 { 1199 int len; 1200 register char *p, *a; 1201 1202 pdata = socket(AF_INET, SOCK_STREAM, 0); 1203 if (pdata < 0) { 1204 perror_reply(425, "Can't open passive connection"); 1205 return; 1206 } 1207 pasv_addr = ctrl_addr; 1208 pasv_addr.sin_port = 0; 1209 (void) seteuid((uid_t)0); 1210 if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) { 1211 (void) seteuid((uid_t)pw->pw_uid); 1212 goto pasv_error; 1213 } 1214 (void) seteuid((uid_t)pw->pw_uid); 1215 len = sizeof(pasv_addr); 1216 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) 1217 goto pasv_error; 1218 if (listen(pdata, 1) < 0) 1219 goto pasv_error; 1220 a = (char *) &pasv_addr.sin_addr; 1221 p = (char *) &pasv_addr.sin_port; 1222 1223 #define UC(b) (((int) b) & 0xff) 1224 1225 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), 1226 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 1227 return; 1228 1229 pasv_error: 1230 (void) close(pdata); 1231 pdata = -1; 1232 perror_reply(425, "Can't open passive connection"); 1233 return; 1234 } 1235 1236 /* 1237 * Generate unique name for file with basename "local". 1238 * The file named "local" is already known to exist. 1239 * Generates failure reply on error. 1240 */ 1241 char * 1242 gunique(local) 1243 char *local; 1244 { 1245 static char new[MAXPATHLEN]; 1246 struct stat st; 1247 char *cp = rindex(local, '/'); 1248 int count = 0; 1249 1250 if (cp) 1251 *cp = '\0'; 1252 if (stat(cp ? local : ".", &st) < 0) { 1253 perror_reply(553, cp ? local : "."); 1254 return((char *) 0); 1255 } 1256 if (cp) 1257 *cp = '/'; 1258 (void) strcpy(new, local); 1259 cp = new + strlen(new); 1260 *cp++ = '.'; 1261 for (count = 1; count < 100; count++) { 1262 (void) sprintf(cp, "%d", count); 1263 if (stat(new, &st) < 0) 1264 return(new); 1265 } 1266 reply(452, "Unique file name cannot be created."); 1267 return((char *) 0); 1268 } 1269 1270 /* 1271 * Format and send reply containing system error number. 1272 */ 1273 perror_reply(code, string) 1274 int code; 1275 char *string; 1276 { 1277 reply(code, "%s: %s.", string, strerror(errno)); 1278 } 1279 1280 static char *onefile[] = { 1281 "", 1282 0 1283 }; 1284 1285 send_file_list(whichfiles) 1286 char *whichfiles; 1287 { 1288 struct stat st; 1289 DIR *dirp = NULL; 1290 struct direct *dir; 1291 FILE *dout = NULL; 1292 register char **dirlist, *dirname; 1293 int simple = 0; 1294 char *strpbrk(); 1295 1296 if (strpbrk(whichfiles, "~{[*?") != NULL) { 1297 extern char **glob(), *globerr; 1298 1299 globerr = NULL; 1300 dirlist = glob(whichfiles); 1301 if (globerr != NULL) { 1302 reply(550, globerr); 1303 return; 1304 } else if (dirlist == NULL) { 1305 errno = ENOENT; 1306 perror_reply(550, whichfiles); 1307 return; 1308 } 1309 } else { 1310 onefile[0] = whichfiles; 1311 dirlist = onefile; 1312 simple = 1; 1313 } 1314 1315 if (setjmp(urgcatch)) { 1316 transflag = 0; 1317 return; 1318 } 1319 while (dirname = *dirlist++) { 1320 if (stat(dirname, &st) < 0) { 1321 /* 1322 * If user typed "ls -l", etc, and the client 1323 * used NLST, do what the user meant. 1324 */ 1325 if (dirname[0] == '-' && *dirlist == NULL && 1326 transflag == 0) { 1327 retrieve("/bin/ls %s", dirname); 1328 return; 1329 } 1330 perror_reply(550, whichfiles); 1331 if (dout != NULL) { 1332 (void) fclose(dout); 1333 transflag = 0; 1334 data = -1; 1335 pdata = -1; 1336 } 1337 return; 1338 } 1339 1340 if ((st.st_mode&S_IFMT) == S_IFREG) { 1341 if (dout == NULL) { 1342 dout = dataconn("file list", (off_t)-1, "w"); 1343 if (dout == NULL) 1344 return; 1345 transflag++; 1346 } 1347 fprintf(dout, "%s%s\n", dirname, 1348 type == TYPE_A ? "\r" : ""); 1349 byte_count += strlen(dirname) + 1; 1350 continue; 1351 } else if ((st.st_mode&S_IFMT) != S_IFDIR) 1352 continue; 1353 1354 if ((dirp = opendir(dirname)) == NULL) 1355 continue; 1356 1357 while ((dir = readdir(dirp)) != NULL) { 1358 char nbuf[MAXPATHLEN]; 1359 1360 if (dir->d_name[0] == '.' && dir->d_namlen == 1) 1361 continue; 1362 if (dir->d_name[0] == '.' && dir->d_name[1] == '.' && 1363 dir->d_namlen == 2) 1364 continue; 1365 1366 sprintf(nbuf, "%s/%s", dirname, dir->d_name); 1367 1368 /* 1369 * We have to do a stat to insure it's 1370 * not a directory or special file. 1371 */ 1372 if (simple || (stat(nbuf, &st) == 0 && 1373 (st.st_mode&S_IFMT) == S_IFREG)) { 1374 if (dout == NULL) { 1375 dout = dataconn("file list", (off_t)-1, 1376 "w"); 1377 if (dout == NULL) 1378 return; 1379 transflag++; 1380 } 1381 if (nbuf[0] == '.' && nbuf[1] == '/') 1382 fprintf(dout, "%s%s\n", &nbuf[2], 1383 type == TYPE_A ? "\r" : ""); 1384 else 1385 fprintf(dout, "%s%s\n", nbuf, 1386 type == TYPE_A ? "\r" : ""); 1387 byte_count += strlen(nbuf) + 1; 1388 } 1389 } 1390 (void) closedir(dirp); 1391 } 1392 1393 if (dout == NULL) 1394 reply(550, "No files found."); 1395 else if (ferror(dout) != 0) 1396 perror_reply(550, "Data connection"); 1397 else 1398 reply(226, "Transfer complete."); 1399 1400 transflag = 0; 1401 if (dout != NULL) 1402 (void) fclose(dout); 1403 data = -1; 1404 pdata = -1; 1405 } 1406 1407 #ifdef SETPROCTITLE 1408 /* 1409 * clobber argv so ps will show what we're doing. 1410 * (stolen from sendmail) 1411 * warning, since this is usually started from inetd.conf, it 1412 * often doesn't have much of an environment or arglist to overwrite. 1413 */ 1414 1415 /*VARARGS1*/ 1416 setproctitle(fmt, a, b, c) 1417 char *fmt; 1418 { 1419 register char *p, *bp, ch; 1420 register int i; 1421 char buf[BUFSIZ]; 1422 1423 (void) sprintf(buf, fmt, a, b, c); 1424 1425 /* make ps print our process name */ 1426 p = Argv[0]; 1427 *p++ = '-'; 1428 1429 i = strlen(buf); 1430 if (i > LastArgv - p - 2) { 1431 i = LastArgv - p - 2; 1432 buf[i] = '\0'; 1433 } 1434 bp = buf; 1435 while (ch = *bp++) 1436 if (ch != '\n' && ch != '\r') 1437 *p++ = ch; 1438 while (p < LastArgv) 1439 *p++ = ' '; 1440 } 1441 #endif /* SETPROCTITLE */ 1442