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