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