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