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.12 1995/08/28 21:30:49 mpp 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 struct timeval timeout; 926 fd_set set; 927 928 FD_ZERO(&set); 929 FD_SET(pdata, &set); 930 931 timeout.tv_usec = 0; 932 timeout.tv_sec = 120; 933 934 if (select(pdata+1, &set, (fd_set *) 0, (fd_set *) 0, &timeout) == 0 || 935 (s = accept(pdata, (struct sockaddr *) &from, &fromlen)) < 0) { 936 reply(425, "Can't open data connection."); 937 (void) close(pdata); 938 pdata = -1; 939 return (NULL); 940 } 941 (void) close(pdata); 942 pdata = s; 943 #ifdef IP_TOS 944 tos = IPTOS_LOWDELAY; 945 (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, 946 sizeof(int)); 947 #endif 948 reply(150, "Opening %s mode data connection for '%s'%s.", 949 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 950 return (fdopen(pdata, mode)); 951 } 952 if (data >= 0) { 953 reply(125, "Using existing data connection for '%s'%s.", 954 name, sizebuf); 955 usedefault = 1; 956 return (fdopen(data, mode)); 957 } 958 if (usedefault) 959 data_dest = his_addr; 960 usedefault = 1; 961 file = getdatasock(mode); 962 if (file == NULL) { 963 reply(425, "Can't create data socket (%s,%d): %s.", 964 inet_ntoa(data_source.sin_addr), 965 ntohs(data_source.sin_port), strerror(errno)); 966 return (NULL); 967 } 968 data = fileno(file); 969 while (connect(data, (struct sockaddr *)&data_dest, 970 sizeof(data_dest)) < 0) { 971 if (errno == EADDRINUSE && retry < swaitmax) { 972 sleep((unsigned) swaitint); 973 retry += swaitint; 974 continue; 975 } 976 perror_reply(425, "Can't build data connection"); 977 (void) fclose(file); 978 data = -1; 979 return (NULL); 980 } 981 reply(150, "Opening %s mode data connection for '%s'%s.", 982 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 983 return (file); 984 } 985 986 /* 987 * Tranfer the contents of "instr" to "outstr" peer using the appropriate 988 * encapsulation of the data subject to Mode, Structure, and Type. 989 * 990 * NB: Form isn't handled. 991 */ 992 static void 993 send_data(instr, outstr, blksize, filesize, isreg) 994 FILE *instr, *outstr; 995 off_t blksize; 996 off_t filesize; 997 int isreg; 998 { 999 int c, cnt, filefd, netfd; 1000 char *buf, *bp; 1001 size_t len; 1002 1003 transflag++; 1004 if (setjmp(urgcatch)) { 1005 transflag = 0; 1006 return; 1007 } 1008 switch (type) { 1009 1010 case TYPE_A: 1011 while ((c = getc(instr)) != EOF) { 1012 byte_count++; 1013 if (c == '\n') { 1014 if (ferror(outstr)) 1015 goto data_err; 1016 (void) putc('\r', outstr); 1017 } 1018 (void) putc(c, outstr); 1019 } 1020 fflush(outstr); 1021 transflag = 0; 1022 if (ferror(instr)) 1023 goto file_err; 1024 if (ferror(outstr)) 1025 goto data_err; 1026 reply(226, "Transfer complete."); 1027 return; 1028 1029 case TYPE_I: 1030 case TYPE_L: 1031 /* 1032 * isreg is only set if we are not doing restart and we 1033 * are sending a regular file 1034 */ 1035 netfd = fileno(outstr); 1036 filefd = fileno(instr); 1037 1038 if (isreg && filesize < (off_t)16 * 1024 * 1024) { 1039 buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd, 1040 (off_t)0); 1041 if (!buf) { 1042 syslog(LOG_WARNING, "mmap(%lu): %m", 1043 (unsigned long)filesize); 1044 goto oldway; 1045 } 1046 bp = buf; 1047 len = filesize; 1048 do { 1049 cnt = write(netfd, bp, len); 1050 len -= cnt; 1051 bp += cnt; 1052 if (cnt > 0) byte_count += cnt; 1053 } while(cnt > 0 && len > 0); 1054 1055 transflag = 0; 1056 munmap(buf, (size_t)filesize); 1057 if (cnt < 0) 1058 goto data_err; 1059 reply(226, "Transfer complete."); 1060 return; 1061 } 1062 1063 oldway: 1064 if ((buf = malloc((u_int)blksize)) == NULL) { 1065 transflag = 0; 1066 perror_reply(451, "Local resource failure: malloc"); 1067 return; 1068 } 1069 1070 while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 && 1071 write(netfd, buf, cnt) == cnt) 1072 byte_count += cnt; 1073 transflag = 0; 1074 (void)free(buf); 1075 if (cnt != 0) { 1076 if (cnt < 0) 1077 goto file_err; 1078 goto data_err; 1079 } 1080 reply(226, "Transfer complete."); 1081 return; 1082 default: 1083 transflag = 0; 1084 reply(550, "Unimplemented TYPE %d in send_data", type); 1085 return; 1086 } 1087 1088 data_err: 1089 transflag = 0; 1090 perror_reply(426, "Data connection"); 1091 return; 1092 1093 file_err: 1094 transflag = 0; 1095 perror_reply(551, "Error on input file"); 1096 } 1097 1098 /* 1099 * Transfer data from peer to "outstr" using the appropriate encapulation of 1100 * the data subject to Mode, Structure, and Type. 1101 * 1102 * N.B.: Form isn't handled. 1103 */ 1104 static int 1105 receive_data(instr, outstr) 1106 FILE *instr, *outstr; 1107 { 1108 int c; 1109 int cnt, bare_lfs = 0; 1110 char buf[BUFSIZ]; 1111 1112 transflag++; 1113 if (setjmp(urgcatch)) { 1114 transflag = 0; 1115 return (-1); 1116 } 1117 switch (type) { 1118 1119 case TYPE_I: 1120 case TYPE_L: 1121 while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) { 1122 if (write(fileno(outstr), buf, cnt) != cnt) 1123 goto file_err; 1124 byte_count += cnt; 1125 } 1126 if (cnt < 0) 1127 goto data_err; 1128 transflag = 0; 1129 return (0); 1130 1131 case TYPE_E: 1132 reply(553, "TYPE E not implemented."); 1133 transflag = 0; 1134 return (-1); 1135 1136 case TYPE_A: 1137 while ((c = getc(instr)) != EOF) { 1138 byte_count++; 1139 if (c == '\n') 1140 bare_lfs++; 1141 while (c == '\r') { 1142 if (ferror(outstr)) 1143 goto data_err; 1144 if ((c = getc(instr)) != '\n') { 1145 (void) putc ('\r', outstr); 1146 if (c == '\0' || c == EOF) 1147 goto contin2; 1148 } 1149 } 1150 (void) putc(c, outstr); 1151 contin2: ; 1152 } 1153 fflush(outstr); 1154 if (ferror(instr)) 1155 goto data_err; 1156 if (ferror(outstr)) 1157 goto file_err; 1158 transflag = 0; 1159 if (bare_lfs) { 1160 lreply(226, 1161 "WARNING! %d bare linefeeds received in ASCII mode", 1162 bare_lfs); 1163 (void)printf(" File may not have transferred correctly.\r\n"); 1164 } 1165 return (0); 1166 default: 1167 reply(550, "Unimplemented TYPE %d in receive_data", type); 1168 transflag = 0; 1169 return (-1); 1170 } 1171 1172 data_err: 1173 transflag = 0; 1174 perror_reply(426, "Data Connection"); 1175 return (-1); 1176 1177 file_err: 1178 transflag = 0; 1179 perror_reply(452, "Error writing file"); 1180 return (-1); 1181 } 1182 1183 void 1184 statfilecmd(filename) 1185 char *filename; 1186 { 1187 FILE *fin; 1188 int c; 1189 char line[LINE_MAX]; 1190 1191 (void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename); 1192 fin = ftpd_popen(line, "r"); 1193 lreply(211, "status of %s:", filename); 1194 while ((c = getc(fin)) != EOF) { 1195 if (c == '\n') { 1196 if (ferror(stdout)){ 1197 perror_reply(421, "control connection"); 1198 (void) ftpd_pclose(fin); 1199 dologout(1); 1200 /* NOTREACHED */ 1201 } 1202 if (ferror(fin)) { 1203 perror_reply(551, filename); 1204 (void) ftpd_pclose(fin); 1205 return; 1206 } 1207 (void) putc('\r', stdout); 1208 } 1209 (void) putc(c, stdout); 1210 } 1211 (void) ftpd_pclose(fin); 1212 reply(211, "End of Status"); 1213 } 1214 1215 void 1216 statcmd() 1217 { 1218 struct sockaddr_in *sin; 1219 u_char *a, *p; 1220 1221 lreply(211, "%s FTP server status:", hostname, version); 1222 printf(" %s\r\n", version); 1223 printf(" Connected to %s", remotehost); 1224 if (!isdigit(remotehost[0])) 1225 printf(" (%s)", inet_ntoa(his_addr.sin_addr)); 1226 printf("\r\n"); 1227 if (logged_in) { 1228 if (guest) 1229 printf(" Logged in anonymously\r\n"); 1230 else 1231 printf(" Logged in as %s\r\n", pw->pw_name); 1232 } else if (askpasswd) 1233 printf(" Waiting for password\r\n"); 1234 else 1235 printf(" Waiting for user name\r\n"); 1236 printf(" TYPE: %s", typenames[type]); 1237 if (type == TYPE_A || type == TYPE_E) 1238 printf(", FORM: %s", formnames[form]); 1239 if (type == TYPE_L) 1240 #if NBBY == 8 1241 printf(" %d", NBBY); 1242 #else 1243 printf(" %d", bytesize); /* need definition! */ 1244 #endif 1245 printf("; STRUcture: %s; transfer MODE: %s\r\n", 1246 strunames[stru], modenames[mode]); 1247 if (data != -1) 1248 printf(" Data connection open\r\n"); 1249 else if (pdata != -1) { 1250 printf(" in Passive mode"); 1251 sin = &pasv_addr; 1252 goto printaddr; 1253 } else if (usedefault == 0) { 1254 printf(" PORT"); 1255 sin = &data_dest; 1256 printaddr: 1257 a = (u_char *) &sin->sin_addr; 1258 p = (u_char *) &sin->sin_port; 1259 #define UC(b) (((int) b) & 0xff) 1260 printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]), 1261 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 1262 #undef UC 1263 } else 1264 printf(" No data connection\r\n"); 1265 reply(211, "End of status"); 1266 } 1267 1268 void 1269 fatal(s) 1270 char *s; 1271 { 1272 1273 reply(451, "Error in server: %s\n", s); 1274 reply(221, "Closing connection due to server error."); 1275 dologout(0); 1276 /* NOTREACHED */ 1277 } 1278 1279 void 1280 #if __STDC__ 1281 reply(int n, const char *fmt, ...) 1282 #else 1283 reply(n, fmt, va_alist) 1284 int n; 1285 char *fmt; 1286 va_dcl 1287 #endif 1288 { 1289 va_list ap; 1290 #if __STDC__ 1291 va_start(ap, fmt); 1292 #else 1293 va_start(ap); 1294 #endif 1295 (void)printf("%d ", n); 1296 (void)vprintf(fmt, ap); 1297 (void)printf("\r\n"); 1298 (void)fflush(stdout); 1299 if (debug) { 1300 syslog(LOG_DEBUG, "<--- %d ", n); 1301 vsyslog(LOG_DEBUG, fmt, ap); 1302 } 1303 } 1304 1305 void 1306 #if __STDC__ 1307 lreply(int n, const char *fmt, ...) 1308 #else 1309 lreply(n, fmt, va_alist) 1310 int n; 1311 char *fmt; 1312 va_dcl 1313 #endif 1314 { 1315 va_list ap; 1316 #if __STDC__ 1317 va_start(ap, fmt); 1318 #else 1319 va_start(ap); 1320 #endif 1321 (void)printf("%d- ", n); 1322 (void)vprintf(fmt, ap); 1323 (void)printf("\r\n"); 1324 (void)fflush(stdout); 1325 if (debug) { 1326 syslog(LOG_DEBUG, "<--- %d- ", n); 1327 vsyslog(LOG_DEBUG, fmt, ap); 1328 } 1329 } 1330 1331 static void 1332 ack(s) 1333 char *s; 1334 { 1335 1336 reply(250, "%s command successful.", s); 1337 } 1338 1339 void 1340 nack(s) 1341 char *s; 1342 { 1343 1344 reply(502, "%s command not implemented.", s); 1345 } 1346 1347 /* ARGSUSED */ 1348 void 1349 yyerror(s) 1350 char *s; 1351 { 1352 char *cp; 1353 1354 if (cp = strchr(cbuf,'\n')) 1355 *cp = '\0'; 1356 reply(500, "'%s': command not understood.", cbuf); 1357 } 1358 1359 void 1360 delete(name) 1361 char *name; 1362 { 1363 struct stat st; 1364 1365 LOGCMD("delete", name); 1366 if (stat(name, &st) < 0) { 1367 perror_reply(550, name); 1368 return; 1369 } 1370 if ((st.st_mode&S_IFMT) == S_IFDIR) { 1371 if (rmdir(name) < 0) { 1372 perror_reply(550, name); 1373 return; 1374 } 1375 goto done; 1376 } 1377 if (unlink(name) < 0) { 1378 perror_reply(550, name); 1379 return; 1380 } 1381 done: 1382 ack("DELE"); 1383 } 1384 1385 void 1386 cwd(path) 1387 char *path; 1388 { 1389 1390 if (chdir(path) < 0) 1391 perror_reply(550, path); 1392 else 1393 ack("CWD"); 1394 } 1395 1396 void 1397 makedir(name) 1398 char *name; 1399 { 1400 1401 LOGCMD("mkdir", name); 1402 if (mkdir(name, 0777) < 0) 1403 perror_reply(550, name); 1404 else 1405 reply(257, "MKD command successful."); 1406 } 1407 1408 void 1409 removedir(name) 1410 char *name; 1411 { 1412 1413 LOGCMD("rmdir", name); 1414 if (rmdir(name) < 0) 1415 perror_reply(550, name); 1416 else 1417 ack("RMD"); 1418 } 1419 1420 void 1421 pwd() 1422 { 1423 char path[MAXPATHLEN + 1]; 1424 1425 if (getwd(path) == (char *)NULL) 1426 reply(550, "%s.", path); 1427 else 1428 reply(257, "\"%s\" is current directory.", path); 1429 } 1430 1431 char * 1432 renamefrom(name) 1433 char *name; 1434 { 1435 struct stat st; 1436 1437 if (stat(name, &st) < 0) { 1438 perror_reply(550, name); 1439 return ((char *)0); 1440 } 1441 reply(350, "File exists, ready for destination name"); 1442 return (name); 1443 } 1444 1445 void 1446 renamecmd(from, to) 1447 char *from, *to; 1448 { 1449 1450 LOGCMD2("rename", from, to); 1451 if (rename(from, to) < 0) 1452 perror_reply(550, "rename"); 1453 else 1454 ack("RNTO"); 1455 } 1456 1457 static void 1458 dolog(sin) 1459 struct sockaddr_in *sin; 1460 { 1461 struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr, 1462 sizeof(struct in_addr), AF_INET); 1463 1464 if (hp) 1465 (void) strncpy(remotehost, hp->h_name, sizeof(remotehost)); 1466 else 1467 (void) strncpy(remotehost, inet_ntoa(sin->sin_addr), 1468 sizeof(remotehost)); 1469 #ifdef SETPROCTITLE 1470 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost); 1471 setproctitle(proctitle); 1472 #endif /* SETPROCTITLE */ 1473 1474 if (logging) 1475 syslog(LOG_INFO, "connection from %s", remotehost); 1476 } 1477 1478 /* 1479 * Record logout in wtmp file 1480 * and exit with supplied status. 1481 */ 1482 void 1483 dologout(status) 1484 int status; 1485 { 1486 1487 if (logged_in) { 1488 (void) seteuid((uid_t)0); 1489 logwtmp(ttyline, "", ""); 1490 } 1491 /* beware of flushing buffers after a SIGPIPE */ 1492 _exit(status); 1493 } 1494 1495 static void 1496 myoob(signo) 1497 int signo; 1498 { 1499 char *cp; 1500 1501 /* only process if transfer occurring */ 1502 if (!transflag) 1503 return; 1504 cp = tmpline; 1505 if (getline(cp, 7, stdin) == NULL) { 1506 reply(221, "You could at least say goodbye."); 1507 dologout(0); 1508 } 1509 upper(cp); 1510 if (strcmp(cp, "ABOR\r\n") == 0) { 1511 tmpline[0] = '\0'; 1512 reply(426, "Transfer aborted. Data connection closed."); 1513 reply(226, "Abort successful"); 1514 longjmp(urgcatch, 1); 1515 } 1516 if (strcmp(cp, "STAT\r\n") == 0) { 1517 if (file_size != (off_t) -1) 1518 reply(213, "Status: %qd of %qd bytes transferred", 1519 byte_count, file_size); 1520 else 1521 reply(213, "Status: %qd bytes transferred", byte_count); 1522 } 1523 } 1524 1525 /* 1526 * Note: a response of 425 is not mentioned as a possible response to 1527 * the PASV command in RFC959. However, it has been blessed as 1528 * a legitimate response by Jon Postel in a telephone conversation 1529 * with Rick Adams on 25 Jan 89. 1530 */ 1531 void 1532 passive() 1533 { 1534 int len; 1535 u_short port; 1536 char *p, *a; 1537 1538 pdata = socket(AF_INET, SOCK_STREAM, 0); 1539 if (pdata < 0) { 1540 perror_reply(425, "Can't open passive connection"); 1541 return; 1542 } 1543 1544 if (restricted_data_ports) { 1545 for (port = FTP_DATA_BOTTOM; port <= FTP_DATA_TOP; port++) { 1546 pasv_addr = ctrl_addr; 1547 pasv_addr.sin_port = htons(port); 1548 (void) seteuid((uid_t)0); 1549 if (bind(pdata, (struct sockaddr *)&pasv_addr, 1550 sizeof(pasv_addr)) < 0) { 1551 (void) seteuid((uid_t)pw->pw_uid); 1552 if (errno == EADDRINUSE) 1553 continue; 1554 else 1555 goto pasv_error; 1556 } 1557 (void) seteuid((uid_t)pw->pw_uid); 1558 break; 1559 } 1560 if (port > FTP_DATA_TOP) 1561 goto pasv_error; 1562 } else { 1563 pasv_addr = ctrl_addr; 1564 pasv_addr.sin_port = 0; 1565 (void) seteuid((uid_t)0); 1566 if (bind(pdata, (struct sockaddr *)&pasv_addr, 1567 sizeof(pasv_addr)) < 0) { 1568 (void) seteuid((uid_t)pw->pw_uid); 1569 goto pasv_error; 1570 } 1571 (void) seteuid((uid_t)pw->pw_uid); 1572 } 1573 1574 len = sizeof(pasv_addr); 1575 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) 1576 goto pasv_error; 1577 if (listen(pdata, 1) < 0) 1578 goto pasv_error; 1579 a = (char *) &pasv_addr.sin_addr; 1580 p = (char *) &pasv_addr.sin_port; 1581 1582 #define UC(b) (((int) b) & 0xff) 1583 1584 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), 1585 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 1586 return; 1587 1588 pasv_error: 1589 (void) close(pdata); 1590 pdata = -1; 1591 perror_reply(425, "Can't open passive connection"); 1592 return; 1593 } 1594 1595 /* 1596 * Generate unique name for file with basename "local". 1597 * The file named "local" is already known to exist. 1598 * Generates failure reply on error. 1599 */ 1600 static char * 1601 gunique(local) 1602 char *local; 1603 { 1604 static char new[MAXPATHLEN]; 1605 struct stat st; 1606 int count; 1607 char *cp; 1608 1609 cp = strrchr(local, '/'); 1610 if (cp) 1611 *cp = '\0'; 1612 if (stat(cp ? local : ".", &st) < 0) { 1613 perror_reply(553, cp ? local : "."); 1614 return ((char *) 0); 1615 } 1616 if (cp) 1617 *cp = '/'; 1618 (void) strcpy(new, local); 1619 cp = new + strlen(new); 1620 *cp++ = '.'; 1621 for (count = 1; count < 100; count++) { 1622 (void)sprintf(cp, "%d", count); 1623 if (stat(new, &st) < 0) 1624 return (new); 1625 } 1626 reply(452, "Unique file name cannot be created."); 1627 return (NULL); 1628 } 1629 1630 /* 1631 * Format and send reply containing system error number. 1632 */ 1633 void 1634 perror_reply(code, string) 1635 int code; 1636 char *string; 1637 { 1638 1639 reply(code, "%s: %s.", string, strerror(errno)); 1640 } 1641 1642 static char *onefile[] = { 1643 "", 1644 0 1645 }; 1646 1647 void 1648 send_file_list(whichf) 1649 char *whichf; 1650 { 1651 struct stat st; 1652 DIR *dirp = NULL; 1653 struct dirent *dir; 1654 FILE *dout = NULL; 1655 char **dirlist, *dirname; 1656 int simple = 0; 1657 int freeglob = 0; 1658 glob_t gl; 1659 1660 if (strpbrk(whichf, "~{[*?") != NULL) { 1661 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; 1662 1663 memset(&gl, 0, sizeof(gl)); 1664 freeglob = 1; 1665 if (glob(whichf, flags, 0, &gl)) { 1666 reply(550, "not found"); 1667 goto out; 1668 } else if (gl.gl_pathc == 0) { 1669 errno = ENOENT; 1670 perror_reply(550, whichf); 1671 goto out; 1672 } 1673 dirlist = gl.gl_pathv; 1674 } else { 1675 onefile[0] = whichf; 1676 dirlist = onefile; 1677 simple = 1; 1678 } 1679 1680 if (setjmp(urgcatch)) { 1681 transflag = 0; 1682 goto out; 1683 } 1684 while (dirname = *dirlist++) { 1685 if (stat(dirname, &st) < 0) { 1686 /* 1687 * If user typed "ls -l", etc, and the client 1688 * used NLST, do what the user meant. 1689 */ 1690 if (dirname[0] == '-' && *dirlist == NULL && 1691 transflag == 0) { 1692 retrieve("/bin/ls %s", dirname); 1693 goto out; 1694 } 1695 perror_reply(550, whichf); 1696 if (dout != NULL) { 1697 (void) fclose(dout); 1698 transflag = 0; 1699 data = -1; 1700 pdata = -1; 1701 } 1702 goto out; 1703 } 1704 1705 if (S_ISREG(st.st_mode)) { 1706 if (dout == NULL) { 1707 dout = dataconn("file list", (off_t)-1, "w"); 1708 if (dout == NULL) 1709 goto out; 1710 transflag++; 1711 } 1712 fprintf(dout, "%s%s\n", dirname, 1713 type == TYPE_A ? "\r" : ""); 1714 byte_count += strlen(dirname) + 1; 1715 continue; 1716 } else if (!S_ISDIR(st.st_mode)) 1717 continue; 1718 1719 if ((dirp = opendir(dirname)) == NULL) 1720 continue; 1721 1722 while ((dir = readdir(dirp)) != NULL) { 1723 char nbuf[MAXPATHLEN]; 1724 1725 if (dir->d_name[0] == '.' && dir->d_namlen == 1) 1726 continue; 1727 if (dir->d_name[0] == '.' && dir->d_name[1] == '.' && 1728 dir->d_namlen == 2) 1729 continue; 1730 1731 sprintf(nbuf, "%s/%s", dirname, dir->d_name); 1732 1733 /* 1734 * We have to do a stat to insure it's 1735 * not a directory or special file. 1736 */ 1737 if (simple || (stat(nbuf, &st) == 0 && 1738 S_ISREG(st.st_mode))) { 1739 if (dout == NULL) { 1740 dout = dataconn("file list", (off_t)-1, 1741 "w"); 1742 if (dout == NULL) 1743 goto out; 1744 transflag++; 1745 } 1746 if (nbuf[0] == '.' && nbuf[1] == '/') 1747 fprintf(dout, "%s%s\n", &nbuf[2], 1748 type == TYPE_A ? "\r" : ""); 1749 else 1750 fprintf(dout, "%s%s\n", nbuf, 1751 type == TYPE_A ? "\r" : ""); 1752 byte_count += strlen(nbuf) + 1; 1753 } 1754 } 1755 (void) closedir(dirp); 1756 } 1757 1758 if (dout == NULL) 1759 reply(550, "No files found."); 1760 else if (ferror(dout) != 0) 1761 perror_reply(550, "Data connection"); 1762 else 1763 reply(226, "Transfer complete."); 1764 1765 transflag = 0; 1766 if (dout != NULL) 1767 (void) fclose(dout); 1768 data = -1; 1769 pdata = -1; 1770 out: 1771 if (freeglob) { 1772 freeglob = 0; 1773 globfree(&gl); 1774 } 1775 } 1776 1777 #ifdef SETPROCTITLE 1778 /* 1779 * Clobber argv so ps will show what we're doing. (Stolen from sendmail.) 1780 * Warning, since this is usually started from inetd.conf, it often doesn't 1781 * have much of an environment or arglist to overwrite. 1782 */ 1783 void 1784 #if __STDC__ 1785 setproctitle(const char *fmt, ...) 1786 #else 1787 setproctitle(fmt, va_alist) 1788 char *fmt; 1789 va_dcl 1790 #endif 1791 { 1792 int i; 1793 va_list ap; 1794 char *p, *bp, ch; 1795 char buf[LINE_MAX]; 1796 1797 #if __STDC__ 1798 va_start(ap, fmt); 1799 #else 1800 va_start(ap); 1801 #endif 1802 (void)vsnprintf(buf, sizeof(buf), fmt, ap); 1803 1804 /* make ps print our process name */ 1805 p = Argv[0]; 1806 *p++ = '-'; 1807 1808 i = strlen(buf); 1809 if (i > LastArgv - p - 2) { 1810 i = LastArgv - p - 2; 1811 buf[i] = '\0'; 1812 } 1813 bp = buf; 1814 while (ch = *bp++) 1815 if (ch != '\n' && ch != '\r') 1816 *p++ = ch; 1817 while (p < LastArgv) 1818 *p++ = ' '; 1819 } 1820 #endif /* SETPROCTITLE */ 1821 1822 #ifdef STATS 1823 logxfer(name, size, start) 1824 char *name; 1825 long size; 1826 long start; 1827 { 1828 char buf[1024]; 1829 char path[MAXPATHLEN + 1]; 1830 long now; 1831 1832 if (statfd >= 0 && getwd(path) != NULL) { 1833 time(&now); 1834 sprintf(buf, "%.20s!%s!%s!%s/%s!%ld!%ld\n", 1835 ctime(&now)+4, ident, remotehost, 1836 path, name, size, now - start + (now == start)); 1837 write(statfd, buf, strlen(buf)); 1838 } 1839 } 1840 1841 char * 1842 copy(s) 1843 char *s; 1844 { 1845 char *p; 1846 1847 p = malloc((unsigned) strlen(s) + 1); 1848 if (p == NULL) 1849 fatal("Ran out of memory."); 1850 (void) strcpy(p, s); 1851 return (p); 1852 } 1853 #endif 1854