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