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