1 /* 2 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $Id: ftpd.c,v 1.11 1995/08/05 19:12:05 pst Exp $ 34 */ 35 36 #ifndef lint 37 static char copyright[] = 38 "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\ 39 The Regents of the University of California. All rights reserved.\n"; 40 #endif /* not lint */ 41 42 #ifndef lint 43 static char sccsid[] = "@(#)ftpd.c 8.4 (Berkeley) 4/16/94"; 44 #endif /* not lint */ 45 46 /* 47 * FTP server. 48 */ 49 #include <sys/param.h> 50 #include <sys/stat.h> 51 #include <sys/ioctl.h> 52 #include <sys/socket.h> 53 #include <sys/wait.h> 54 #include <sys/mman.h> 55 56 #include <netinet/in.h> 57 #include <netinet/in_systm.h> 58 #include <netinet/ip.h> 59 #include <netinet/tcp.h> 60 61 #define FTP_NAMES 62 #include <arpa/ftp.h> 63 #include <arpa/inet.h> 64 #include <arpa/telnet.h> 65 66 #include <ctype.h> 67 #include <dirent.h> 68 #include <err.h> 69 #include <errno.h> 70 #include <fcntl.h> 71 #include <glob.h> 72 #include <limits.h> 73 #include <netdb.h> 74 #include <pwd.h> 75 #include <setjmp.h> 76 #include <signal.h> 77 #include <stdio.h> 78 #include <stdlib.h> 79 #include <string.h> 80 #include <syslog.h> 81 #include <time.h> 82 #include <unistd.h> 83 84 #ifdef SKEY 85 #include <skey.h> 86 #endif 87 88 #include "pathnames.h" 89 #include "extern.h" 90 91 #if __STDC__ 92 #include <stdarg.h> 93 #else 94 #include <varargs.h> 95 #endif 96 97 static char version[] = "Version 6.00"; 98 99 extern off_t restart_point; 100 extern char cbuf[]; 101 102 struct sockaddr_in ctrl_addr; 103 struct sockaddr_in data_source; 104 struct sockaddr_in data_dest; 105 struct sockaddr_in his_addr; 106 struct sockaddr_in pasv_addr; 107 108 int data; 109 jmp_buf errcatch, urgcatch; 110 int logged_in; 111 struct passwd *pw; 112 int debug; 113 int timeout = 900; /* timeout after 15 minutes of inactivity */ 114 int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ 115 int logging; 116 int restricted_data_ports = 1; 117 int guest; 118 #ifdef STATS 119 int stats; 120 int statfd = -1; 121 #endif 122 int type; 123 int form; 124 int stru; /* avoid C keyword */ 125 int mode; 126 int usedefault = 1; /* for data transfers */ 127 int pdata = -1; /* for passive mode */ 128 sig_atomic_t transflag; 129 off_t file_size; 130 off_t byte_count; 131 #if !defined(CMASK) || CMASK == 0 132 #undef CMASK 133 #define CMASK 027 134 #endif 135 int defumask = CMASK; /* default umask value */ 136 char tmpline[7]; 137 char hostname[MAXHOSTNAMELEN]; 138 char remotehost[MAXHOSTNAMELEN]; 139 #ifdef STATS 140 char *ident = NULL; 141 #endif 142 143 /* 144 * Timeout intervals for retrying connections 145 * to hosts that don't accept PORT cmds. This 146 * is a kludge, but given the problems with TCP... 147 */ 148 #define SWAITMAX 90 /* wait at most 90 seconds */ 149 #define SWAITINT 5 /* interval between retries */ 150 151 int swaitmax = SWAITMAX; 152 int swaitint = SWAITINT; 153 154 #ifdef SETPROCTITLE 155 char **Argv = NULL; /* pointer to argument vector */ 156 char *LastArgv = NULL; /* end of argv */ 157 char proctitle[LINE_MAX]; /* initial part of title */ 158 #endif /* SETPROCTITLE */ 159 160 #ifdef SKEY 161 int pwok = 0; 162 char addr_string[20]; /* XXX */ 163 #endif 164 165 #define LOGCMD(cmd, file) \ 166 if (logging > 1) \ 167 syslog(LOG_INFO,"%s %s%s", cmd, \ 168 *(file) == '/' ? "" : curdir(), file); 169 #define LOGCMD2(cmd, file1, file2) \ 170 if (logging > 1) \ 171 syslog(LOG_INFO,"%s %s%s %s%s", cmd, \ 172 *(file1) == '/' ? "" : curdir(), file1, \ 173 *(file2) == '/' ? "" : curdir(), file2); 174 #define LOGBYTES(cmd, file, cnt) \ 175 if (logging > 1) { \ 176 if (cnt == (off_t)-1) \ 177 syslog(LOG_INFO,"%s %s%s", cmd, \ 178 *(file) == '/' ? "" : curdir(), file); \ 179 else \ 180 syslog(LOG_INFO, "%s %s%s = %qd bytes", \ 181 cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \ 182 } 183 184 static void ack __P((char *)); 185 static void myoob __P((int)); 186 static int checkuser __P((char *)); 187 static FILE *dataconn __P((char *, off_t, char *)); 188 static void dolog __P((struct sockaddr_in *)); 189 static char *curdir __P((void)); 190 static void end_login __P((void)); 191 static FILE *getdatasock __P((char *)); 192 static char *gunique __P((char *)); 193 static void lostconn __P((int)); 194 static int receive_data __P((FILE *, FILE *)); 195 static void send_data __P((FILE *, FILE *, off_t, off_t, int)); 196 static struct passwd * 197 sgetpwnam __P((char *)); 198 static char *sgetsave __P((char *)); 199 200 static char * 201 curdir() 202 { 203 static char path[MAXPATHLEN+1+1]; /* path + '/' + '\0' */ 204 205 if (getcwd(path, sizeof(path)-2) == NULL) 206 return (""); 207 if (path[1] != '\0') /* special case for root dir. */ 208 strcat(path, "/"); 209 /* For guest account, skip / since it's chrooted */ 210 return (guest ? path+1 : path); 211 } 212 213 int 214 main(argc, argv, envp) 215 int argc; 216 char *argv[]; 217 char **envp; 218 { 219 int addrlen, ch, on = 1, tos; 220 char *cp, line[LINE_MAX]; 221 FILE *fd; 222 223 tzset(); /* in case no timezone database in ~ftp */ 224 225 /* 226 * LOG_NDELAY sets up the logging connection immediately, 227 * necessary for anonymous ftp's that chroot and can't do it later. 228 */ 229 openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); 230 addrlen = sizeof(his_addr); 231 if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { 232 syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); 233 exit(1); 234 } 235 #ifdef SKEY 236 strcpy(addr_string, inet_ntoa(his_addr.sin_addr)); 237 #endif 238 addrlen = sizeof(ctrl_addr); 239 if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { 240 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); 241 exit(1); 242 } 243 #ifdef IP_TOS 244 tos = IPTOS_LOWDELAY; 245 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) 246 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 247 #endif 248 data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); 249 debug = 0; 250 #ifdef SETPROCTITLE 251 /* 252 * Save start and extent of argv for setproctitle. 253 */ 254 Argv = argv; 255 while (*envp) 256 envp++; 257 LastArgv = envp[-1] + strlen(envp[-1]); 258 #endif /* SETPROCTITLE */ 259 260 261 #ifdef STATS 262 while ((ch = getopt(argc, argv, "dlSt:T:u:v")) != EOF) { 263 #else 264 while ((ch = getopt(argc, argv, "dlUt:T:u:v")) != EOF) { 265 #endif 266 switch (ch) { 267 case 'd': 268 debug = 1; 269 break; 270 271 case 'l': 272 logging++; /* > 1 == extra logging */ 273 break; 274 275 case 'U': 276 restricted_data_ports = 0; 277 break; 278 279 case 't': 280 timeout = atoi(optarg); 281 if (maxtimeout < timeout) 282 maxtimeout = timeout; 283 break; 284 #ifdef STATS 285 case 'S': 286 stats = 1; 287 break; 288 #endif 289 case 'T': 290 maxtimeout = atoi(optarg); 291 if (timeout > maxtimeout) 292 timeout = maxtimeout; 293 break; 294 295 case 'u': 296 { 297 long val = 0; 298 299 val = strtol(optarg, &optarg, 8); 300 if (*optarg != '\0' || val < 0) 301 warnx("bad value for -u"); 302 else 303 defumask = val; 304 break; 305 } 306 307 case 'v': 308 debug = 1; 309 break; 310 311 default: 312 warnx("unknown flag -%c ignored", optopt); 313 break; 314 } 315 } 316 (void) freopen(_PATH_DEVNULL, "w", stderr); 317 (void) signal(SIGPIPE, lostconn); 318 (void) signal(SIGCHLD, SIG_IGN); 319 if ((int)signal(SIGURG, myoob) < 0) 320 syslog(LOG_ERR, "signal: %m"); 321 322 /* Try to handle urgent data inline */ 323 #ifdef SO_OOBINLINE 324 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) 325 syslog(LOG_ERR, "setsockopt: %m"); 326 #endif 327 328 #ifdef F_SETOWN 329 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) 330 syslog(LOG_ERR, "fcntl F_SETOWN: %m"); 331 #endif 332 dolog(&his_addr); 333 /* 334 * Set up default state 335 */ 336 data = -1; 337 type = TYPE_A; 338 form = FORM_N; 339 stru = STRU_F; 340 mode = MODE_S; 341 tmpline[0] = '\0'; 342 343 /* If logins are disabled, print out the message. */ 344 if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) { 345 while (fgets(line, sizeof(line), fd) != NULL) { 346 if ((cp = strchr(line, '\n')) != NULL) 347 *cp = '\0'; 348 lreply(530, "%s", line); 349 } 350 (void) fflush(stdout); 351 (void) fclose(fd); 352 reply(530, "System not available."); 353 exit(0); 354 } 355 if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) { 356 while (fgets(line, sizeof(line), fd) != NULL) { 357 if ((cp = strchr(line, '\n')) != NULL) 358 *cp = '\0'; 359 lreply(220, "%s", line); 360 } 361 (void) fflush(stdout); 362 (void) fclose(fd); 363 /* reply(220,) must follow */ 364 } 365 (void) gethostname(hostname, sizeof(hostname)); 366 reply(220, "%s FTP server (%s) ready.", hostname, version); 367 (void) setjmp(errcatch); 368 for (;;) 369 (void) yyparse(); 370 /* NOTREACHED */ 371 } 372 373 static void 374 lostconn(signo) 375 int signo; 376 { 377 378 if (debug) 379 syslog(LOG_DEBUG, "lost connection"); 380 dologout(-1); 381 } 382 383 static char ttyline[20]; 384 385 /* 386 * Helper function for sgetpwnam(). 387 */ 388 static char * 389 sgetsave(s) 390 char *s; 391 { 392 char *new = malloc((unsigned) strlen(s) + 1); 393 394 if (new == NULL) { 395 perror_reply(421, "Local resource failure: malloc"); 396 dologout(1); 397 /* NOTREACHED */ 398 } 399 (void) strcpy(new, s); 400 return (new); 401 } 402 403 /* 404 * Save the result of a getpwnam. Used for USER command, since 405 * the data returned must not be clobbered by any other command 406 * (e.g., globbing). 407 */ 408 static struct passwd * 409 sgetpwnam(name) 410 char *name; 411 { 412 static struct passwd save; 413 struct passwd *p; 414 415 if ((p = getpwnam(name)) == NULL) 416 return (p); 417 if (save.pw_name) { 418 free(save.pw_name); 419 free(save.pw_passwd); 420 free(save.pw_gecos); 421 free(save.pw_dir); 422 free(save.pw_shell); 423 } 424 save = *p; 425 save.pw_name = sgetsave(p->pw_name); 426 save.pw_passwd = sgetsave(p->pw_passwd); 427 save.pw_gecos = sgetsave(p->pw_gecos); 428 save.pw_dir = sgetsave(p->pw_dir); 429 save.pw_shell = sgetsave(p->pw_shell); 430 return (&save); 431 } 432 433 static int login_attempts; /* number of failed login attempts */ 434 static int askpasswd; /* had user command, ask for passwd */ 435 static char curname[10]; /* current USER name */ 436 437 /* 438 * USER command. 439 * Sets global passwd pointer pw if named account exists and is acceptable; 440 * sets askpasswd if a PASS command is expected. If logged in previously, 441 * need to reset state. If name is "ftp" or "anonymous", the name is not in 442 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return. 443 * If account doesn't exist, ask for passwd anyway. Otherwise, check user 444 * requesting login privileges. Disallow anyone who does not have a standard 445 * shell as returned by getusershell(). Disallow anyone mentioned in the file 446 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. 447 */ 448 void 449 user(name) 450 char *name; 451 { 452 char *cp, *shell; 453 454 if (logged_in) { 455 if (guest) { 456 reply(530, "Can't change user from guest login."); 457 return; 458 } 459 end_login(); 460 } 461 462 guest = 0; 463 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { 464 if (checkuser("ftp") || checkuser("anonymous")) 465 reply(530, "User %s access denied.", name); 466 else if ((pw = sgetpwnam("ftp")) != NULL) { 467 guest = 1; 468 askpasswd = 1; 469 reply(331, 470 "Guest login ok, send your email address as password."); 471 } else 472 reply(530, "User %s unknown.", name); 473 if (!askpasswd && logging) 474 syslog(LOG_NOTICE, 475 "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost); 476 return; 477 } 478 if (pw = sgetpwnam(name)) { 479 if ((shell = pw->pw_shell) == NULL || *shell == 0) 480 shell = _PATH_BSHELL; 481 while ((cp = getusershell()) != NULL) 482 if (strcmp(cp, shell) == 0) 483 break; 484 endusershell(); 485 486 if (cp == NULL || checkuser(name)) { 487 reply(530, "User %s access denied.", name); 488 if (logging) 489 syslog(LOG_NOTICE, 490 "FTP LOGIN REFUSED FROM %s, %s", 491 remotehost, name); 492 pw = (struct passwd *) NULL; 493 return; 494 } 495 } 496 if (logging) 497 strncpy(curname, name, sizeof(curname)-1); 498 #ifdef SKEY 499 pwok = skeyaccess(name, NULL, remotehost, addr_string); 500 reply(331, "%s", skey_challenge(name, pw, pwok)); 501 #else 502 reply(331, "Password required for %s.", name); 503 #endif 504 askpasswd = 1; 505 /* 506 * Delay before reading passwd after first failed 507 * attempt to slow down passwd-guessing programs. 508 */ 509 if (login_attempts) 510 sleep((unsigned) login_attempts); 511 } 512 513 /* 514 * Check if a user is in the file _PATH_FTPUSERS 515 */ 516 static int 517 checkuser(name) 518 char *name; 519 { 520 FILE *fd; 521 int found = 0; 522 char *p, line[BUFSIZ]; 523 524 if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) { 525 while (fgets(line, sizeof(line), fd) != NULL) 526 if ((p = strchr(line, '\n')) != NULL) { 527 *p = '\0'; 528 if (line[0] == '#') 529 continue; 530 if (strcmp(line, name) == 0) { 531 found = 1; 532 break; 533 } 534 } 535 (void) fclose(fd); 536 } 537 return (found); 538 } 539 540 /* 541 * Terminate login as previous user, if any, resetting state; 542 * used when USER command is given or login fails. 543 */ 544 static void 545 end_login() 546 { 547 548 (void) seteuid((uid_t)0); 549 if (logged_in) 550 logwtmp(ttyline, "", ""); 551 pw = NULL; 552 logged_in = 0; 553 guest = 0; 554 } 555 556 void 557 pass(passwd) 558 char *passwd; 559 { 560 char *salt, *xpasswd; 561 FILE *fd; 562 static char homedir[MAXPATHLEN]; 563 564 if (logged_in || askpasswd == 0) { 565 reply(503, "Login with USER first."); 566 return; 567 } 568 askpasswd = 0; 569 if (!guest) { /* "ftp" is only account allowed no password */ 570 if (pw == NULL) 571 salt = "xx"; 572 else 573 salt = pw->pw_passwd; 574 #ifdef SKEY 575 xpasswd = skey_crypt(passwd, salt, pw, pwok); 576 pwok = 0; 577 #else 578 xpasswd = crypt(passwd, salt); 579 #endif 580 /* The strcmp does not catch null passwords! */ 581 if (pw == NULL || *pw->pw_passwd == '\0' || 582 (pw->pw_expire && time(NULL) >= pw->pw_expire) || 583 strcmp(xpasswd, pw->pw_passwd)) { 584 reply(530, "Login incorrect."); 585 if (logging) 586 syslog(LOG_NOTICE, 587 "FTP LOGIN FAILED FROM %s, %s", 588 remotehost, curname); 589 pw = NULL; 590 if (login_attempts++ >= 5) { 591 syslog(LOG_NOTICE, 592 "repeated login failures from %s", 593 remotehost); 594 exit(0); 595 } 596 return; 597 } 598 } 599 login_attempts = 0; /* this time successful */ 600 if (setegid((gid_t)pw->pw_gid) < 0) { 601 reply(550, "Can't set gid."); 602 return; 603 } 604 (void) initgroups(pw->pw_name, pw->pw_gid); 605 606 /* open wtmp before chroot */ 607 (void)sprintf(ttyline, "ftp%d", getpid()); 608 logwtmp(ttyline, pw->pw_name, remotehost); 609 logged_in = 1; 610 611 #ifdef STATS 612 if (guest && stats == 1 && statfd < 0) 613 if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0) 614 stats = 0; 615 #endif 616 617 if (guest) { 618 /* 619 * We MUST do a chdir() after the chroot. Otherwise 620 * the old current directory will be accessible as "." 621 * outside the new root! 622 */ 623 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { 624 reply(550, "Can't set guest privileges."); 625 goto bad; 626 } 627 } else if (chdir(pw->pw_dir) < 0) { 628 if (chdir("/") < 0) { 629 reply(530, "User %s: can't change directory to %s.", 630 pw->pw_name, pw->pw_dir); 631 goto bad; 632 } else 633 lreply(230, "No directory! Logging in with home=/"); 634 } 635 if (seteuid((uid_t)pw->pw_uid) < 0) { 636 reply(550, "Can't set uid."); 637 goto bad; 638 } 639 640 /* 641 * Set home directory so that use of ~ (tilde) works correctly. 642 */ 643 if (getcwd(homedir, MAXPATHLEN) != NULL) 644 setenv("HOME", homedir, 1); 645 646 /* 647 * Display a login message, if it exists. 648 * N.B. reply(230,) must follow the message. 649 */ 650 if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) { 651 char *cp, line[LINE_MAX]; 652 653 while (fgets(line, sizeof(line), fd) != NULL) { 654 if ((cp = strchr(line, '\n')) != NULL) 655 *cp = '\0'; 656 lreply(230, "%s", line); 657 } 658 (void) fflush(stdout); 659 (void) fclose(fd); 660 } 661 if (guest) { 662 #ifdef STATS 663 char * copy(); 664 665 if (ident != NULL) 666 free(ident); 667 ident = (char *) copy(passwd); 668 #endif 669 reply(230, "Guest login ok, access restrictions apply."); 670 #ifdef SETPROCTITLE 671 snprintf(proctitle, sizeof(proctitle), 672 "%s: anonymous/%.*s", remotehost, 673 sizeof(proctitle) - sizeof(remotehost) - 674 sizeof(": anonymous/"), passwd); 675 setproctitle(proctitle); 676 #endif /* SETPROCTITLE */ 677 if (logging) 678 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s", 679 remotehost, passwd); 680 } else { 681 reply(230, "User %s logged in.", pw->pw_name); 682 #ifdef SETPROCTITLE 683 snprintf(proctitle, sizeof(proctitle), 684 "%s: %s", remotehost, pw->pw_name); 685 setproctitle(proctitle); 686 #endif /* SETPROCTITLE */ 687 if (logging) 688 syslog(LOG_INFO, "FTP LOGIN FROM %s as %s", 689 remotehost, pw->pw_name); 690 } 691 (void) umask(defumask); 692 return; 693 bad: 694 /* Forget all about it... */ 695 end_login(); 696 } 697 698 void 699 retrieve(cmd, name) 700 char *cmd, *name; 701 { 702 FILE *fin, *dout; 703 struct stat st; 704 int (*closefunc) __P((FILE *)); 705 #ifdef STATS 706 long start; 707 #endif 708 709 if (cmd == 0) { 710 fin = fopen(name, "r"), closefunc = fclose; 711 st.st_size = 0; 712 } else { 713 char line[BUFSIZ]; 714 715 (void) sprintf(line, cmd, name), name = line; 716 fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose; 717 st.st_size = -1; 718 st.st_blksize = BUFSIZ; 719 } 720 if (fin == NULL) { 721 if (errno != 0) { 722 perror_reply(550, name); 723 if (cmd == 0) { 724 LOGCMD("get", name); 725 } 726 } 727 return; 728 } 729 byte_count = -1; 730 if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) { 731 reply(550, "%s: not a plain file.", name); 732 goto done; 733 } 734 if (restart_point) { 735 if (type == TYPE_A) { 736 off_t i, n; 737 int c; 738 739 n = restart_point; 740 i = 0; 741 while (i++ < n) { 742 if ((c=getc(fin)) == EOF) { 743 perror_reply(550, name); 744 goto done; 745 } 746 if (c == '\n') 747 i++; 748 } 749 } else if (lseek(fileno(fin), restart_point, L_SET) < 0) { 750 perror_reply(550, name); 751 goto done; 752 } 753 } 754 dout = dataconn(name, st.st_size, "w"); 755 if (dout == NULL) 756 goto done; 757 #ifdef STATS 758 time(&start); 759 #endif 760 send_data(fin, dout, st.st_blksize, st.st_size, 761 restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)); 762 #ifdef STATS 763 if (cmd == 0 && guest && stats) 764 logxfer( name, st.st_size, start); 765 #endif 766 (void) fclose(dout); 767 data = -1; 768 pdata = -1; 769 done: 770 if (cmd == 0) 771 LOGBYTES("get", name, byte_count); 772 (*closefunc)(fin); 773 } 774 775 void 776 store(name, mode, unique) 777 char *name, *mode; 778 int unique; 779 { 780 FILE *fout, *din; 781 struct stat st; 782 int (*closefunc) __P((FILE *)); 783 784 if (unique && stat(name, &st) == 0 && 785 (name = gunique(name)) == NULL) { 786 LOGCMD(*mode == 'w' ? "put" : "append", name); 787 return; 788 } 789 790 if (restart_point) 791 mode = "r+"; 792 fout = fopen(name, mode); 793 closefunc = fclose; 794 if (fout == NULL) { 795 perror_reply(553, name); 796 LOGCMD(*mode == 'w' ? "put" : "append", name); 797 return; 798 } 799 byte_count = -1; 800 if (restart_point) { 801 if (type == TYPE_A) { 802 off_t i, n; 803 int c; 804 805 n = restart_point; 806 i = 0; 807 while (i++ < n) { 808 if ((c=getc(fout)) == EOF) { 809 perror_reply(550, name); 810 goto done; 811 } 812 if (c == '\n') 813 i++; 814 } 815 /* 816 * We must do this seek to "current" position 817 * because we are changing from reading to 818 * writing. 819 */ 820 if (fseek(fout, 0L, L_INCR) < 0) { 821 perror_reply(550, name); 822 goto done; 823 } 824 } else if (lseek(fileno(fout), restart_point, L_SET) < 0) { 825 perror_reply(550, name); 826 goto done; 827 } 828 } 829 din = dataconn(name, (off_t)-1, "r"); 830 if (din == NULL) 831 goto done; 832 if (receive_data(din, fout) == 0) { 833 if (unique) 834 reply(226, "Transfer complete (unique file name:%s).", 835 name); 836 else 837 reply(226, "Transfer complete."); 838 } 839 (void) fclose(din); 840 data = -1; 841 pdata = -1; 842 done: 843 LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count); 844 (*closefunc)(fout); 845 } 846 847 static FILE * 848 getdatasock(mode) 849 char *mode; 850 { 851 int on = 1, s, t, tries; 852 853 if (data >= 0) 854 return (fdopen(data, mode)); 855 (void) seteuid((uid_t)0); 856 s = socket(AF_INET, SOCK_STREAM, 0); 857 if (s < 0) 858 goto bad; 859 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 860 (char *) &on, sizeof(on)) < 0) 861 goto bad; 862 /* anchor socket to avoid multi-homing problems */ 863 data_source.sin_family = AF_INET; 864 data_source.sin_addr = ctrl_addr.sin_addr; 865 for (tries = 1; ; tries++) { 866 if (bind(s, (struct sockaddr *)&data_source, 867 sizeof(data_source)) >= 0) 868 break; 869 if (errno != EADDRINUSE || tries > 10) 870 goto bad; 871 sleep(tries); 872 } 873 (void) seteuid((uid_t)pw->pw_uid); 874 #ifdef IP_TOS 875 on = IPTOS_THROUGHPUT; 876 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 877 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 878 #endif 879 #ifdef TCP_NOPUSH 880 /* 881 * Turn off push flag to keep sender TCP from sending short packets 882 * at the boundaries of each write(). Should probably do a SO_SNDBUF 883 * to set the send buffer size as well, but that may not be desirable 884 * in heavy-load situations. 885 */ 886 on = 1; 887 if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0) 888 syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m"); 889 #endif 890 #ifdef SO_SNDBUF 891 on = 65536; 892 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0) 893 syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m"); 894 #endif 895 896 return (fdopen(s, mode)); 897 bad: 898 /* Return the real value of errno (close may change it) */ 899 t = errno; 900 (void) seteuid((uid_t)pw->pw_uid); 901 (void) close(s); 902 errno = t; 903 return (NULL); 904 } 905 906 static FILE * 907 dataconn(name, size, mode) 908 char *name; 909 off_t size; 910 char *mode; 911 { 912 char sizebuf[32]; 913 FILE *file; 914 int retry = 0, tos; 915 916 file_size = size; 917 byte_count = 0; 918 if (size != (off_t) -1) 919 (void) sprintf(sizebuf, " (%qd bytes)", size); 920 else 921 (void) strcpy(sizebuf, ""); 922 if (pdata >= 0) { 923 struct sockaddr_in from; 924 int s, fromlen = sizeof(from); 925 926 s = accept(pdata, (struct sockaddr *)&from, &fromlen); 927 if (s < 0) { 928 reply(425, "Can't open data connection."); 929 (void) close(pdata); 930 pdata = -1; 931 return (NULL); 932 } 933 (void) close(pdata); 934 pdata = s; 935 #ifdef IP_TOS 936 tos = IPTOS_LOWDELAY; 937 (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, 938 sizeof(int)); 939 #endif 940 reply(150, "Opening %s mode data connection for '%s'%s.", 941 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 942 return (fdopen(pdata, mode)); 943 } 944 if (data >= 0) { 945 reply(125, "Using existing data connection for '%s'%s.", 946 name, sizebuf); 947 usedefault = 1; 948 return (fdopen(data, mode)); 949 } 950 if (usedefault) 951 data_dest = his_addr; 952 usedefault = 1; 953 file = getdatasock(mode); 954 if (file == NULL) { 955 reply(425, "Can't create data socket (%s,%d): %s.", 956 inet_ntoa(data_source.sin_addr), 957 ntohs(data_source.sin_port), strerror(errno)); 958 return (NULL); 959 } 960 data = fileno(file); 961 while (connect(data, (struct sockaddr *)&data_dest, 962 sizeof(data_dest)) < 0) { 963 if (errno == EADDRINUSE && retry < swaitmax) { 964 sleep((unsigned) swaitint); 965 retry += swaitint; 966 continue; 967 } 968 perror_reply(425, "Can't build data connection"); 969 (void) fclose(file); 970 data = -1; 971 return (NULL); 972 } 973 reply(150, "Opening %s mode data connection for '%s'%s.", 974 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 975 return (file); 976 } 977 978 /* 979 * Tranfer the contents of "instr" to "outstr" peer using the appropriate 980 * encapsulation of the data subject to Mode, Structure, and Type. 981 * 982 * NB: Form isn't handled. 983 */ 984 static void 985 send_data(instr, outstr, blksize, filesize, isreg) 986 FILE *instr, *outstr; 987 off_t blksize; 988 off_t filesize; 989 int isreg; 990 { 991 int c, cnt, filefd, netfd; 992 char *buf, *bp; 993 size_t len; 994 995 transflag++; 996 if (setjmp(urgcatch)) { 997 transflag = 0; 998 return; 999 } 1000 switch (type) { 1001 1002 case TYPE_A: 1003 while ((c = getc(instr)) != EOF) { 1004 byte_count++; 1005 if (c == '\n') { 1006 if (ferror(outstr)) 1007 goto data_err; 1008 (void) putc('\r', outstr); 1009 } 1010 (void) putc(c, outstr); 1011 } 1012 fflush(outstr); 1013 transflag = 0; 1014 if (ferror(instr)) 1015 goto file_err; 1016 if (ferror(outstr)) 1017 goto data_err; 1018 reply(226, "Transfer complete."); 1019 return; 1020 1021 case TYPE_I: 1022 case TYPE_L: 1023 /* 1024 * isreg is only set if we are not doing restart and we 1025 * are sending a regular file 1026 */ 1027 netfd = fileno(outstr); 1028 filefd = fileno(instr); 1029 1030 if (isreg && filesize < (off_t)16 * 1024 * 1024) { 1031 buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd, 1032 (off_t)0); 1033 if (!buf) { 1034 syslog(LOG_WARNING, "mmap(%lu): %m", 1035 (unsigned long)filesize); 1036 goto oldway; 1037 } 1038 bp = buf; 1039 len = filesize; 1040 do { 1041 cnt = write(netfd, bp, len); 1042 len -= cnt; 1043 bp += cnt; 1044 if (cnt > 0) byte_count += cnt; 1045 } while(cnt > 0 && len > 0); 1046 1047 transflag = 0; 1048 munmap(buf, (size_t)filesize); 1049 if (cnt < 0) 1050 goto data_err; 1051 reply(226, "Transfer complete."); 1052 return; 1053 } 1054 1055 oldway: 1056 if ((buf = malloc((u_int)blksize)) == NULL) { 1057 transflag = 0; 1058 perror_reply(451, "Local resource failure: malloc"); 1059 return; 1060 } 1061 1062 while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 && 1063 write(netfd, buf, cnt) == cnt) 1064 byte_count += cnt; 1065 transflag = 0; 1066 (void)free(buf); 1067 if (cnt != 0) { 1068 if (cnt < 0) 1069 goto file_err; 1070 goto data_err; 1071 } 1072 reply(226, "Transfer complete."); 1073 return; 1074 default: 1075 transflag = 0; 1076 reply(550, "Unimplemented TYPE %d in send_data", type); 1077 return; 1078 } 1079 1080 data_err: 1081 transflag = 0; 1082 perror_reply(426, "Data connection"); 1083 return; 1084 1085 file_err: 1086 transflag = 0; 1087 perror_reply(551, "Error on input file"); 1088 } 1089 1090 /* 1091 * Transfer data from peer to "outstr" using the appropriate encapulation of 1092 * the data subject to Mode, Structure, and Type. 1093 * 1094 * N.B.: Form isn't handled. 1095 */ 1096 static int 1097 receive_data(instr, outstr) 1098 FILE *instr, *outstr; 1099 { 1100 int c; 1101 int cnt, bare_lfs = 0; 1102 char buf[BUFSIZ]; 1103 1104 transflag++; 1105 if (setjmp(urgcatch)) { 1106 transflag = 0; 1107 return (-1); 1108 } 1109 switch (type) { 1110 1111 case TYPE_I: 1112 case TYPE_L: 1113 while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) { 1114 if (write(fileno(outstr), buf, cnt) != cnt) 1115 goto file_err; 1116 byte_count += cnt; 1117 } 1118 if (cnt < 0) 1119 goto data_err; 1120 transflag = 0; 1121 return (0); 1122 1123 case TYPE_E: 1124 reply(553, "TYPE E not implemented."); 1125 transflag = 0; 1126 return (-1); 1127 1128 case TYPE_A: 1129 while ((c = getc(instr)) != EOF) { 1130 byte_count++; 1131 if (c == '\n') 1132 bare_lfs++; 1133 while (c == '\r') { 1134 if (ferror(outstr)) 1135 goto data_err; 1136 if ((c = getc(instr)) != '\n') { 1137 (void) putc ('\r', outstr); 1138 if (c == '\0' || c == EOF) 1139 goto contin2; 1140 } 1141 } 1142 (void) putc(c, outstr); 1143 contin2: ; 1144 } 1145 fflush(outstr); 1146 if (ferror(instr)) 1147 goto data_err; 1148 if (ferror(outstr)) 1149 goto file_err; 1150 transflag = 0; 1151 if (bare_lfs) { 1152 lreply(226, 1153 "WARNING! %d bare linefeeds received in ASCII mode", 1154 bare_lfs); 1155 (void)printf(" File may not have transferred correctly.\r\n"); 1156 } 1157 return (0); 1158 default: 1159 reply(550, "Unimplemented TYPE %d in receive_data", type); 1160 transflag = 0; 1161 return (-1); 1162 } 1163 1164 data_err: 1165 transflag = 0; 1166 perror_reply(426, "Data Connection"); 1167 return (-1); 1168 1169 file_err: 1170 transflag = 0; 1171 perror_reply(452, "Error writing file"); 1172 return (-1); 1173 } 1174 1175 void 1176 statfilecmd(filename) 1177 char *filename; 1178 { 1179 FILE *fin; 1180 int c; 1181 char line[LINE_MAX]; 1182 1183 (void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename); 1184 fin = ftpd_popen(line, "r"); 1185 lreply(211, "status of %s:", filename); 1186 while ((c = getc(fin)) != EOF) { 1187 if (c == '\n') { 1188 if (ferror(stdout)){ 1189 perror_reply(421, "control connection"); 1190 (void) ftpd_pclose(fin); 1191 dologout(1); 1192 /* NOTREACHED */ 1193 } 1194 if (ferror(fin)) { 1195 perror_reply(551, filename); 1196 (void) ftpd_pclose(fin); 1197 return; 1198 } 1199 (void) putc('\r', stdout); 1200 } 1201 (void) putc(c, stdout); 1202 } 1203 (void) ftpd_pclose(fin); 1204 reply(211, "End of Status"); 1205 } 1206 1207 void 1208 statcmd() 1209 { 1210 struct sockaddr_in *sin; 1211 u_char *a, *p; 1212 1213 lreply(211, "%s FTP server status:", hostname, version); 1214 printf(" %s\r\n", version); 1215 printf(" Connected to %s", remotehost); 1216 if (!isdigit(remotehost[0])) 1217 printf(" (%s)", inet_ntoa(his_addr.sin_addr)); 1218 printf("\r\n"); 1219 if (logged_in) { 1220 if (guest) 1221 printf(" Logged in anonymously\r\n"); 1222 else 1223 printf(" Logged in as %s\r\n", pw->pw_name); 1224 } else if (askpasswd) 1225 printf(" Waiting for password\r\n"); 1226 else 1227 printf(" Waiting for user name\r\n"); 1228 printf(" TYPE: %s", typenames[type]); 1229 if (type == TYPE_A || type == TYPE_E) 1230 printf(", FORM: %s", formnames[form]); 1231 if (type == TYPE_L) 1232 #if NBBY == 8 1233 printf(" %d", NBBY); 1234 #else 1235 printf(" %d", bytesize); /* need definition! */ 1236 #endif 1237 printf("; STRUcture: %s; transfer MODE: %s\r\n", 1238 strunames[stru], modenames[mode]); 1239 if (data != -1) 1240 printf(" Data connection open\r\n"); 1241 else if (pdata != -1) { 1242 printf(" in Passive mode"); 1243 sin = &pasv_addr; 1244 goto printaddr; 1245 } else if (usedefault == 0) { 1246 printf(" PORT"); 1247 sin = &data_dest; 1248 printaddr: 1249 a = (u_char *) &sin->sin_addr; 1250 p = (u_char *) &sin->sin_port; 1251 #define UC(b) (((int) b) & 0xff) 1252 printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]), 1253 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 1254 #undef UC 1255 } else 1256 printf(" No data connection\r\n"); 1257 reply(211, "End of status"); 1258 } 1259 1260 void 1261 fatal(s) 1262 char *s; 1263 { 1264 1265 reply(451, "Error in server: %s\n", s); 1266 reply(221, "Closing connection due to server error."); 1267 dologout(0); 1268 /* NOTREACHED */ 1269 } 1270 1271 void 1272 #if __STDC__ 1273 reply(int n, const char *fmt, ...) 1274 #else 1275 reply(n, fmt, va_alist) 1276 int n; 1277 char *fmt; 1278 va_dcl 1279 #endif 1280 { 1281 va_list ap; 1282 #if __STDC__ 1283 va_start(ap, fmt); 1284 #else 1285 va_start(ap); 1286 #endif 1287 (void)printf("%d ", n); 1288 (void)vprintf(fmt, ap); 1289 (void)printf("\r\n"); 1290 (void)fflush(stdout); 1291 if (debug) { 1292 syslog(LOG_DEBUG, "<--- %d ", n); 1293 vsyslog(LOG_DEBUG, fmt, ap); 1294 } 1295 } 1296 1297 void 1298 #if __STDC__ 1299 lreply(int n, const char *fmt, ...) 1300 #else 1301 lreply(n, fmt, va_alist) 1302 int n; 1303 char *fmt; 1304 va_dcl 1305 #endif 1306 { 1307 va_list ap; 1308 #if __STDC__ 1309 va_start(ap, fmt); 1310 #else 1311 va_start(ap); 1312 #endif 1313 (void)printf("%d- ", n); 1314 (void)vprintf(fmt, ap); 1315 (void)printf("\r\n"); 1316 (void)fflush(stdout); 1317 if (debug) { 1318 syslog(LOG_DEBUG, "<--- %d- ", n); 1319 vsyslog(LOG_DEBUG, fmt, ap); 1320 } 1321 } 1322 1323 static void 1324 ack(s) 1325 char *s; 1326 { 1327 1328 reply(250, "%s command successful.", s); 1329 } 1330 1331 void 1332 nack(s) 1333 char *s; 1334 { 1335 1336 reply(502, "%s command not implemented.", s); 1337 } 1338 1339 /* ARGSUSED */ 1340 void 1341 yyerror(s) 1342 char *s; 1343 { 1344 char *cp; 1345 1346 if (cp = strchr(cbuf,'\n')) 1347 *cp = '\0'; 1348 reply(500, "'%s': command not understood.", cbuf); 1349 } 1350 1351 void 1352 delete(name) 1353 char *name; 1354 { 1355 struct stat st; 1356 1357 LOGCMD("delete", name); 1358 if (stat(name, &st) < 0) { 1359 perror_reply(550, name); 1360 return; 1361 } 1362 if ((st.st_mode&S_IFMT) == S_IFDIR) { 1363 if (rmdir(name) < 0) { 1364 perror_reply(550, name); 1365 return; 1366 } 1367 goto done; 1368 } 1369 if (unlink(name) < 0) { 1370 perror_reply(550, name); 1371 return; 1372 } 1373 done: 1374 ack("DELE"); 1375 } 1376 1377 void 1378 cwd(path) 1379 char *path; 1380 { 1381 1382 if (chdir(path) < 0) 1383 perror_reply(550, path); 1384 else 1385 ack("CWD"); 1386 } 1387 1388 void 1389 makedir(name) 1390 char *name; 1391 { 1392 1393 LOGCMD("mkdir", name); 1394 if (mkdir(name, 0777) < 0) 1395 perror_reply(550, name); 1396 else 1397 reply(257, "MKD command successful."); 1398 } 1399 1400 void 1401 removedir(name) 1402 char *name; 1403 { 1404 1405 LOGCMD("rmdir", name); 1406 if (rmdir(name) < 0) 1407 perror_reply(550, name); 1408 else 1409 ack("RMD"); 1410 } 1411 1412 void 1413 pwd() 1414 { 1415 char path[MAXPATHLEN + 1]; 1416 1417 if (getwd(path) == (char *)NULL) 1418 reply(550, "%s.", path); 1419 else 1420 reply(257, "\"%s\" is current directory.", path); 1421 } 1422 1423 char * 1424 renamefrom(name) 1425 char *name; 1426 { 1427 struct stat st; 1428 1429 if (stat(name, &st) < 0) { 1430 perror_reply(550, name); 1431 return ((char *)0); 1432 } 1433 reply(350, "File exists, ready for destination name"); 1434 return (name); 1435 } 1436 1437 void 1438 renamecmd(from, to) 1439 char *from, *to; 1440 { 1441 1442 LOGCMD2("rename", from, to); 1443 if (rename(from, to) < 0) 1444 perror_reply(550, "rename"); 1445 else 1446 ack("RNTO"); 1447 } 1448 1449 static void 1450 dolog(sin) 1451 struct sockaddr_in *sin; 1452 { 1453 struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr, 1454 sizeof(struct in_addr), AF_INET); 1455 1456 if (hp) 1457 (void) strncpy(remotehost, hp->h_name, sizeof(remotehost)); 1458 else 1459 (void) strncpy(remotehost, inet_ntoa(sin->sin_addr), 1460 sizeof(remotehost)); 1461 #ifdef SETPROCTITLE 1462 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost); 1463 setproctitle(proctitle); 1464 #endif /* SETPROCTITLE */ 1465 1466 if (logging) 1467 syslog(LOG_INFO, "connection from %s", remotehost); 1468 } 1469 1470 /* 1471 * Record logout in wtmp file 1472 * and exit with supplied status. 1473 */ 1474 void 1475 dologout(status) 1476 int status; 1477 { 1478 1479 if (logged_in) { 1480 (void) seteuid((uid_t)0); 1481 logwtmp(ttyline, "", ""); 1482 } 1483 /* beware of flushing buffers after a SIGPIPE */ 1484 _exit(status); 1485 } 1486 1487 static void 1488 myoob(signo) 1489 int signo; 1490 { 1491 char *cp; 1492 1493 /* only process if transfer occurring */ 1494 if (!transflag) 1495 return; 1496 cp = tmpline; 1497 if (getline(cp, 7, stdin) == NULL) { 1498 reply(221, "You could at least say goodbye."); 1499 dologout(0); 1500 } 1501 upper(cp); 1502 if (strcmp(cp, "ABOR\r\n") == 0) { 1503 tmpline[0] = '\0'; 1504 reply(426, "Transfer aborted. Data connection closed."); 1505 reply(226, "Abort successful"); 1506 longjmp(urgcatch, 1); 1507 } 1508 if (strcmp(cp, "STAT\r\n") == 0) { 1509 if (file_size != (off_t) -1) 1510 reply(213, "Status: %qd of %qd bytes transferred", 1511 byte_count, file_size); 1512 else 1513 reply(213, "Status: %qd bytes transferred", byte_count); 1514 } 1515 } 1516 1517 /* 1518 * Note: a response of 425 is not mentioned as a possible response to 1519 * the PASV command in RFC959. However, it has been blessed as 1520 * a legitimate response by Jon Postel in a telephone conversation 1521 * with Rick Adams on 25 Jan 89. 1522 */ 1523 void 1524 passive() 1525 { 1526 int len; 1527 u_short port; 1528 char *p, *a; 1529 1530 pdata = socket(AF_INET, SOCK_STREAM, 0); 1531 if (pdata < 0) { 1532 perror_reply(425, "Can't open passive connection"); 1533 return; 1534 } 1535 1536 if (restricted_data_ports) { 1537 for (port = FTP_DATA_BOTTOM; port <= FTP_DATA_TOP; port++) { 1538 pasv_addr = ctrl_addr; 1539 pasv_addr.sin_port = htons(port); 1540 (void) seteuid((uid_t)0); 1541 if (bind(pdata, (struct sockaddr *)&pasv_addr, 1542 sizeof(pasv_addr)) < 0) { 1543 (void) seteuid((uid_t)pw->pw_uid); 1544 if (errno == EADDRINUSE) 1545 continue; 1546 else 1547 goto pasv_error; 1548 } 1549 (void) seteuid((uid_t)pw->pw_uid); 1550 break; 1551 } 1552 if (port > FTP_DATA_TOP) 1553 goto pasv_error; 1554 } else { 1555 pasv_addr = ctrl_addr; 1556 pasv_addr.sin_port = 0; 1557 (void) seteuid((uid_t)0); 1558 if (bind(pdata, (struct sockaddr *)&pasv_addr, 1559 sizeof(pasv_addr)) < 0) { 1560 (void) seteuid((uid_t)pw->pw_uid); 1561 goto pasv_error; 1562 } 1563 (void) seteuid((uid_t)pw->pw_uid); 1564 } 1565 1566 len = sizeof(pasv_addr); 1567 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) 1568 goto pasv_error; 1569 if (listen(pdata, 1) < 0) 1570 goto pasv_error; 1571 a = (char *) &pasv_addr.sin_addr; 1572 p = (char *) &pasv_addr.sin_port; 1573 1574 #define UC(b) (((int) b) & 0xff) 1575 1576 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), 1577 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 1578 return; 1579 1580 pasv_error: 1581 (void) close(pdata); 1582 pdata = -1; 1583 perror_reply(425, "Can't open passive connection"); 1584 return; 1585 } 1586 1587 /* 1588 * Generate unique name for file with basename "local". 1589 * The file named "local" is already known to exist. 1590 * Generates failure reply on error. 1591 */ 1592 static char * 1593 gunique(local) 1594 char *local; 1595 { 1596 static char new[MAXPATHLEN]; 1597 struct stat st; 1598 int count; 1599 char *cp; 1600 1601 cp = strrchr(local, '/'); 1602 if (cp) 1603 *cp = '\0'; 1604 if (stat(cp ? local : ".", &st) < 0) { 1605 perror_reply(553, cp ? local : "."); 1606 return ((char *) 0); 1607 } 1608 if (cp) 1609 *cp = '/'; 1610 (void) strcpy(new, local); 1611 cp = new + strlen(new); 1612 *cp++ = '.'; 1613 for (count = 1; count < 100; count++) { 1614 (void)sprintf(cp, "%d", count); 1615 if (stat(new, &st) < 0) 1616 return (new); 1617 } 1618 reply(452, "Unique file name cannot be created."); 1619 return (NULL); 1620 } 1621 1622 /* 1623 * Format and send reply containing system error number. 1624 */ 1625 void 1626 perror_reply(code, string) 1627 int code; 1628 char *string; 1629 { 1630 1631 reply(code, "%s: %s.", string, strerror(errno)); 1632 } 1633 1634 static char *onefile[] = { 1635 "", 1636 0 1637 }; 1638 1639 void 1640 send_file_list(whichf) 1641 char *whichf; 1642 { 1643 struct stat st; 1644 DIR *dirp = NULL; 1645 struct dirent *dir; 1646 FILE *dout = NULL; 1647 char **dirlist, *dirname; 1648 int simple = 0; 1649 int freeglob = 0; 1650 glob_t gl; 1651 1652 if (strpbrk(whichf, "~{[*?") != NULL) { 1653 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; 1654 1655 memset(&gl, 0, sizeof(gl)); 1656 freeglob = 1; 1657 if (glob(whichf, flags, 0, &gl)) { 1658 reply(550, "not found"); 1659 goto out; 1660 } else if (gl.gl_pathc == 0) { 1661 errno = ENOENT; 1662 perror_reply(550, whichf); 1663 goto out; 1664 } 1665 dirlist = gl.gl_pathv; 1666 } else { 1667 onefile[0] = whichf; 1668 dirlist = onefile; 1669 simple = 1; 1670 } 1671 1672 if (setjmp(urgcatch)) { 1673 transflag = 0; 1674 goto out; 1675 } 1676 while (dirname = *dirlist++) { 1677 if (stat(dirname, &st) < 0) { 1678 /* 1679 * If user typed "ls -l", etc, and the client 1680 * used NLST, do what the user meant. 1681 */ 1682 if (dirname[0] == '-' && *dirlist == NULL && 1683 transflag == 0) { 1684 retrieve("/bin/ls %s", dirname); 1685 goto out; 1686 } 1687 perror_reply(550, whichf); 1688 if (dout != NULL) { 1689 (void) fclose(dout); 1690 transflag = 0; 1691 data = -1; 1692 pdata = -1; 1693 } 1694 goto out; 1695 } 1696 1697 if (S_ISREG(st.st_mode)) { 1698 if (dout == NULL) { 1699 dout = dataconn("file list", (off_t)-1, "w"); 1700 if (dout == NULL) 1701 goto out; 1702 transflag++; 1703 } 1704 fprintf(dout, "%s%s\n", dirname, 1705 type == TYPE_A ? "\r" : ""); 1706 byte_count += strlen(dirname) + 1; 1707 continue; 1708 } else if (!S_ISDIR(st.st_mode)) 1709 continue; 1710 1711 if ((dirp = opendir(dirname)) == NULL) 1712 continue; 1713 1714 while ((dir = readdir(dirp)) != NULL) { 1715 char nbuf[MAXPATHLEN]; 1716 1717 if (dir->d_name[0] == '.' && dir->d_namlen == 1) 1718 continue; 1719 if (dir->d_name[0] == '.' && dir->d_name[1] == '.' && 1720 dir->d_namlen == 2) 1721 continue; 1722 1723 sprintf(nbuf, "%s/%s", dirname, dir->d_name); 1724 1725 /* 1726 * We have to do a stat to insure it's 1727 * not a directory or special file. 1728 */ 1729 if (simple || (stat(nbuf, &st) == 0 && 1730 S_ISREG(st.st_mode))) { 1731 if (dout == NULL) { 1732 dout = dataconn("file list", (off_t)-1, 1733 "w"); 1734 if (dout == NULL) 1735 goto out; 1736 transflag++; 1737 } 1738 if (nbuf[0] == '.' && nbuf[1] == '/') 1739 fprintf(dout, "%s%s\n", &nbuf[2], 1740 type == TYPE_A ? "\r" : ""); 1741 else 1742 fprintf(dout, "%s%s\n", nbuf, 1743 type == TYPE_A ? "\r" : ""); 1744 byte_count += strlen(nbuf) + 1; 1745 } 1746 } 1747 (void) closedir(dirp); 1748 } 1749 1750 if (dout == NULL) 1751 reply(550, "No files found."); 1752 else if (ferror(dout) != 0) 1753 perror_reply(550, "Data connection"); 1754 else 1755 reply(226, "Transfer complete."); 1756 1757 transflag = 0; 1758 if (dout != NULL) 1759 (void) fclose(dout); 1760 data = -1; 1761 pdata = -1; 1762 out: 1763 if (freeglob) { 1764 freeglob = 0; 1765 globfree(&gl); 1766 } 1767 } 1768 1769 #ifdef SETPROCTITLE 1770 /* 1771 * Clobber argv so ps will show what we're doing. (Stolen from sendmail.) 1772 * Warning, since this is usually started from inetd.conf, it often doesn't 1773 * have much of an environment or arglist to overwrite. 1774 */ 1775 void 1776 #if __STDC__ 1777 setproctitle(const char *fmt, ...) 1778 #else 1779 setproctitle(fmt, va_alist) 1780 char *fmt; 1781 va_dcl 1782 #endif 1783 { 1784 int i; 1785 va_list ap; 1786 char *p, *bp, ch; 1787 char buf[LINE_MAX]; 1788 1789 #if __STDC__ 1790 va_start(ap, fmt); 1791 #else 1792 va_start(ap); 1793 #endif 1794 (void)vsnprintf(buf, sizeof(buf), fmt, ap); 1795 1796 /* make ps print our process name */ 1797 p = Argv[0]; 1798 *p++ = '-'; 1799 1800 i = strlen(buf); 1801 if (i > LastArgv - p - 2) { 1802 i = LastArgv - p - 2; 1803 buf[i] = '\0'; 1804 } 1805 bp = buf; 1806 while (ch = *bp++) 1807 if (ch != '\n' && ch != '\r') 1808 *p++ = ch; 1809 while (p < LastArgv) 1810 *p++ = ' '; 1811 } 1812 #endif /* SETPROCTITLE */ 1813 1814 #ifdef STATS 1815 logxfer(name, size, start) 1816 char *name; 1817 long size; 1818 long start; 1819 { 1820 char buf[1024]; 1821 char path[MAXPATHLEN + 1]; 1822 long now; 1823 1824 if (statfd >= 0 && getwd(path) != NULL) { 1825 time(&now); 1826 sprintf(buf, "%.20s!%s!%s!%s/%s!%ld!%ld\n", 1827 ctime(&now)+4, ident, remotehost, 1828 path, name, size, now - start + (now == start)); 1829 write(statfd, buf, strlen(buf)); 1830 } 1831 } 1832 1833 char * 1834 copy(s) 1835 char *s; 1836 { 1837 char *p; 1838 1839 p = malloc((unsigned) strlen(s) + 1); 1840 if (p == NULL) 1841 fatal("Ran out of memory."); 1842 (void) strcpy(p, s); 1843 return (p); 1844 } 1845 #endif 1846