ftpd.c revision 1.13
1104477Ssam/* $OpenBSD: ftpd.c,v 1.13 1996/08/08 16:22:37 downsj Exp $ */ 2104477Ssam/* $NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $ */ 3104477Ssam 4139749Simp/* 5104477Ssam * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994 6104477Ssam * The Regents of the University of California. All rights reserved. 7104477Ssam * 8104477Ssam * Redistribution and use in source and binary forms, with or without 9104477Ssam * modification, are permitted provided that the following conditions 10104477Ssam * are met: 11104477Ssam * 1. Redistributions of source code must retain the above copyright 12104477Ssam * notice, this list of conditions and the following disclaimer. 13104477Ssam * 2. Redistributions in binary form must reproduce the above copyright 14104477Ssam * notice, this list of conditions and the following disclaimer in the 15104477Ssam * documentation and/or other materials provided with the distribution. 16104477Ssam * 3. All advertising materials mentioning features or use of this software 17104477Ssam * must display the following acknowledgement: 18104477Ssam * This product includes software developed by the University of 19104477Ssam * California, Berkeley and its contributors. 20104477Ssam * 4. Neither the name of the University nor the names of its contributors 21104477Ssam * may be used to endorse or promote products derived from this software 22104477Ssam * without specific prior written permission. 23104477Ssam * 24104477Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25104477Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26104477Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27104477Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28104477Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29104477Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30104477Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31104477Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32104477Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33104477Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34104477Ssam * SUCH DAMAGE. 35104477Ssam */ 36104477Ssam 37104477Ssam#ifndef lint 38104477Ssamstatic char copyright[] = 39104477Ssam"@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\ 40104477Ssam The Regents of the University of California. All rights reserved.\n"; 41104477Ssam#endif /* not lint */ 42104477Ssam 43104477Ssam#ifndef lint 44104477Ssam#if 0 45104477Ssamstatic char sccsid[] = "@(#)ftpd.c 8.4 (Berkeley) 4/16/94"; 46104477Ssam#else 47104477Ssamstatic char rcsid[] = "$NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $"; 48104477Ssam#endif 49104477Ssam#endif /* not lint */ 50104477Ssam 51104477Ssam/* 52104477Ssam * FTP server. 53104477Ssam */ 54104477Ssam#include <sys/param.h> 55104477Ssam#include <sys/stat.h> 56104477Ssam#include <sys/ioctl.h> 57104477Ssam#include <sys/socket.h> 58104477Ssam#include <sys/wait.h> 59104477Ssam#include <sys/mman.h> 60104477Ssam 61104477Ssam#include <netinet/in.h> 62104477Ssam#include <netinet/in_systm.h> 63104477Ssam#include <netinet/ip.h> 64104477Ssam#include <netinet/tcp.h> 65104477Ssam 66104477Ssam#define FTP_NAMES 67104477Ssam#include <arpa/ftp.h> 68104477Ssam#include <arpa/inet.h> 69104477Ssam#include <arpa/telnet.h> 70120915Ssam 71120915Ssam#include <ctype.h> 72104477Ssam#include <dirent.h> 73104477Ssam#include <err.h> 74104477Ssam#include <errno.h> 75104477Ssam#include <fcntl.h> 76104477Ssam#include <glob.h> 77104477Ssam#include <limits.h> 78104477Ssam#include <netdb.h> 79104477Ssam#include <pwd.h> 80104477Ssam#include <setjmp.h> 81104477Ssam#include <signal.h> 82104477Ssam#include <stdio.h> 83104477Ssam#include <stdlib.h> 84213091Sgonzo#include <string.h> 85213091Sgonzo#include <syslog.h> 86104477Ssam#include <time.h> 87104477Ssam#include <unistd.h> 88104477Ssam#include <utmp.h> 89104477Ssam 90104477Ssam#include "pathnames.h" 91104477Ssam#include "extern.h" 92104477Ssam 93104477Ssam#if __STDC__ 94104477Ssam#include <stdarg.h> 95104477Ssam#else 96104477Ssam#include <varargs.h> 97104477Ssam#endif 98104477Ssam 99104477Ssamstatic char version[] = "Version 6.1/OpenBSD"; 100104477Ssam 101104477Ssamextern off_t restart_point; 102213091Sgonzoextern char cbuf[]; 103104477Ssam 104104477Ssamstruct sockaddr_in server_addr; 105104477Ssamstruct sockaddr_in ctrl_addr; 106136526Ssamstruct sockaddr_in data_source; 107158705Spjdstruct sockaddr_in data_dest; 108120915Ssamstruct sockaddr_in his_addr; 109104477Ssamstruct sockaddr_in pasv_addr; 110104477Ssam 111104477Ssamint daemon_mode = 0; 112104477Ssamint data; 113104477Ssamjmp_buf errcatch, urgcatch; 114104477Ssamint logged_in; 115104477Ssamstruct passwd *pw; 116104477Ssamint debug = 0; 117104477Ssamint timeout = 900; /* timeout after 15 minutes of inactivity */ 118104477Ssamint maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ 119104477Ssamint logging; 120104477Ssamint high_data_ports = 0; 121104477Ssamint guest; 122104477Ssamint stats; 123104477Ssamint statfd = -1; 124104477Ssamint dochroot; 125104477Ssamint type; 126104477Ssamint form; 127104477Ssamint stru; /* avoid C keyword */ 128104477Ssamint mode; 129104477Ssamint doutmp = 0; /* update utmp file */ 130104477Ssamint usedefault = 1; /* for data transfers */ 131104477Ssamint pdata = -1; /* for passive mode */ 132104477Ssamsig_atomic_t transflag; 133104477Ssamoff_t file_size; 134104477Ssamoff_t byte_count; 135104477Ssam#if !defined(CMASK) || CMASK == 0 136104477Ssam#undef CMASK 137104477Ssam#define CMASK 027 138104477Ssam#endif 139104477Ssamint defumask = CMASK; /* default umask value */ 140104477Ssamchar tmpline[7]; 141104477Ssamchar hostname[MAXHOSTNAMELEN]; 142104477Ssamchar remotehost[MAXHOSTNAMELEN]; 143104477Ssamstatic char ttyline[20]; 144104477Ssamchar *tty = ttyline; /* for klogin */ 145140480Ssamstatic struct utmp utmp; /* for utmp */ 146104477Ssam 147104477Ssam#if defined(KERBEROS) 148104477Ssamint notickets = 1; 149104477Ssamchar *krbtkfile_env = NULL; 150104477Ssam#endif 151104477Ssam 152213091Sgonzochar *ident = NULL; 153213091Sgonzo 154213091Sgonzo 155213091Sgonzo/* 156213091Sgonzo * Timeout intervals for retrying connections 157213091Sgonzo * to hosts that don't accept PORT cmds. This 158213091Sgonzo * is a kludge, but given the problems with TCP... 159213091Sgonzo */ 160213091Sgonzo#define SWAITMAX 90 /* wait at most 90 seconds */ 161104477Ssam#define SWAITINT 5 /* interval between retries */ 162104477Ssam 163136526Ssamint swaitmax = SWAITMAX; 164136526Ssamint swaitint = SWAITINT; 165104477Ssam 166104477Ssam#ifdef HASSETPROCTITLE 167104477Ssamchar proctitle[BUFSIZ]; /* initial part of title */ 168104477Ssam#endif /* HASSETPROCTITLE */ 169120915Ssam 170120915Ssam#define LOGCMD(cmd, file) \ 171120915Ssam if (logging > 1) \ 172104477Ssam syslog(LOG_INFO,"%s %s%s", cmd, \ 173104477Ssam *(file) == '/' ? "" : curdir(), file); 174104477Ssam#define LOGCMD2(cmd, file1, file2) \ 175104477Ssam if (logging > 1) \ 176112124Ssam syslog(LOG_INFO,"%s %s%s %s%s", cmd, \ 177112124Ssam *(file1) == '/' ? "" : curdir(), file1, \ 178112124Ssam *(file2) == '/' ? "" : curdir(), file2); 179104477Ssam#define LOGBYTES(cmd, file, cnt) \ 180104477Ssam if (logging > 1) { \ 181104477Ssam if (cnt == (off_t)-1) \ 182104477Ssam syslog(LOG_INFO,"%s %s%s", cmd, \ 183104477Ssam *(file) == '/' ? "" : curdir(), file); \ 184104477Ssam else \ 185104477Ssam syslog(LOG_INFO, "%s %s%s = %qd bytes", \ 186104477Ssam cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \ 187167755Ssam } 188167755Ssam 189167755Ssamstatic void ack __P((char *)); 190104477Ssamstatic void myoob __P((int)); 191104477Ssamstatic int checkuser __P((char *, char *)); 192104477Ssamstatic FILE *dataconn __P((char *, off_t, char *)); 193104477Ssamstatic void dolog __P((struct sockaddr_in *)); 194104477Ssamstatic char *curdir __P((void)); 195104477Ssamstatic void end_login __P((void)); 196104477Ssamstatic FILE *getdatasock __P((char *)); 197104477Ssamstatic char *gunique __P((char *)); 198104477Ssamstatic void lostconn __P((int)); 199104477Ssamstatic void sigquit __P((int)); 200104477Ssamstatic int receive_data __P((FILE *, FILE *)); 201104477Ssamstatic void send_data __P((FILE *, FILE *, off_t, off_t, int)); 202104477Ssamstatic struct passwd * 203104477Ssam sgetpwnam __P((char *)); 204104477Ssamstatic char *sgetsave __P((char *)); 205104477Ssamstatic void reapchild __P((int)); 206104477Ssam 207104477Ssamvoid logxfer __P((char *, off_t, time_t)); 208104477Ssam 209104477Ssamstatic char * 210104477Ssamcurdir() 211104477Ssam{ 212104477Ssam static char path[MAXPATHLEN+1+1]; /* path + '/' + '\0' */ 213104477Ssam 214104477Ssam if (getcwd(path, sizeof(path)-2) == NULL) 215104477Ssam return (""); 216104477Ssam if (path[1] != '\0') /* special case for root dir. */ 217104477Ssam strcat(path, "/"); 218104477Ssam /* For guest account, skip / since it's chrooted */ 219104477Ssam return (guest ? path+1 : path); 220104477Ssam} 221104477Ssam 222104477Ssamint 223104477Ssammain(argc, argv, envp) 224104477Ssam int argc; 225104477Ssam char *argv[]; 226104477Ssam char **envp; 227104477Ssam{ 228104477Ssam int addrlen, ch, on = 1, tos; 229104477Ssam char *cp, line[LINE_MAX]; 230104477Ssam FILE *fd; 231104477Ssam char *argstr = "dDhlSt:T:u:Uv"; 232104477Ssam 233104477Ssam tzset(); /* in case no timezone database in ~ftp */ 234104477Ssam 235104477Ssam /* set this here so klogin can use it... */ 236104477Ssam (void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid()); 237104477Ssam 238104477Ssam while ((ch = getopt(argc, argv, argstr)) != EOF) { 239104477Ssam switch (ch) { 240104477Ssam case 'd': 241104477Ssam debug = 1; 242104477Ssam break; 243104477Ssam 244104477Ssam case 'D': 245104477Ssam daemon_mode = 1; 246104477Ssam break; 247104477Ssam 248104477Ssam case 'h': 249104477Ssam high_data_ports = 1; 250104477Ssam break; 251104477Ssam 252104477Ssam case 'l': 253104477Ssam logging++; /* > 1 == extra logging */ 254104477Ssam break; 255104477Ssam 256104477Ssam case 'S': 257104477Ssam stats = 1; 258104477Ssam break; 259104477Ssam 260104477Ssam case 't': 261104477Ssam timeout = atoi(optarg); 262104477Ssam if (maxtimeout < timeout) 263104477Ssam maxtimeout = timeout; 264104477Ssam break; 265104477Ssam 266104477Ssam case 'T': 267104477Ssam maxtimeout = atoi(optarg); 268104477Ssam if (timeout > maxtimeout) 269104477Ssam timeout = maxtimeout; 270104477Ssam break; 271104477Ssam 272104477Ssam case 'u': 273120915Ssam { 274104477Ssam long val = 0; 275104477Ssam 276104477Ssam val = strtol(optarg, &optarg, 8); 277104477Ssam if (*optarg != '\0' || val < 0) 278104477Ssam warnx("bad value for -u"); 279104477Ssam else 280104477Ssam defumask = val; 281104477Ssam break; 282104477Ssam } 283104477Ssam 284104477Ssam case 'U': 285104477Ssam doutmp = 1; 286104477Ssam break; 287104477Ssam 288104477Ssam case 'v': 289104477Ssam debug = 1; 290104477Ssam break; 291104477Ssam 292104477Ssam default: 293104477Ssam warnx("unknown flag -%c ignored", optopt); 294104477Ssam break; 295104477Ssam } 296104477Ssam } 297104477Ssam 298104477Ssam (void) freopen(_PATH_DEVNULL, "w", stderr); 299104477Ssam 300104477Ssam /* 301104477Ssam * LOG_NDELAY sets up the logging connection immediately, 302104477Ssam * necessary for anonymous ftp's that chroot and can't do it later. 303104477Ssam */ 304104477Ssam openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); 305104477Ssam 306104477Ssam if (daemon_mode) { 307104477Ssam int ctl_sock, fd; 308104477Ssam struct servent *sv; 309104477Ssam 310104477Ssam /* 311104477Ssam * Detach from parent. 312104477Ssam */ 313104477Ssam if (daemon(1, 1) < 0) { 314104477Ssam syslog(LOG_ERR, "failed to become a daemon"); 315104477Ssam exit(1); 316104477Ssam } 317104477Ssam (void) signal(SIGCHLD, reapchild); 318104477Ssam /* 319104477Ssam * Get port number for ftp/tcp. 320104477Ssam */ 321104477Ssam sv = getservbyname("ftp", "tcp"); 322104477Ssam if (sv == NULL) { 323104477Ssam syslog(LOG_ERR, "getservbyname for ftp failed"); 324104477Ssam exit(1); 325104477Ssam } 326104477Ssam /* 327104477Ssam * Open a socket, bind it to the FTP port, and start 328104477Ssam * listening. 329104477Ssam */ 330104477Ssam ctl_sock = socket(AF_INET, SOCK_STREAM, 0); 331104477Ssam if (ctl_sock < 0) { 332104477Ssam syslog(LOG_ERR, "control socket: %m"); 333104477Ssam exit(1); 334104477Ssam } 335104477Ssam if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR, 336104477Ssam (char *)&on, sizeof(on)) < 0) 337104477Ssam syslog(LOG_ERR, "control setsockopt: %m");; 338104477Ssam server_addr.sin_family = AF_INET; 339104477Ssam server_addr.sin_addr.s_addr = INADDR_ANY; 340104477Ssam server_addr.sin_port = sv->s_port; 341104477Ssam if (bind(ctl_sock, (struct sockaddr *)&server_addr, 342104477Ssam sizeof(server_addr))) { 343104477Ssam syslog(LOG_ERR, "control bind: %m"); 344104477Ssam exit(1); 345104477Ssam } 346104477Ssam if (listen(ctl_sock, 32) < 0) { 347104477Ssam syslog(LOG_ERR, "control listen: %m"); 348104477Ssam exit(1); 349104477Ssam } 350104477Ssam /* 351104477Ssam * Loop forever accepting connection requests and forking off 352104477Ssam * children to handle them. 353104477Ssam */ 354104477Ssam while (1) { 355104477Ssam addrlen = sizeof(his_addr); 356104477Ssam fd = accept(ctl_sock, (struct sockaddr *)&his_addr, 357104477Ssam &addrlen); 358104477Ssam if (fork() == 0) { 359104477Ssam /* child */ 360104477Ssam (void) dup2(fd, 0); 361104477Ssam (void) dup2(fd, 1); 362104477Ssam close(ctl_sock); 363104477Ssam break; 364 } 365 close(fd); 366 } 367 } else { 368 addrlen = sizeof(his_addr); 369 if (getpeername(0, (struct sockaddr *)&his_addr, 370 &addrlen) < 0) { 371 syslog(LOG_ERR, "getpeername (%s): %m", argv[0]); 372 exit(1); 373 } 374 } 375 376 (void) signal(SIGHUP, sigquit); 377 (void) signal(SIGINT, sigquit); 378 (void) signal(SIGQUIT, sigquit); 379 (void) signal(SIGTERM, sigquit); 380 (void) signal(SIGPIPE, lostconn); 381 (void) signal(SIGCHLD, SIG_IGN); 382 if ((long)signal(SIGURG, myoob) < 0) 383 syslog(LOG_ERR, "signal: %m"); 384 385 addrlen = sizeof(ctrl_addr); 386 if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { 387 syslog(LOG_ERR, "getsockname (%s): %m", argv[0]); 388 exit(1); 389 } 390#ifdef IP_TOS 391 tos = IPTOS_LOWDELAY; 392 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) 393 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 394#endif 395 data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); 396 397 /* Try to handle urgent data inline */ 398#ifdef SO_OOBINLINE 399 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) 400 syslog(LOG_ERR, "setsockopt: %m"); 401#endif 402 403#ifdef F_SETOWN 404 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) 405 syslog(LOG_ERR, "fcntl F_SETOWN: %m"); 406#endif 407 dolog(&his_addr); 408 /* 409 * Set up default state 410 */ 411 data = -1; 412 type = TYPE_A; 413 form = FORM_N; 414 stru = STRU_F; 415 mode = MODE_S; 416 tmpline[0] = '\0'; 417 418 /* If logins are disabled, print out the message. */ 419 if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) { 420 while (fgets(line, sizeof(line), fd) != NULL) { 421 if ((cp = strchr(line, '\n')) != NULL) 422 *cp = '\0'; 423 lreply(530, "%s", line); 424 } 425 (void) fflush(stdout); 426 (void) fclose(fd); 427 reply(530, "System not available."); 428 exit(0); 429 } 430 if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) { 431 while (fgets(line, sizeof(line), fd) != NULL) { 432 if ((cp = strchr(line, '\n')) != NULL) 433 *cp = '\0'; 434 lreply(220, "%s", line); 435 } 436 (void) fflush(stdout); 437 (void) fclose(fd); 438 /* reply(220,) must follow */ 439 } 440 (void) gethostname(hostname, sizeof(hostname)); 441 reply(220, "%s FTP server (%s) ready.", hostname, version); 442 (void) setjmp(errcatch); 443 for (;;) 444 (void) yyparse(); 445 /* NOTREACHED */ 446} 447 448/* 449 * Signal handlers. 450 */ 451 452static void 453lostconn(signo) 454 int signo; 455{ 456 457 if (debug) 458 syslog(LOG_DEBUG, "lost connection"); 459 dologout(-1); 460} 461 462static void 463sigquit(signo) 464 int signo; 465{ 466 syslog(LOG_ERR, "got signal %s", strsignal(signo)); 467 468 dologout(-1); 469} 470 471/* 472 * Helper function for sgetpwnam(). 473 */ 474static char * 475sgetsave(s) 476 char *s; 477{ 478 char *new = malloc((unsigned) strlen(s) + 1); 479 480 if (new == NULL) { 481 perror_reply(421, "Local resource failure: malloc"); 482 dologout(1); 483 /* NOTREACHED */ 484 } 485 (void) strcpy(new, s); 486 return (new); 487} 488 489/* 490 * Save the result of a getpwnam. Used for USER command, since 491 * the data returned must not be clobbered by any other command 492 * (e.g., globbing). 493 */ 494static struct passwd * 495sgetpwnam(name) 496 char *name; 497{ 498 static struct passwd save; 499 struct passwd *p; 500 501 if ((p = getpwnam(name)) == NULL) 502 return (p); 503 if (save.pw_name) { 504 free(save.pw_name); 505 free(save.pw_passwd); 506 free(save.pw_gecos); 507 free(save.pw_dir); 508 free(save.pw_shell); 509 } 510 save = *p; 511 save.pw_name = sgetsave(p->pw_name); 512 save.pw_passwd = sgetsave(p->pw_passwd); 513 save.pw_gecos = sgetsave(p->pw_gecos); 514 save.pw_dir = sgetsave(p->pw_dir); 515 save.pw_shell = sgetsave(p->pw_shell); 516 return (&save); 517} 518 519static int login_attempts; /* number of failed login attempts */ 520static int askpasswd; /* had user command, ask for passwd */ 521static char curname[10]; /* current USER name */ 522 523/* 524 * USER command. 525 * Sets global passwd pointer pw if named account exists and is acceptable; 526 * sets askpasswd if a PASS command is expected. If logged in previously, 527 * need to reset state. If name is "ftp" or "anonymous", the name is not in 528 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return. 529 * If account doesn't exist, ask for passwd anyway. Otherwise, check user 530 * requesting login privileges. Disallow anyone who does not have a standard 531 * shell as returned by getusershell(). Disallow anyone mentioned in the file 532 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. 533 */ 534void 535user(name) 536 char *name; 537{ 538 char *cp, *shell; 539 540 if (logged_in) { 541 if (guest) { 542 reply(530, "Can't change user from guest login."); 543 return; 544 } else if (dochroot) { 545 reply(530, "Can't change user from chroot user."); 546 return; 547 } 548 end_login(); 549 } 550 551 guest = 0; 552 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { 553 if (checkuser(_PATH_FTPUSERS, "ftp") || 554 checkuser(_PATH_FTPUSERS, "anonymous")) 555 reply(530, "User %s access denied.", name); 556 else if ((pw = sgetpwnam("ftp")) != NULL) { 557 guest = 1; 558 askpasswd = 1; 559 reply(331, 560 "Guest login ok, type your name as password."); 561 } else 562 reply(530, "User %s unknown.", name); 563 if (!askpasswd && logging) 564 syslog(LOG_NOTICE, 565 "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost); 566 return; 567 } 568 if (pw = sgetpwnam(name)) { 569 if ((shell = pw->pw_shell) == NULL || *shell == 0) 570 shell = _PATH_BSHELL; 571 while ((cp = getusershell()) != NULL) 572 if (strcmp(cp, shell) == 0) 573 break; 574 endusershell(); 575 576 if (cp == NULL || checkuser(_PATH_FTPUSERS, name)) { 577 reply(530, "User %s access denied.", name); 578 if (logging) 579 syslog(LOG_NOTICE, 580 "FTP LOGIN REFUSED FROM %s, %s", 581 remotehost, name); 582 pw = (struct passwd *) NULL; 583 return; 584 } 585 } 586 if (logging) 587 strncpy(curname, name, sizeof(curname)-1); 588#ifdef SKEY 589 if (!skey_haskey(name)) { 590 char *myskey, *skey_keyinfo __P((char *name)); 591 592 myskey = skey_keyinfo(name); 593 reply(331, "Password [%s] for %s required.", 594 myskey ? myskey : "error getting challenge", name); 595 } else 596#endif 597 reply(331, "Password required for %s.", name); 598 599 askpasswd = 1; 600 /* 601 * Delay before reading passwd after first failed 602 * attempt to slow down passwd-guessing programs. 603 */ 604 if (login_attempts) 605 sleep((unsigned) login_attempts); 606} 607 608/* 609 * Check if a user is in the file "fname" 610 */ 611static int 612checkuser(fname, name) 613 char *fname; 614 char *name; 615{ 616 FILE *fd; 617 int found = 0; 618 char *p, line[BUFSIZ]; 619 620 if ((fd = fopen(fname, "r")) != NULL) { 621 while (fgets(line, sizeof(line), fd) != NULL) 622 if ((p = strchr(line, '\n')) != NULL) { 623 *p = '\0'; 624 if (line[0] == '#') 625 continue; 626 if (strcmp(line, name) == 0) { 627 found = 1; 628 break; 629 } 630 } 631 (void) fclose(fd); 632 } 633 return (found); 634} 635 636/* 637 * Terminate login as previous user, if any, resetting state; 638 * used when USER command is given or login fails. 639 */ 640static void 641end_login() 642{ 643 644 (void) seteuid((uid_t)0); 645 if (logged_in) { 646 logwtmp(ttyline, "", ""); 647 if (doutmp) 648 logout(utmp.ut_line); 649 } 650 pw = NULL; 651 logged_in = 0; 652 guest = 0; 653 dochroot = 0; 654} 655 656void 657pass(passwd) 658 char *passwd; 659{ 660 int rval; 661 FILE *fd; 662 static char homedir[MAXPATHLEN]; 663 664 if (logged_in || askpasswd == 0) { 665 reply(503, "Login with USER first."); 666 return; 667 } 668 askpasswd = 0; 669 if (!guest) { /* "ftp" is only account allowed no password */ 670 if (pw == NULL) { 671 rval = 1; /* failure below */ 672 goto skip; 673 } 674#if defined(KERBEROS) 675 rval = klogin(pw, "", hostname, passwd); 676 if (rval == 0) 677 goto skip; 678#endif 679#ifdef SKEY 680 if (skey_haskey(pw->pw_name) == 0 && 681 (skey_passcheck(pw->pw_name, passwd) != -1)) { 682 rval = 0; 683 goto skip; 684 } 685#endif 686 /* the strcmp does not catch null passwords! */ 687 if (pw == NULL || *pw->pw_passwd == '\0' || 688 strcmp(crypt(passwd, (pw ? pw->pw_passwd : "xx")), pw->pw_passwd)) { 689 rval = 1; /* failure */ 690 goto skip; 691 } 692 rval = 0; 693 694skip: 695 /* 696 * If rval == 1, the user failed the authentication check 697 * above. If rval == 0, either Kerberos or local authentication 698 * succeeded. 699 */ 700 if (rval) { 701 reply(530, "Login incorrect."); 702 if (logging) 703 syslog(LOG_NOTICE, 704 "FTP LOGIN FAILED FROM %s, %s", 705 remotehost, curname); 706 pw = NULL; 707 if (login_attempts++ >= 5) { 708 syslog(LOG_NOTICE, 709 "repeated login failures from %s", 710 remotehost); 711 exit(0); 712 } 713 return; 714 } 715 } 716 login_attempts = 0; /* this time successful */ 717 if (setegid((gid_t)pw->pw_gid) < 0) { 718 reply(550, "Can't set gid."); 719 return; 720 } 721 (void) initgroups(pw->pw_name, pw->pw_gid); 722 723 /* open wtmp before chroot */ 724 logwtmp(ttyline, pw->pw_name, remotehost); 725 726 /* open utmp before chroot */ 727 if (doutmp) { 728 memset((void *)&utmp, 0, sizeof(utmp)); 729 (void)time(&utmp.ut_time); 730 (void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name)); 731 (void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host)); 732 (void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line)); 733 login(&utmp); 734 } 735 736 /* open stats file before chroot */ 737 if (guest && (stats == 1) && (statfd < 0)) 738 if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0) 739 stats = 0; 740 741 logged_in = 1; 742 743 dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name); 744 if (guest) { 745 /* 746 * We MUST do a chdir() after the chroot. Otherwise 747 * the old current directory will be accessible as "." 748 * outside the new root! 749 */ 750 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { 751 reply(550, "Can't set guest privileges."); 752 goto bad; 753 } 754 } else if (dochroot) { 755 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { 756 reply(550, "Can't change root."); 757 goto bad; 758 } 759 } else if (chdir(pw->pw_dir) < 0) { 760 if (chdir("/") < 0) { 761 reply(530, "User %s: can't change directory to %s.", 762 pw->pw_name, pw->pw_dir); 763 goto bad; 764 } else 765 lreply(230, "No directory! Logging in with home=/"); 766 } 767 if (seteuid((uid_t)pw->pw_uid) < 0) { 768 reply(550, "Can't set uid."); 769 goto bad; 770 } 771 772 /* 773 * Set home directory so that use of ~ (tilde) works correctly. 774 */ 775 if (getcwd(homedir, MAXPATHLEN) != NULL) 776 setenv("HOME", homedir, 1); 777 778 /* 779 * Display a login message, if it exists. 780 * N.B. reply(230,) must follow the message. 781 */ 782 if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) { 783 char *cp, line[LINE_MAX]; 784 785 while (fgets(line, sizeof(line), fd) != NULL) { 786 if ((cp = strchr(line, '\n')) != NULL) 787 *cp = '\0'; 788 lreply(230, "%s", line); 789 } 790 (void) fflush(stdout); 791 (void) fclose(fd); 792 } 793 if (guest) { 794 if (ident != NULL) 795 free(ident); 796 ident = strdup(passwd); 797 if (ident == (char *)NULL) 798 fatal("Ran out of memory."); 799 reply(230, "Guest login ok, access restrictions apply."); 800#ifdef HASSETPROCTITLE 801 snprintf(proctitle, sizeof(proctitle), 802 "%s: anonymous/%.*s", remotehost, 803 sizeof(proctitle) - sizeof(remotehost) - 804 sizeof(": anonymous/"), passwd); 805 setproctitle(proctitle); 806#endif /* HASSETPROCTITLE */ 807 if (logging) 808 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s", 809 remotehost, passwd); 810 } else { 811 reply(230, "User %s logged in.", pw->pw_name); 812#ifdef HASSETPROCTITLE 813 snprintf(proctitle, sizeof(proctitle), 814 "%s: %s", remotehost, pw->pw_name); 815 setproctitle(proctitle); 816#endif /* HASSETPROCTITLE */ 817 if (logging) 818 syslog(LOG_INFO, "FTP LOGIN FROM %s as %s", 819 remotehost, pw->pw_name); 820 } 821 (void) umask(defumask); 822 return; 823bad: 824 /* Forget all about it... */ 825 end_login(); 826} 827 828void 829retrieve(cmd, name) 830 char *cmd, *name; 831{ 832 FILE *fin, *dout; 833 struct stat st; 834 int (*closefunc) __P((FILE *)); 835 time_t start; 836 837 if (cmd == 0) { 838 fin = fopen(name, "r"), closefunc = fclose; 839 st.st_size = 0; 840 } else { 841 char line[BUFSIZ]; 842 843 (void) snprintf(line, sizeof(line), cmd, name); 844 name = line; 845 fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose; 846 st.st_size = -1; 847 st.st_blksize = BUFSIZ; 848 } 849 if (fin == NULL) { 850 if (errno != 0) { 851 perror_reply(550, name); 852 if (cmd == 0) { 853 LOGCMD("get", name); 854 } 855 } 856 return; 857 } 858 byte_count = -1; 859 if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) { 860 reply(550, "%s: not a plain file.", name); 861 goto done; 862 } 863 if (restart_point) { 864 if (type == TYPE_A) { 865 off_t i, n; 866 int c; 867 868 n = restart_point; 869 i = 0; 870 while (i++ < n) { 871 if ((c=getc(fin)) == EOF) { 872 perror_reply(550, name); 873 goto done; 874 } 875 if (c == '\n') 876 i++; 877 } 878 } else if (lseek(fileno(fin), restart_point, L_SET) < 0) { 879 perror_reply(550, name); 880 goto done; 881 } 882 } 883 dout = dataconn(name, st.st_size, "w"); 884 if (dout == NULL) 885 goto done; 886 time(&start); 887 send_data(fin, dout, st.st_blksize, st.st_size, 888 (restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode))); 889 if ((cmd == 0) && guest && stats) 890 logxfer(name, st.st_size, start); 891 (void) fclose(dout); 892 data = -1; 893 pdata = -1; 894done: 895 if (cmd == 0) 896 LOGBYTES("get", name, byte_count); 897 (*closefunc)(fin); 898} 899 900void 901store(name, mode, unique) 902 char *name, *mode; 903 int unique; 904{ 905 FILE *fout, *din; 906 struct stat st; 907 int (*closefunc) __P((FILE *)); 908 909 if (unique && stat(name, &st) == 0 && 910 (name = gunique(name)) == NULL) { 911 LOGCMD(*mode == 'w' ? "put" : "append", name); 912 return; 913 } 914 915 if (restart_point) 916 mode = "r+"; 917 fout = fopen(name, mode); 918 closefunc = fclose; 919 if (fout == NULL) { 920 perror_reply(553, name); 921 LOGCMD(*mode == 'w' ? "put" : "append", name); 922 return; 923 } 924 byte_count = -1; 925 if (restart_point) { 926 if (type == TYPE_A) { 927 off_t i, n; 928 int c; 929 930 n = restart_point; 931 i = 0; 932 while (i++ < n) { 933 if ((c=getc(fout)) == EOF) { 934 perror_reply(550, name); 935 goto done; 936 } 937 if (c == '\n') 938 i++; 939 } 940 /* 941 * We must do this seek to "current" position 942 * because we are changing from reading to 943 * writing. 944 */ 945 if (fseek(fout, 0L, L_INCR) < 0) { 946 perror_reply(550, name); 947 goto done; 948 } 949 } else if (lseek(fileno(fout), restart_point, L_SET) < 0) { 950 perror_reply(550, name); 951 goto done; 952 } 953 } 954 din = dataconn(name, (off_t)-1, "r"); 955 if (din == NULL) 956 goto done; 957 if (receive_data(din, fout) == 0) { 958 if (unique) 959 reply(226, "Transfer complete (unique file name:%s).", 960 name); 961 else 962 reply(226, "Transfer complete."); 963 } 964 (void) fclose(din); 965 data = -1; 966 pdata = -1; 967done: 968 LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count); 969 (*closefunc)(fout); 970} 971 972static FILE * 973getdatasock(mode) 974 char *mode; 975{ 976 int on = 1, s, t, tries; 977 978 if (data >= 0) 979 return (fdopen(data, mode)); 980 (void) seteuid((uid_t)0); 981 s = socket(AF_INET, SOCK_STREAM, 0); 982 if (s < 0) 983 goto bad; 984 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 985 (char *) &on, sizeof(on)) < 0) 986 goto bad; 987 /* anchor socket to avoid multi-homing problems */ 988 data_source.sin_len = sizeof(struct sockaddr_in); 989 data_source.sin_family = AF_INET; 990 data_source.sin_addr = ctrl_addr.sin_addr; 991 for (tries = 1; ; tries++) { 992 if (bind(s, (struct sockaddr *)&data_source, 993 sizeof(data_source)) >= 0) 994 break; 995 if (errno != EADDRINUSE || tries > 10) 996 goto bad; 997 sleep(tries); 998 } 999 (void) seteuid((uid_t)pw->pw_uid); 1000#ifdef IP_TOS 1001 on = IPTOS_THROUGHPUT; 1002 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 1003 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 1004#endif 1005#ifdef TCP_NOPUSH 1006 /* 1007 * Turn off push flag to keep sender TCP from sending short packets 1008 * at the boundaries of each write(). Should probably do a SO_SNDBUF 1009 * to set the send buffer size as well, but that may not be desirable 1010 * in heavy-load situations. 1011 */ 1012 on = 1; 1013 if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0) 1014 syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m"); 1015#endif 1016#ifdef SO_SNDBUF 1017 on = 65536; 1018 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0) 1019 syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m"); 1020#endif 1021 1022 return (fdopen(s, mode)); 1023bad: 1024 /* Return the real value of errno (close may change it) */ 1025 t = errno; 1026 (void) seteuid((uid_t)pw->pw_uid); 1027 (void) close(s); 1028 errno = t; 1029 return (NULL); 1030} 1031 1032static FILE * 1033dataconn(name, size, mode) 1034 char *name; 1035 off_t size; 1036 char *mode; 1037{ 1038 char sizebuf[32]; 1039 FILE *file; 1040 int retry = 0, tos; 1041 1042 file_size = size; 1043 byte_count = 0; 1044 if (size != (off_t) -1) { 1045 (void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)", 1046 size); 1047 } else 1048 sizebuf[0] = '\0'; 1049 if (pdata >= 0) { 1050 struct sockaddr_in from; 1051 int s, fromlen = sizeof(from); 1052 1053 s = accept(pdata, (struct sockaddr *)&from, &fromlen); 1054 if (s < 0) { 1055 reply(425, "Can't open data connection."); 1056 (void) close(pdata); 1057 pdata = -1; 1058 return (NULL); 1059 } 1060 if (ntohs(from.sin_port) < IPPORT_RESERVED) { 1061 perror_reply(425, "Can't build data connection"); 1062 (void) close(pdata); 1063 (void) close(s); 1064 pdata = -1; 1065 return (NULL); 1066 } 1067 if (from.sin_addr.s_addr != his_addr.sin_addr.s_addr) { 1068 perror_reply(435, "Can't build data connection"); 1069 (void) close(pdata); 1070 (void) close(s); 1071 pdata = -1; 1072 return (NULL); 1073 } 1074 (void) close(pdata); 1075 pdata = s; 1076#ifdef IP_TOS 1077 tos = IPTOS_THROUGHPUT; 1078 (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, 1079 sizeof(int)); 1080#endif 1081 reply(150, "Opening %s mode data connection for '%s'%s.", 1082 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 1083 return (fdopen(pdata, mode)); 1084 } 1085 if (data >= 0) { 1086 reply(125, "Using existing data connection for '%s'%s.", 1087 name, sizebuf); 1088 usedefault = 1; 1089 return (fdopen(data, mode)); 1090 } 1091 if (usedefault) 1092 data_dest = his_addr; 1093 usedefault = 1; 1094 file = getdatasock(mode); 1095 if (file == NULL) { 1096 reply(425, "Can't create data socket (%s,%d): %s.", 1097 inet_ntoa(data_source.sin_addr), 1098 ntohs(data_source.sin_port), strerror(errno)); 1099 return (NULL); 1100 } 1101 data = fileno(file); 1102 1103 /* 1104 * attempt to connect to reserved port on client machine; 1105 * this looks like an attack 1106 */ 1107 if (ntohs(data_dest.sin_port) < IPPORT_RESERVED) { 1108 perror_reply(425, "Can't build data connection"); 1109 (void) fclose(file); 1110 data = -1; 1111 return NULL; 1112 } 1113 if (data_dest.sin_addr.s_addr != his_addr.sin_addr.s_addr) { 1114 perror_reply(435, "Can't build data connection"); 1115 (void) fclose(file); 1116 data = -1; 1117 return NULL; 1118 } 1119 while (connect(data, (struct sockaddr *)&data_dest, 1120 sizeof(data_dest)) < 0) { 1121 if (errno == EADDRINUSE && retry < swaitmax) { 1122 sleep((unsigned) swaitint); 1123 retry += swaitint; 1124 continue; 1125 } 1126 perror_reply(425, "Can't build data connection"); 1127 (void) fclose(file); 1128 data = -1; 1129 return (NULL); 1130 } 1131 reply(150, "Opening %s mode data connection for '%s'%s.", 1132 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 1133 return (file); 1134} 1135 1136/* 1137 * Tranfer the contents of "instr" to "outstr" peer using the appropriate 1138 * encapsulation of the data subject to Mode, Structure, and Type. 1139 * 1140 * NB: Form isn't handled. 1141 */ 1142static void 1143send_data(instr, outstr, blksize, filesize, isreg) 1144 FILE *instr, *outstr; 1145 off_t blksize; 1146 off_t filesize; 1147 int isreg; 1148{ 1149 int c, cnt, filefd, netfd; 1150 char *buf, *bp; 1151 size_t len; 1152 1153 transflag++; 1154 if (setjmp(urgcatch)) { 1155 transflag = 0; 1156 return; 1157 } 1158 switch (type) { 1159 1160 case TYPE_A: 1161 while ((c = getc(instr)) != EOF) { 1162 byte_count++; 1163 if (c == '\n') { 1164 if (ferror(outstr)) 1165 goto data_err; 1166 (void) putc('\r', outstr); 1167 } 1168 (void) putc(c, outstr); 1169 } 1170 fflush(outstr); 1171 transflag = 0; 1172 if (ferror(instr)) 1173 goto file_err; 1174 if (ferror(outstr)) 1175 goto data_err; 1176 reply(226, "Transfer complete."); 1177 return; 1178 1179 case TYPE_I: 1180 case TYPE_L: 1181 /* 1182 * isreg is only set if we are not doing restart and we 1183 * are sending a regular file 1184 */ 1185 netfd = fileno(outstr); 1186 filefd = fileno(instr); 1187 1188 if (isreg && filesize < (off_t)16 * 1024 * 1024) { 1189 buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd, 1190 (off_t)0); 1191 if (!buf) { 1192 syslog(LOG_WARNING, "mmap(%lu): %m", 1193 (unsigned long)filesize); 1194 goto oldway; 1195 } 1196 bp = buf; 1197 len = filesize; 1198 do { 1199 cnt = write(netfd, bp, len); 1200 len -= cnt; 1201 bp += cnt; 1202 if (cnt > 0) byte_count += cnt; 1203 } while(cnt > 0 && len > 0); 1204 1205 transflag = 0; 1206 munmap(buf, (size_t)filesize); 1207 if (cnt < 0) 1208 goto data_err; 1209 reply(226, "Transfer complete."); 1210 return; 1211 } 1212 1213oldway: 1214 if ((buf = malloc((u_int)blksize)) == NULL) { 1215 transflag = 0; 1216 perror_reply(451, "Local resource failure: malloc"); 1217 return; 1218 } 1219 1220 while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 && 1221 write(netfd, buf, cnt) == cnt) 1222 byte_count += cnt; 1223 transflag = 0; 1224 (void)free(buf); 1225 if (cnt != 0) { 1226 if (cnt < 0) 1227 goto file_err; 1228 goto data_err; 1229 } 1230 reply(226, "Transfer complete."); 1231 return; 1232 default: 1233 transflag = 0; 1234 reply(550, "Unimplemented TYPE %d in send_data", type); 1235 return; 1236 } 1237 1238data_err: 1239 transflag = 0; 1240 perror_reply(426, "Data connection"); 1241 return; 1242 1243file_err: 1244 transflag = 0; 1245 perror_reply(551, "Error on input file"); 1246} 1247 1248/* 1249 * Transfer data from peer to "outstr" using the appropriate encapulation of 1250 * the data subject to Mode, Structure, and Type. 1251 * 1252 * N.B.: Form isn't handled. 1253 */ 1254static int 1255receive_data(instr, outstr) 1256 FILE *instr, *outstr; 1257{ 1258 int c; 1259 int cnt, bare_lfs = 0; 1260 char buf[BUFSIZ]; 1261 1262 transflag++; 1263 if (setjmp(urgcatch)) { 1264 transflag = 0; 1265 return (-1); 1266 } 1267 switch (type) { 1268 1269 case TYPE_I: 1270 case TYPE_L: 1271 while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) { 1272 if (write(fileno(outstr), buf, cnt) != cnt) 1273 goto file_err; 1274 byte_count += cnt; 1275 } 1276 if (cnt < 0) 1277 goto data_err; 1278 transflag = 0; 1279 return (0); 1280 1281 case TYPE_E: 1282 reply(553, "TYPE E not implemented."); 1283 transflag = 0; 1284 return (-1); 1285 1286 case TYPE_A: 1287 while ((c = getc(instr)) != EOF) { 1288 byte_count++; 1289 if (c == '\n') 1290 bare_lfs++; 1291 while (c == '\r') { 1292 if (ferror(outstr)) 1293 goto data_err; 1294 if ((c = getc(instr)) != '\n') { 1295 (void) putc ('\r', outstr); 1296 if (c == '\0' || c == EOF) 1297 goto contin2; 1298 } 1299 } 1300 (void) putc(c, outstr); 1301 contin2: ; 1302 } 1303 fflush(outstr); 1304 if (ferror(instr)) 1305 goto data_err; 1306 if (ferror(outstr)) 1307 goto file_err; 1308 transflag = 0; 1309 if (bare_lfs) { 1310 lreply(226, 1311 "WARNING! %d bare linefeeds received in ASCII mode", 1312 bare_lfs); 1313 (void)printf(" File may not have transferred correctly.\r\n"); 1314 } 1315 return (0); 1316 default: 1317 reply(550, "Unimplemented TYPE %d in receive_data", type); 1318 transflag = 0; 1319 return (-1); 1320 } 1321 1322data_err: 1323 transflag = 0; 1324 perror_reply(426, "Data Connection"); 1325 return (-1); 1326 1327file_err: 1328 transflag = 0; 1329 perror_reply(452, "Error writing file"); 1330 return (-1); 1331} 1332 1333void 1334statfilecmd(filename) 1335 char *filename; 1336{ 1337 FILE *fin; 1338 int c; 1339 char line[LINE_MAX]; 1340 1341 (void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename); 1342 fin = ftpd_popen(line, "r"); 1343 lreply(211, "status of %s:", filename); 1344 while ((c = getc(fin)) != EOF) { 1345 if (c == '\n') { 1346 if (ferror(stdout)){ 1347 perror_reply(421, "control connection"); 1348 (void) ftpd_pclose(fin); 1349 dologout(1); 1350 /* NOTREACHED */ 1351 } 1352 if (ferror(fin)) { 1353 perror_reply(551, filename); 1354 (void) ftpd_pclose(fin); 1355 return; 1356 } 1357 (void) putc('\r', stdout); 1358 } 1359 (void) putc(c, stdout); 1360 } 1361 (void) ftpd_pclose(fin); 1362 reply(211, "End of Status"); 1363} 1364 1365void 1366statcmd() 1367{ 1368 struct sockaddr_in *sin; 1369 u_char *a, *p; 1370 1371 lreply(211, "%s FTP server status:", hostname, version); 1372 printf(" %s\r\n", version); 1373 printf(" Connected to %s", remotehost); 1374 if (!isdigit(remotehost[0])) 1375 printf(" (%s)", inet_ntoa(his_addr.sin_addr)); 1376 printf("\r\n"); 1377 if (logged_in) { 1378 if (guest) 1379 printf(" Logged in anonymously\r\n"); 1380 else 1381 printf(" Logged in as %s\r\n", pw->pw_name); 1382 } else if (askpasswd) 1383 printf(" Waiting for password\r\n"); 1384 else 1385 printf(" Waiting for user name\r\n"); 1386 printf(" TYPE: %s", typenames[type]); 1387 if (type == TYPE_A || type == TYPE_E) 1388 printf(", FORM: %s", formnames[form]); 1389 if (type == TYPE_L) 1390#if NBBY == 8 1391 printf(" %d", NBBY); 1392#else 1393 printf(" %d", bytesize); /* need definition! */ 1394#endif 1395 printf("; STRUcture: %s; transfer MODE: %s\r\n", 1396 strunames[stru], modenames[mode]); 1397 if (data != -1) 1398 printf(" Data connection open\r\n"); 1399 else if (pdata != -1) { 1400 printf(" in Passive mode"); 1401 sin = &pasv_addr; 1402 goto printaddr; 1403 } else if (usedefault == 0) { 1404 printf(" PORT"); 1405 sin = &data_dest; 1406printaddr: 1407 a = (u_char *) &sin->sin_addr; 1408 p = (u_char *) &sin->sin_port; 1409#define UC(b) (((int) b) & 0xff) 1410 printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]), 1411 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 1412#undef UC 1413 } else 1414 printf(" No data connection\r\n"); 1415 reply(211, "End of status"); 1416} 1417 1418void 1419fatal(s) 1420 char *s; 1421{ 1422 1423 reply(451, "Error in server: %s\n", s); 1424 reply(221, "Closing connection due to server error."); 1425 dologout(0); 1426 /* NOTREACHED */ 1427} 1428 1429void 1430#if __STDC__ 1431reply(int n, const char *fmt, ...) 1432#else 1433reply(n, fmt, va_alist) 1434 int n; 1435 char *fmt; 1436 va_dcl 1437#endif 1438{ 1439 va_list ap; 1440#if __STDC__ 1441 va_start(ap, fmt); 1442#else 1443 va_start(ap); 1444#endif 1445 (void)printf("%d ", n); 1446 (void)vprintf(fmt, ap); 1447 (void)printf("\r\n"); 1448 (void)fflush(stdout); 1449 if (debug) { 1450 syslog(LOG_DEBUG, "<--- %d ", n); 1451 vsyslog(LOG_DEBUG, fmt, ap); 1452 } 1453} 1454 1455void 1456#if __STDC__ 1457lreply(int n, const char *fmt, ...) 1458#else 1459lreply(n, fmt, va_alist) 1460 int n; 1461 char *fmt; 1462 va_dcl 1463#endif 1464{ 1465 va_list ap; 1466#if __STDC__ 1467 va_start(ap, fmt); 1468#else 1469 va_start(ap); 1470#endif 1471 (void)printf("%d- ", n); 1472 (void)vprintf(fmt, ap); 1473 (void)printf("\r\n"); 1474 (void)fflush(stdout); 1475 if (debug) { 1476 syslog(LOG_DEBUG, "<--- %d- ", n); 1477 vsyslog(LOG_DEBUG, fmt, ap); 1478 } 1479} 1480 1481static void 1482ack(s) 1483 char *s; 1484{ 1485 1486 reply(250, "%s command successful.", s); 1487} 1488 1489void 1490nack(s) 1491 char *s; 1492{ 1493 1494 reply(502, "%s command not implemented.", s); 1495} 1496 1497/* ARGSUSED */ 1498void 1499yyerror(s) 1500 char *s; 1501{ 1502 char *cp; 1503 1504 if (cp = strchr(cbuf,'\n')) 1505 *cp = '\0'; 1506 reply(500, "'%s': command not understood.", cbuf); 1507} 1508 1509void 1510delete(name) 1511 char *name; 1512{ 1513 struct stat st; 1514 1515 LOGCMD("delete", name); 1516 if (stat(name, &st) < 0) { 1517 perror_reply(550, name); 1518 return; 1519 } 1520 if ((st.st_mode&S_IFMT) == S_IFDIR) { 1521 if (rmdir(name) < 0) { 1522 perror_reply(550, name); 1523 return; 1524 } 1525 goto done; 1526 } 1527 if (unlink(name) < 0) { 1528 perror_reply(550, name); 1529 return; 1530 } 1531done: 1532 ack("DELE"); 1533} 1534 1535void 1536cwd(path) 1537 char *path; 1538{ 1539 1540 if (chdir(path) < 0) 1541 perror_reply(550, path); 1542 else 1543 ack("CWD"); 1544} 1545 1546void 1547makedir(name) 1548 char *name; 1549{ 1550 1551 LOGCMD("mkdir", name); 1552 if (mkdir(name, 0777) < 0) 1553 perror_reply(550, name); 1554 else 1555 reply(257, "MKD command successful."); 1556} 1557 1558void 1559removedir(name) 1560 char *name; 1561{ 1562 1563 LOGCMD("rmdir", name); 1564 if (rmdir(name) < 0) 1565 perror_reply(550, name); 1566 else 1567 ack("RMD"); 1568} 1569 1570void 1571pwd() 1572{ 1573 char path[MAXPATHLEN + 1]; 1574 1575 if (getwd(path) == (char *)NULL) 1576 reply(550, "%s.", path); 1577 else 1578 reply(257, "\"%s\" is current directory.", path); 1579} 1580 1581char * 1582renamefrom(name) 1583 char *name; 1584{ 1585 struct stat st; 1586 1587 if (stat(name, &st) < 0) { 1588 perror_reply(550, name); 1589 return ((char *)0); 1590 } 1591 reply(350, "File exists, ready for destination name"); 1592 return (name); 1593} 1594 1595void 1596renamecmd(from, to) 1597 char *from, *to; 1598{ 1599 1600 LOGCMD2("rename", from, to); 1601 if (rename(from, to) < 0) 1602 perror_reply(550, "rename"); 1603 else 1604 ack("RNTO"); 1605} 1606 1607static void 1608dolog(sin) 1609 struct sockaddr_in *sin; 1610{ 1611 struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr, 1612 sizeof(struct in_addr), AF_INET); 1613 1614 if (hp) 1615 (void) strncpy(remotehost, hp->h_name, sizeof(remotehost)); 1616 else 1617 (void) strncpy(remotehost, inet_ntoa(sin->sin_addr), 1618 sizeof(remotehost)); 1619#ifdef HASSETPROCTITLE 1620 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost); 1621 setproctitle(proctitle); 1622#endif /* HASSETPROCTITLE */ 1623 1624 if (logging) 1625 syslog(LOG_INFO, "connection from %s", remotehost); 1626} 1627 1628/* 1629 * Record logout in wtmp file 1630 * and exit with supplied status. 1631 */ 1632void 1633dologout(status) 1634 int status; 1635{ 1636 1637 if (logged_in) { 1638 (void) seteuid((uid_t)0); 1639 logwtmp(ttyline, "", ""); 1640 if (doutmp) 1641 logout(utmp.ut_line); 1642#if defined(KERBEROS) 1643 if (!notickets && krbtkfile_env) 1644 unlink(krbtkfile_env); 1645#endif 1646 } 1647 /* beware of flushing buffers after a SIGPIPE */ 1648 _exit(status); 1649} 1650 1651static void 1652myoob(signo) 1653 int signo; 1654{ 1655 char *cp; 1656 1657 /* only process if transfer occurring */ 1658 if (!transflag) 1659 return; 1660 cp = tmpline; 1661 if (getline(cp, 7, stdin) == NULL) { 1662 reply(221, "You could at least say goodbye."); 1663 dologout(0); 1664 } 1665 upper(cp); 1666 if (strcmp(cp, "ABOR\r\n") == 0) { 1667 tmpline[0] = '\0'; 1668 reply(426, "Transfer aborted. Data connection closed."); 1669 reply(226, "Abort successful"); 1670 longjmp(urgcatch, 1); 1671 } 1672 if (strcmp(cp, "STAT\r\n") == 0) { 1673 if (file_size != (off_t) -1) 1674 reply(213, "Status: %qd of %qd bytes transferred", 1675 byte_count, file_size); 1676 else 1677 reply(213, "Status: %qd bytes transferred", byte_count); 1678 } 1679} 1680 1681/* 1682 * Note: a response of 425 is not mentioned as a possible response to 1683 * the PASV command in RFC959. However, it has been blessed as 1684 * a legitimate response by Jon Postel in a telephone conversation 1685 * with Rick Adams on 25 Jan 89. 1686 */ 1687void 1688passive() 1689{ 1690 int len, on; 1691 u_short port; 1692 char *p, *a; 1693 1694 if (pw == NULL) { 1695 reply(530, "Please login with USER and PASS"); 1696 return; 1697 } 1698 pdata = socket(AF_INET, SOCK_STREAM, 0); 1699 if (pdata < 0) { 1700 perror_reply(425, "Can't open passive connection"); 1701 return; 1702 } 1703 1704 on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT; 1705 if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE, 1706 (char *)&on, sizeof(on)) < 0) 1707 goto pasv_error; 1708 1709 pasv_addr = ctrl_addr; 1710 pasv_addr.sin_port = 0; 1711 if (bind(pdata, (struct sockaddr *)&pasv_addr, 1712 sizeof(pasv_addr)) < 0) 1713 goto pasv_error; 1714 1715 len = sizeof(pasv_addr); 1716 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) 1717 goto pasv_error; 1718 if (listen(pdata, 1) < 0) 1719 goto pasv_error; 1720 a = (char *) &pasv_addr.sin_addr; 1721 p = (char *) &pasv_addr.sin_port; 1722 1723#define UC(b) (((int) b) & 0xff) 1724 1725 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), 1726 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 1727 return; 1728 1729pasv_error: 1730 (void) close(pdata); 1731 pdata = -1; 1732 perror_reply(425, "Can't open passive connection"); 1733 return; 1734} 1735 1736/* 1737 * Generate unique name for file with basename "local". 1738 * The file named "local" is already known to exist. 1739 * Generates failure reply on error. 1740 */ 1741static char * 1742gunique(local) 1743 char *local; 1744{ 1745 static char new[MAXPATHLEN]; 1746 struct stat st; 1747 int count; 1748 char *cp; 1749 1750 cp = strrchr(local, '/'); 1751 if (cp) 1752 *cp = '\0'; 1753 if (stat(cp ? local : ".", &st) < 0) { 1754 perror_reply(553, cp ? local : "."); 1755 return ((char *) 0); 1756 } 1757 if (cp) 1758 *cp = '/'; 1759 (void) strncpy(new, local, sizeof(new)); 1760 cp = new + strlen(new); 1761 *cp++ = '.'; 1762 for (count = 1; count < 100; count++) { 1763 (void)snprintf(cp, sizeof(new) - (cp - new), "%d", count); 1764 if (stat(new, &st) < 0) 1765 return (new); 1766 } 1767 reply(452, "Unique file name cannot be created."); 1768 return (NULL); 1769} 1770 1771/* 1772 * Format and send reply containing system error number. 1773 */ 1774void 1775perror_reply(code, string) 1776 int code; 1777 char *string; 1778{ 1779 1780 reply(code, "%s: %s.", string, strerror(errno)); 1781} 1782 1783static char *onefile[] = { 1784 "", 1785 0 1786}; 1787 1788void 1789send_file_list(whichf) 1790 char *whichf; 1791{ 1792 struct stat st; 1793 DIR *dirp = NULL; 1794 struct dirent *dir; 1795 FILE *dout = NULL; 1796 char **dirlist, *dirname; 1797 int simple = 0; 1798 int freeglob = 0; 1799 glob_t gl; 1800 1801 if (strpbrk(whichf, "~{[*?") != NULL) { 1802 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; 1803 1804 memset(&gl, 0, sizeof(gl)); 1805 freeglob = 1; 1806 if (glob(whichf, flags, 0, &gl)) { 1807 reply(550, "not found"); 1808 goto out; 1809 } else if (gl.gl_pathc == 0) { 1810 errno = ENOENT; 1811 perror_reply(550, whichf); 1812 goto out; 1813 } 1814 dirlist = gl.gl_pathv; 1815 } else { 1816 onefile[0] = whichf; 1817 dirlist = onefile; 1818 simple = 1; 1819 } 1820 1821 if (setjmp(urgcatch)) { 1822 transflag = 0; 1823 goto out; 1824 } 1825 while (dirname = *dirlist++) { 1826 if (stat(dirname, &st) < 0) { 1827 /* 1828 * If user typed "ls -l", etc, and the client 1829 * used NLST, do what the user meant. 1830 */ 1831 if (dirname[0] == '-' && *dirlist == NULL && 1832 transflag == 0) { 1833 retrieve("/bin/ls %s", dirname); 1834 goto out; 1835 } 1836 perror_reply(550, whichf); 1837 if (dout != NULL) { 1838 (void) fclose(dout); 1839 transflag = 0; 1840 data = -1; 1841 pdata = -1; 1842 } 1843 goto out; 1844 } 1845 1846 if (S_ISREG(st.st_mode)) { 1847 if (dout == NULL) { 1848 dout = dataconn("file list", (off_t)-1, "w"); 1849 if (dout == NULL) 1850 goto out; 1851 transflag++; 1852 } 1853 fprintf(dout, "%s%s\n", dirname, 1854 type == TYPE_A ? "\r" : ""); 1855 byte_count += strlen(dirname) + 1; 1856 continue; 1857 } else if (!S_ISDIR(st.st_mode)) 1858 continue; 1859 1860 if ((dirp = opendir(dirname)) == NULL) 1861 continue; 1862 1863 while ((dir = readdir(dirp)) != NULL) { 1864 char nbuf[MAXPATHLEN]; 1865 1866 if (dir->d_name[0] == '.' && dir->d_namlen == 1) 1867 continue; 1868 if (dir->d_name[0] == '.' && dir->d_name[1] == '.' && 1869 dir->d_namlen == 2) 1870 continue; 1871 1872 snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname, 1873 dir->d_name); 1874 1875 /* 1876 * We have to do a stat to insure it's 1877 * not a directory or special file. 1878 */ 1879 if (simple || (stat(nbuf, &st) == 0 && 1880 S_ISREG(st.st_mode))) { 1881 if (dout == NULL) { 1882 dout = dataconn("file list", (off_t)-1, 1883 "w"); 1884 if (dout == NULL) 1885 goto out; 1886 transflag++; 1887 } 1888 if (nbuf[0] == '.' && nbuf[1] == '/') 1889 fprintf(dout, "%s%s\n", &nbuf[2], 1890 type == TYPE_A ? "\r" : ""); 1891 else 1892 fprintf(dout, "%s%s\n", nbuf, 1893 type == TYPE_A ? "\r" : ""); 1894 byte_count += strlen(nbuf) + 1; 1895 } 1896 } 1897 (void) closedir(dirp); 1898 } 1899 1900 if (dout == NULL) 1901 reply(550, "No files found."); 1902 else if (ferror(dout) != 0) 1903 perror_reply(550, "Data connection"); 1904 else 1905 reply(226, "Transfer complete."); 1906 1907 transflag = 0; 1908 if (dout != NULL) 1909 (void) fclose(dout); 1910 data = -1; 1911 pdata = -1; 1912out: 1913 if (freeglob) { 1914 freeglob = 0; 1915 globfree(&gl); 1916 } 1917} 1918 1919static void 1920reapchild(signo) 1921 int signo; 1922{ 1923 while (wait3(NULL, WNOHANG, NULL) > 0); 1924} 1925 1926void 1927logxfer(name, size, start) 1928 char *name; 1929 off_t size; 1930 time_t start; 1931{ 1932 char buf[1024]; 1933 char path[MAXPATHLEN + 1]; 1934 time_t now; 1935 1936 if ((statfd >= 0) && (getwd(path) != NULL)) { 1937 time(&now); 1938 snprintf(buf, sizeof(buf), "%.20s!%s!%s!%s/%s!%qd!%ld\n", 1939 ctime(&now)+4, ident, remotehost, 1940 path, name, size, now - start + (now == start)); 1941 write(statfd, buf, strlen(buf)); 1942 } 1943} 1944