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