1/* $NetBSD: ftpd.c,v 1.187 2008/09/13 03:30:35 lukem Exp $ */ 2 3/* 4 * Copyright (c) 1997-2004 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Luke Mewburn. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39/* 40 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994 41 * The Regents of the University of California. All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. Neither the name of the University nor the names of its contributors 52 * may be used to endorse or promote products derived from this software 53 * without specific prior written permission. 54 * 55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 65 * SUCH DAMAGE. 66 */ 67 68/* 69 * Copyright (C) 1997 and 1998 WIDE Project. 70 * All rights reserved. 71 * 72 * Redistribution and use in source and binary forms, with or without 73 * modification, are permitted provided that the following conditions 74 * are met: 75 * 1. Redistributions of source code must retain the above copyright 76 * notice, this list of conditions and the following disclaimer. 77 * 2. Redistributions in binary form must reproduce the above copyright 78 * notice, this list of conditions and the following disclaimer in the 79 * documentation and/or other materials provided with the distribution. 80 * 3. Neither the name of the project nor the names of its contributors 81 * may be used to endorse or promote products derived from this software 82 * without specific prior written permission. 83 * 84 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 85 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 86 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 87 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 88 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 89 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 90 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 91 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 92 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 93 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 94 * SUCH DAMAGE. 95 */ 96 97#include <sys/cdefs.h> 98#ifndef lint 99__COPYRIGHT( 100"@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\ 101 The Regents of the University of California. All rights reserved.\n"); 102#endif /* not lint */ 103 104#ifndef lint 105#if 0 106static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95"; 107#else 108__RCSID("$NetBSD: ftpd.c,v 1.176 2006/05/09 20:18:06 mrg Exp $"); 109#endif 110__FBSDID("$FreeBSD$"); 111#endif /* not lint */ 112 113/* 114 * FTP server. 115 */ 116#include <sys/param.h> 117#include <sys/stat.h> 118#include <sys/ioctl.h> 119#include <sys/socket.h> 120#include <sys/wait.h> 121#include <sys/mman.h> 122#include <sys/resource.h> 123 124#include <netinet/in.h> 125#include <netinet/in_systm.h> 126#include <netinet/ip.h> 127 128#define FTP_NAMES 129#include <arpa/ftp.h> 130#include <arpa/inet.h> 131#include <arpa/telnet.h> 132 133#include <ctype.h> 134#include <dirent.h> 135#include <err.h> 136#include <errno.h> 137#include <fcntl.h> 138#include <fnmatch.h> 139#include <glob.h> 140#include <grp.h> 141#include <limits.h> 142#include <netdb.h> 143#include <pwd.h> 144#include <poll.h> 145#include <signal.h> 146#include <stdarg.h> 147#include <stdio.h> 148#include <stdlib.h> 149#include <string.h> 150#include <syslog.h> 151#include <time.h> 152#include <tzfile.h> 153#include <unistd.h> 154#include <util.h> 155#ifdef SUPPORT_UTMP 156#include <utmp.h> 157#endif 158#ifdef SUPPORT_UTMPX 159#include <utmpx.h> 160#endif 161#ifdef SKEY 162#include <skey.h> 163#endif 164#ifdef KERBEROS5 165#include <com_err.h> 166#include <krb5/krb5.h> 167#endif 168 169#ifdef LOGIN_CAP 170#include <login_cap.h> 171#endif 172 173#ifdef USE_PAM 174#include <security/pam_appl.h> 175#endif 176 177#define GLOBAL 178#include "extern.h" 179#include "pathnames.h" 180#include "version.h" 181 182#include "nbsd_pidfile.h" 183 184volatile sig_atomic_t transflag; 185volatile sig_atomic_t urgflag; 186 187int data; 188int Dflag; 189int sflag; 190int stru; /* avoid C keyword */ 191int mode; 192int dataport; /* use specific data port */ 193int dopidfile; /* maintain pid file */ 194int doutmp; /* update utmp file */ 195int dowtmp; /* update wtmp file */ 196int doxferlog; /* syslog/write wu-ftpd style xferlog entries */ 197int xferlogfd; /* fd to write wu-ftpd xferlog entries to */ 198int dropprivs; /* if privileges should or have been dropped */ 199int mapped; /* IPv4 connection on AF_INET6 socket */ 200off_t file_size; 201off_t byte_count; 202static char ttyline[20]; 203 204#ifdef USE_PAM 205static int auth_pam(struct passwd **, const char *); 206pam_handle_t *pamh = NULL; 207#endif 208 209#ifdef SUPPORT_UTMP 210static struct utmp utmp; /* for utmp */ 211#endif 212#ifdef SUPPORT_UTMPX 213static struct utmpx utmpx; /* for utmpx */ 214#endif 215 216static const char *anondir = NULL; 217static const char *confdir = _DEFAULT_CONFDIR; 218 219static char *curname; /* current USER name */ 220static size_t curname_len; /* length of curname (include NUL) */ 221 222#if defined(KERBEROS) || defined(KERBEROS5) 223int has_ccache = 0; 224int notickets = 1; 225char *krbtkfile_env = NULL; 226char *tty = ttyline; 227int login_krb5_forwardable_tgt = 0; 228#endif 229 230int epsvall = 0; 231 232/* 233 * Timeout intervals for retrying connections 234 * to hosts that don't accept PORT cmds. This 235 * is a kludge, but given the problems with TCP... 236 */ 237#define SWAITMAX 90 /* wait at most 90 seconds */ 238#define SWAITINT 5 /* interval between retries */ 239 240int swaitmax = SWAITMAX; 241int swaitint = SWAITINT; 242 243enum send_status { 244 SS_SUCCESS, 245 SS_ABORTED, /* transfer aborted */ 246 SS_NO_TRANSFER, /* no transfer made yet */ 247 SS_FILE_ERROR, /* file read error */ 248 SS_DATA_ERROR /* data send error */ 249}; 250 251#ifdef USE_OPIE 252#include <opie.h> 253static struct opie opiedata; 254static char opieprompt[OPIE_CHALLENGE_MAX+1]; 255static int pwok; 256#endif 257 258static int bind_pasv_addr(void); 259static int checkuser(const char *, const char *, int, int, char **); 260static int checkaccess(const char *); 261static int checkpassword(const struct passwd *, const char *); 262static void end_login(void); 263static FILE *getdatasock(const char *); 264static char *gunique(const char *); 265static void login_utmp(const char *, const char *, const char *, 266 struct sockinet *); 267static void logremotehost(struct sockinet *); 268static void lostconn(int); 269static void toolong(int); 270static void sigquit(int); 271static void sigurg(int); 272static int handleoobcmd(void); 273static int receive_data(FILE *, FILE *); 274static int send_data(FILE *, FILE *, const struct stat *, int); 275static struct passwd *sgetpwnam(const char *); 276static int write_data(int, char *, size_t, off_t *, struct timeval *, 277 int); 278static enum send_status 279 send_data_with_read(int, int, const struct stat *, int); 280static enum send_status 281 send_data_with_mmap(int, int, const struct stat *, int); 282static void logrusage(const struct rusage *, const struct rusage *); 283static void logout_utmp(void); 284 285int main(int, char *[]); 286 287#if defined(KERBEROS) 288int klogin(struct passwd *, char *, char *, char *); 289void kdestroy(void); 290#endif 291#if defined(KERBEROS5) 292int k5login(struct passwd *, char *, char *, char *); 293void k5destroy(void); 294#endif 295 296int 297main(int argc, char *argv[]) 298{ 299 int ch, on = 1, tos, keepalive; 300 socklen_t addrlen; 301#ifdef KERBEROS5 302 krb5_error_code kerror; 303#endif 304 char *p; 305 const char *xferlogname = NULL; 306 long l; 307 struct sigaction sa; 308 sa_family_t af = AF_UNSPEC; 309 310 connections = 1; 311 ftpd_debug = 0; 312 logging = 0; 313 pdata = -1; 314 Dflag = 0; 315 sflag = 0; 316 dataport = 0; 317 dopidfile = 1; /* default: DO use a pid file to count users */ 318 doutmp = 0; /* default: Do NOT log to utmp */ 319 dowtmp = 1; /* default: DO log to wtmp */ 320 doxferlog = 0; /* default: Do NOT syslog xferlog */ 321 xferlogfd = -1; /* default: Do NOT write xferlog file */ 322 dropprivs = 0; 323 mapped = 0; 324 usedefault = 1; 325 emailaddr = NULL; 326 hostname[0] = '\0'; 327 homedir[0] = '\0'; 328 gidcount = 0; 329 is_oob = 0; 330 version = FTPD_VERSION; 331 332 /* 333 * LOG_NDELAY sets up the logging connection immediately, 334 * necessary for anonymous ftp's that chroot and can't do it later. 335 */ 336 openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); 337 338 while ((ch = getopt(argc, argv, 339 "46a:c:C:Dde:h:HlL:P:qQrst:T:uUvV:wWX")) != -1) { 340 switch (ch) { 341 case '4': 342 af = AF_INET; 343 break; 344 345 case '6': 346 af = AF_INET6; 347 break; 348 349 case 'a': 350 anondir = optarg; 351 break; 352 353 case 'c': 354 confdir = optarg; 355 break; 356 357 case 'C': 358 pw = sgetpwnam(optarg); 359 exit(checkaccess(optarg) ? 0 : 1); 360 /* NOTREACHED */ 361 362 case 'D': 363 Dflag = 1; 364 break; 365 366 case 'd': 367 case 'v': /* deprecated */ 368 ftpd_debug = 1; 369 break; 370 371 case 'e': 372 emailaddr = optarg; 373 break; 374 375 case 'h': 376 strlcpy(hostname, optarg, sizeof(hostname)); 377 break; 378 379 case 'H': 380 if (gethostname(hostname, sizeof(hostname)) == -1) 381 hostname[0] = '\0'; 382 hostname[sizeof(hostname) - 1] = '\0'; 383 break; 384 385 case 'l': 386 logging++; /* > 1 == extra logging */ 387 break; 388 389 case 'L': 390 xferlogname = optarg; 391 break; 392 393 case 'P': 394 errno = 0; 395 p = NULL; 396 l = strtol(optarg, &p, 10); 397 if (errno || *optarg == '\0' || *p != '\0' || 398 l < IPPORT_RESERVED || 399 l > IPPORT_ANONMAX) { 400 syslog(LOG_WARNING, "Invalid dataport %s", 401 optarg); 402 dataport = 0; 403 } 404 dataport = (int)l; 405 break; 406 407 case 'q': 408 dopidfile = 1; 409 break; 410 411 case 'Q': 412 dopidfile = 0; 413 break; 414 415 case 'r': 416 dropprivs = 1; 417 break; 418 419 case 's': 420 sflag = 1; 421 break; 422 423 case 't': 424 case 'T': 425 syslog(LOG_WARNING, 426 "-%c has been deprecated in favour of ftpd.conf", 427 ch); 428 break; 429 430 case 'u': 431 doutmp = 1; 432 break; 433 434 case 'U': 435 doutmp = 0; 436 break; 437 438 case 'V': 439 if (EMPTYSTR(optarg) || strcmp(optarg, "-") == 0) 440 version = NULL; 441 else 442 version = ftpd_strdup(optarg); 443 break; 444 445 case 'w': 446 dowtmp = 1; 447 break; 448 449 case 'W': 450 dowtmp = 0; 451 break; 452 453 case 'X': 454 doxferlog |= 1; 455 break; 456 457 default: 458 if (optopt == 'a' || optopt == 'C') 459 exit(1); 460 syslog(LOG_WARNING, "unknown flag -%c ignored", optopt); 461 break; 462 } 463 } 464 if (EMPTYSTR(confdir)) 465 confdir = _DEFAULT_CONFDIR; 466 467 if (dowtmp) { 468#ifdef SUPPORT_UTMPX 469 ftpd_initwtmpx(); 470#endif 471#ifdef SUPPORT_UTMP 472 ftpd_initwtmp(); 473#endif 474 } 475 errno = 0; 476 l = sysconf(_SC_LOGIN_NAME_MAX); 477 if (l == -1 && errno != 0) { 478 syslog(LOG_ERR, "sysconf _SC_LOGIN_NAME_MAX: %m"); 479 exit(1); 480 } else if (l <= 0) { 481 syslog(LOG_WARNING, "using conservative LOGIN_NAME_MAX value"); 482 curname_len = _POSIX_LOGIN_NAME_MAX; 483 } else 484 curname_len = (size_t)l; 485 curname = malloc(curname_len); 486 if (curname == NULL) { 487 syslog(LOG_ERR, "malloc: %m"); 488 exit(1); 489 } 490 curname[0] = '\0'; 491 492 if (Dflag) { 493 int error, fd, i, n, *socks; 494 struct pollfd *fds; 495 struct addrinfo hints, *res, *res0; 496 497 if (daemon(1, 0) == -1) { 498 syslog(LOG_ERR, "failed to daemonize: %m"); 499 exit(1); 500 } 501 (void)memset(&sa, 0, sizeof(sa)); 502 sa.sa_handler = SIG_IGN; 503 sa.sa_flags = SA_NOCLDWAIT; 504 sigemptyset(&sa.sa_mask); 505 (void)sigaction(SIGCHLD, &sa, NULL); 506 507 (void)memset(&hints, 0, sizeof(hints)); 508 hints.ai_flags = AI_PASSIVE; 509 hints.ai_family = af; 510 hints.ai_socktype = SOCK_STREAM; 511 error = getaddrinfo(NULL, "ftp", &hints, &res0); 512 if (error) { 513 syslog(LOG_ERR, "getaddrinfo: %s", gai_strerror(error)); 514 exit(1); 515 } 516 517 for (n = 0, res = res0; res != NULL; res = res->ai_next) 518 n++; 519 if (n == 0) { 520 syslog(LOG_ERR, "no addresses available"); 521 exit(1); 522 } 523 socks = malloc(n * sizeof(int)); 524 fds = malloc(n * sizeof(struct pollfd)); 525 if (socks == NULL || fds == NULL) { 526 syslog(LOG_ERR, "malloc: %m"); 527 exit(1); 528 } 529 530 for (n = 0, res = res0; res != NULL; res = res->ai_next) { 531 socks[n] = socket(res->ai_family, res->ai_socktype, 532 res->ai_protocol); 533 if (socks[n] == -1) 534 continue; 535 (void)setsockopt(socks[n], SOL_SOCKET, SO_REUSEADDR, 536 &on, sizeof(on)); 537 if (bind(socks[n], res->ai_addr, res->ai_addrlen) 538 == -1) { 539 (void)close(socks[n]); 540 continue; 541 } 542 if (listen(socks[n], 12) == -1) { 543 (void)close(socks[n]); 544 continue; 545 } 546 547 fds[n].fd = socks[n]; 548 fds[n].events = POLLIN; 549 n++; 550 } 551 if (n == 0) { 552 syslog(LOG_ERR, "%m"); 553 exit(1); 554 } 555 freeaddrinfo(res0); 556 557 if (pidfile(NULL) == -1) 558 syslog(LOG_ERR, "failed to write a pid file: %m"); 559 560 for (;;) { 561 if (poll(fds, n, INFTIM) == -1) { 562 if (errno == EINTR) 563 continue; 564 syslog(LOG_ERR, "poll: %m"); 565 exit(1); 566 } 567 for (i = 0; i < n; i++) { 568 if (fds[i].revents & POLLIN) { 569 fd = accept(fds[i].fd, NULL, NULL); 570 if (fd == -1) { 571 syslog(LOG_ERR, "accept: %m"); 572 continue; 573 } 574 switch (fork()) { 575 case -1: 576 syslog(LOG_ERR, "fork: %m"); 577 break; 578 case 0: 579 goto child; 580 /* NOTREACHED */ 581 } 582 (void)close(fd); 583 } 584 } 585 } 586 child: 587 (void)dup2(fd, STDIN_FILENO); 588 (void)dup2(fd, STDOUT_FILENO); 589 (void)dup2(fd, STDERR_FILENO); 590 for (i = 0; i < n; i++) 591 (void)close(socks[i]); 592 } 593 594 memset((char *)&his_addr, 0, sizeof(his_addr)); 595 addrlen = sizeof(his_addr.si_su); 596 if (getpeername(0, (struct sockaddr *)&his_addr.si_su, &addrlen) < 0) { 597 syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); 598 exit(1); 599 } 600 his_addr.su_len = addrlen; 601 memset((char *)&ctrl_addr, 0, sizeof(ctrl_addr)); 602 addrlen = sizeof(ctrl_addr.si_su); 603 if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { 604 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); 605 exit(1); 606 } 607 ctrl_addr.su_len = addrlen; 608#ifdef INET6 609 if (his_addr.su_family == AF_INET6 610 && IN6_IS_ADDR_V4MAPPED(&his_addr.su_6addr)) { 611#if 1 612 /* 613 * IPv4 control connection arrived to AF_INET6 socket. 614 * I hate to do this, but this is the easiest solution. 615 * 616 * The assumption is untrue on SIIT environment. 617 */ 618 struct sockinet tmp_addr; 619 const int off = sizeof(struct in6_addr) - sizeof(struct in_addr); 620 621 tmp_addr = his_addr; 622 memset(&his_addr, 0, sizeof(his_addr)); 623 his_addr.su_family = AF_INET; 624 his_addr.su_len = sizeof(his_addr.si_su.su_sin); 625 memcpy(&his_addr.su_addr, &tmp_addr.su_6addr.s6_addr[off], 626 sizeof(his_addr.su_addr)); 627 his_addr.su_port = tmp_addr.su_port; 628 629 tmp_addr = ctrl_addr; 630 memset(&ctrl_addr, 0, sizeof(ctrl_addr)); 631 ctrl_addr.su_family = AF_INET; 632 ctrl_addr.su_len = sizeof(ctrl_addr.si_su.su_sin); 633 memcpy(&ctrl_addr.su_addr, &tmp_addr.su_6addr.s6_addr[off], 634 sizeof(ctrl_addr.su_addr)); 635 ctrl_addr.su_port = tmp_addr.su_port; 636#else 637 while (fgets(line, sizeof(line), fd) != NULL) { 638 if ((cp = strchr(line, '\n')) != NULL) 639 *cp = '\0'; 640 reply(-530, "%s", line); 641 } 642 (void) fflush(stdout); 643 (void) fclose(fd); 644 reply(530, 645 "Connection from IPv4 mapped address is not supported."); 646 exit(0); 647#endif 648 649 mapped = 1; 650 } else 651#endif /* INET6 */ 652 mapped = 0; 653#ifdef IP_TOS 654 if (!mapped && his_addr.su_family == AF_INET) { 655 tos = IPTOS_LOWDELAY; 656 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, 657 sizeof(int)) < 0) 658 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 659 } 660#endif 661 /* if the hostname hasn't been given, attempt to determine it */ 662 if (hostname[0] == '\0') { 663 if (getnameinfo((struct sockaddr *)&ctrl_addr.si_su, 664 ctrl_addr.su_len, hostname, sizeof(hostname), NULL, 0, 0) 665 != 0) 666 (void)gethostname(hostname, sizeof(hostname)); 667 hostname[sizeof(hostname) - 1] = '\0'; 668 } 669 670 /* set this here so klogin can use it... */ 671 (void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid()); 672 673 (void) freopen(_PATH_DEVNULL, "w", stderr); 674 675 memset(&sa, 0, sizeof(sa)); 676 sa.sa_handler = SIG_DFL; 677 sa.sa_flags = SA_RESTART; 678 sigemptyset(&sa.sa_mask); 679 (void) sigaction(SIGCHLD, &sa, NULL); 680 681 sa.sa_handler = sigquit; 682 sa.sa_flags = SA_RESTART; 683 sigfillset(&sa.sa_mask); /* block all sigs in these handlers */ 684 (void) sigaction(SIGHUP, &sa, NULL); 685 (void) sigaction(SIGINT, &sa, NULL); 686 (void) sigaction(SIGQUIT, &sa, NULL); 687 (void) sigaction(SIGTERM, &sa, NULL); 688 sa.sa_handler = lostconn; 689 (void) sigaction(SIGPIPE, &sa, NULL); 690 sa.sa_handler = toolong; 691 (void) sigaction(SIGALRM, &sa, NULL); 692 sa.sa_handler = sigurg; 693 (void) sigaction(SIGURG, &sa, NULL); 694 695 /* Try to handle urgent data inline */ 696#ifdef SO_OOBINLINE 697 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) 698 syslog(LOG_WARNING, "setsockopt: %m"); 699#endif 700 /* Set keepalives on the socket to detect dropped connections. */ 701#ifdef SO_KEEPALIVE 702 keepalive = 1; 703 if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, 704 sizeof(int)) < 0) 705 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 706#endif 707 708#ifdef F_SETOWN 709 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) 710 syslog(LOG_WARNING, "fcntl F_SETOWN: %m"); 711#endif 712 logremotehost(&his_addr); 713 /* 714 * Set up default state 715 */ 716 data = -1; 717 type = TYPE_A; 718 form = FORM_N; 719 stru = STRU_F; 720 mode = MODE_S; 721 tmpline[0] = '\0'; 722 hasyyerrored = 0; 723 724#ifdef KERBEROS5 725 kerror = krb5_init_context(&kcontext); 726 if (kerror) { 727 syslog(LOG_ERR, "%s when initializing Kerberos context", 728 error_message(kerror)); 729 exit(0); 730 } 731#endif /* KERBEROS5 */ 732 733 init_curclass(); 734 curclass.timeout = 300; /* 5 minutes, as per login(1) */ 735 curclass.type = CLASS_REAL; 736 737 /* If logins are disabled, print out the message. */ 738 if (display_file(_PATH_NOLOGIN, 530)) { 739 reply(530, "System not available."); 740 exit(0); 741 } 742 (void)display_file(conffilename(_NAME_FTPWELCOME), 220); 743 /* reply(220,) must follow */ 744 if (EMPTYSTR(version)) 745 reply(220, "%s FTP server ready.", hostname); 746 else 747 reply(220, "%s FTP server (%s) ready.", hostname, version); 748 749 if (xferlogname != NULL) { 750 xferlogfd = open(xferlogname, O_WRONLY | O_APPEND | O_CREAT, 751 0660); 752 if (xferlogfd == -1) 753 syslog(LOG_WARNING, "open xferlog `%s': %m", 754 xferlogname); 755 else 756 doxferlog |= 2; 757 } 758 759 ftp_loop(); 760 /* NOTREACHED */ 761} 762 763static void 764lostconn(int signo) 765{ 766 767 if (ftpd_debug) 768 syslog(LOG_DEBUG, "lost connection"); 769 dologout(1); 770} 771 772static void 773toolong(int signo) 774{ 775 776 /* XXXSIGRACE */ 777 reply(421, 778 "Timeout (" LLF " seconds): closing control connection.", 779 (LLT)curclass.timeout); 780 if (logging) 781 syslog(LOG_INFO, "User %s timed out after " LLF " seconds", 782 (pw ? pw->pw_name : "unknown"), (LLT)curclass.timeout); 783 dologout(1); 784} 785 786static void 787sigquit(int signo) 788{ 789 790 if (ftpd_debug) 791 syslog(LOG_DEBUG, "got signal %d", signo); 792 dologout(1); 793} 794 795static void 796sigurg(int signo) 797{ 798 799 urgflag = 1; 800} 801 802 803/* 804 * Save the result of a getpwnam. Used for USER command, since 805 * the data returned must not be clobbered by any other command 806 * (e.g., globbing). 807 */ 808static struct passwd * 809sgetpwnam(const char *name) 810{ 811 static struct passwd save; 812 struct passwd *p; 813 814 if ((p = getpwnam(name)) == NULL) 815 return (p); 816 if (save.pw_name) { 817 free((char *)save.pw_name); 818 memset(save.pw_passwd, 0, strlen(save.pw_passwd)); 819 free((char *)save.pw_passwd); 820 free((char *)save.pw_gecos); 821 free((char *)save.pw_dir); 822 free((char *)save.pw_shell); 823 } 824 save = *p; 825 save.pw_name = ftpd_strdup(p->pw_name); 826 save.pw_passwd = ftpd_strdup(p->pw_passwd); 827 save.pw_gecos = ftpd_strdup(p->pw_gecos); 828 save.pw_dir = ftpd_strdup(p->pw_dir); 829 save.pw_shell = ftpd_strdup(p->pw_shell); 830 return (&save); 831} 832 833static int login_attempts; /* number of failed login attempts */ 834static int askpasswd; /* had USER command, ask for PASSwd */ 835static int permitted; /* USER permitted */ 836 837/* 838 * USER command. 839 * Sets global passwd pointer pw if named account exists and is acceptable; 840 * sets askpasswd if a PASS command is expected. If logged in previously, 841 * need to reset state. If name is "ftp" or "anonymous", the name is not in 842 * _NAME_FTPUSERS, and ftp account exists, set guest and pw, then just return. 843 * If account doesn't exist, ask for passwd anyway. Otherwise, check user 844 * requesting login privileges. Disallow anyone who does not have a standard 845 * shell as returned by getusershell(). Disallow anyone mentioned in the file 846 * _NAME_FTPUSERS to allow people such as root and uucp to be avoided. 847 */ 848void 849user(const char *name) 850{ 851 char *class; 852#ifdef LOGIN_CAP 853 login_cap_t *lc = NULL; 854#endif 855 856 class = NULL; 857 if (logged_in) { 858 switch (curclass.type) { 859 case CLASS_GUEST: 860 reply(530, "Can't change user from guest login."); 861 return; 862 case CLASS_CHROOT: 863 reply(530, "Can't change user from chroot user."); 864 return; 865 case CLASS_REAL: 866 if (dropprivs) { 867 reply(530, "Can't change user."); 868 return; 869 } 870 end_login(); 871 break; 872 default: 873 abort(); 874 } 875 } 876 877#if defined(KERBEROS) 878 kdestroy(); 879#endif 880#if defined(KERBEROS5) 881 k5destroy(); 882#endif 883 884 curclass.type = CLASS_REAL; 885 askpasswd = 0; 886 permitted = 0; 887 888 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { 889 /* need `pw' setup for checkaccess() and checkuser () */ 890 if ((pw = sgetpwnam("ftp")) == NULL) 891 reply(530, "User %s unknown.", name); 892 else if (! checkaccess("ftp") || ! checkaccess("anonymous")) 893 reply(530, "User %s access denied.", name); 894 else { 895 curclass.type = CLASS_GUEST; 896 askpasswd = 1; 897 reply(331, 898 "Guest login ok, type your name as password."); 899 } 900 if (!askpasswd) { 901 if (logging) 902 syslog(LOG_NOTICE, 903 "ANONYMOUS FTP LOGIN REFUSED FROM %s", 904 remotehost); 905 end_login(); 906 goto cleanup_user; 907 } 908 name = "ftp"; 909 } else 910 pw = sgetpwnam(name); 911 912 strlcpy(curname, name, curname_len); 913 914 /* check user in /etc/ftpusers, and setup class */ 915 permitted = checkuser(_NAME_FTPUSERS, curname, 1, 0, &class); 916 917 /* check user in /etc/ftpchroot */ 918 lc = login_getpwclass(pw); 919 if (checkuser(_NAME_FTPCHROOT, curname, 0, 0, NULL) 920#ifdef LOGIN_CAP /* Allow login.conf configuration as well */ 921 || login_getcapbool(lc, "ftp-chroot", 0) 922#endif 923 ) { 924 if (curclass.type == CLASS_GUEST) { 925 syslog(LOG_NOTICE, 926 "Can't change guest user to chroot class; remove entry in %s", 927 _NAME_FTPCHROOT); 928 exit(1); 929 } 930 curclass.type = CLASS_CHROOT; 931 } 932 /* determine default class */ 933 if (class == NULL) { 934 switch (curclass.type) { 935 case CLASS_GUEST: 936 class = ftpd_strdup("guest"); 937 break; 938 case CLASS_CHROOT: 939 class = ftpd_strdup("chroot"); 940 break; 941 case CLASS_REAL: 942 class = ftpd_strdup("real"); 943 break; 944 default: 945 syslog(LOG_ERR, "unknown curclass.type %d; aborting", 946 curclass.type); 947 abort(); 948 } 949 } 950 /* parse ftpd.conf, setting up various parameters */ 951 parse_conf(class); 952 /* if not guest user, check for valid shell */ 953 if (pw == NULL) 954 permitted = 0; 955 else { 956 const char *cp, *shell; 957 958 if ((shell = pw->pw_shell) == NULL || *shell == 0) 959 shell = _PATH_BSHELL; 960 while ((cp = getusershell()) != NULL) 961 if (strcmp(cp, shell) == 0) 962 break; 963 endusershell(); 964 if (cp == NULL && curclass.type != CLASS_GUEST) 965 permitted = 0; 966 } 967 968 /* deny quickly (after USER not PASS) if requested */ 969 if (CURCLASS_FLAGS_ISSET(denyquick) && !permitted) { 970 reply(530, "User %s may not use FTP.", curname); 971 if (logging) 972 syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s", 973 remotehost, curname); 974 end_login(); 975 goto cleanup_user; 976 } 977 978 /* if haven't asked yet (i.e, not anon), ask now */ 979 if (!askpasswd) { 980 askpasswd = 1; 981#ifdef SKEY 982 if (skey_haskey(curname) == 0) { 983 const char *myskey; 984 985 myskey = skey_keyinfo(curname); 986 reply(331, "Password [ %s ] required for %s.", 987 myskey ? myskey : "error getting challenge", 988 curname); 989 } else 990#endif 991#ifdef USE_OPIE 992 if (opiechallenge(&opiedata, (char *)curname, opieprompt) == 993 0) { 994 pwok = (pw != NULL) && 995 opieaccessfile(remotehost) && 996 opiealways(pw->pw_dir); 997 reply(331, "Response to %s %s for %s.", 998 opieprompt, pwok ? "requested" : "required", 999 curname); 1000 } else 1001#endif 1002 reply(331, "Password required for %s.", curname); 1003 } 1004 1005 cleanup_user: 1006#ifdef LOGIN_CAP 1007 login_close(lc); 1008#endif 1009 /* 1010 * Delay before reading passwd after first failed 1011 * attempt to slow down passwd-guessing programs. 1012 */ 1013 if (login_attempts) 1014 sleep((unsigned) login_attempts); 1015 1016 if (class) 1017 free(class); 1018} 1019 1020/* 1021 * Determine whether something is to happen (allow access, chroot) 1022 * for a user. Each line is a shell-style glob followed by 1023 * `yes' or `no'. 1024 * 1025 * For backward compatibility, `allow' and `deny' are synonymns 1026 * for `yes' and `no', respectively. 1027 * 1028 * Each glob is matched against the username in turn, and the first 1029 * match found is used. If no match is found, the result is the 1030 * argument `def'. If a match is found but without and explicit 1031 * `yes'/`no', the result is the opposite of def. 1032 * 1033 * If the file doesn't exist at all, the result is the argument 1034 * `nofile' 1035 * 1036 * Any line starting with `#' is considered a comment and ignored. 1037 * 1038 * Returns 0 if the user is denied, or 1 if they are allowed. 1039 * 1040 * NOTE: needs struct passwd *pw setup before use. 1041 */ 1042static int 1043checkuser(const char *fname, const char *name, int def, int nofile, 1044 char **retclass) 1045{ 1046 FILE *fd; 1047 int retval; 1048 char *word, *perm, *class, *buf, *p; 1049 size_t len, line; 1050 1051 retval = def; 1052 if (retclass != NULL) 1053 *retclass = NULL; 1054 if ((fd = fopen(conffilename(fname), "r")) == NULL) 1055 return nofile; 1056 1057 line = 0; 1058 for (; 1059 (buf = fparseln(fd, &len, &line, NULL, FPARSELN_UNESCCOMM | 1060 FPARSELN_UNESCCONT | FPARSELN_UNESCESC)) != NULL; 1061 free(buf), buf = NULL) { 1062 word = perm = class = NULL; 1063 p = buf; 1064 if (len < 1) 1065 continue; 1066 if (p[len - 1] == '\n') 1067 p[--len] = '\0'; 1068 if (EMPTYSTR(p)) 1069 continue; 1070 1071 NEXTWORD(p, word); 1072 NEXTWORD(p, perm); 1073 NEXTWORD(p, class); 1074 if (EMPTYSTR(word)) 1075 continue; 1076 if (!EMPTYSTR(class)) { 1077 if (strcasecmp(class, "all") == 0 || 1078 strcasecmp(class, "none") == 0) { 1079 syslog(LOG_WARNING, 1080 "%s line %d: illegal user-defined class `%s' - skipping entry", 1081 fname, (int)line, class); 1082 continue; 1083 } 1084 } 1085 1086 /* have a host specifier */ 1087 if ((p = strchr(word, '@')) != NULL) { 1088 unsigned long net, mask, addr; 1089 int bits; 1090 1091 *p++ = '\0'; 1092 /* check against network or CIDR */ 1093 if (isdigit((unsigned char)*p) && 1094 (bits = inet_net_pton(AF_INET, p, 1095 &net, sizeof(net))) != -1) { 1096 net = ntohl(net); 1097 mask = 0xffffffffU << (32 - bits); 1098 addr = ntohl(his_addr.su_addr.s_addr); 1099 if ((addr & mask) != net) 1100 continue; 1101 1102 /* check against hostname glob */ 1103 } else if (fnmatch(p, remotehost, FNM_CASEFOLD) != 0) 1104 continue; 1105 } 1106 1107 /* have a group specifier */ 1108 if ((p = strchr(word, ':')) != NULL) { 1109 gid_t *groups, *ng; 1110 int gsize, i, found; 1111 1112 if (pw == NULL) 1113 continue; /* no match for unknown user */ 1114 *p++ = '\0'; 1115 groups = NULL; 1116 gsize = 16; 1117 do { 1118 ng = realloc(groups, gsize * sizeof(gid_t)); 1119 if (ng == NULL) 1120 fatal( 1121 "Local resource failure: realloc"); 1122 groups = ng; 1123 } while (getgrouplist(pw->pw_name, pw->pw_gid, 1124 groups, &gsize) == -1); 1125 found = 0; 1126 for (i = 0; i < gsize; i++) { 1127 struct group *g; 1128 1129 if ((g = getgrgid(groups[i])) == NULL) 1130 continue; 1131 if (fnmatch(p, g->gr_name, 0) == 0) { 1132 found = 1; 1133 break; 1134 } 1135 } 1136 free(groups); 1137 if (!found) 1138 continue; 1139 } 1140 1141 /* check against username glob */ 1142 if (fnmatch(word, name, 0) != 0) 1143 continue; 1144 1145 if (perm != NULL && 1146 ((strcasecmp(perm, "allow") == 0) || 1147 (strcasecmp(perm, "yes") == 0))) 1148 retval = 1; 1149 else if (perm != NULL && 1150 ((strcasecmp(perm, "deny") == 0) || 1151 (strcasecmp(perm, "no") == 0))) 1152 retval = 0; 1153 else 1154 retval = !def; 1155 if (!EMPTYSTR(class) && retclass != NULL) 1156 *retclass = ftpd_strdup(class); 1157 free(buf); 1158 break; 1159 } 1160 (void) fclose(fd); 1161 return (retval); 1162} 1163 1164/* 1165 * Check if user is allowed by /etc/ftpusers 1166 * returns 1 for yes, 0 for no 1167 * 1168 * NOTE: needs struct passwd *pw setup (for checkuser()) 1169 */ 1170static int 1171checkaccess(const char *name) 1172{ 1173 1174 return (checkuser(_NAME_FTPUSERS, name, 1, 0, NULL)); 1175} 1176 1177static void 1178login_utmp(const char *line, const char *name, const char *host, 1179 struct sockinet *haddr) 1180{ 1181#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP) 1182 struct timeval tv; 1183 (void)gettimeofday(&tv, NULL); 1184#endif 1185#ifdef SUPPORT_UTMPX 1186 if (doutmp) { 1187 (void)memset(&utmpx, 0, sizeof(utmpx)); 1188 utmpx.ut_tv = tv; 1189 utmpx.ut_pid = getpid(); 1190 utmpx.ut_id[0] = 'f'; 1191 utmpx.ut_id[1] = 't'; 1192 utmpx.ut_id[2] = 'p'; 1193 utmpx.ut_id[3] = '*'; 1194 utmpx.ut_type = USER_PROCESS; 1195 (void)strncpy(utmpx.ut_name, name, sizeof(utmpx.ut_name)); 1196 (void)strncpy(utmpx.ut_line, line, sizeof(utmpx.ut_line)); 1197 (void)strncpy(utmpx.ut_host, host, sizeof(utmpx.ut_host)); 1198 (void)memcpy(&utmpx.ut_ss, &haddr->si_su, haddr->su_len); 1199 ftpd_loginx(&utmpx); 1200 } 1201 if (dowtmp) 1202 ftpd_logwtmpx(line, name, host, haddr, 0, USER_PROCESS); 1203#endif 1204#ifdef SUPPORT_UTMP 1205 if (doutmp) { 1206 (void)memset(&utmp, 0, sizeof(utmp)); 1207 (void)time(&utmp.ut_time); 1208 (void)strncpy(utmp.ut_name, name, sizeof(utmp.ut_name)); 1209 (void)strncpy(utmp.ut_line, line, sizeof(utmp.ut_line)); 1210 (void)strncpy(utmp.ut_host, host, sizeof(utmp.ut_host)); 1211 ftpd_login(&utmp); 1212 } 1213 if (dowtmp) 1214 ftpd_logwtmp(line, name, host); 1215#endif 1216} 1217 1218static void 1219logout_utmp(void) 1220{ 1221#ifdef SUPPORT_UTMPX 1222 int okwtmpx = dowtmp; 1223#endif 1224#ifdef SUPPORT_UTMP 1225 int okwtmp = dowtmp; 1226#endif 1227 if (logged_in) { 1228#ifdef SUPPORT_UTMPX 1229 if (doutmp) 1230 okwtmpx &= ftpd_logoutx(ttyline, 0, DEAD_PROCESS); 1231 if (okwtmpx) 1232 ftpd_logwtmpx(ttyline, "", "", NULL, 0, DEAD_PROCESS); 1233#endif 1234#ifdef SUPPORT_UTMP 1235 if (doutmp) 1236 okwtmp &= ftpd_logout(ttyline); 1237 if (okwtmp) 1238 ftpd_logwtmp(ttyline, "", ""); 1239#endif 1240 } 1241} 1242 1243/* 1244 * Terminate login as previous user (if any), resetting state; 1245 * used when USER command is given or login fails. 1246 */ 1247static void 1248end_login(void) 1249{ 1250#ifdef USE_PAM 1251 int e; 1252#endif 1253 logout_utmp(); 1254 show_chdir_messages(-1); /* flush chdir cache */ 1255 if (pw != NULL && pw->pw_passwd != NULL) 1256 memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); 1257 pw = NULL; 1258 logged_in = 0; 1259 askpasswd = 0; 1260 permitted = 0; 1261 quietmessages = 0; 1262 gidcount = 0; 1263 curclass.type = CLASS_REAL; 1264 (void) seteuid((uid_t)0); 1265#ifdef LOGIN_CAP 1266 setusercontext(NULL, getpwuid(0), 0, LOGIN_SETALL & ~(LOGIN_SETLOGIN | 1267 LOGIN_SETUSER | LOGIN_SETGROUP | LOGIN_SETPATH | 1268 LOGIN_SETENV)); 1269#endif 1270#ifdef USE_PAM 1271 if (pamh) { 1272 if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) 1273 syslog(LOG_ERR, "pam_setcred: %s", 1274 pam_strerror(pamh, e)); 1275 if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS) 1276 syslog(LOG_ERR, "pam_close_session: %s", 1277 pam_strerror(pamh, e)); 1278 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) 1279 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); 1280 pamh = NULL; 1281 } 1282#endif 1283} 1284 1285void 1286pass(const char *passwd) 1287{ 1288 int rval; 1289 char root[MAXPATHLEN]; 1290#ifdef LOGIN_CAP 1291 login_cap_t *lc = NULL; 1292#endif 1293#ifdef USE_PAM 1294 int e; 1295#endif 1296 if (logged_in || askpasswd == 0) { 1297 reply(503, "Login with USER first."); 1298 return; 1299 } 1300 askpasswd = 0; 1301 if (curclass.type != CLASS_GUEST) { 1302 /* "ftp" is the only account allowed with no password */ 1303 if (pw == NULL) { 1304 rval = 1; /* failure below */ 1305 goto skip; 1306 } 1307#ifdef USE_PAM 1308 rval = auth_pam(&pw, passwd); 1309#ifdef notdef 1310 /* If PAM fails, we proceed with other authentications */ 1311 if (rval >= 0) { 1312#ifdef USE_OPIE 1313 opieunlock(); 1314#endif 1315 goto skip; 1316 } 1317#else 1318 /* If PAM fails, that's it */ 1319 goto skip; 1320#endif 1321#endif 1322#if defined(KERBEROS) 1323 if (klogin(pw, "", hostname, (char *)passwd) == 0) { 1324 rval = 0; 1325 goto skip; 1326 } 1327#endif 1328#if defined(KERBEROS5) 1329 if (k5login(pw, "", hostname, (char *)passwd) == 0) { 1330 rval = 0; 1331 goto skip; 1332 } 1333#endif 1334#ifdef SKEY 1335 if (skey_haskey(pw->pw_name) == 0) { 1336 char *p; 1337 int r; 1338 1339 p = ftpd_strdup(passwd); 1340 r = skey_passcheck(pw->pw_name, p); 1341 free(p); 1342 if (r != -1) { 1343 rval = 0; 1344 goto skip; 1345 } 1346 } 1347#endif 1348#ifdef USE_OPIE 1349 if (opieverify(&opiedata, (char *)passwd) == 0) { 1350 /* OPIE says ok, check expire time */ 1351 if (pw->pw_expire && time(NULL) >= pw->pw_expire) 1352 rval = 2; 1353 else 1354 rval = 0; 1355 goto skip; 1356 } 1357#endif 1358 if (!sflag) 1359 rval = checkpassword(pw, passwd); 1360 else 1361 rval = 1; 1362 1363 skip: 1364 1365 /* 1366 * If rval > 0, the user failed the authentication check 1367 * above. If rval == 0, either Kerberos or local 1368 * authentication succeeded. 1369 */ 1370 if (rval) { 1371 reply(530, "%s", rval == 2 ? "Password expired." : 1372 "Login incorrect."); 1373 if (logging) { 1374 syslog(LOG_NOTICE, 1375 "FTP LOGIN FAILED FROM %s", remotehost); 1376 syslog(LOG_AUTHPRIV | LOG_NOTICE, 1377 "FTP LOGIN FAILED FROM %s, %s", 1378 remotehost, curname); 1379 } 1380 pw = NULL; 1381 if (login_attempts++ >= 5) { 1382 syslog(LOG_NOTICE, 1383 "repeated login failures from %s", 1384 remotehost); 1385 exit(0); 1386 } 1387 return; 1388 } 1389 } 1390 1391 /* password ok; check if anything else prevents login */ 1392 if (! permitted) { 1393 reply(530, "User %s may not use FTP.", pw->pw_name); 1394 if (logging) 1395 syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s", 1396 remotehost, pw->pw_name); 1397 goto bad; 1398 } 1399 1400 login_attempts = 0; /* this time successful */ 1401 if (setegid((gid_t)pw->pw_gid) < 0) { 1402 reply(550, "Can't set gid."); 1403 goto bad; 1404 } 1405#ifdef LOGIN_CAP 1406 if ((lc = login_getpwclass(pw)) != NULL) { 1407#ifdef notyet 1408 char remote_ip[NI_MAXHOST]; 1409 1410 if (getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len, 1411 remote_ip, sizeof(remote_ip) - 1, NULL, 0, 1412 NI_NUMERICHOST)) 1413 *remote_ip = 0; 1414 remote_ip[sizeof(remote_ip) - 1] = 0; 1415 if (!auth_hostok(lc, remotehost, remote_ip)) { 1416 syslog(LOG_INFO|LOG_AUTH, 1417 "FTP LOGIN FAILED (HOST) as %s: permission denied.", 1418 pw->pw_name); 1419 reply(530, "Permission denied."); 1420 pw = NULL; 1421 return; 1422 } 1423 if (!auth_timeok(lc, time(NULL))) { 1424 reply(530, "Login not available right now."); 1425 pw = NULL; 1426 return; 1427 } 1428#endif 1429 } 1430 setsid(); 1431 setusercontext(lc, pw, 0, LOGIN_SETALL & 1432 ~(LOGIN_SETUSER | LOGIN_SETPATH | LOGIN_SETENV)); 1433#else 1434 (void) initgroups(pw->pw_name, pw->pw_gid); 1435 /* cache groups for cmds.c::matchgroup() */ 1436#endif 1437#ifdef USE_PAM 1438 if (pamh) { 1439 if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) { 1440 syslog(LOG_ERR, "pam_open_session: %s", 1441 pam_strerror(pamh, e)); 1442 } else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED)) 1443 != PAM_SUCCESS) { 1444 syslog(LOG_ERR, "pam_setcred: %s", 1445 pam_strerror(pamh, e)); 1446 } 1447 } 1448#endif 1449 gidcount = getgroups(0, NULL); 1450 if (gidlist) 1451 free(gidlist); 1452 gidlist = malloc(gidcount * sizeof *gidlist); 1453 gidcount = getgroups(gidcount, gidlist); 1454 1455 /* open utmp/wtmp before chroot */ 1456 login_utmp(ttyline, pw->pw_name, remotehost, &his_addr); 1457 1458 logged_in = 1; 1459 1460 connections = 1; 1461 if (dopidfile) 1462 count_users(); 1463 if (curclass.limit != -1 && connections > curclass.limit) { 1464 if (! EMPTYSTR(curclass.limitfile)) 1465 (void)display_file(conffilename(curclass.limitfile), 1466 530); 1467 reply(530, 1468 "User %s access denied, connection limit of " LLF 1469 " reached.", 1470 pw->pw_name, (LLT)curclass.limit); 1471 syslog(LOG_NOTICE, 1472 "Maximum connection limit of " LLF 1473 " for class %s reached, login refused for %s", 1474 (LLT)curclass.limit, curclass.classname, pw->pw_name); 1475 goto bad; 1476 } 1477 1478 homedir[0] = '/'; 1479 switch (curclass.type) { 1480 case CLASS_GUEST: 1481 /* 1482 * We MUST do a chdir() after the chroot. Otherwise 1483 * the old current directory will be accessible as "." 1484 * outside the new root! 1485 */ 1486 format_path(root, 1487 curclass.chroot ? curclass.chroot : 1488 anondir ? anondir : 1489 pw->pw_dir); 1490 format_path(homedir, 1491 curclass.homedir ? curclass.homedir : 1492 "/"); 1493 if (EMPTYSTR(homedir)) 1494 homedir[0] = '/'; 1495 if (EMPTYSTR(root) || chroot(root) < 0) { 1496 syslog(LOG_NOTICE, 1497 "GUEST user %s: can't chroot to %s: %m", 1498 pw->pw_name, root); 1499 goto bad_guest; 1500 } 1501 if (chdir(homedir) < 0) { 1502 syslog(LOG_NOTICE, 1503 "GUEST user %s: can't chdir to %s: %m", 1504 pw->pw_name, homedir); 1505 bad_guest: 1506 reply(550, "Can't set guest privileges."); 1507 goto bad; 1508 } 1509 break; 1510 case CLASS_CHROOT: 1511 format_path(root, 1512 curclass.chroot ? curclass.chroot : 1513 pw->pw_dir); 1514 format_path(homedir, 1515 curclass.homedir ? curclass.homedir : 1516 "/"); 1517 if (EMPTYSTR(homedir)) 1518 homedir[0] = '/'; 1519 if (EMPTYSTR(root) || chroot(root) < 0) { 1520 syslog(LOG_NOTICE, 1521 "CHROOT user %s: can't chroot to %s: %m", 1522 pw->pw_name, root); 1523 goto bad_chroot; 1524 } 1525 if (chdir(homedir) < 0) { 1526 syslog(LOG_NOTICE, 1527 "CHROOT user %s: can't chdir to %s: %m", 1528 pw->pw_name, homedir); 1529 bad_chroot: 1530 reply(550, "Can't change root."); 1531 goto bad; 1532 } 1533 break; 1534 case CLASS_REAL: 1535 /* only chroot REAL if explicitly requested */ 1536 if (! EMPTYSTR(curclass.chroot)) { 1537 format_path(root, curclass.chroot); 1538 if (EMPTYSTR(root) || chroot(root) < 0) { 1539 syslog(LOG_NOTICE, 1540 "REAL user %s: can't chroot to %s: %m", 1541 pw->pw_name, root); 1542 goto bad_chroot; 1543 } 1544 } 1545 format_path(homedir, 1546 curclass.homedir ? curclass.homedir : 1547 pw->pw_dir); 1548 if (EMPTYSTR(homedir) || chdir(homedir) < 0) { 1549 if (chdir("/") < 0) { 1550 syslog(LOG_NOTICE, 1551 "REAL user %s: can't chdir to %s: %m", 1552 pw->pw_name, 1553 !EMPTYSTR(homedir) ? homedir : "/"); 1554 reply(530, 1555 "User %s: can't change directory to %s.", 1556 pw->pw_name, 1557 !EMPTYSTR(homedir) ? homedir : "/"); 1558 goto bad; 1559 } else { 1560 reply(-230, 1561 "No directory! Logging in with home=/"); 1562 homedir[0] = '/'; 1563 } 1564 } 1565 break; 1566 } 1567#ifndef LOGIN_CAP 1568 setsid(); 1569 setlogin(pw->pw_name); 1570#endif 1571 if (dropprivs || 1572 (curclass.type != CLASS_REAL && 1573 ntohs(ctrl_addr.su_port) > IPPORT_RESERVED + 1)) { 1574 dropprivs++; 1575 if (setgid((gid_t)pw->pw_gid) < 0) { 1576 reply(550, "Can't set gid."); 1577 goto bad; 1578 } 1579 if (setuid((uid_t)pw->pw_uid) < 0) { 1580 reply(550, "Can't set uid."); 1581 goto bad; 1582 } 1583 } else { 1584 if (seteuid((uid_t)pw->pw_uid) < 0) { 1585 reply(550, "Can't set uid."); 1586 goto bad; 1587 } 1588 } 1589 setenv("HOME", homedir, 1); 1590 1591 if (curclass.type == CLASS_GUEST && passwd[0] == '-') 1592 quietmessages = 1; 1593 1594 /* 1595 * Display a login message, if it exists. 1596 * N.B. reply(230,) must follow the message. 1597 */ 1598 if (! EMPTYSTR(curclass.motd)) 1599 (void)display_file(conffilename(curclass.motd), 230); 1600 show_chdir_messages(230); 1601 if (curclass.type == CLASS_GUEST) { 1602 char *p; 1603 1604 reply(230, "Guest login ok, access restrictions apply."); 1605#if HAVE_SETPROCTITLE 1606 snprintf(proctitle, sizeof(proctitle), 1607 "%s: anonymous/%s", remotehost, passwd); 1608 setproctitle("%s", proctitle); 1609#endif /* HAVE_SETPROCTITLE */ 1610 if (logging) 1611 syslog(LOG_INFO, 1612 "ANONYMOUS FTP LOGIN FROM %s, %s (class: %s, type: %s)", 1613 remotehost, passwd, 1614 curclass.classname, CURCLASSTYPE); 1615 /* store guest password reply into pw_passwd */ 1616 REASSIGN(pw->pw_passwd, ftpd_strdup(passwd)); 1617 for (p = pw->pw_passwd; *p; p++) 1618 if (!isgraph((unsigned char)*p)) 1619 *p = '_'; 1620 } else { 1621 reply(230, "User %s logged in.", pw->pw_name); 1622#if HAVE_SETPROCTITLE 1623 snprintf(proctitle, sizeof(proctitle), 1624 "%s: %s", remotehost, pw->pw_name); 1625 setproctitle("%s", proctitle); 1626#endif /* HAVE_SETPROCTITLE */ 1627 if (logging) 1628 syslog(LOG_INFO, 1629 "FTP LOGIN FROM %s as %s (class: %s, type: %s)", 1630 remotehost, pw->pw_name, 1631 curclass.classname, CURCLASSTYPE); 1632 } 1633 (void) umask(curclass.umask); 1634#ifdef LOGIN_CAP 1635 login_close(lc); 1636#endif 1637 return; 1638 1639 bad: 1640#ifdef LOGIN_CAP 1641 login_close(lc); 1642#endif 1643 /* Forget all about it... */ 1644 end_login(); 1645} 1646 1647void 1648retrieve(char *argv[], const char *name) 1649{ 1650 FILE *fin, *dout; 1651 struct stat st; 1652 int (*closefunc)(FILE *) = NULL; 1653 int dolog, sendrv, closerv, stderrfd, isconversion, isdata, isls; 1654 struct timeval start, finish, td, *tdp; 1655 struct rusage rusage_before, rusage_after; 1656 const char *dispname; 1657 char *error; 1658 1659 sendrv = closerv = stderrfd = -1; 1660 isconversion = isdata = isls = dolog = 0; 1661 tdp = NULL; 1662 dispname = name; 1663 fin = dout = NULL; 1664 error = NULL; 1665 if (argv == NULL) { /* if not running a command ... */ 1666 dolog = 1; 1667 isdata = 1; 1668 fin = fopen(name, "r"); 1669 closefunc = fclose; 1670 if (fin == NULL) /* doesn't exist?; try a conversion */ 1671 argv = do_conversion(name); 1672 if (argv != NULL) { 1673 isconversion++; 1674 syslog(LOG_DEBUG, "get command: '%s' on '%s'", 1675 argv[0], name); 1676 } 1677 } 1678 if (argv != NULL) { 1679 char temp[MAXPATHLEN]; 1680 1681 if (strcmp(argv[0], INTERNAL_LS) == 0) { 1682 isls = 1; 1683 stderrfd = -1; 1684 } else { 1685 (void)snprintf(temp, sizeof(temp), "%s", TMPFILE); 1686 stderrfd = mkstemp(temp); 1687 if (stderrfd != -1) 1688 (void)unlink(temp); 1689 } 1690 dispname = argv[0]; 1691 fin = ftpd_popen(argv, "r", stderrfd); 1692 closefunc = ftpd_pclose; 1693 st.st_size = -1; 1694 st.st_blksize = BUFSIZ; 1695 } 1696 if (fin == NULL) { 1697 if (errno != 0) { 1698 perror_reply(550, dispname); 1699 if (dolog) 1700 logxfer("get", -1, name, NULL, NULL, 1701 strerror(errno)); 1702 } 1703 goto cleanupretrieve; 1704 } 1705 byte_count = -1; 1706 if (argv == NULL 1707 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) { 1708 error = "Not a plain file"; 1709 reply(550, "%s: %s.", dispname, error); 1710 goto done; 1711 } 1712 if (restart_point) { 1713 if (type == TYPE_A) { 1714 off_t i; 1715 int c; 1716 1717 for (i = 0; i < restart_point; i++) { 1718 if ((c=getc(fin)) == EOF) { 1719 error = strerror(errno); 1720 perror_reply(550, dispname); 1721 goto done; 1722 } 1723 if (c == '\n') 1724 i++; 1725 } 1726 } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) { 1727 error = strerror(errno); 1728 perror_reply(550, dispname); 1729 goto done; 1730 } 1731 } 1732 dout = dataconn(dispname, st.st_size, "w"); 1733 if (dout == NULL) 1734 goto done; 1735 1736 (void)getrusage(RUSAGE_SELF, &rusage_before); 1737 (void)gettimeofday(&start, NULL); 1738 sendrv = send_data(fin, dout, &st, isdata); 1739 (void)gettimeofday(&finish, NULL); 1740 (void)getrusage(RUSAGE_SELF, &rusage_after); 1741 closedataconn(dout); /* close now to affect timing stats */ 1742 timersub(&finish, &start, &td); 1743 tdp = &td; 1744 done: 1745 if (dolog) { 1746 logxfer("get", byte_count, name, NULL, tdp, error); 1747 if (tdp != NULL) 1748 logrusage(&rusage_before, &rusage_after); 1749 } 1750 closerv = (*closefunc)(fin); 1751 if (sendrv == 0) { 1752 FILE *errf; 1753 struct stat sb; 1754 1755 if (!isls && argv != NULL && closerv != 0) { 1756 reply(-226, 1757 "Command returned an exit status of %d", 1758 closerv); 1759 if (isconversion) 1760 syslog(LOG_WARNING, 1761 "retrieve command: '%s' returned %d", 1762 argv[0], closerv); 1763 } 1764 if (!isls && argv != NULL && stderrfd != -1 && 1765 (fstat(stderrfd, &sb) == 0) && sb.st_size > 0 && 1766 ((errf = fdopen(stderrfd, "r")) != NULL)) { 1767 char *cp, line[LINE_MAX]; 1768 1769 reply(-226, "Command error messages:"); 1770 rewind(errf); 1771 while (fgets(line, sizeof(line), errf) != NULL) { 1772 if ((cp = strchr(line, '\n')) != NULL) 1773 *cp = '\0'; 1774 reply(0, " %s", line); 1775 } 1776 (void) fflush(stdout); 1777 (void) fclose(errf); 1778 /* a reply(226,) must follow */ 1779 } 1780 reply(226, "Transfer complete."); 1781 } 1782 cleanupretrieve: 1783 if (stderrfd != -1) 1784 (void)close(stderrfd); 1785 if (isconversion) 1786 free(argv); 1787} 1788 1789void 1790store(const char *name, const char *fmode, int unique) 1791{ 1792 FILE *fout, *din; 1793 struct stat st; 1794 int (*closefunc)(FILE *); 1795 struct timeval start, finish, td, *tdp; 1796 char *desc, *error; 1797 1798 din = NULL; 1799 desc = (*fmode == 'w') ? "put" : "append"; 1800 error = NULL; 1801 if (unique && stat(name, &st) == 0 && 1802 (name = gunique(name)) == NULL) { 1803 logxfer(desc, -1, name, NULL, NULL, 1804 "cannot create unique file"); 1805 goto cleanupstore; 1806 } 1807 1808 if (restart_point) 1809 fmode = "r+"; 1810 fout = fopen(name, fmode); 1811 closefunc = fclose; 1812 tdp = NULL; 1813 if (fout == NULL) { 1814 perror_reply(553, name); 1815 logxfer(desc, -1, name, NULL, NULL, strerror(errno)); 1816 goto cleanupstore; 1817 } 1818 byte_count = -1; 1819 if (restart_point) { 1820 if (type == TYPE_A) { 1821 off_t i; 1822 int c; 1823 1824 for (i = 0; i < restart_point; i++) { 1825 if ((c=getc(fout)) == EOF) { 1826 error = strerror(errno); 1827 perror_reply(550, name); 1828 goto done; 1829 } 1830 if (c == '\n') 1831 i++; 1832 } 1833 /* 1834 * We must do this seek to "current" position 1835 * because we are changing from reading to 1836 * writing. 1837 */ 1838 if (fseek(fout, 0L, SEEK_CUR) < 0) { 1839 error = strerror(errno); 1840 perror_reply(550, name); 1841 goto done; 1842 } 1843 } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) { 1844 error = strerror(errno); 1845 perror_reply(550, name); 1846 goto done; 1847 } 1848 } 1849 din = dataconn(name, (off_t)-1, "r"); 1850 if (din == NULL) 1851 goto done; 1852 (void)gettimeofday(&start, NULL); 1853 if (receive_data(din, fout) == 0) { 1854 if (unique) 1855 reply(226, "Transfer complete (unique file name:%s).", 1856 name); 1857 else 1858 reply(226, "Transfer complete."); 1859 } 1860 (void)gettimeofday(&finish, NULL); 1861 closedataconn(din); /* close now to affect timing stats */ 1862 timersub(&finish, &start, &td); 1863 tdp = &td; 1864 done: 1865 logxfer(desc, byte_count, name, NULL, tdp, error); 1866 (*closefunc)(fout); 1867 cleanupstore: 1868 ; 1869} 1870 1871static FILE * 1872getdatasock(const char *fmode) 1873{ 1874 int on, s, t, tries; 1875 in_port_t port; 1876 1877 on = 1; 1878 if (data >= 0) 1879 return (fdopen(data, fmode)); 1880 if (! dropprivs) 1881 (void) seteuid((uid_t)0); 1882 s = socket(ctrl_addr.su_family, SOCK_STREAM, 0); 1883 if (s < 0) 1884 goto bad; 1885 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 1886 (char *) &on, sizeof(on)) < 0) 1887 goto bad; 1888 if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 1889 (char *) &on, sizeof(on)) < 0) 1890 goto bad; 1891 /* anchor socket to avoid multi-homing problems */ 1892 data_source = ctrl_addr; 1893 /* 1894 * By default source port for PORT connctions is 1895 * ctrlport-1 (see RFC959 section 5.2). 1896 * However, if privs have been dropped and that 1897 * would be < IPPORT_RESERVED, use a random port 1898 * instead. 1899 */ 1900 if (dataport) 1901 port = dataport; 1902 else 1903 port = ntohs(ctrl_addr.su_port) - 1; 1904 if (dropprivs && port < IPPORT_RESERVED) 1905 port = 0; /* use random port */ 1906 data_source.su_port = htons(port); 1907 1908 for (tries = 1; ; tries++) { 1909 if (bind(s, (struct sockaddr *)&data_source.si_su, 1910 data_source.su_len) >= 0) 1911 break; 1912 if (errno != EADDRINUSE || tries > 10) 1913 goto bad; 1914 sleep(tries); 1915 } 1916 if (! dropprivs) 1917 (void) seteuid((uid_t)pw->pw_uid); 1918#ifdef IP_TOS 1919 if (!mapped && ctrl_addr.su_family == AF_INET) { 1920 on = IPTOS_THROUGHPUT; 1921 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, 1922 sizeof(int)) < 0) 1923 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 1924 } 1925#endif 1926 return (fdopen(s, fmode)); 1927 bad: 1928 /* Return the real value of errno (close may change it) */ 1929 t = errno; 1930 if (! dropprivs) 1931 (void) seteuid((uid_t)pw->pw_uid); 1932 (void) close(s); 1933 errno = t; 1934 return (NULL); 1935} 1936 1937FILE * 1938dataconn(const char *name, off_t size, const char *fmode) 1939{ 1940 char sizebuf[32]; 1941 FILE *file; 1942 int retry, tos, keepalive, conerrno; 1943 1944 file_size = size; 1945 byte_count = 0; 1946 if (size != (off_t) -1) 1947 (void)snprintf(sizebuf, sizeof(sizebuf), " (" LLF " byte%s)", 1948 (LLT)size, PLURAL(size)); 1949 else 1950 sizebuf[0] = '\0'; 1951 if (pdata >= 0) { 1952 struct sockinet from; 1953 int s; 1954 socklen_t fromlen = sizeof(from.su_len); 1955 1956 (void) alarm(curclass.timeout); 1957 s = accept(pdata, (struct sockaddr *)&from.si_su, &fromlen); 1958 (void) alarm(0); 1959 if (s < 0) { 1960 reply(425, "Can't open data connection."); 1961 (void) close(pdata); 1962 pdata = -1; 1963 return (NULL); 1964 } 1965 (void) close(pdata); 1966 pdata = s; 1967 switch (from.su_family) { 1968 case AF_INET: 1969#ifdef IP_TOS 1970 if (!mapped) { 1971 tos = IPTOS_THROUGHPUT; 1972 (void) setsockopt(s, IPPROTO_IP, IP_TOS, 1973 (char *)&tos, sizeof(int)); 1974 } 1975 break; 1976#endif 1977 } 1978 /* Set keepalives on the socket to detect dropped conns. */ 1979#ifdef SO_KEEPALIVE 1980 keepalive = 1; 1981 (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 1982 (char *)&keepalive, sizeof(int)); 1983#endif 1984 reply(150, "Opening %s mode data connection for '%s'%s.", 1985 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 1986 return (fdopen(pdata, fmode)); 1987 } 1988 if (data >= 0) { 1989 reply(125, "Using existing data connection for '%s'%s.", 1990 name, sizebuf); 1991 usedefault = 1; 1992 return (fdopen(data, fmode)); 1993 } 1994 if (usedefault) 1995 data_dest = his_addr; 1996 usedefault = 1; 1997 retry = conerrno = 0; 1998 do { 1999 file = getdatasock(fmode); 2000 if (file == NULL) { 2001 char hbuf[NI_MAXHOST]; 2002 char pbuf[NI_MAXSERV]; 2003 2004 if (getnameinfo((struct sockaddr *)&data_source.si_su, 2005 data_source.su_len, hbuf, sizeof(hbuf), pbuf, 2006 sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV)) 2007 strlcpy(hbuf, "?", sizeof(hbuf)); 2008 reply(425, "Can't create data socket (%s,%s): %s.", 2009 hbuf, pbuf, strerror(errno)); 2010 return (NULL); 2011 } 2012 data = fileno(file); 2013 conerrno = 0; 2014 if (connect(data, (struct sockaddr *)&data_dest.si_su, 2015 data_dest.su_len) == 0) 2016 break; 2017 conerrno = errno; 2018 (void) fclose(file); 2019 file = NULL; 2020 data = -1; 2021 if (conerrno == EADDRINUSE) { 2022 sleep((unsigned) swaitint); 2023 retry += swaitint; 2024 } else { 2025 break; 2026 } 2027 } while (retry <= swaitmax); 2028 if (conerrno != 0) { 2029 perror_reply(425, "Can't build data connection"); 2030 return (NULL); 2031 } 2032 reply(150, "Opening %s mode data connection for '%s'%s.", 2033 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 2034 return (file); 2035} 2036 2037void 2038closedataconn(FILE *fd) 2039{ 2040 2041 if (fd == NULL) 2042 return; 2043 (void)fclose(fd); 2044 data = -1; 2045 if (pdata >= 0) 2046 (void)close(pdata); 2047 pdata = -1; 2048} 2049 2050int 2051write_data(int fd, char *buf, size_t size, off_t *bufrem, 2052 struct timeval *then, int isdata) 2053{ 2054 struct timeval now, td; 2055 ssize_t c; 2056 2057 while (size > 0) { 2058 c = size; 2059 if (curclass.writesize) { 2060 if (curclass.writesize < c) 2061 c = curclass.writesize; 2062 } 2063 if (curclass.rateget) { 2064 if (*bufrem < c) 2065 c = *bufrem; 2066 } 2067 (void) alarm(curclass.timeout); 2068 c = write(fd, buf, c); 2069 if (c <= 0) 2070 return (1); 2071 buf += c; 2072 size -= c; 2073 byte_count += c; 2074 if (isdata) { 2075 total_data_out += c; 2076 total_data += c; 2077 } 2078 total_bytes_out += c; 2079 total_bytes += c; 2080 if (curclass.rateget) { 2081 *bufrem -= c; 2082 if (*bufrem == 0) { 2083 (void)gettimeofday(&now, NULL); 2084 timersub(&now, then, &td); 2085 if (td.tv_sec == 0) { 2086 usleep(1000000 - td.tv_usec); 2087 (void)gettimeofday(then, NULL); 2088 } else 2089 *then = now; 2090 *bufrem = curclass.rateget; 2091 } 2092 } 2093 } 2094 return (0); 2095} 2096 2097static enum send_status 2098send_data_with_read(int filefd, int netfd, const struct stat *st, int isdata) 2099{ 2100 struct timeval then; 2101 off_t bufrem; 2102 size_t readsize; 2103 char *buf; 2104 int c, error; 2105 2106 if (curclass.readsize) 2107 readsize = curclass.readsize; 2108 else 2109 readsize = (size_t)st->st_blksize; 2110 if ((buf = malloc(readsize)) == NULL) { 2111 perror_reply(451, "Local resource failure: malloc"); 2112 return (SS_NO_TRANSFER); 2113 } 2114 2115 if (curclass.rateget) { 2116 bufrem = curclass.rateget; 2117 (void)gettimeofday(&then, NULL); 2118 } 2119 while (1) { 2120 (void) alarm(curclass.timeout); 2121 c = read(filefd, buf, readsize); 2122 if (c == 0) 2123 error = SS_SUCCESS; 2124 else if (c < 0) 2125 error = SS_FILE_ERROR; 2126 else if (write_data(netfd, buf, c, &bufrem, &then, isdata)) 2127 error = SS_DATA_ERROR; 2128 else if (urgflag && handleoobcmd()) 2129 error = SS_ABORTED; 2130 else 2131 continue; 2132 2133 free(buf); 2134 return (error); 2135 } 2136} 2137 2138static enum send_status 2139send_data_with_mmap(int filefd, int netfd, const struct stat *st, int isdata) 2140{ 2141 struct timeval then; 2142 off_t bufrem, filesize, off, origoff; 2143 size_t mapsize, winsize; 2144 int error, sendbufsize, sendlowat; 2145 void *win; 2146 2147 if (curclass.sendbufsize) { 2148 sendbufsize = curclass.sendbufsize; 2149 if (setsockopt(netfd, SOL_SOCKET, SO_SNDBUF, 2150 &sendbufsize, sizeof(int)) == -1) 2151 syslog(LOG_WARNING, "setsockopt(SO_SNDBUF, %d): %m", 2152 sendbufsize); 2153 } 2154 2155 if (curclass.sendlowat) { 2156 sendlowat = curclass.sendlowat; 2157 if (setsockopt(netfd, SOL_SOCKET, SO_SNDLOWAT, 2158 &sendlowat, sizeof(int)) == -1) 2159 syslog(LOG_WARNING, "setsockopt(SO_SNDLOWAT, %d): %m", 2160 sendlowat); 2161 } 2162 2163 winsize = curclass.mmapsize; 2164 filesize = st->st_size; 2165 if (ftpd_debug) 2166 syslog(LOG_INFO, "mmapsize = %ld, writesize = %ld", 2167 (long)winsize, (long)curclass.writesize); 2168 if (winsize == 0) 2169 goto try_read; 2170 2171 off = lseek(filefd, (off_t)0, SEEK_CUR); 2172 if (off == -1) 2173 goto try_read; 2174 2175 origoff = off; 2176 if (curclass.rateget) { 2177 bufrem = curclass.rateget; 2178 (void)gettimeofday(&then, NULL); 2179 } 2180 while (1) { 2181 mapsize = MIN(filesize - off, winsize); 2182 if (mapsize == 0) 2183 break; 2184 win = mmap(NULL, mapsize, PROT_READ, 2185 MAP_FILE|MAP_SHARED, filefd, off); 2186 if (win == MAP_FAILED) { 2187 if (off == origoff) 2188 goto try_read; 2189 return (SS_FILE_ERROR); 2190 } 2191 (void) madvise(win, mapsize, MADV_SEQUENTIAL); 2192 error = write_data(netfd, win, mapsize, &bufrem, &then, 2193 isdata); 2194 (void) madvise(win, mapsize, MADV_DONTNEED); 2195 munmap(win, mapsize); 2196 if (urgflag && handleoobcmd()) 2197 return (SS_ABORTED); 2198 if (error) 2199 return (SS_DATA_ERROR); 2200 off += mapsize; 2201 } 2202 return (SS_SUCCESS); 2203 2204 try_read: 2205 return (send_data_with_read(filefd, netfd, st, isdata)); 2206} 2207 2208/* 2209 * Tranfer the contents of "instr" to "outstr" peer using the appropriate 2210 * encapsulation of the data subject to Mode, Structure, and Type. 2211 * 2212 * NB: Form isn't handled. 2213 */ 2214static int 2215send_data(FILE *instr, FILE *outstr, const struct stat *st, int isdata) 2216{ 2217 int c, filefd, netfd, rval; 2218 2219 urgflag = 0; 2220 transflag = 1; 2221 rval = -1; 2222 2223 switch (type) { 2224 2225 case TYPE_A: 2226 /* XXXLUKEM: rate limit ascii send (get) */ 2227 (void) alarm(curclass.timeout); 2228 while ((c = getc(instr)) != EOF) { 2229 if (urgflag && handleoobcmd()) 2230 goto cleanup_send_data; 2231 byte_count++; 2232 if (c == '\n') { 2233 if (ferror(outstr)) 2234 goto data_err; 2235 (void) putc('\r', outstr); 2236 if (isdata) { 2237 total_data_out++; 2238 total_data++; 2239 } 2240 total_bytes_out++; 2241 total_bytes++; 2242 } 2243 (void) putc(c, outstr); 2244 if (isdata) { 2245 total_data_out++; 2246 total_data++; 2247 } 2248 total_bytes_out++; 2249 total_bytes++; 2250 if ((byte_count % 4096) == 0) 2251 (void) alarm(curclass.timeout); 2252 } 2253 (void) alarm(0); 2254 fflush(outstr); 2255 if (ferror(instr)) 2256 goto file_err; 2257 if (ferror(outstr)) 2258 goto data_err; 2259 rval = 0; 2260 goto cleanup_send_data; 2261 2262 case TYPE_I: 2263 case TYPE_L: 2264 filefd = fileno(instr); 2265 netfd = fileno(outstr); 2266 switch (send_data_with_mmap(filefd, netfd, st, isdata)) { 2267 2268 case SS_SUCCESS: 2269 break; 2270 2271 case SS_ABORTED: 2272 case SS_NO_TRANSFER: 2273 goto cleanup_send_data; 2274 2275 case SS_FILE_ERROR: 2276 goto file_err; 2277 2278 case SS_DATA_ERROR: 2279 goto data_err; 2280 } 2281 rval = 0; 2282 goto cleanup_send_data; 2283 2284 default: 2285 reply(550, "Unimplemented TYPE %d in send_data", type); 2286 goto cleanup_send_data; 2287 } 2288 2289 data_err: 2290 (void) alarm(0); 2291 perror_reply(426, "Data connection"); 2292 goto cleanup_send_data; 2293 2294 file_err: 2295 (void) alarm(0); 2296 perror_reply(551, "Error on input file"); 2297 goto cleanup_send_data; 2298 2299 cleanup_send_data: 2300 (void) alarm(0); 2301 transflag = 0; 2302 urgflag = 0; 2303 if (isdata) { 2304 total_files_out++; 2305 total_files++; 2306 } 2307 total_xfers_out++; 2308 total_xfers++; 2309 return (rval); 2310} 2311 2312/* 2313 * Transfer data from peer to "outstr" using the appropriate encapulation of 2314 * the data subject to Mode, Structure, and Type. 2315 * 2316 * N.B.: Form isn't handled. 2317 */ 2318static int 2319receive_data(FILE *instr, FILE *outstr) 2320{ 2321 int c, bare_lfs, netfd, filefd, rval; 2322 off_t byteswritten; 2323 char *buf; 2324 size_t readsize; 2325 struct sigaction sa, sa_saved; 2326 struct stat st; 2327#ifdef __GNUC__ 2328 (void) &bare_lfs; 2329#endif 2330 2331 memset(&sa, 0, sizeof(sa)); 2332 sigfillset(&sa.sa_mask); 2333 sa.sa_flags = SA_RESTART; 2334 sa.sa_handler = lostconn; 2335 (void) sigaction(SIGALRM, &sa, &sa_saved); 2336 2337 bare_lfs = 0; 2338 urgflag = 0; 2339 transflag = 1; 2340 rval = -1; 2341 byteswritten = 0; 2342 buf = NULL; 2343 2344#define FILESIZECHECK(x) \ 2345 do { \ 2346 if (curclass.maxfilesize != -1 && \ 2347 (x) > curclass.maxfilesize) { \ 2348 errno = EFBIG; \ 2349 goto file_err; \ 2350 } \ 2351 } while (0) 2352 2353 switch (type) { 2354 2355 case TYPE_I: 2356 case TYPE_L: 2357 netfd = fileno(instr); 2358 filefd = fileno(outstr); 2359 (void) alarm(curclass.timeout); 2360 if (curclass.readsize) 2361 readsize = curclass.readsize; 2362 else if (fstat(filefd, &st)) 2363 readsize = (size_t)st.st_blksize; 2364 else 2365 readsize = BUFSIZ; 2366 if ((buf = malloc(readsize)) == NULL) { 2367 perror_reply(451, "Local resource failure: malloc"); 2368 goto cleanup_recv_data; 2369 } 2370 if (curclass.rateput) { 2371 while (1) { 2372 int d; 2373 struct timeval then, now, td; 2374 off_t bufrem; 2375 2376 (void)gettimeofday(&then, NULL); 2377 errno = c = d = 0; 2378 for (bufrem = curclass.rateput; bufrem > 0; ) { 2379 if ((c = read(netfd, buf, 2380 MIN(readsize, bufrem))) <= 0) 2381 goto recvdone; 2382 if (urgflag && handleoobcmd()) 2383 goto cleanup_recv_data; 2384 FILESIZECHECK(byte_count + c); 2385 if ((d = write(filefd, buf, c)) != c) 2386 goto file_err; 2387 (void) alarm(curclass.timeout); 2388 bufrem -= c; 2389 byte_count += c; 2390 total_data_in += c; 2391 total_data += c; 2392 total_bytes_in += c; 2393 total_bytes += c; 2394 } 2395 (void)gettimeofday(&now, NULL); 2396 timersub(&now, &then, &td); 2397 if (td.tv_sec == 0) 2398 usleep(1000000 - td.tv_usec); 2399 } 2400 } else { 2401 while ((c = read(netfd, buf, readsize)) > 0) { 2402 if (urgflag && handleoobcmd()) 2403 goto cleanup_recv_data; 2404 FILESIZECHECK(byte_count + c); 2405 if (write(filefd, buf, c) != c) 2406 goto file_err; 2407 (void) alarm(curclass.timeout); 2408 byte_count += c; 2409 total_data_in += c; 2410 total_data += c; 2411 total_bytes_in += c; 2412 total_bytes += c; 2413 } 2414 } 2415 recvdone: 2416 if (c < 0) 2417 goto data_err; 2418 rval = 0; 2419 goto cleanup_recv_data; 2420 2421 case TYPE_E: 2422 reply(553, "TYPE E not implemented."); 2423 goto cleanup_recv_data; 2424 2425 case TYPE_A: 2426 (void) alarm(curclass.timeout); 2427 /* XXXLUKEM: rate limit ascii receive (put) */ 2428 while ((c = getc(instr)) != EOF) { 2429 if (urgflag && handleoobcmd()) 2430 goto cleanup_recv_data; 2431 byte_count++; 2432 total_data_in++; 2433 total_data++; 2434 total_bytes_in++; 2435 total_bytes++; 2436 if ((byte_count % 4096) == 0) 2437 (void) alarm(curclass.timeout); 2438 if (c == '\n') 2439 bare_lfs++; 2440 while (c == '\r') { 2441 if (ferror(outstr)) 2442 goto data_err; 2443 if ((c = getc(instr)) != '\n') { 2444 byte_count++; 2445 total_data_in++; 2446 total_data++; 2447 total_bytes_in++; 2448 total_bytes++; 2449 if ((byte_count % 4096) == 0) 2450 (void) alarm(curclass.timeout); 2451 byteswritten++; 2452 FILESIZECHECK(byteswritten); 2453 (void) putc ('\r', outstr); 2454 if (c == '\0' || c == EOF) 2455 goto contin2; 2456 } 2457 } 2458 byteswritten++; 2459 FILESIZECHECK(byteswritten); 2460 (void) putc(c, outstr); 2461 contin2: ; 2462 } 2463 (void) alarm(0); 2464 fflush(outstr); 2465 if (ferror(instr)) 2466 goto data_err; 2467 if (ferror(outstr)) 2468 goto file_err; 2469 if (bare_lfs) { 2470 reply(-226, 2471 "WARNING! %d bare linefeeds received in ASCII mode", 2472 bare_lfs); 2473 reply(0, "File may not have transferred correctly."); 2474 } 2475 rval = 0; 2476 goto cleanup_recv_data; 2477 2478 default: 2479 reply(550, "Unimplemented TYPE %d in receive_data", type); 2480 goto cleanup_recv_data; 2481 } 2482#undef FILESIZECHECK 2483 2484 data_err: 2485 (void) alarm(0); 2486 perror_reply(426, "Data Connection"); 2487 goto cleanup_recv_data; 2488 2489 file_err: 2490 (void) alarm(0); 2491 perror_reply(452, "Error writing file"); 2492 goto cleanup_recv_data; 2493 2494 cleanup_recv_data: 2495 (void) alarm(0); 2496 (void) sigaction(SIGALRM, &sa_saved, NULL); 2497 if (buf) 2498 free(buf); 2499 transflag = 0; 2500 urgflag = 0; 2501 total_files_in++; 2502 total_files++; 2503 total_xfers_in++; 2504 total_xfers++; 2505 return (rval); 2506} 2507 2508void 2509statcmd(void) 2510{ 2511 struct sockinet *su = NULL; 2512 static char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; 2513 u_char *a, *p; 2514 int ispassive, af; 2515 off_t otbi, otbo, otb; 2516 2517 a = p = (u_char *)NULL; 2518 2519 reply(-211, "%s FTP server status:", hostname); 2520 reply(0, "Version: %s", EMPTYSTR(version) ? "<suppressed>" : version); 2521 hbuf[0] = '\0'; 2522 if (!getnameinfo((struct sockaddr *)&his_addr.si_su, his_addr.su_len, 2523 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) 2524 && strcmp(remotehost, hbuf) != 0) 2525 reply(0, "Connected to %s (%s)", remotehost, hbuf); 2526 else 2527 reply(0, "Connected to %s", remotehost); 2528 2529 if (logged_in) { 2530 if (curclass.type == CLASS_GUEST) 2531 reply(0, "Logged in anonymously"); 2532 else 2533 reply(0, "Logged in as %s%s", pw->pw_name, 2534 curclass.type == CLASS_CHROOT ? " (chroot)" : ""); 2535 } else if (askpasswd) 2536 reply(0, "Waiting for password"); 2537 else 2538 reply(0, "Waiting for user name"); 2539 cprintf(stdout, " TYPE: %s", typenames[type]); 2540 if (type == TYPE_A || type == TYPE_E) 2541 cprintf(stdout, ", FORM: %s", formnames[form]); 2542 if (type == TYPE_L) { 2543#if NBBY == 8 2544 cprintf(stdout, " %d", NBBY); 2545#else 2546 /* XXX: `bytesize' needs to be defined in this case */ 2547 cprintf(stdout, " %d", bytesize); 2548#endif 2549 } 2550 cprintf(stdout, "; STRUcture: %s; transfer MODE: %s\r\n", 2551 strunames[stru], modenames[mode]); 2552 ispassive = 0; 2553 if (data != -1) { 2554 reply(0, "Data connection open"); 2555 su = NULL; 2556 } else if (pdata != -1) { 2557 reply(0, "in Passive mode"); 2558 if (curclass.advertise.su_len != 0) 2559 su = &curclass.advertise; 2560 else 2561 su = &pasv_addr; 2562 ispassive = 1; 2563 goto printaddr; 2564 } else if (usedefault == 0) { 2565 su = (struct sockinet *)&data_dest; 2566 2567 if (epsvall) { 2568 reply(0, "EPSV only mode (EPSV ALL)"); 2569 goto epsvonly; 2570 } 2571 printaddr: 2572 /* PASV/PORT */ 2573 if (su->su_family == AF_INET) { 2574 a = (u_char *) &su->su_addr; 2575 p = (u_char *) &su->su_port; 2576#define UC(b) (((int) b) & 0xff) 2577 reply(0, "%s (%d,%d,%d,%d,%d,%d)", 2578 ispassive ? "PASV" : "PORT" , 2579 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 2580 UC(p[0]), UC(p[1])); 2581 } 2582 2583 /* LPSV/LPRT */ 2584 { 2585 int alen, i; 2586 2587 alen = 0; 2588 switch (su->su_family) { 2589 case AF_INET: 2590 a = (u_char *) &su->su_addr; 2591 p = (u_char *) &su->su_port; 2592 alen = sizeof(su->su_addr); 2593 af = 4; 2594 break; 2595#ifdef INET6 2596 case AF_INET6: 2597 a = (u_char *) &su->su_6addr; 2598 p = (u_char *) &su->su_port; 2599 alen = sizeof(su->su_6addr); 2600 af = 6; 2601 break; 2602#endif 2603 default: 2604 af = 0; 2605 break; 2606 } 2607 if (af) { 2608 cprintf(stdout, " %s (%d,%d", 2609 ispassive ? "LPSV" : "LPRT", af, alen); 2610 for (i = 0; i < alen; i++) 2611 cprintf(stdout, ",%d", UC(a[i])); 2612 cprintf(stdout, ",%d,%d,%d)\r\n", 2613 2, UC(p[0]), UC(p[1])); 2614#undef UC 2615 } 2616 } 2617 2618 /* EPRT/EPSV */ 2619 epsvonly: 2620 af = af2epsvproto(su->su_family); 2621 hbuf[0] = '\0'; 2622 if (af > 0) { 2623 struct sockinet tmp; 2624 2625 tmp = *su; 2626#ifdef INET6 2627 if (tmp.su_family == AF_INET6) 2628 tmp.su_scope_id = 0; 2629#endif 2630 if (getnameinfo((struct sockaddr *)&tmp.si_su, 2631 tmp.su_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), 2632 NI_NUMERICHOST | NI_NUMERICSERV) == 0) 2633 reply(0, "%s (|%d|%s|%s|)", 2634 ispassive ? "EPSV" : "EPRT", 2635 af, hbuf, sbuf); 2636 } 2637 } else 2638 reply(0, "No data connection"); 2639 2640 if (logged_in) { 2641 reply(0, 2642 "Data sent: " LLF " byte%s in " LLF " file%s", 2643 (LLT)total_data_out, PLURAL(total_data_out), 2644 (LLT)total_files_out, PLURAL(total_files_out)); 2645 reply(0, 2646 "Data received: " LLF " byte%s in " LLF " file%s", 2647 (LLT)total_data_in, PLURAL(total_data_in), 2648 (LLT)total_files_in, PLURAL(total_files_in)); 2649 reply(0, 2650 "Total data: " LLF " byte%s in " LLF " file%s", 2651 (LLT)total_data, PLURAL(total_data), 2652 (LLT)total_files, PLURAL(total_files)); 2653 } 2654 otbi = total_bytes_in; 2655 otbo = total_bytes_out; 2656 otb = total_bytes; 2657 reply(0, "Traffic sent: " LLF " byte%s in " LLF " transfer%s", 2658 (LLT)otbo, PLURAL(otbo), 2659 (LLT)total_xfers_out, PLURAL(total_xfers_out)); 2660 reply(0, "Traffic received: " LLF " byte%s in " LLF " transfer%s", 2661 (LLT)otbi, PLURAL(otbi), 2662 (LLT)total_xfers_in, PLURAL(total_xfers_in)); 2663 reply(0, "Total traffic: " LLF " byte%s in " LLF " transfer%s", 2664 (LLT)otb, PLURAL(otb), 2665 (LLT)total_xfers, PLURAL(total_xfers)); 2666 2667 if (logged_in && !CURCLASS_FLAGS_ISSET(private)) { 2668 struct ftpconv *cp; 2669 2670 reply(0, "%s", ""); 2671 reply(0, "Class: %s, type: %s", 2672 curclass.classname, CURCLASSTYPE); 2673 reply(0, "Check PORT/LPRT commands: %sabled", 2674 CURCLASS_FLAGS_ISSET(checkportcmd) ? "en" : "dis"); 2675 if (! EMPTYSTR(curclass.display)) 2676 reply(0, "Display file: %s", curclass.display); 2677 if (! EMPTYSTR(curclass.notify)) 2678 reply(0, "Notify fileglob: %s", curclass.notify); 2679 reply(0, "Idle timeout: " LLF ", maximum timeout: " LLF, 2680 (LLT)curclass.timeout, (LLT)curclass.maxtimeout); 2681 reply(0, "Current connections: %d", connections); 2682 if (curclass.limit == -1) 2683 reply(0, "Maximum connections: unlimited"); 2684 else 2685 reply(0, "Maximum connections: " LLF, 2686 (LLT)curclass.limit); 2687 if (curclass.limitfile) 2688 reply(0, "Connection limit exceeded message file: %s", 2689 conffilename(curclass.limitfile)); 2690 if (! EMPTYSTR(curclass.chroot)) 2691 reply(0, "Chroot format: %s", curclass.chroot); 2692 reply(0, "Deny bad ftpusers(5) quickly: %sabled", 2693 CURCLASS_FLAGS_ISSET(denyquick) ? "en" : "dis"); 2694 if (! EMPTYSTR(curclass.homedir)) 2695 reply(0, "Homedir format: %s", curclass.homedir); 2696 if (curclass.maxfilesize == -1) 2697 reply(0, "Maximum file size: unlimited"); 2698 else 2699 reply(0, "Maximum file size: " LLF, 2700 (LLT)curclass.maxfilesize); 2701 if (! EMPTYSTR(curclass.motd)) 2702 reply(0, "MotD file: %s", conffilename(curclass.motd)); 2703 reply(0, 2704 "Modify commands (CHMOD, DELE, MKD, RMD, RNFR, UMASK): %sabled", 2705 CURCLASS_FLAGS_ISSET(modify) ? "en" : "dis"); 2706 reply(0, "Upload commands (APPE, STOR, STOU): %sabled", 2707 CURCLASS_FLAGS_ISSET(upload) ? "en" : "dis"); 2708 reply(0, "Sanitize file names: %sabled", 2709 CURCLASS_FLAGS_ISSET(sanenames) ? "en" : "dis"); 2710 reply(0, "PASV/LPSV/EPSV connections: %sabled", 2711 CURCLASS_FLAGS_ISSET(passive) ? "en" : "dis"); 2712 if (curclass.advertise.su_len != 0) { 2713 char buf[50]; /* big enough for IPv6 address */ 2714 const char *bp; 2715 2716 bp = inet_ntop(curclass.advertise.su_family, 2717 (void *)&curclass.advertise.su_addr, 2718 buf, sizeof(buf)); 2719 if (bp != NULL) 2720 reply(0, "PASV advertise address: %s", bp); 2721 } 2722 if (curclass.portmin && curclass.portmax) 2723 reply(0, "PASV port range: " LLF " - " LLF, 2724 (LLT)curclass.portmin, (LLT)curclass.portmax); 2725 if (curclass.rateget) 2726 reply(0, "Rate get limit: " LLF " bytes/sec", 2727 (LLT)curclass.rateget); 2728 else 2729 reply(0, "Rate get limit: disabled"); 2730 if (curclass.rateput) 2731 reply(0, "Rate put limit: " LLF " bytes/sec", 2732 (LLT)curclass.rateput); 2733 else 2734 reply(0, "Rate put limit: disabled"); 2735 if (curclass.mmapsize) 2736 reply(0, "Mmap size: " LLF, (LLT)curclass.mmapsize); 2737 else 2738 reply(0, "Mmap size: disabled"); 2739 if (curclass.readsize) 2740 reply(0, "Read size: " LLF, (LLT)curclass.readsize); 2741 else 2742 reply(0, "Read size: default"); 2743 if (curclass.writesize) 2744 reply(0, "Write size: " LLF, (LLT)curclass.writesize); 2745 else 2746 reply(0, "Write size: default"); 2747 if (curclass.recvbufsize) 2748 reply(0, "Receive buffer size: " LLF, 2749 (LLT)curclass.recvbufsize); 2750 else 2751 reply(0, "Receive buffer size: default"); 2752 if (curclass.sendbufsize) 2753 reply(0, "Send buffer size: " LLF, 2754 (LLT)curclass.sendbufsize); 2755 else 2756 reply(0, "Send buffer size: default"); 2757 if (curclass.sendlowat) 2758 reply(0, "Send low water mark: " LLF, 2759 (LLT)curclass.sendlowat); 2760 else 2761 reply(0, "Send low water mark: default"); 2762 reply(0, "Umask: %.04o", curclass.umask); 2763 for (cp = curclass.conversions; cp != NULL; cp=cp->next) { 2764 if (cp->suffix == NULL || cp->types == NULL || 2765 cp->command == NULL) 2766 continue; 2767 reply(0, "Conversion: %s [%s] disable: %s, command: %s", 2768 cp->suffix, cp->types, cp->disable, cp->command); 2769 } 2770 } 2771 2772 reply(211, "End of status"); 2773} 2774 2775void 2776fatal(const char *s) 2777{ 2778 2779 reply(451, "Error in server: %s\n", s); 2780 reply(221, "Closing connection due to server error."); 2781 dologout(0); 2782 /* NOTREACHED */ 2783} 2784 2785/* 2786 * reply() -- 2787 * depending on the value of n, display fmt with a trailing CRLF and 2788 * prefix of: 2789 * n < -1 prefix the message with abs(n) + "-" (initial line) 2790 * n == 0 prefix the message with 4 spaces (middle lines) 2791 * n > 0 prefix the message with n + " " (final line) 2792 */ 2793void 2794reply(int n, const char *fmt, ...) 2795{ 2796 char msg[MAXPATHLEN * 2 + 100]; 2797 size_t b; 2798 va_list ap; 2799 2800 b = 0; 2801 if (n == 0) 2802 b = snprintf(msg, sizeof(msg), " "); 2803 else if (n < 0) 2804 b = snprintf(msg, sizeof(msg), "%d-", -n); 2805 else 2806 b = snprintf(msg, sizeof(msg), "%d ", n); 2807 va_start(ap, fmt); 2808 vsnprintf(msg + b, sizeof(msg) - b, fmt, ap); 2809 va_end(ap); 2810 cprintf(stdout, "%s\r\n", msg); 2811 (void)fflush(stdout); 2812 if (ftpd_debug) 2813 syslog(LOG_DEBUG, "<--- %s", msg); 2814} 2815 2816static void 2817logremotehost(struct sockinet *who) 2818{ 2819 2820 if (getnameinfo((struct sockaddr *)&who->si_su, 2821 who->su_len, remotehost, sizeof(remotehost), NULL, 0, 0)) 2822 strlcpy(remotehost, "?", sizeof(remotehost)); 2823 2824#if HAVE_SETPROCTITLE 2825 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost); 2826 setproctitle("%s", proctitle); 2827#endif /* HAVE_SETPROCTITLE */ 2828 if (logging) 2829 syslog(LOG_INFO, "connection from %s to %s", 2830 remotehost, hostname); 2831} 2832 2833/* 2834 * Record logout in wtmp file and exit with supplied status. 2835 * NOTE: because this is called from signal handlers it cannot 2836 * use stdio (or call other functions that use stdio). 2837 */ 2838void 2839dologout(int status) 2840{ 2841 /* 2842 * Prevent reception of SIGURG from resulting in a resumption 2843 * back to the main program loop. 2844 */ 2845 transflag = 0; 2846 logout_utmp(); 2847 if (logged_in) { 2848#ifdef KERBEROS 2849 if (!notickets && krbtkfile_env) 2850 unlink(krbtkfile_env); 2851#endif 2852 } 2853 /* beware of flushing buffers after a SIGPIPE */ 2854 if (xferlogfd != -1) 2855 close(xferlogfd); 2856 _exit(status); 2857} 2858 2859void 2860abor(void) 2861{ 2862 2863 if (!transflag) 2864 return; 2865 tmpline[0] = '\0'; 2866 is_oob = 0; 2867 reply(426, "Transfer aborted. Data connection closed."); 2868 reply(226, "Abort successful"); 2869 transflag = 0; /* flag that the transfer has aborted */ 2870} 2871 2872void 2873statxfer(void) 2874{ 2875 2876 if (!transflag) 2877 return; 2878 tmpline[0] = '\0'; 2879 is_oob = 0; 2880 if (file_size != (off_t) -1) 2881 reply(213, 2882 "Status: " LLF " of " LLF " byte%s transferred", 2883 (LLT)byte_count, (LLT)file_size, 2884 PLURAL(byte_count)); 2885 else 2886 reply(213, "Status: " LLF " byte%s transferred", 2887 (LLT)byte_count, PLURAL(byte_count)); 2888} 2889 2890/* 2891 * Call when urgflag != 0 to handle Out Of Band commands. 2892 * Returns non zero if the OOB command aborted the transfer 2893 * by setting transflag to 0. (c.f., "ABOR"). 2894 */ 2895static int 2896handleoobcmd() 2897{ 2898 char *cp; 2899 int ret; 2900 2901 if (!urgflag) 2902 return (0); 2903 urgflag = 0; 2904 /* only process if transfer occurring */ 2905 if (!transflag) 2906 return (0); 2907 cp = tmpline; 2908 ret = getline(cp, sizeof(tmpline)-1, stdin); 2909 if (ret == -1) { 2910 reply(221, "You could at least say goodbye."); 2911 dologout(0); 2912 } else if (ret == -2) { 2913 /* Ignore truncated command */ 2914 /* XXX: abort xfer with "500 command too long", & return 1 ? */ 2915 return 0; 2916 } 2917 /* 2918 * Manually parse OOB commands, because we can't 2919 * recursively call the yacc parser... 2920 */ 2921 if (strcasecmp(cp, "ABOR\r\n") == 0) { 2922 abor(); 2923 } else if (strcasecmp(cp, "STAT\r\n") == 0) { 2924 statxfer(); 2925 } else { 2926 /* XXX: error with "500 unknown command" ? */ 2927 } 2928 return (transflag == 0); 2929} 2930 2931static int 2932bind_pasv_addr(void) 2933{ 2934 static int passiveport; 2935 int port, len; 2936 2937 len = pasv_addr.su_len; 2938 if (curclass.portmin == 0 && curclass.portmax == 0) { 2939 pasv_addr.su_port = 0; 2940 return (bind(pdata, (struct sockaddr *)&pasv_addr.si_su, len)); 2941 } 2942 2943 if (passiveport == 0) { 2944 srand(getpid()); 2945 passiveport = rand() % (curclass.portmax - curclass.portmin) 2946 + curclass.portmin; 2947 } 2948 2949 port = passiveport; 2950 while (1) { 2951 port++; 2952 if (port > curclass.portmax) 2953 port = curclass.portmin; 2954 else if (port == passiveport) { 2955 errno = EAGAIN; 2956 return (-1); 2957 } 2958 pasv_addr.su_port = htons(port); 2959 if (bind(pdata, (struct sockaddr *)&pasv_addr.si_su, len) == 0) 2960 break; 2961 if (errno != EADDRINUSE) 2962 return (-1); 2963 } 2964 passiveport = port; 2965 return (0); 2966} 2967 2968/* 2969 * Note: a response of 425 is not mentioned as a possible response to 2970 * the PASV command in RFC959. However, it has been blessed as 2971 * a legitimate response by Jon Postel in a telephone conversation 2972 * with Rick Adams on 25 Jan 89. 2973 */ 2974void 2975passive(void) 2976{ 2977 socklen_t len, recvbufsize; 2978 char *p, *a; 2979 2980 if (pdata >= 0) 2981 close(pdata); 2982 pdata = socket(AF_INET, SOCK_STREAM, 0); 2983 if (pdata < 0 || !logged_in) { 2984 perror_reply(425, "Can't open passive connection"); 2985 return; 2986 } 2987 pasv_addr = ctrl_addr; 2988 2989 if (bind_pasv_addr() < 0) 2990 goto pasv_error; 2991 len = pasv_addr.su_len; 2992 if (getsockname(pdata, (struct sockaddr *) &pasv_addr.si_su, &len) < 0) 2993 goto pasv_error; 2994 pasv_addr.su_len = len; 2995 if (curclass.recvbufsize) { 2996 recvbufsize = curclass.recvbufsize; 2997 if (setsockopt(pdata, SOL_SOCKET, SO_RCVBUF, &recvbufsize, 2998 sizeof(int)) == -1) 2999 syslog(LOG_WARNING, "setsockopt(SO_RCVBUF, %d): %m", 3000 recvbufsize); 3001 } 3002 if (listen(pdata, 1) < 0) 3003 goto pasv_error; 3004 if (curclass.advertise.su_len != 0) 3005 a = (char *) &curclass.advertise.su_addr; 3006 else 3007 a = (char *) &pasv_addr.su_addr; 3008 p = (char *) &pasv_addr.su_port; 3009 3010#define UC(b) (((int) b) & 0xff) 3011 3012 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), 3013 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 3014 return; 3015 3016 pasv_error: 3017 (void) close(pdata); 3018 pdata = -1; 3019 perror_reply(425, "Can't open passive connection"); 3020 return; 3021} 3022 3023/* 3024 * convert protocol identifier to/from AF 3025 */ 3026int 3027lpsvproto2af(int proto) 3028{ 3029 3030 switch (proto) { 3031 case 4: 3032 return AF_INET; 3033#ifdef INET6 3034 case 6: 3035 return AF_INET6; 3036#endif 3037 default: 3038 return -1; 3039 } 3040} 3041 3042int 3043af2lpsvproto(int af) 3044{ 3045 3046 switch (af) { 3047 case AF_INET: 3048 return 4; 3049#ifdef INET6 3050 case AF_INET6: 3051 return 6; 3052#endif 3053 default: 3054 return -1; 3055 } 3056} 3057 3058int 3059epsvproto2af(int proto) 3060{ 3061 3062 switch (proto) { 3063 case 1: 3064 return AF_INET; 3065#ifdef INET6 3066 case 2: 3067 return AF_INET6; 3068#endif 3069 default: 3070 return -1; 3071 } 3072} 3073 3074int 3075af2epsvproto(int af) 3076{ 3077 3078 switch (af) { 3079 case AF_INET: 3080 return 1; 3081#ifdef INET6 3082 case AF_INET6: 3083 return 2; 3084#endif 3085 default: 3086 return -1; 3087 } 3088} 3089 3090/* 3091 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...) 3092 * 229 Entering Extended Passive Mode (|||port|) 3093 */ 3094void 3095long_passive(char *cmd, int pf) 3096{ 3097 socklen_t len; 3098 char *p, *a; 3099 3100 if (!logged_in) { 3101 syslog(LOG_NOTICE, "long passive but not logged in"); 3102 reply(503, "Login with USER first."); 3103 return; 3104 } 3105 3106 if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) { 3107 /* 3108 * XXX: only EPRT/EPSV ready clients will understand this 3109 */ 3110 if (strcmp(cmd, "EPSV") != 0) 3111 reply(501, "Network protocol mismatch"); /*XXX*/ 3112 else 3113 epsv_protounsupp("Network protocol mismatch"); 3114 3115 return; 3116 } 3117 3118 if (pdata >= 0) 3119 close(pdata); 3120 pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0); 3121 if (pdata < 0) { 3122 perror_reply(425, "Can't open passive connection"); 3123 return; 3124 } 3125 pasv_addr = ctrl_addr; 3126 if (bind_pasv_addr() < 0) 3127 goto pasv_error; 3128 len = pasv_addr.su_len; 3129 if (getsockname(pdata, (struct sockaddr *) &pasv_addr.si_su, &len) < 0) 3130 goto pasv_error; 3131 pasv_addr.su_len = len; 3132 if (listen(pdata, 1) < 0) 3133 goto pasv_error; 3134 p = (char *) &pasv_addr.su_port; 3135 3136#define UC(b) (((int) b) & 0xff) 3137 3138 if (strcmp(cmd, "LPSV") == 0) { 3139 struct sockinet *advert; 3140 3141 if (curclass.advertise.su_len != 0) 3142 advert = &curclass.advertise; 3143 else 3144 advert = &pasv_addr; 3145 switch (advert->su_family) { 3146 case AF_INET: 3147 a = (char *) &advert->su_addr; 3148 reply(228, 3149 "Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d)", 3150 4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 3151 2, UC(p[0]), UC(p[1])); 3152 return; 3153#ifdef INET6 3154 case AF_INET6: 3155 a = (char *) &advert->su_6addr; 3156 reply(228, 3157 "Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)", 3158 6, 16, 3159 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 3160 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]), 3161 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]), 3162 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]), 3163 2, UC(p[0]), UC(p[1])); 3164 return; 3165#endif 3166 } 3167#undef UC 3168 } else if (strcmp(cmd, "EPSV") == 0) { 3169 switch (pasv_addr.su_family) { 3170 case AF_INET: 3171#ifdef INET6 3172 case AF_INET6: 3173#endif 3174 reply(229, "Entering Extended Passive Mode (|||%d|)", 3175 ntohs(pasv_addr.su_port)); 3176 return; 3177 } 3178 } else { 3179 /* more proper error code? */ 3180 } 3181 3182 pasv_error: 3183 (void) close(pdata); 3184 pdata = -1; 3185 perror_reply(425, "Can't open passive connection"); 3186 return; 3187} 3188 3189int 3190extended_port(const char *arg) 3191{ 3192 char *tmp = NULL; 3193 char *result[3]; 3194 char *p, *q; 3195 char delim; 3196 struct addrinfo hints; 3197 struct addrinfo *res = NULL; 3198 int i; 3199 unsigned long proto; 3200 3201 tmp = ftpd_strdup(arg); 3202 p = tmp; 3203 delim = p[0]; 3204 p++; 3205 memset(result, 0, sizeof(result)); 3206 for (i = 0; i < 3; i++) { 3207 q = strchr(p, delim); 3208 if (!q || *q != delim) 3209 goto parsefail; 3210 *q++ = '\0'; 3211 result[i] = p; 3212 p = q; 3213 } 3214 3215 /* some more sanity checks */ 3216 errno = 0; 3217 p = NULL; 3218 (void)strtoul(result[2], &p, 10); 3219 if (errno || !*result[2] || *p) 3220 goto parsefail; 3221 errno = 0; 3222 p = NULL; 3223 proto = strtoul(result[0], &p, 10); 3224 if (errno || !*result[0] || *p) 3225 goto protounsupp; 3226 3227 memset(&hints, 0, sizeof(hints)); 3228 hints.ai_family = epsvproto2af((int)proto); 3229 if (hints.ai_family < 0) 3230 goto protounsupp; 3231 hints.ai_socktype = SOCK_STREAM; 3232 hints.ai_flags = AI_NUMERICHOST; 3233 if (getaddrinfo(result[1], result[2], &hints, &res)) 3234 goto parsefail; 3235 if (res->ai_next) 3236 goto parsefail; 3237 if (sizeof(data_dest) < res->ai_addrlen) 3238 goto parsefail; 3239 memcpy(&data_dest.si_su, res->ai_addr, res->ai_addrlen); 3240 data_dest.su_len = res->ai_addrlen; 3241#ifdef INET6 3242 if (his_addr.su_family == AF_INET6 && 3243 data_dest.su_family == AF_INET6) { 3244 /* XXX: more sanity checks! */ 3245 data_dest.su_scope_id = his_addr.su_scope_id; 3246 } 3247#endif 3248 3249 if (tmp != NULL) 3250 free(tmp); 3251 if (res) 3252 freeaddrinfo(res); 3253 return 0; 3254 3255 parsefail: 3256 reply(500, "Invalid argument, rejected."); 3257 usedefault = 1; 3258 if (tmp != NULL) 3259 free(tmp); 3260 if (res) 3261 freeaddrinfo(res); 3262 return -1; 3263 3264 protounsupp: 3265 epsv_protounsupp("Protocol not supported"); 3266 usedefault = 1; 3267 if (tmp != NULL) 3268 free(tmp); 3269 return -1; 3270} 3271 3272/* 3273 * 522 Protocol not supported (proto,...) 3274 * as we assume address family for control and data connections are the same, 3275 * we do not return the list of address families we support - instead, we 3276 * return the address family of the control connection. 3277 */ 3278void 3279epsv_protounsupp(const char *message) 3280{ 3281 int proto; 3282 3283 proto = af2epsvproto(ctrl_addr.su_family); 3284 if (proto < 0) 3285 reply(501, "%s", message); /* XXX */ 3286 else 3287 reply(522, "%s, use (%d)", message, proto); 3288} 3289 3290/* 3291 * Generate unique name for file with basename "local". 3292 * The file named "local" is already known to exist. 3293 * Generates failure reply on error. 3294 * 3295 * XXX: this function should under go changes similar to 3296 * the mktemp(3)/mkstemp(3) changes. 3297 */ 3298static char * 3299gunique(const char *local) 3300{ 3301 static char new[MAXPATHLEN]; 3302 struct stat st; 3303 char *cp; 3304 int count; 3305 3306 cp = strrchr(local, '/'); 3307 if (cp) 3308 *cp = '\0'; 3309 if (stat(cp ? local : ".", &st) < 0) { 3310 perror_reply(553, cp ? local : "."); 3311 return (NULL); 3312 } 3313 if (cp) 3314 *cp = '/'; 3315 for (count = 1; count < 100; count++) { 3316 (void)snprintf(new, sizeof(new) - 1, "%s.%d", local, count); 3317 if (stat(new, &st) < 0) 3318 return (new); 3319 } 3320 reply(452, "Unique file name cannot be created."); 3321 return (NULL); 3322} 3323 3324/* 3325 * Format and send reply containing system error number. 3326 */ 3327void 3328perror_reply(int code, const char *string) 3329{ 3330 int save_errno; 3331 3332 save_errno = errno; 3333 reply(code, "%s: %s.", string, strerror(errno)); 3334 errno = save_errno; 3335} 3336 3337static char *onefile[] = { 3338 "", 3339 0 3340}; 3341 3342void 3343send_file_list(const char *whichf) 3344{ 3345 struct stat st; 3346 DIR *dirp = NULL; 3347 struct dirent *dir; 3348 FILE *dout = NULL; 3349 char **dirlist, *dirname, *p; 3350 char *notglob = NULL; 3351 int simple = 0; 3352 int freeglob = 0; 3353 glob_t gl; 3354 3355#ifdef __GNUC__ 3356 (void) &dout; 3357 (void) &dirlist; 3358 (void) &simple; 3359 (void) &freeglob; 3360#endif 3361 urgflag = 0; 3362 3363 p = NULL; 3364 if (strpbrk(whichf, "~{[*?") != NULL) { 3365 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE|GLOB_LIMIT; 3366 3367 memset(&gl, 0, sizeof(gl)); 3368 freeglob = 1; 3369 if (glob(whichf, flags, 0, &gl)) { 3370 reply(450, "Not found"); 3371 goto cleanup_send_file_list; 3372 } else if (gl.gl_pathc == 0) { 3373 errno = ENOENT; 3374 perror_reply(450, whichf); 3375 goto cleanup_send_file_list; 3376 } 3377 dirlist = gl.gl_pathv; 3378 } else { 3379 notglob = ftpd_strdup(whichf); 3380 onefile[0] = notglob; 3381 dirlist = onefile; 3382 simple = 1; 3383 } 3384 /* XXX: } for vi sm */ 3385 3386 while ((dirname = *dirlist++) != NULL) { 3387 int trailingslash = 0; 3388 3389 if (stat(dirname, &st) < 0) { 3390 /* 3391 * If user typed "ls -l", etc, and the client 3392 * used NLST, do what the user meant. 3393 */ 3394 /* XXX: nuke this support? */ 3395 if (dirname[0] == '-' && *dirlist == NULL && 3396 transflag == 0) { 3397 char *argv[] = { INTERNAL_LS, "", NULL }; 3398 3399 argv[1] = dirname; 3400 retrieve(argv, dirname); 3401 goto cleanup_send_file_list; 3402 } 3403 perror_reply(450, whichf); 3404 goto cleanup_send_file_list; 3405 } 3406 3407 if (S_ISREG(st.st_mode)) { 3408 /* 3409 * XXXRFC: 3410 * should we follow RFC959 and not work 3411 * for non directories? 3412 */ 3413 if (dout == NULL) { 3414 dout = dataconn("file list", (off_t)-1, "w"); 3415 if (dout == NULL) 3416 goto cleanup_send_file_list; 3417 transflag = 1; 3418 } 3419 cprintf(dout, "%s%s\n", dirname, 3420 type == TYPE_A ? "\r" : ""); 3421 continue; 3422 } else if (!S_ISDIR(st.st_mode)) 3423 continue; 3424 3425 if (dirname[strlen(dirname) - 1] == '/') 3426 trailingslash++; 3427 3428 if ((dirp = opendir(dirname)) == NULL) 3429 continue; 3430 3431 while ((dir = readdir(dirp)) != NULL) { 3432 char nbuf[MAXPATHLEN]; 3433 3434 if (urgflag && handleoobcmd()) 3435 goto cleanup_send_file_list; 3436 3437 if (ISDOTDIR(dir->d_name) || ISDOTDOTDIR(dir->d_name)) 3438 continue; 3439 3440 (void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname, 3441 trailingslash ? "" : "/", dir->d_name); 3442 3443 /* 3444 * We have to do a stat to ensure it's 3445 * not a directory or special file. 3446 */ 3447 /* 3448 * XXXRFC: 3449 * should we follow RFC959 and filter out 3450 * non files ? lukem - NO!, or not until 3451 * our ftp client uses MLS{T,D} for completion. 3452 */ 3453 if (simple || (stat(nbuf, &st) == 0 && 3454 S_ISREG(st.st_mode))) { 3455 if (dout == NULL) { 3456 dout = dataconn("file list", (off_t)-1, 3457 "w"); 3458 if (dout == NULL) 3459 goto cleanup_send_file_list; 3460 transflag = 1; 3461 } 3462 p = nbuf; 3463 if (nbuf[0] == '.' && nbuf[1] == '/') 3464 p = &nbuf[2]; 3465 cprintf(dout, "%s%s\n", p, 3466 type == TYPE_A ? "\r" : ""); 3467 } 3468 } 3469 (void) closedir(dirp); 3470 } 3471 3472 if (dout == NULL) 3473 reply(450, "No files found."); 3474 else if (ferror(dout) != 0) 3475 perror_reply(451, "Data connection"); 3476 else 3477 reply(226, "Transfer complete."); 3478 3479 cleanup_send_file_list: 3480 closedataconn(dout); 3481 transflag = 0; 3482 urgflag = 0; 3483 total_xfers++; 3484 total_xfers_out++; 3485 if (notglob) 3486 free(notglob); 3487 if (freeglob) 3488 globfree(&gl); 3489} 3490 3491char * 3492conffilename(const char *s) 3493{ 3494 static char filename[MAXPATHLEN]; 3495 3496 if (*s == '/') 3497 strlcpy(filename, s, sizeof(filename)); 3498 else 3499 (void)snprintf(filename, sizeof(filename), "%s/%s", confdir ,s); 3500 return (filename); 3501} 3502 3503/* 3504 * logxfer -- 3505 * if logging > 1, then based on the arguments, syslog a message: 3506 * if bytes != -1 "<command> <file1> = <bytes> bytes" 3507 * else if file2 != NULL "<command> <file1> <file2>" 3508 * else "<command> <file1>" 3509 * if elapsed != NULL, append "in xxx.yyy seconds" 3510 * if error != NULL, append ": " + error 3511 * 3512 * if doxferlog != 0, bytes != -1, and command is "get", "put", 3513 * or "append", syslog and/or write a wu-ftpd style xferlog entry 3514 */ 3515void 3516logxfer(const char *command, off_t bytes, const char *file1, const char *file2, 3517 const struct timeval *elapsed, const char *error) 3518{ 3519 char buf[MAXPATHLEN * 2 + 100]; 3520 char realfile1[MAXPATHLEN], realfile2[MAXPATHLEN]; 3521 const char *r1, *r2; 3522 char direction; 3523 size_t len; 3524 time_t now; 3525 3526 if (logging <=1 && !doxferlog) 3527 return; 3528 3529 r1 = r2 = NULL; 3530 if ((r1 = realpath(file1, realfile1)) == NULL) 3531 r1 = file1; 3532 if (file2 != NULL) 3533 if ((r2 = realpath(file2, realfile2)) == NULL) 3534 r2 = file2; 3535 3536 /* 3537 * syslog command 3538 */ 3539 if (logging > 1) { 3540 len = snprintf(buf, sizeof(buf), "%s %s", command, r1); 3541 if (bytes != (off_t)-1) 3542 len += snprintf(buf + len, sizeof(buf) - len, 3543 " = " LLF " byte%s", (LLT) bytes, PLURAL(bytes)); 3544 else if (r2 != NULL) 3545 len += snprintf(buf + len, sizeof(buf) - len, 3546 " %s", r2); 3547 if (elapsed != NULL) 3548 len += snprintf(buf + len, sizeof(buf) - len, 3549 " in %ld.%.03d seconds", elapsed->tv_sec, 3550 (int)(elapsed->tv_usec / 1000)); 3551 if (error != NULL) 3552 len += snprintf(buf + len, sizeof(buf) - len, 3553 ": %s", error); 3554 syslog(LOG_INFO, "%s", buf); 3555 } 3556 3557 /* 3558 * syslog wu-ftpd style log entry, prefixed with "xferlog: " 3559 */ 3560 if (!doxferlog || bytes == -1) 3561 return; 3562 3563 if (strcmp(command, "get") == 0) 3564 direction = 'o'; 3565 else if (strcmp(command, "put") == 0 || strcmp(command, "append") == 0) 3566 direction = 'i'; 3567 else 3568 return; 3569 3570 time(&now); 3571 len = snprintf(buf, sizeof(buf), 3572 "%.24s %ld %s " LLF " %s %c %s %c %c %s FTP 0 * %c\n", 3573 3574/* 3575 * XXX: wu-ftpd puts ' (send)' or ' (recv)' in the syslog message, and removes 3576 * the full date. This may be problematic for accurate log parsing, 3577 * given that syslog messages don't contain the full date. 3578 */ 3579 ctime(&now), 3580 elapsed == NULL ? 0 : elapsed->tv_sec + (elapsed->tv_usec > 0), 3581 remotehost, 3582 (LLT) bytes, 3583 r1, 3584 type == TYPE_A ? 'a' : 'b', 3585 "_", /* XXX: take conversions into account? */ 3586 direction, 3587 3588 curclass.type == CLASS_GUEST ? 'a' : 3589 curclass.type == CLASS_CHROOT ? 'g' : 3590 curclass.type == CLASS_REAL ? 'r' : '?', 3591 3592 curclass.type == CLASS_GUEST ? pw->pw_passwd : pw->pw_name, 3593 error != NULL ? 'i' : 'c' 3594 ); 3595 3596 if ((doxferlog & 2) && xferlogfd != -1) 3597 write(xferlogfd, buf, len); 3598 if ((doxferlog & 1)) { 3599 buf[len-1] = '\n'; /* strip \n from syslog message */ 3600 syslog(LOG_INFO, "xferlog: %s", buf); 3601 } 3602} 3603 3604/* 3605 * Log the resource usage. 3606 * 3607 * XXX: more resource usage to logging? 3608 */ 3609void 3610logrusage(const struct rusage *rusage_before, 3611 const struct rusage *rusage_after) 3612{ 3613 struct timeval usrtime, systime; 3614 3615 if (logging <= 1) 3616 return; 3617 3618 timersub(&rusage_after->ru_utime, &rusage_before->ru_utime, &usrtime); 3619 timersub(&rusage_after->ru_stime, &rusage_before->ru_stime, &systime); 3620 syslog(LOG_INFO, "%ld.%.03du %ld.%.03ds %ld+%ldio %ldpf+%ldw", 3621 usrtime.tv_sec, (int)(usrtime.tv_usec / 1000), 3622 systime.tv_sec, (int)(systime.tv_usec / 1000), 3623 rusage_after->ru_inblock - rusage_before->ru_inblock, 3624 rusage_after->ru_oublock - rusage_before->ru_oublock, 3625 rusage_after->ru_majflt - rusage_before->ru_majflt, 3626 rusage_after->ru_nswap - rusage_before->ru_nswap); 3627} 3628 3629/* 3630 * Determine if `password' is valid for user given in `pw'. 3631 * Returns 2 if password expired, 1 if otherwise failed, 0 if ok 3632 */ 3633int 3634checkpassword(const struct passwd *pwent, const char *password) 3635{ 3636 char *orig, *new; 3637 time_t change, expire, now; 3638 3639 change = expire = 0; 3640 if (pwent == NULL) 3641 return 1; 3642 3643 time(&now); 3644 orig = pwent->pw_passwd; /* save existing password */ 3645 expire = pwent->pw_expire; 3646 change = (pwent->pw_change == _PASSWORD_CHGNOW)? now : pwent->pw_change; 3647 3648 if (orig[0] == '\0') /* don't allow empty passwords */ 3649 return 1; 3650 3651 new = crypt(password, orig); /* encrypt given password */ 3652 if (strcmp(new, orig) != 0) /* compare */ 3653 return 1; 3654 3655 if ((expire && now >= expire) || (change && now >= change)) 3656 return 2; /* check if expired */ 3657 3658 return 0; /* OK! */ 3659} 3660 3661char * 3662ftpd_strdup(const char *s) 3663{ 3664 char *new = strdup(s); 3665 3666 if (new == NULL) 3667 fatal("Local resource failure: malloc"); 3668 /* NOTREACHED */ 3669 return (new); 3670} 3671 3672/* 3673 * As per fprintf(), but increment total_bytes and total_bytes_out, 3674 * by the appropriate amount. 3675 */ 3676void 3677cprintf(FILE *fd, const char *fmt, ...) 3678{ 3679 off_t b; 3680 va_list ap; 3681 3682 va_start(ap, fmt); 3683 b = vfprintf(fd, fmt, ap); 3684 va_end(ap); 3685 total_bytes += b; 3686 total_bytes_out += b; 3687} 3688 3689#ifdef USE_PAM 3690/* 3691 * the following code is stolen from imap-uw PAM authentication module and 3692 * login.c 3693 */ 3694#define COPY_STRING(s) (s ? strdup(s) : NULL) 3695 3696struct cred_t { 3697 const char *uname; /* user name */ 3698 const char *pass; /* password */ 3699}; 3700typedef struct cred_t cred_t; 3701 3702static int 3703auth_conv(int num_msg, const struct pam_message **msg, 3704 struct pam_response **resp, void *appdata) 3705{ 3706 int i; 3707 cred_t *cred = (cred_t *) appdata; 3708 struct pam_response *myreply; 3709 3710 myreply = calloc(num_msg, sizeof *myreply); 3711 if (myreply == NULL) 3712 return PAM_BUF_ERR; 3713 3714 for (i = 0; i < num_msg; i++) { 3715 switch (msg[i]->msg_style) { 3716 case PAM_PROMPT_ECHO_ON: /* assume want user name */ 3717 myreply[i].resp_retcode = PAM_SUCCESS; 3718 myreply[i].resp = COPY_STRING(cred->uname); 3719 /* PAM frees resp. */ 3720 break; 3721 case PAM_PROMPT_ECHO_OFF: /* assume want password */ 3722 myreply[i].resp_retcode = PAM_SUCCESS; 3723 myreply[i].resp = COPY_STRING(cred->pass); 3724 /* PAM frees resp. */ 3725 break; 3726 case PAM_TEXT_INFO: 3727 case PAM_ERROR_MSG: 3728 myreply[i].resp_retcode = PAM_SUCCESS; 3729 myreply[i].resp = NULL; 3730 break; 3731 default: /* unknown message style */ 3732 free(myreply); 3733 return PAM_CONV_ERR; 3734 } 3735 } 3736 3737 *resp = myreply; 3738 return PAM_SUCCESS; 3739} 3740 3741/* 3742 * Attempt to authenticate the user using PAM. Returns 0 if the user is 3743 * authenticated, or 1 if not authenticated. If some sort of PAM system 3744 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this 3745 * function returns -1. This can be used as an indication that we should 3746 * fall back to a different authentication mechanism. 3747 */ 3748static int 3749auth_pam(struct passwd **ppw, const char *pwstr) 3750{ 3751 const char *tmpl_user; 3752 const void *item; 3753 int rval; 3754 int e; 3755 cred_t auth_cred = { (*ppw)->pw_name, pwstr }; 3756 struct pam_conv conv = { &auth_conv, &auth_cred }; 3757 3758 e = pam_start("ftpd", (*ppw)->pw_name, &conv, &pamh); 3759 if (e != PAM_SUCCESS) { 3760 /* 3761 * In OpenPAM, it's OK to pass NULL to pam_strerror() 3762 * if context creation has failed in the first place. 3763 */ 3764 syslog(LOG_ERR, "pam_start: %s", pam_strerror(NULL, e)); 3765 return -1; 3766 } 3767 3768 e = pam_set_item(pamh, PAM_RHOST, remotehost); 3769 if (e != PAM_SUCCESS) { 3770 syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s", 3771 pam_strerror(pamh, e)); 3772 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) { 3773 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); 3774 } 3775 pamh = NULL; 3776 return -1; 3777 } 3778 3779 e = pam_authenticate(pamh, 0); 3780 switch (e) { 3781 case PAM_SUCCESS: 3782 /* 3783 * With PAM we support the concept of a "template" 3784 * user. The user enters a login name which is 3785 * authenticated by PAM, usually via a remote service 3786 * such as RADIUS or TACACS+. If authentication 3787 * succeeds, a different but related "template" name 3788 * is used for setting the credentials, shell, and 3789 * home directory. The name the user enters need only 3790 * exist on the remote authentication server, but the 3791 * template name must be present in the local password 3792 * database. 3793 * 3794 * This is supported by two various mechanisms in the 3795 * individual modules. However, from the application's 3796 * point of view, the template user is always passed 3797 * back as a changed value of the PAM_USER item. 3798 */ 3799 if ((e = pam_get_item(pamh, PAM_USER, &item)) == 3800 PAM_SUCCESS) { 3801 tmpl_user = (const char *) item; 3802 if (strcmp((*ppw)->pw_name, tmpl_user) != 0) 3803 *ppw = sgetpwnam(tmpl_user); 3804 } else 3805 syslog(LOG_ERR, "Couldn't get PAM_USER: %s", 3806 pam_strerror(pamh, e)); 3807 rval = 0; 3808 break; 3809 3810 case PAM_AUTH_ERR: 3811 case PAM_USER_UNKNOWN: 3812 case PAM_MAXTRIES: 3813 rval = 1; 3814 break; 3815 3816 default: 3817 syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e)); 3818 rval = -1; 3819 break; 3820 } 3821 3822 if (rval == 0) { 3823 e = pam_acct_mgmt(pamh, 0); 3824 if (e != PAM_SUCCESS) { 3825 syslog(LOG_ERR, "pam_acct_mgmt: %s", 3826 pam_strerror(pamh, e)); 3827 rval = 1; 3828 } 3829 } 3830 3831 if (rval != 0) { 3832 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) { 3833 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); 3834 } 3835 pamh = NULL; 3836 } 3837 return rval; 3838} 3839 3840#endif /* USE_PAM */ 3841