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