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