1 /* $NetBSD: ftpd.c,v 1.61 1998/12/28 04:54:01 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __COPYRIGHT( 39 "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\ 40 The Regents of the University of California. All rights reserved.\n"); 41 #endif /* not lint */ 42 43 #ifndef lint 44 #if 0 45 static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95"; 46 #else 47 __RCSID("$NetBSD: ftpd.c,v 1.61 1998/12/28 04:54:01 lukem Exp $"); 48 #endif 49 #endif /* not lint */ 50 51 /* 52 * FTP server. 53 */ 54 #include <sys/param.h> 55 #include <sys/stat.h> 56 #include <sys/ioctl.h> 57 #include <sys/socket.h> 58 #include <sys/wait.h> 59 60 #include <netinet/in.h> 61 #include <netinet/in_systm.h> 62 #include <netinet/ip.h> 63 64 #define FTP_NAMES 65 #include <arpa/ftp.h> 66 #include <arpa/inet.h> 67 #include <arpa/telnet.h> 68 69 #include <ctype.h> 70 #include <dirent.h> 71 #include <err.h> 72 #include <errno.h> 73 #include <fcntl.h> 74 #include <fnmatch.h> 75 #include <glob.h> 76 #include <limits.h> 77 #include <netdb.h> 78 #include <pwd.h> 79 #include <setjmp.h> 80 #include <signal.h> 81 #include <stdio.h> 82 #include <stdlib.h> 83 #include <string.h> 84 #include <syslog.h> 85 #include <time.h> 86 #include <unistd.h> 87 #ifdef SKEY 88 #include <skey.h> 89 #endif 90 #ifdef KERBEROS5 91 #include <krb5.h> 92 #endif 93 94 #include "extern.h" 95 #include "pathnames.h" 96 97 #if __STDC__ 98 #include <stdarg.h> 99 #else 100 #include <varargs.h> 101 #endif 102 103 #ifndef TRUE 104 #define TRUE 1 105 #define FALSE 0 106 #endif 107 108 const char version[] = "Version: 7.1.0"; 109 110 struct sockaddr_in ctrl_addr; 111 struct sockaddr_in data_source; 112 struct sockaddr_in data_dest; 113 struct sockaddr_in his_addr; 114 struct sockaddr_in pasv_addr; 115 116 int data; 117 jmp_buf errcatch, urgcatch; 118 int logged_in; 119 struct passwd *pw; 120 int debug; 121 int sflag; 122 int logging; 123 int guest; 124 int dochroot; 125 int type; 126 int form; 127 int stru; /* avoid C keyword */ 128 int mode; 129 int usedefault = 1; /* for data transfers */ 130 int pdata = -1; /* for passive mode */ 131 sig_atomic_t transflag; 132 off_t file_size; 133 off_t byte_count; 134 char tmpline[7]; 135 char hostname[MAXHOSTNAMELEN+1]; 136 char remotehost[MAXHOSTNAMELEN+1]; 137 static char ttyline[20]; 138 char *tty = ttyline; /* for klogin */ 139 140 static char *anondir = NULL; 141 static char confdir[MAXPATHLEN]; 142 143 #if defined(KERBEROS) || defined(KERBEROS5) 144 int notickets = 1; 145 char *krbtkfile_env = NULL; 146 #endif 147 148 /* 149 * Timeout intervals for retrying connections 150 * to hosts that don't accept PORT cmds. This 151 * is a kludge, but given the problems with TCP... 152 */ 153 #define SWAITMAX 90 /* wait at most 90 seconds */ 154 #define SWAITINT 5 /* interval between retries */ 155 156 int swaitmax = SWAITMAX; 157 int swaitint = SWAITINT; 158 159 #ifdef HASSETPROCTITLE 160 char proctitle[BUFSIZ]; /* initial part of title */ 161 #endif /* HASSETPROCTITLE */ 162 163 static void ack __P((char *)); 164 static void myoob __P((int)); 165 static int checkuser __P((const char *, const char *, int, int)); 166 static int checkaccess __P((const char *)); 167 static FILE *dataconn __P((char *, off_t, char *)); 168 static void dolog __P((struct sockaddr_in *)); 169 static void end_login __P((void)); 170 static FILE *getdatasock __P((char *)); 171 static char *gunique __P((char *)); 172 static void lostconn __P((int)); 173 static int receive_data __P((FILE *, FILE *)); 174 static void replydirname __P((const char *, const char *)); 175 static int send_data __P((FILE *, FILE *, off_t)); 176 static struct passwd * 177 sgetpwnam __P((const char *)); 178 179 int main __P((int, char *[])); 180 181 #if defined(KERBEROS) || defined(KERBEROS5) 182 int klogin __P((struct passwd *, char *, char *, char *)); 183 void kdestroy __P((void)); 184 #endif 185 int 186 main(argc, argv) 187 int argc; 188 char *argv[]; 189 { 190 int addrlen, ch, on = 1, tos; 191 char *cp, line[LINE_MAX]; 192 FILE *fd; 193 #ifdef KERBEROS5 194 krb5_error_code kerror; 195 #endif 196 197 debug = 0; 198 logging = 0; 199 sflag = 0; 200 (void)strcpy(confdir, _DEFAULT_CONFDIR); 201 202 while ((ch = getopt(argc, argv, "a:c:C:dlst:T:u:v")) != -1) { 203 switch (ch) { 204 case 'a': 205 anondir = optarg; 206 break; 207 208 case 'c': 209 (void)strncpy(confdir, optarg, sizeof(confdir)); 210 confdir[sizeof(confdir)-1] = '\0'; 211 break; 212 213 case 'C': 214 exit(checkaccess(optarg)); 215 /* NOTREACHED */ 216 217 case 'd': 218 case 'v': /* deprecated */ 219 debug = 1; 220 break; 221 222 case 'l': 223 logging++; /* > 1 == extra logging */ 224 break; 225 226 case 's': 227 sflag = 1; 228 break; 229 230 case 't': 231 case 'T': 232 case 'u': 233 warnx("-%c has been deprecated in favour of ftpd.conf", 234 ch); 235 break; 236 237 default: 238 if (optopt == 'a' || optopt == 'C') 239 exit(1); 240 warnx("unknown flag -%c ignored", optopt); 241 break; 242 } 243 } 244 245 /* 246 * LOG_NDELAY sets up the logging connection immediately, 247 * necessary for anonymous ftp's that chroot and can't do it later. 248 */ 249 openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); 250 addrlen = sizeof(his_addr); 251 if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { 252 syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); 253 exit(1); 254 } 255 addrlen = sizeof(ctrl_addr); 256 if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { 257 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); 258 exit(1); 259 } 260 #ifdef IP_TOS 261 tos = IPTOS_LOWDELAY; 262 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) 263 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 264 #endif 265 data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); 266 267 /* set this here so klogin can use it... */ 268 (void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid()); 269 270 (void) freopen(_PATH_DEVNULL, "w", stderr); 271 (void) signal(SIGPIPE, lostconn); 272 (void) signal(SIGCHLD, SIG_IGN); 273 if ((long)signal(SIGURG, myoob) < 0) 274 syslog(LOG_ERR, "signal: %m"); 275 276 /* Try to handle urgent data inline */ 277 #ifdef SO_OOBINLINE 278 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) 279 syslog(LOG_ERR, "setsockopt: %m"); 280 #endif 281 282 #ifdef F_SETOWN 283 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) 284 syslog(LOG_ERR, "fcntl F_SETOWN: %m"); 285 #endif 286 dolog(&his_addr); 287 /* 288 * Set up default state 289 */ 290 data = -1; 291 type = TYPE_A; 292 form = FORM_N; 293 stru = STRU_F; 294 mode = MODE_S; 295 tmpline[0] = '\0'; 296 hasyyerrored = 0; 297 298 #ifdef KERBEROS5 299 kerror = krb5_init_context(&kcontext); 300 if (kerror) { 301 syslog(LOG_NOTICE, "%s when initializing Kerberos context", 302 error_message(kerror)); 303 exit(0); 304 } 305 #endif /* KERBEROS5 */ 306 307 /* If logins are disabled, print out the message. */ 308 if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) { 309 while (fgets(line, sizeof(line), fd) != NULL) { 310 if ((cp = strchr(line, '\n')) != NULL) 311 *cp = '\0'; 312 lreply(530, "%s", line); 313 } 314 (void) fflush(stdout); 315 (void) fclose(fd); 316 reply(530, "System not available."); 317 exit(0); 318 } 319 if ((fd = fopen(conffilename(_PATH_FTPWELCOME), "r")) != NULL) { 320 while (fgets(line, sizeof(line), fd) != NULL) { 321 if ((cp = strchr(line, '\n')) != NULL) 322 *cp = '\0'; 323 lreply(220, "%s", line); 324 } 325 (void) fflush(stdout); 326 (void) fclose(fd); 327 /* reply(220,) must follow */ 328 } 329 (void)gethostname(hostname, sizeof(hostname)); 330 hostname[sizeof(hostname) - 1] = '\0'; 331 reply(220, "%s FTP server (%s) ready.", hostname, version); 332 curclass.timeout = 300; /* 5 minutes, as per login(1) */ 333 (void) setjmp(errcatch); 334 for (;;) 335 (void) yyparse(); 336 /* NOTREACHED */ 337 } 338 339 static void 340 lostconn(signo) 341 int signo; 342 { 343 344 if (debug) 345 syslog(LOG_DEBUG, "lost connection"); 346 dologout(1); 347 } 348 349 /* 350 * Save the result of a getpwnam. Used for USER command, since 351 * the data returned must not be clobbered by any other command 352 * (e.g., globbing). 353 */ 354 static struct passwd * 355 sgetpwnam(name) 356 const char *name; 357 { 358 static struct passwd save; 359 struct passwd *p; 360 361 if ((p = getpwnam(name)) == NULL) 362 return (p); 363 if (save.pw_name) { 364 free((char *)save.pw_name); 365 free((char *)save.pw_passwd); 366 free((char *)save.pw_gecos); 367 free((char *)save.pw_dir); 368 free((char *)save.pw_shell); 369 } 370 save = *p; 371 save.pw_name = xstrdup(p->pw_name); 372 save.pw_passwd = xstrdup(p->pw_passwd); 373 save.pw_gecos = xstrdup(p->pw_gecos); 374 save.pw_dir = xstrdup(p->pw_dir); 375 save.pw_shell = xstrdup(p->pw_shell); 376 return (&save); 377 } 378 379 static int login_attempts; /* number of failed login attempts */ 380 static int askpasswd; /* had user command, ask for passwd */ 381 static char curname[10]; /* current USER name */ 382 383 /* 384 * USER command. 385 * Sets global passwd pointer pw if named account exists and is acceptable; 386 * sets askpasswd if a PASS command is expected. If logged in previously, 387 * need to reset state. If name is "ftp" or "anonymous", the name is not in 388 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return. 389 * If account doesn't exist, ask for passwd anyway. Otherwise, check user 390 * requesting login privileges. Disallow anyone who does not have a standard 391 * shell as returned by getusershell(). Disallow anyone mentioned in the file 392 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. 393 */ 394 void 395 user(name) 396 char *name; 397 { 398 if (logged_in) { 399 if (guest) { 400 reply(530, "Can't change user from guest login."); 401 return; 402 } else if (dochroot) { 403 reply(530, "Can't change user from chroot user."); 404 return; 405 } 406 end_login(); 407 } 408 409 #if defined(KERBEROS) || defined(KERBEROS5) 410 kdestroy(); 411 #endif 412 413 guest = 0; 414 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { 415 if (checkaccess("ftp") || checkaccess("anonymous")) 416 reply(530, "User %s access denied.", name); 417 else if ((pw = sgetpwnam("ftp")) != NULL) { 418 guest = 1; 419 askpasswd = 1; 420 reply(331, 421 "Guest login ok, type your name as password."); 422 } else 423 reply(530, "User %s unknown.", name); 424 if (!askpasswd && logging) 425 syslog(LOG_NOTICE, 426 "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost); 427 return; 428 } 429 430 pw = sgetpwnam(name); 431 if (logging) 432 strncpy(curname, name, sizeof(curname)-1); 433 434 #ifdef SKEY 435 if (skey_haskey(name) == 0) { 436 char *myskey; 437 438 myskey = skey_keyinfo(name); 439 reply(331, "Password [%s] required for %s.", 440 myskey ? myskey : "error getting challenge", name); 441 } else 442 #endif 443 reply(331, "Password required for %s.", name); 444 445 askpasswd = 1; 446 /* 447 * Delay before reading passwd after first failed 448 * attempt to slow down passwd-guessing programs. 449 */ 450 if (login_attempts) 451 sleep((unsigned) login_attempts); 452 } 453 454 /* 455 * Determine whether something is to happen (allow access, chroot) 456 * for a user. Each line is a shell-style glob followed by 457 * `yes' or `no'. 458 * 459 * For backward compatability, `allow' and `deny' are synonymns 460 * for `yes' and `no', respectively. 461 * 462 * Each glob is matched against the username in turn, and the first 463 * match found is used. If no match is found, the result is the 464 * argument `def'. If a match is found but without and explicit 465 * `yes'/`no', the result is the opposite of def. 466 * 467 * If the file doesn't exist at all, the result is the argument 468 * `nofile' 469 * 470 * Any line starting with `#' is considered a comment and ignored. 471 * 472 * Returns FALSE if the user is denied, or TRUE if they are allowed. 473 */ 474 int 475 checkuser(fname, name, def, nofile) 476 const char *fname, *name; 477 int def, nofile; 478 { 479 FILE *fd; 480 int retval; 481 char *glob, *perm, line[BUFSIZ]; 482 483 retval = def; 484 if ((fd = fopen(conffilename(fname), "r")) == NULL) 485 return nofile; 486 487 while (fgets(line, sizeof(line), fd) != NULL) { 488 glob = strtok(line, " \t\n"); 489 if (glob[0] == '#') 490 continue; 491 perm = strtok(NULL, " \t\n"); 492 if (fnmatch(glob, name, 0) == 0) { 493 if (perm != NULL && 494 ((strcasecmp(perm, "allow") == 0) || 495 (strcasecmp(perm, "yes") == 0))) 496 retval = TRUE; 497 else if (perm != NULL && 498 ((strcasecmp(perm, "deny") == 0) || 499 (strcasecmp(perm, "no") == 0))) 500 retval = FALSE; 501 else 502 retval = !def; 503 break; 504 } 505 } 506 (void) fclose(fd); 507 return (retval); 508 } 509 510 /* 511 * Check if user is allowed by /etc/ftpusers 512 * returns 0 for yes, 1 for no 513 */ 514 int 515 checkaccess(name) 516 const char *name; 517 { 518 519 return (! checkuser(_PATH_FTPUSERS, name, TRUE, FALSE)); 520 } 521 522 /* 523 * Terminate login as previous user, if any, resetting state; 524 * used when USER command is given or login fails. 525 */ 526 static void 527 end_login() 528 { 529 530 (void) seteuid((uid_t)0); 531 if (logged_in) 532 logwtmp(ttyline, "", ""); 533 pw = NULL; 534 logged_in = 0; 535 guest = 0; 536 dochroot = 0; 537 } 538 539 void 540 pass(passwd) 541 char *passwd; 542 { 543 int rval; 544 FILE *fd; 545 char const *cp, *shell, *home; 546 547 if (logged_in || askpasswd == 0) { 548 reply(503, "Login with USER first."); 549 return; 550 } 551 askpasswd = 0; 552 if (!guest) { /* "ftp" is only account allowed no password */ 553 if (pw == NULL) { 554 rval = 1; /* failure below */ 555 goto skip; 556 } 557 #ifdef KERBEROS 558 if (klogin(pw, "", hostname, passwd) == 0) { 559 rval = 0; 560 goto skip; 561 } 562 #endif 563 #ifdef KERBEROS5 564 if (klogin(pw, "", hostname, passwd) == 0) { 565 rval = 0; 566 goto skip; 567 } 568 #endif 569 #ifdef SKEY 570 if (skey_haskey(pw->pw_name) == 0 && 571 skey_passcheck(pw->pw_name, passwd) != -1) { 572 rval = 0; 573 goto skip; 574 } 575 #endif 576 if (!sflag && *pw->pw_passwd != '\0' && 577 !strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd)) { 578 rval = 0; 579 goto skip; 580 } 581 rval = 1; 582 583 skip: 584 if (pw != NULL && pw->pw_expire && time(NULL) >= pw->pw_expire) 585 rval = 2; 586 /* 587 * If rval > 0, the user failed the authentication check 588 * above. If rval == 0, either Kerberos or local authentication 589 * succeeded. 590 */ 591 if (rval) { 592 reply(530, rval == 2 ? "Password expired." : 593 "Login incorrect."); 594 if (logging) { 595 syslog(LOG_NOTICE, 596 "FTP LOGIN FAILED FROM %s", remotehost); 597 syslog(LOG_AUTHPRIV | LOG_NOTICE, 598 "FTP LOGIN FAILED FROM %s, %s", 599 remotehost, curname); 600 } 601 pw = NULL; 602 if (login_attempts++ >= 5) { 603 syslog(LOG_NOTICE, 604 "repeated login failures from %s", 605 remotehost); 606 exit(0); 607 } 608 return; 609 } 610 } 611 612 /* password was ok; see if anything else prevents login */ 613 if (checkaccess(pw->pw_name)) { 614 reply(530, "User %s may not use FTP.", pw->pw_name); 615 if (logging) 616 syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s", 617 remotehost, pw->pw_name); 618 pw = (struct passwd *) NULL; 619 return; 620 } 621 /* check for valid shell, if not guest user */ 622 if ((shell = pw->pw_shell) == NULL || *shell == 0) 623 shell = _PATH_BSHELL; 624 while ((cp = getusershell()) != NULL) 625 if (strcmp(cp, shell) == 0) 626 break; 627 endusershell(); 628 if (cp == NULL && guest == 0) { 629 reply(530, "User %s may not use FTP.", pw->pw_name); 630 if (logging) 631 syslog(LOG_NOTICE, 632 "FTP LOGIN REFUSED FROM %s, %s", 633 remotehost, pw->pw_name); 634 pw = (struct passwd *) NULL; 635 return; 636 } 637 638 login_attempts = 0; /* this time successful */ 639 if (setegid((gid_t)pw->pw_gid) < 0) { 640 reply(550, "Can't set gid."); 641 return; 642 } 643 (void) initgroups(pw->pw_name, pw->pw_gid); 644 645 /* open wtmp before chroot */ 646 logwtmp(ttyline, pw->pw_name, remotehost); 647 logged_in = 1; 648 649 dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name, FALSE, FALSE); 650 651 /* parse ftpd.conf, setting up various parameters */ 652 if (guest) 653 parse_conf(CLASS_GUEST); 654 else if (dochroot) 655 parse_conf(CLASS_CHROOT); 656 else 657 parse_conf(CLASS_REAL); 658 659 home = "/"; 660 if (guest) { 661 /* 662 * We MUST do a chdir() after the chroot. Otherwise 663 * the old current directory will be accessible as "." 664 * outside the new root! 665 */ 666 if (chroot(anondir ? anondir : pw->pw_dir) < 0 || 667 chdir("/") < 0) { 668 reply(550, "Can't set guest privileges."); 669 goto bad; 670 } 671 } else if (dochroot) { 672 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { 673 reply(550, "Can't change root."); 674 goto bad; 675 } 676 } else if (chdir(pw->pw_dir) < 0) { 677 if (chdir("/") < 0) { 678 reply(530, "User %s: can't change directory to %s.", 679 pw->pw_name, pw->pw_dir); 680 goto bad; 681 } else 682 lreply(230, "No directory! Logging in with home=/"); 683 } else 684 home = pw->pw_dir; 685 if (seteuid((uid_t)pw->pw_uid) < 0) { 686 reply(550, "Can't set uid."); 687 goto bad; 688 } 689 setenv("HOME", home, 1); 690 691 692 /* 693 * Display a login message, if it exists. 694 * N.B. reply(230,) must follow the message. 695 */ 696 if ((fd = fopen(conffilename(_PATH_FTPLOGINMESG), "r")) != NULL) { 697 char *cp, line[LINE_MAX]; 698 699 while (fgets(line, sizeof(line), fd) != NULL) { 700 if ((cp = strchr(line, '\n')) != NULL) 701 *cp = '\0'; 702 lreply(230, "%s", line); 703 } 704 (void) fflush(stdout); 705 (void) fclose(fd); 706 } 707 show_chdir_messages(230); 708 if (guest) { 709 reply(230, "Guest login ok, access restrictions apply."); 710 #ifdef HASSETPROCTITLE 711 snprintf(proctitle, sizeof(proctitle), 712 "%s: anonymous/%.*s", remotehost, 713 (int) (sizeof(proctitle) - sizeof(remotehost) - 714 sizeof(": anonymous/")), passwd); 715 setproctitle(proctitle); 716 #endif /* HASSETPROCTITLE */ 717 if (logging) 718 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s", 719 remotehost, passwd); 720 } else { 721 reply(230, "User %s logged in.", pw->pw_name); 722 #ifdef HASSETPROCTITLE 723 snprintf(proctitle, sizeof(proctitle), 724 "%s: %s", remotehost, pw->pw_name); 725 setproctitle(proctitle); 726 #endif /* HASSETPROCTITLE */ 727 if (logging) 728 syslog(LOG_INFO, "FTP LOGIN FROM %s as %s", 729 remotehost, pw->pw_name); 730 } 731 (void) umask(curclass.umask); 732 return; 733 bad: 734 /* Forget all about it... */ 735 end_login(); 736 } 737 738 void 739 retrieve(cmd, name) 740 char *cmd, *name; 741 { 742 FILE *fin = NULL, *dout; 743 struct stat st; 744 int (*closefunc) __P((FILE *)) = NULL; 745 int log, sendrv, closerv, stderrfd, isconversion; 746 747 sendrv = closerv = stderrfd = -1; 748 isconversion = 0; 749 log = (cmd == 0); 750 if (cmd == NULL) { 751 fin = fopen(name, "r"), closefunc = fclose; 752 if (fin == NULL) 753 cmd = do_conversion(name); 754 if (cmd != NULL) { 755 isconversion++; 756 syslog(LOG_INFO, "get command: '%s'", cmd); 757 } 758 } 759 if (cmd != NULL) { 760 char line[BUFSIZ]; 761 char temp[MAXPATHLEN + 1]; 762 763 (void)snprintf(temp, sizeof(temp), "%s", TMPFILE); 764 stderrfd = mkstemp(temp); 765 if (stderrfd != -1) 766 (void)unlink(temp); 767 (void)snprintf(line, sizeof(line), cmd, name), name = line; 768 fin = ftpd_popen(line, "r", stderrfd), closefunc = ftpd_pclose; 769 st.st_size = -1; 770 st.st_blksize = BUFSIZ; 771 } 772 if (fin == NULL) { 773 if (errno != 0) { 774 perror_reply(550, name); 775 if (log) { 776 logcmd("get", -1, name, NULL); 777 } 778 } 779 if (stderrfd != -1) 780 (void)close(stderrfd); 781 return; 782 } 783 byte_count = -1; 784 if (cmd == NULL 785 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) { 786 reply(550, "%s: not a plain file.", name); 787 goto done; 788 } 789 if (restart_point) { 790 if (type == TYPE_A) { 791 off_t i; 792 int c; 793 794 for (i = 0; i < restart_point; i++) { 795 if ((c=getc(fin)) == EOF) { 796 perror_reply(550, name); 797 goto done; 798 } 799 if (c == '\n') 800 i++; 801 } 802 } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) { 803 perror_reply(550, name); 804 goto done; 805 } 806 } 807 dout = dataconn(name, st.st_size, "w"); 808 if (dout == NULL) 809 goto done; 810 sendrv = send_data(fin, dout, st.st_blksize); 811 (void) fclose(dout); 812 data = -1; 813 pdata = -1; 814 done: 815 if (log) 816 logcmd("get", byte_count, name, NULL); 817 closerv = (*closefunc)(fin); 818 if (sendrv == 0) { 819 FILE *err; 820 struct stat sb; 821 822 if (cmd != NULL && closerv != 0) { 823 lreply(226, 824 "Command returned an exit status of %d", 825 closerv); 826 if (isconversion) 827 syslog(LOG_INFO, 828 "get command: '%s' returned %d", 829 cmd, closerv); 830 } 831 if (cmd != NULL && stderrfd != -1 && 832 (fstat(stderrfd, &sb) == 0) && sb.st_size > 0 && 833 ((err = fdopen(stderrfd, "r")) != NULL)) { 834 char *cp, line[LINE_MAX]; 835 836 lreply(226, "Command error messages:"); 837 rewind(err); 838 while (fgets(line, sizeof(line), err) != NULL) { 839 if ((cp = strchr(line, '\n')) != NULL) 840 *cp = '\0'; 841 lreply(226, " %s", line); 842 } 843 (void) fflush(stdout); 844 (void) fclose(err); 845 lreply(226, "End of command error messages."); 846 /* a reply(226,) must follow */ 847 } 848 reply(226, "Transfer complete."); 849 } 850 if (stderrfd != -1) 851 (void)close(stderrfd); 852 } 853 854 void 855 store(name, mode, unique) 856 char *name, *mode; 857 int unique; 858 { 859 FILE *fout, *din; 860 struct stat st; 861 int (*closefunc) __P((FILE *)); 862 863 if (unique && stat(name, &st) == 0 && 864 (name = gunique(name)) == NULL) { 865 logcmd(*mode == 'w' ? "put" : "append", -1, name, NULL); 866 return; 867 } 868 869 if (restart_point) 870 mode = "r+"; 871 fout = fopen(name, mode); 872 closefunc = fclose; 873 if (fout == NULL) { 874 perror_reply(553, name); 875 logcmd(*mode == 'w' ? "put" : "append", -1, name, NULL); 876 return; 877 } 878 byte_count = -1; 879 if (restart_point) { 880 if (type == TYPE_A) { 881 off_t i; 882 int c; 883 884 for (i = 0; i < restart_point; i++) { 885 if ((c=getc(fout)) == EOF) { 886 perror_reply(550, name); 887 goto done; 888 } 889 if (c == '\n') 890 i++; 891 } 892 /* 893 * We must do this seek to "current" position 894 * because we are changing from reading to 895 * writing. 896 */ 897 if (fseek(fout, 0L, SEEK_CUR) < 0) { 898 perror_reply(550, name); 899 goto done; 900 } 901 } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) { 902 perror_reply(550, name); 903 goto done; 904 } 905 } 906 din = dataconn(name, (off_t)-1, "r"); 907 if (din == NULL) 908 goto done; 909 if (receive_data(din, fout) == 0) { 910 if (unique) 911 reply(226, "Transfer complete (unique file name:%s).", 912 name); 913 else 914 reply(226, "Transfer complete."); 915 } 916 (void) fclose(din); 917 data = -1; 918 pdata = -1; 919 done: 920 logcmd(*mode == 'w' ? "put" : "append", byte_count, name, NULL); 921 (*closefunc)(fout); 922 } 923 924 static FILE * 925 getdatasock(mode) 926 char *mode; 927 { 928 int on = 1, s, t, tries; 929 930 if (data >= 0) 931 return (fdopen(data, mode)); 932 (void) seteuid((uid_t)0); 933 s = socket(AF_INET, SOCK_STREAM, 0); 934 if (s < 0) 935 goto bad; 936 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 937 (char *) &on, sizeof(on)) < 0) 938 goto bad; 939 /* anchor socket to avoid multi-homing problems */ 940 data_source.sin_len = sizeof(struct sockaddr_in); 941 data_source.sin_family = AF_INET; 942 data_source.sin_addr = ctrl_addr.sin_addr; 943 for (tries = 1; ; tries++) { 944 if (bind(s, (struct sockaddr *)&data_source, 945 sizeof(data_source)) >= 0) 946 break; 947 if (errno != EADDRINUSE || tries > 10) 948 goto bad; 949 sleep(tries); 950 } 951 (void) seteuid((uid_t)pw->pw_uid); 952 #ifdef IP_TOS 953 on = IPTOS_THROUGHPUT; 954 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 955 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 956 #endif 957 return (fdopen(s, mode)); 958 bad: 959 /* Return the real value of errno (close may change it) */ 960 t = errno; 961 (void) seteuid((uid_t)pw->pw_uid); 962 (void) close(s); 963 errno = t; 964 return (NULL); 965 } 966 967 static FILE * 968 dataconn(name, size, mode) 969 char *name; 970 off_t size; 971 char *mode; 972 { 973 char sizebuf[32]; 974 FILE *file; 975 int retry = 0, tos; 976 977 file_size = size; 978 byte_count = 0; 979 if (size != (off_t) -1) 980 (void)snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)", 981 (long long)size); 982 else 983 sizebuf[0] = '\0'; 984 if (pdata >= 0) { 985 struct sockaddr_in from; 986 int s, fromlen = sizeof(from); 987 988 (void) alarm(curclass.timeout); 989 s = accept(pdata, (struct sockaddr *)&from, &fromlen); 990 (void) alarm(0); 991 if (s < 0) { 992 reply(425, "Can't open data connection."); 993 (void) close(pdata); 994 pdata = -1; 995 return (NULL); 996 } 997 (void) close(pdata); 998 pdata = s; 999 #ifdef IP_TOS 1000 tos = IPTOS_THROUGHPUT; 1001 (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, 1002 sizeof(int)); 1003 #endif 1004 reply(150, "Opening %s mode data connection for '%s'%s.", 1005 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 1006 return (fdopen(pdata, mode)); 1007 } 1008 if (data >= 0) { 1009 reply(125, "Using existing data connection for '%s'%s.", 1010 name, sizebuf); 1011 usedefault = 1; 1012 return (fdopen(data, mode)); 1013 } 1014 if (usedefault) 1015 data_dest = his_addr; 1016 usedefault = 1; 1017 file = getdatasock(mode); 1018 if (file == NULL) { 1019 reply(425, "Can't create data socket (%s,%d): %s.", 1020 inet_ntoa(data_source.sin_addr), 1021 ntohs(data_source.sin_port), strerror(errno)); 1022 return (NULL); 1023 } 1024 data = fileno(file); 1025 while (connect(data, (struct sockaddr *)&data_dest, 1026 sizeof(data_dest)) < 0) { 1027 if (errno == EADDRINUSE && retry < swaitmax) { 1028 sleep((unsigned) swaitint); 1029 retry += swaitint; 1030 continue; 1031 } 1032 perror_reply(425, "Can't build data connection"); 1033 (void) fclose(file); 1034 data = -1; 1035 return (NULL); 1036 } 1037 reply(150, "Opening %s mode data connection for '%s'%s.", 1038 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 1039 return (file); 1040 } 1041 1042 /* 1043 * Tranfer the contents of "instr" to "outstr" peer using the appropriate 1044 * encapsulation of the data subject * to Mode, Structure, and Type. 1045 * 1046 * NB: Form isn't handled. 1047 */ 1048 static int 1049 send_data(instr, outstr, blksize) 1050 FILE *instr, *outstr; 1051 off_t blksize; 1052 { 1053 int c, cnt, filefd, netfd; 1054 char *buf; 1055 1056 transflag++; 1057 if (setjmp(urgcatch)) { 1058 transflag = 0; 1059 return (-1); 1060 } 1061 1062 switch (type) { 1063 1064 case TYPE_A: 1065 while ((c = getc(instr)) != EOF) { 1066 byte_count++; 1067 if (c == '\n') { 1068 if (ferror(outstr)) 1069 goto data_err; 1070 (void) putc('\r', outstr); 1071 } 1072 (void) putc(c, outstr); 1073 } 1074 fflush(outstr); 1075 transflag = 0; 1076 if (ferror(instr)) 1077 goto file_err; 1078 if (ferror(outstr)) 1079 goto data_err; 1080 return (0); 1081 1082 case TYPE_I: 1083 case TYPE_L: 1084 if ((buf = malloc((u_int)blksize)) == NULL) { 1085 transflag = 0; 1086 perror_reply(451, "Local resource failure: malloc"); 1087 return (-1); 1088 } 1089 netfd = fileno(outstr); 1090 filefd = fileno(instr); 1091 while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 && 1092 write(netfd, buf, cnt) == cnt) 1093 byte_count += cnt; 1094 transflag = 0; 1095 (void)free(buf); 1096 if (cnt != 0) { 1097 if (cnt < 0) 1098 goto file_err; 1099 goto data_err; 1100 } 1101 return (0); 1102 default: 1103 transflag = 0; 1104 reply(550, "Unimplemented TYPE %d in send_data", type); 1105 return (-1); 1106 } 1107 1108 data_err: 1109 transflag = 0; 1110 perror_reply(426, "Data connection"); 1111 return (-1); 1112 1113 file_err: 1114 transflag = 0; 1115 perror_reply(551, "Error on input file"); 1116 return (-1); 1117 } 1118 1119 /* 1120 * Transfer data from peer to "outstr" using the appropriate encapulation of 1121 * the data subject to Mode, Structure, and Type. 1122 * 1123 * N.B.: Form isn't handled. 1124 */ 1125 static int 1126 receive_data(instr, outstr) 1127 FILE *instr, *outstr; 1128 { 1129 int c, cnt, bare_lfs; 1130 char buf[BUFSIZ]; 1131 #ifdef __GNUC__ 1132 (void) &bare_lfs; 1133 #endif 1134 1135 bare_lfs = 0; 1136 transflag++; 1137 if (setjmp(urgcatch)) { 1138 transflag = 0; 1139 return (-1); 1140 } 1141 1142 switch (type) { 1143 1144 case TYPE_I: 1145 case TYPE_L: 1146 while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) { 1147 if (write(fileno(outstr), buf, cnt) != cnt) 1148 goto file_err; 1149 byte_count += cnt; 1150 } 1151 if (cnt < 0) 1152 goto data_err; 1153 transflag = 0; 1154 return (0); 1155 1156 case TYPE_E: 1157 reply(553, "TYPE E not implemented."); 1158 transflag = 0; 1159 return (-1); 1160 1161 case TYPE_A: 1162 while ((c = getc(instr)) != EOF) { 1163 byte_count++; 1164 if (c == '\n') 1165 bare_lfs++; 1166 while (c == '\r') { 1167 if (ferror(outstr)) 1168 goto data_err; 1169 if ((c = getc(instr)) != '\n') { 1170 (void) putc ('\r', outstr); 1171 if (c == '\0' || c == EOF) 1172 goto contin2; 1173 } 1174 } 1175 (void) putc(c, outstr); 1176 contin2: ; 1177 } 1178 fflush(outstr); 1179 if (ferror(instr)) 1180 goto data_err; 1181 if (ferror(outstr)) 1182 goto file_err; 1183 transflag = 0; 1184 if (bare_lfs) { 1185 lreply(226, 1186 "WARNING! %d bare linefeeds received in ASCII mode", 1187 bare_lfs); 1188 (void)printf(" File may not have transferred correctly.\r\n"); 1189 } 1190 return (0); 1191 default: 1192 reply(550, "Unimplemented TYPE %d in receive_data", type); 1193 transflag = 0; 1194 return (-1); 1195 } 1196 1197 data_err: 1198 transflag = 0; 1199 perror_reply(426, "Data Connection"); 1200 return (-1); 1201 1202 file_err: 1203 transflag = 0; 1204 perror_reply(452, "Error writing file"); 1205 return (-1); 1206 } 1207 1208 void 1209 statfilecmd(filename) 1210 char *filename; 1211 { 1212 FILE *fin; 1213 int c; 1214 char line[LINE_MAX]; 1215 1216 (void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename); 1217 fin = ftpd_popen(line, "r", STDOUT_FILENO); 1218 lreply(211, "status of %s:", filename); 1219 while ((c = getc(fin)) != EOF) { 1220 if (c == '\n') { 1221 if (ferror(stdout)){ 1222 perror_reply(421, "control connection"); 1223 (void) ftpd_pclose(fin); 1224 dologout(1); 1225 /* NOTREACHED */ 1226 } 1227 if (ferror(fin)) { 1228 perror_reply(551, filename); 1229 (void) ftpd_pclose(fin); 1230 return; 1231 } 1232 (void) putc('\r', stdout); 1233 } 1234 (void) putc(c, stdout); 1235 } 1236 (void) ftpd_pclose(fin); 1237 reply(211, "End of Status"); 1238 } 1239 1240 void 1241 statcmd() 1242 { 1243 struct sockaddr_in *sin; 1244 u_char *a, *p; 1245 1246 lreply(211, "%s FTP server status:", hostname); 1247 lreply(211, "%s", version); 1248 if (isdigit(remotehost[0])) 1249 lreply(211, "Connected to %s", remotehost); 1250 else 1251 lreply(211, "Connected to %s (%s)", remotehost, 1252 inet_ntoa(his_addr.sin_addr)); 1253 if (logged_in) { 1254 if (guest) 1255 lreply(211, "Logged in anonymously"); 1256 else 1257 lreply(211, "Logged in as %s", pw->pw_name); 1258 } else if (askpasswd) 1259 lreply(211, "Waiting for password"); 1260 else 1261 lreply(211, "Waiting for user name"); 1262 printf("211- TYPE: %s", typenames[type]); 1263 if (type == TYPE_A || type == TYPE_E) 1264 printf(", FORM: %s", formnames[form]); 1265 if (type == TYPE_L) 1266 #if NBBY == 8 1267 printf(" %d", NBBY); 1268 #else 1269 printf(" %d", bytesize); /* need definition! */ 1270 #endif 1271 printf("; STRUcture: %s; transfer MODE: %s\r\n", 1272 strunames[stru], modenames[mode]); 1273 if (data != -1) 1274 lreply(211, "Data connection open"); 1275 else if (pdata != -1) { 1276 printf("211- in Passive mode"); 1277 sin = &pasv_addr; 1278 goto printaddr; 1279 } else if (usedefault == 0) { 1280 printf("211- PORT"); 1281 sin = &data_dest; 1282 printaddr: 1283 a = (u_char *) &sin->sin_addr; 1284 p = (u_char *) &sin->sin_port; 1285 #define UC(b) (((int) b) & 0xff) 1286 printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]), 1287 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 1288 #undef UC 1289 } else 1290 lreply(211, "No data connection"); 1291 1292 if (logged_in) { 1293 struct ftpconv *cp; 1294 1295 lreply(211, ""); 1296 lreply(211, "Class: %s", curclass.classname); 1297 lreply(211, "Check PORT commands: %sabled", 1298 curclass.checkportcmd ? "en" : "dis"); 1299 if (curclass.display) 1300 lreply(211, "Display file: %s", curclass.display); 1301 if (curclass.notify) 1302 lreply(211, "Notify fileglob: %s", curclass.notify); 1303 lreply(211, "Idle timeout: %d, maximum timeout: %d", 1304 curclass.timeout, curclass.maxtimeout); 1305 lreply(211, "DELE, MKD, RMD, UMASK, CHMOD commands: %sabled", 1306 curclass.modify ? "en" : "dis"); 1307 lreply(211, "Umask: %.04o", curclass.umask); 1308 for (cp = curclass.conversions; cp != NULL; cp=cp->next) { 1309 if (cp->suffix == NULL || cp->types == NULL || 1310 cp->command == NULL) 1311 continue; 1312 lreply(211, 1313 "Conversion: %s [%s] disable: %s, command: %s", 1314 cp->suffix, cp->types, cp->disable, cp->command); 1315 } 1316 } 1317 1318 reply(211, "End of status"); 1319 } 1320 1321 void 1322 fatal(s) 1323 char *s; 1324 { 1325 1326 reply(451, "Error in server: %s\n", s); 1327 reply(221, "Closing connection due to server error."); 1328 dologout(0); 1329 /* NOTREACHED */ 1330 } 1331 1332 void 1333 #ifdef __STDC__ 1334 reply(int n, const char *fmt, ...) 1335 #else 1336 reply(n, fmt, va_alist) 1337 int n; 1338 char *fmt; 1339 va_dcl 1340 #endif 1341 { 1342 va_list ap; 1343 #ifdef __STDC__ 1344 va_start(ap, fmt); 1345 #else 1346 va_start(ap); 1347 #endif 1348 (void)printf("%d ", n); 1349 (void)vprintf(fmt, ap); 1350 (void)printf("\r\n"); 1351 (void)fflush(stdout); 1352 if (debug) { 1353 syslog(LOG_DEBUG, "<--- %d ", n); 1354 vsyslog(LOG_DEBUG, fmt, ap); 1355 } 1356 } 1357 1358 void 1359 #ifdef __STDC__ 1360 lreply(int n, const char *fmt, ...) 1361 #else 1362 lreply(n, fmt, va_alist) 1363 int n; 1364 char *fmt; 1365 va_dcl 1366 #endif 1367 { 1368 va_list ap; 1369 #ifdef __STDC__ 1370 va_start(ap, fmt); 1371 #else 1372 va_start(ap); 1373 #endif 1374 (void)printf("%d- ", n); 1375 (void)vprintf(fmt, ap); 1376 (void)printf("\r\n"); 1377 (void)fflush(stdout); 1378 if (debug) { 1379 syslog(LOG_DEBUG, "<--- %d- ", n); 1380 vsyslog(LOG_DEBUG, fmt, ap); 1381 } 1382 } 1383 1384 static void 1385 ack(s) 1386 char *s; 1387 { 1388 1389 reply(250, "%s command successful.", s); 1390 } 1391 1392 void 1393 delete(name) 1394 char *name; 1395 { 1396 1397 logcmd("delete", -1, name, NULL); 1398 if (remove(name) < 0) 1399 perror_reply(550, name); 1400 else 1401 ack("DELE"); 1402 } 1403 1404 void 1405 cwd(path) 1406 const char *path; 1407 { 1408 1409 if (chdir(path) < 0) 1410 perror_reply(550, path); 1411 else { 1412 show_chdir_messages(250); 1413 ack("CWD"); 1414 } 1415 } 1416 1417 static void 1418 replydirname(name, message) 1419 const char *name, *message; 1420 { 1421 char npath[MAXPATHLEN + 1]; 1422 int i; 1423 1424 for (i = 0; *name != '\0' && i < sizeof(npath) - 1; i++, name++) { 1425 npath[i] = *name; 1426 if (*name == '"') 1427 npath[++i] = '"'; 1428 } 1429 npath[i] = '\0'; 1430 reply(257, "\"%s\" %s", npath, message); 1431 } 1432 1433 void 1434 makedir(name) 1435 char *name; 1436 { 1437 1438 logcmd("mkdir", -1, name, NULL); 1439 if (mkdir(name, 0777) < 0) 1440 perror_reply(550, name); 1441 else 1442 replydirname(name, "directory created."); 1443 } 1444 1445 void 1446 removedir(name) 1447 char *name; 1448 { 1449 1450 logcmd("rmdir", -1, name, NULL); 1451 if (rmdir(name) < 0) 1452 perror_reply(550, name); 1453 else 1454 ack("RMD"); 1455 } 1456 1457 void 1458 pwd() 1459 { 1460 char path[MAXPATHLEN + 1]; 1461 1462 if (getcwd(path, sizeof(path) - 1) == NULL) 1463 reply(550, "Can't get the current directory: %s.", 1464 strerror(errno)); 1465 else 1466 replydirname(path, "is the current directory."); 1467 } 1468 1469 char * 1470 renamefrom(name) 1471 char *name; 1472 { 1473 struct stat st; 1474 1475 if (stat(name, &st) < 0) { 1476 perror_reply(550, name); 1477 return (NULL); 1478 } 1479 reply(350, "File exists, ready for destination name"); 1480 return (name); 1481 } 1482 1483 void 1484 renamecmd(from, to) 1485 char *from, *to; 1486 { 1487 1488 logcmd("rename", -1, from, to); 1489 if (rename(from, to) < 0) 1490 perror_reply(550, "rename"); 1491 else 1492 ack("RNTO"); 1493 } 1494 1495 static void 1496 dolog(sin) 1497 struct sockaddr_in *sin; 1498 { 1499 struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr, 1500 sizeof(struct in_addr), AF_INET); 1501 1502 if (hp) 1503 (void)strncpy(remotehost, hp->h_name, sizeof(remotehost)); 1504 else 1505 (void)strncpy(remotehost, inet_ntoa(sin->sin_addr), 1506 sizeof(remotehost)); 1507 remotehost[sizeof(remotehost) - 1] = '\0'; 1508 #ifdef HASSETPROCTITLE 1509 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost); 1510 setproctitle(proctitle); 1511 #endif /* HASSETPROCTITLE */ 1512 1513 if (logging) 1514 syslog(LOG_INFO, "connection from %s", remotehost); 1515 } 1516 1517 /* 1518 * Record logout in wtmp file 1519 * and exit with supplied status. 1520 */ 1521 void 1522 dologout(status) 1523 int status; 1524 { 1525 /* 1526 * Prevent reception of SIGURG from resulting in a resumption 1527 * back to the main program loop. 1528 */ 1529 transflag = 0; 1530 1531 if (logged_in) { 1532 (void) seteuid((uid_t)0); 1533 logwtmp(ttyline, "", ""); 1534 #ifdef KERBEROS 1535 if (!notickets && krbtkfile_env) 1536 unlink(krbtkfile_env); 1537 #endif 1538 } 1539 /* beware of flushing buffers after a SIGPIPE */ 1540 _exit(status); 1541 } 1542 1543 static void 1544 myoob(signo) 1545 int signo; 1546 { 1547 char *cp; 1548 1549 /* only process if transfer occurring */ 1550 if (!transflag) 1551 return; 1552 cp = tmpline; 1553 if (getline(cp, 7, stdin) == NULL) { 1554 reply(221, "You could at least say goodbye."); 1555 dologout(0); 1556 } 1557 if (strcasecmp(cp, "ABOR\r\n") == 0) { 1558 tmpline[0] = '\0'; 1559 reply(426, "Transfer aborted. Data connection closed."); 1560 reply(226, "Abort successful"); 1561 longjmp(urgcatch, 1); 1562 } 1563 if (strcasecmp(cp, "STAT\r\n") == 0) { 1564 if (file_size != (off_t) -1) 1565 reply(213, "Status: %qd of %qd bytes transferred", 1566 byte_count, file_size); 1567 else 1568 reply(213, "Status: %qd bytes transferred", byte_count); 1569 } 1570 } 1571 1572 /* 1573 * Note: a response of 425 is not mentioned as a possible response to 1574 * the PASV command in RFC959. However, it has been blessed as 1575 * a legitimate response by Jon Postel in a telephone conversation 1576 * with Rick Adams on 25 Jan 89. 1577 */ 1578 void 1579 passive() 1580 { 1581 int len; 1582 char *p, *a; 1583 1584 pdata = socket(AF_INET, SOCK_STREAM, 0); 1585 if (pdata < 0 || !logged_in) { 1586 perror_reply(425, "Can't open passive connection"); 1587 return; 1588 } 1589 pasv_addr = ctrl_addr; 1590 pasv_addr.sin_port = 0; 1591 (void) seteuid((uid_t)0); 1592 if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) { 1593 (void) seteuid((uid_t)pw->pw_uid); 1594 goto pasv_error; 1595 } 1596 (void) seteuid((uid_t)pw->pw_uid); 1597 len = sizeof(pasv_addr); 1598 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) 1599 goto pasv_error; 1600 if (listen(pdata, 1) < 0) 1601 goto pasv_error; 1602 a = (char *) &pasv_addr.sin_addr; 1603 p = (char *) &pasv_addr.sin_port; 1604 1605 #define UC(b) (((int) b) & 0xff) 1606 1607 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), 1608 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 1609 return; 1610 1611 pasv_error: 1612 (void) close(pdata); 1613 pdata = -1; 1614 perror_reply(425, "Can't open passive connection"); 1615 return; 1616 } 1617 1618 /* 1619 * Generate unique name for file with basename "local". 1620 * The file named "local" is already known to exist. 1621 * Generates failure reply on error. 1622 * 1623 * XXX this function should under go changes similar to 1624 * the mktemp(3)/mkstemp(3) changes. 1625 */ 1626 static char * 1627 gunique(local) 1628 char *local; 1629 { 1630 static char new[MAXPATHLEN + 1]; 1631 struct stat st; 1632 int count, len; 1633 char *cp; 1634 1635 cp = strrchr(local, '/'); 1636 if (cp) 1637 *cp = '\0'; 1638 if (stat(cp ? local : ".", &st) < 0) { 1639 perror_reply(553, cp ? local : "."); 1640 return (NULL); 1641 } 1642 if (cp) 1643 *cp = '/'; 1644 (void) strcpy(new, local); 1645 len = strlen(new); 1646 cp = new + len; 1647 *cp++ = '.'; 1648 for (count = 1; count < 100; count++) { 1649 (void)snprintf(cp, sizeof(new) - len - 2, "%d", count); 1650 if (stat(new, &st) < 0) 1651 return (new); 1652 } 1653 reply(452, "Unique file name cannot be created."); 1654 return (NULL); 1655 } 1656 1657 /* 1658 * Format and send reply containing system error number. 1659 */ 1660 void 1661 perror_reply(code, string) 1662 int code; 1663 const char *string; 1664 { 1665 1666 reply(code, "%s: %s.", string, strerror(errno)); 1667 } 1668 1669 static char *onefile[] = { 1670 "", 1671 0 1672 }; 1673 1674 void 1675 send_file_list(whichf) 1676 char *whichf; 1677 { 1678 struct stat st; 1679 DIR *dirp = NULL; 1680 struct dirent *dir; 1681 FILE *dout = NULL; 1682 char **dirlist, *dirname; 1683 int simple = 0; 1684 int freeglob = 0; 1685 glob_t gl; 1686 #ifdef __GNUC__ 1687 (void) &dout; 1688 (void) &dirlist; 1689 (void) &simple; 1690 (void) &freeglob; 1691 #endif 1692 1693 if (strpbrk(whichf, "~{[*?") != NULL) { 1694 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; 1695 1696 memset(&gl, 0, sizeof(gl)); 1697 freeglob = 1; 1698 if (glob(whichf, flags, 0, &gl)) { 1699 reply(550, "not found"); 1700 goto out; 1701 } else if (gl.gl_pathc == 0) { 1702 errno = ENOENT; 1703 perror_reply(550, whichf); 1704 goto out; 1705 } 1706 dirlist = gl.gl_pathv; 1707 } else { 1708 onefile[0] = whichf; 1709 dirlist = onefile; 1710 simple = 1; 1711 } 1712 1713 if (setjmp(urgcatch)) { 1714 transflag = 0; 1715 goto out; 1716 } 1717 while ((dirname = *dirlist++) != NULL) { 1718 int trailingslash = 0; 1719 1720 if (stat(dirname, &st) < 0) { 1721 /* 1722 * If user typed "ls -l", etc, and the client 1723 * used NLST, do what the user meant. 1724 */ 1725 if (dirname[0] == '-' && *dirlist == NULL && 1726 transflag == 0) { 1727 retrieve("/bin/ls %s", dirname); 1728 goto out; 1729 } 1730 perror_reply(550, whichf); 1731 if (dout != NULL) { 1732 (void) fclose(dout); 1733 transflag = 0; 1734 data = -1; 1735 pdata = -1; 1736 } 1737 goto out; 1738 } 1739 1740 if (S_ISREG(st.st_mode)) { 1741 if (dout == NULL) { 1742 dout = dataconn("file list", (off_t)-1, "w"); 1743 if (dout == NULL) 1744 goto out; 1745 transflag++; 1746 } 1747 fprintf(dout, "%s%s\n", dirname, 1748 type == TYPE_A ? "\r" : ""); 1749 byte_count += strlen(dirname) + 1; 1750 continue; 1751 } else if (!S_ISDIR(st.st_mode)) 1752 continue; 1753 1754 if (dirname[strlen(dirname) - 1] == '/') 1755 trailingslash++; 1756 1757 if ((dirp = opendir(dirname)) == NULL) 1758 continue; 1759 1760 while ((dir = readdir(dirp)) != NULL) { 1761 char nbuf[MAXPATHLEN + 1]; 1762 1763 if (dir->d_name[0] == '.' && dir->d_namlen == 1) 1764 continue; 1765 if (dir->d_name[0] == '.' && dir->d_name[1] == '.' && 1766 dir->d_namlen == 2) 1767 continue; 1768 1769 (void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname, 1770 trailingslash ? "" : "/", dir->d_name); 1771 1772 /* 1773 * We have to do a stat to ensure it's 1774 * not a directory or special file. 1775 */ 1776 if (simple || (stat(nbuf, &st) == 0 && 1777 S_ISREG(st.st_mode))) { 1778 if (dout == NULL) { 1779 dout = dataconn("file list", (off_t)-1, 1780 "w"); 1781 if (dout == NULL) 1782 goto out; 1783 transflag++; 1784 } 1785 if (nbuf[0] == '.' && nbuf[1] == '/') 1786 fprintf(dout, "%s%s\n", &nbuf[2], 1787 type == TYPE_A ? "\r" : ""); 1788 else 1789 fprintf(dout, "%s%s\n", nbuf, 1790 type == TYPE_A ? "\r" : ""); 1791 byte_count += strlen(nbuf) + 1; 1792 } 1793 } 1794 (void) closedir(dirp); 1795 } 1796 1797 if (dout == NULL) 1798 reply(550, "No files found."); 1799 else if (ferror(dout) != 0) 1800 perror_reply(550, "Data connection"); 1801 else 1802 reply(226, "Transfer complete."); 1803 1804 transflag = 0; 1805 if (dout != NULL) 1806 (void) fclose(dout); 1807 data = -1; 1808 pdata = -1; 1809 out: 1810 if (freeglob) { 1811 freeglob = 0; 1812 globfree(&gl); 1813 } 1814 } 1815 1816 char * 1817 conffilename(s) 1818 const char *s; 1819 { 1820 static char filename[MAXPATHLEN + 1]; 1821 1822 (void)snprintf(filename, sizeof(filename), "%s/%s", confdir ,s); 1823 return filename; 1824 } 1825