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