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