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 #define FTP_NAMES 35 #include "ftpd_locl.h" 36 #ifdef KRB5 37 #include <krb5.h> 38 #endif 39 #include "getarg.h" 40 41 RCSID("$Id: ftpd.c,v 1.166 2003/04/16 15:02:05 lha Exp $"); 42 43 static char version[] = "Version 6.00"; 44 45 extern off_t restart_point; 46 extern char cbuf[]; 47 48 struct sockaddr_storage ctrl_addr_ss; 49 struct sockaddr *ctrl_addr = (struct sockaddr *)&ctrl_addr_ss; 50 51 struct sockaddr_storage data_source_ss; 52 struct sockaddr *data_source = (struct sockaddr *)&data_source_ss; 53 54 struct sockaddr_storage data_dest_ss; 55 struct sockaddr *data_dest = (struct sockaddr *)&data_dest_ss; 56 57 struct sockaddr_storage his_addr_ss; 58 struct sockaddr *his_addr = (struct sockaddr *)&his_addr_ss; 59 60 struct sockaddr_storage pasv_addr_ss; 61 struct sockaddr *pasv_addr = (struct sockaddr *)&pasv_addr_ss; 62 63 int data; 64 jmp_buf errcatch, urgcatch; 65 int oobflag; 66 int logged_in; 67 struct passwd *pw; 68 int debug = 0; 69 int ftpd_timeout = 900; /* timeout after 15 minutes of inactivity */ 70 int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ 71 int restricted_data_ports = 1; 72 int logging; 73 int guest; 74 int dochroot; 75 int type; 76 int form; 77 int stru; /* avoid C keyword */ 78 int mode; 79 int usedefault = 1; /* for data transfers */ 80 int pdata = -1; /* for passive mode */ 81 int transflag; 82 off_t file_size; 83 off_t byte_count; 84 #if !defined(CMASK) || CMASK == 0 85 #undef CMASK 86 #define CMASK 027 87 #endif 88 int defumask = CMASK; /* default umask value */ 89 int guest_umask = 0777; /* Paranoia for anonymous users */ 90 char tmpline[10240]; 91 char hostname[MaxHostNameLen]; 92 char remotehost[MaxHostNameLen]; 93 static char ttyline[20]; 94 95 #define AUTH_PLAIN (1 << 0) /* allow sending passwords */ 96 #define AUTH_OTP (1 << 1) /* passwords are one-time */ 97 #define AUTH_FTP (1 << 2) /* allow anonymous login */ 98 99 static int auth_level = 0; /* Only allow kerberos login by default */ 100 101 /* 102 * Timeout intervals for retrying connections 103 * to hosts that don't accept PORT cmds. This 104 * is a kludge, but given the problems with TCP... 105 */ 106 #define SWAITMAX 90 /* wait at most 90 seconds */ 107 #define SWAITINT 5 /* interval between retries */ 108 109 int swaitmax = SWAITMAX; 110 int swaitint = SWAITINT; 111 112 #ifdef HAVE_SETPROCTITLE 113 char proctitle[BUFSIZ]; /* initial part of title */ 114 #endif /* HAVE_SETPROCTITLE */ 115 116 #define LOGCMD(cmd, file) \ 117 if (logging > 1) \ 118 syslog(LOG_INFO,"%s %s%s", cmd, \ 119 *(file) == '/' ? "" : curdir(), file); 120 #define LOGCMD2(cmd, file1, file2) \ 121 if (logging > 1) \ 122 syslog(LOG_INFO,"%s %s%s %s%s", cmd, \ 123 *(file1) == '/' ? "" : curdir(), file1, \ 124 *(file2) == '/' ? "" : curdir(), file2); 125 #define LOGBYTES(cmd, file, cnt) \ 126 if (logging > 1) { \ 127 if (cnt == (off_t)-1) \ 128 syslog(LOG_INFO,"%s %s%s", cmd, \ 129 *(file) == '/' ? "" : curdir(), file); \ 130 else \ 131 syslog(LOG_INFO, "%s %s%s = %ld bytes", \ 132 cmd, (*(file) == '/') ? "" : curdir(), file, (long)cnt); \ 133 } 134 135 static void ack (char *); 136 static void myoob (int); 137 static int checkuser (char *, char *); 138 static int checkaccess (char *); 139 static FILE *dataconn (const char *, off_t, const char *); 140 static void dolog (struct sockaddr *sa, int len); 141 static void end_login (void); 142 static FILE *getdatasock (const char *); 143 static char *gunique (char *); 144 static RETSIGTYPE lostconn (int); 145 static int receive_data (FILE *, FILE *); 146 static void send_data (FILE *, FILE *); 147 static struct passwd * sgetpwnam (char *); 148 149 static char * 150 curdir(void) 151 { 152 static char path[MaxPathLen+1]; /* path + '/' + '\0' */ 153 154 if (getcwd(path, sizeof(path)-1) == NULL) 155 return (""); 156 if (path[1] != '\0') /* special case for root dir. */ 157 strlcat(path, "/", sizeof(path)); 158 /* For guest account, skip / since it's chrooted */ 159 return (guest ? path+1 : path); 160 } 161 162 #ifndef LINE_MAX 163 #define LINE_MAX 1024 164 #endif 165 166 static int 167 parse_auth_level(char *str) 168 { 169 char *p; 170 int ret = 0; 171 char *foo = NULL; 172 173 for(p = strtok_r(str, ",", &foo); 174 p; 175 p = strtok_r(NULL, ",", &foo)) { 176 if(strcmp(p, "user") == 0) 177 ; 178 #ifdef OTP 179 else if(strcmp(p, "otp") == 0) 180 ret |= AUTH_PLAIN|AUTH_OTP; 181 #endif 182 else if(strcmp(p, "ftp") == 0 || 183 strcmp(p, "safe") == 0) 184 ret |= AUTH_FTP; 185 else if(strcmp(p, "plain") == 0) 186 ret |= AUTH_PLAIN; 187 else if(strcmp(p, "none") == 0) 188 ret |= AUTH_PLAIN|AUTH_FTP; 189 else 190 warnx("bad value for -a: `%s'", p); 191 } 192 return ret; 193 } 194 195 /* 196 * Print usage and die. 197 */ 198 199 static int interactive_flag; 200 static char *guest_umask_string; 201 static char *port_string; 202 static char *umask_string; 203 static char *auth_string; 204 205 int use_builtin_ls = -1; 206 207 static int help_flag; 208 static int version_flag; 209 210 static const char *good_chars = "+-=_,."; 211 212 struct getargs args[] = { 213 { NULL, 'a', arg_string, &auth_string, "required authentication" }, 214 { NULL, 'i', arg_flag, &interactive_flag, "don't assume stdin is a socket" }, 215 { NULL, 'p', arg_string, &port_string, "what port to listen to" }, 216 { NULL, 'g', arg_string, &guest_umask_string, "umask for guest logins" }, 217 { NULL, 'l', arg_counter, &logging, "log more stuff", "" }, 218 { NULL, 't', arg_integer, &ftpd_timeout, "initial timeout" }, 219 { NULL, 'T', arg_integer, &maxtimeout, "max timeout" }, 220 { NULL, 'u', arg_string, &umask_string, "umask for user logins" }, 221 { NULL, 'U', arg_negative_flag, &restricted_data_ports, "don't use high data ports" }, 222 { NULL, 'd', arg_flag, &debug, "enable debugging" }, 223 { NULL, 'v', arg_flag, &debug, "enable debugging" }, 224 { "builtin-ls", 'B', arg_flag, &use_builtin_ls, "use built-in ls to list files" }, 225 { "good-chars", 0, arg_string, &good_chars, "allowed anonymous upload filename chars" }, 226 { "version", 0, arg_flag, &version_flag }, 227 { "help", 'h', arg_flag, &help_flag } 228 }; 229 230 static int num_args = sizeof(args) / sizeof(args[0]); 231 232 static void 233 usage (int code) 234 { 235 arg_printusage(args, num_args, NULL, ""); 236 exit (code); 237 } 238 239 /* output contents of a file */ 240 static int 241 show_file(const char *file, int code) 242 { 243 FILE *f; 244 char buf[128]; 245 246 f = fopen(file, "r"); 247 if(f == NULL) 248 return -1; 249 while(fgets(buf, sizeof(buf), f)){ 250 buf[strcspn(buf, "\r\n")] = '\0'; 251 lreply(code, "%s", buf); 252 } 253 fclose(f); 254 return 0; 255 } 256 257 int 258 main(int argc, char **argv) 259 { 260 socklen_t his_addr_len, ctrl_addr_len; 261 int on = 1; 262 int port; 263 struct servent *sp; 264 265 int optind = 0; 266 267 setprogname (argv[0]); 268 269 /* detach from any tickets and tokens */ 270 { 271 #ifdef KRB4 272 char tkfile[1024]; 273 snprintf(tkfile, sizeof(tkfile), 274 "/tmp/ftp_%u", (unsigned)getpid()); 275 krb_set_tkt_string(tkfile); 276 #endif 277 #if defined(KRB4) && defined(KRB5) 278 if(k_hasafs()) 279 k_setpag(); 280 #endif 281 } 282 283 if(getarg(args, num_args, argc, argv, &optind)) 284 usage(1); 285 286 if(help_flag) 287 usage(0); 288 289 if(version_flag) { 290 print_version(NULL); 291 exit(0); 292 } 293 294 if(auth_string) 295 auth_level = parse_auth_level(auth_string); 296 { 297 char *p; 298 long val = 0; 299 300 if(guest_umask_string) { 301 val = strtol(guest_umask_string, &p, 8); 302 if (*p != '\0' || val < 0) 303 warnx("bad value for -g"); 304 else 305 guest_umask = val; 306 } 307 if(umask_string) { 308 val = strtol(umask_string, &p, 8); 309 if (*p != '\0' || val < 0) 310 warnx("bad value for -u"); 311 else 312 defumask = val; 313 } 314 } 315 sp = getservbyname("ftp", "tcp"); 316 if(sp) 317 port = sp->s_port; 318 else 319 port = htons(21); 320 if(port_string) { 321 sp = getservbyname(port_string, "tcp"); 322 if(sp) 323 port = sp->s_port; 324 else 325 if(isdigit((unsigned char)port_string[0])) 326 port = htons(atoi(port_string)); 327 else 328 warnx("bad value for -p"); 329 } 330 331 if (maxtimeout < ftpd_timeout) 332 maxtimeout = ftpd_timeout; 333 334 #if 0 335 if (ftpd_timeout > maxtimeout) 336 ftpd_timeout = maxtimeout; 337 #endif 338 339 if(interactive_flag) 340 mini_inetd (port); 341 342 /* 343 * LOG_NDELAY sets up the logging connection immediately, 344 * necessary for anonymous ftp's that chroot and can't do it later. 345 */ 346 openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); 347 his_addr_len = sizeof(his_addr_ss); 348 if (getpeername(STDIN_FILENO, his_addr, &his_addr_len) < 0) { 349 syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); 350 exit(1); 351 } 352 ctrl_addr_len = sizeof(ctrl_addr_ss); 353 if (getsockname(STDIN_FILENO, ctrl_addr, &ctrl_addr_len) < 0) { 354 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); 355 exit(1); 356 } 357 #if defined(IP_TOS) && defined(HAVE_SETSOCKOPT) 358 { 359 int tos = IPTOS_LOWDELAY; 360 361 if (setsockopt(STDIN_FILENO, IPPROTO_IP, IP_TOS, 362 (void *)&tos, sizeof(int)) < 0) 363 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 364 } 365 #endif 366 data_source->sa_family = ctrl_addr->sa_family; 367 socket_set_port (data_source, 368 htons(ntohs(socket_get_port(ctrl_addr)) - 1)); 369 370 /* set this here so it can be put in wtmp */ 371 snprintf(ttyline, sizeof(ttyline), "ftp%u", (unsigned)getpid()); 372 373 374 /* freopen(_PATH_DEVNULL, "w", stderr); */ 375 signal(SIGPIPE, lostconn); 376 signal(SIGCHLD, SIG_IGN); 377 #ifdef SIGURG 378 if (signal(SIGURG, myoob) == SIG_ERR) 379 syslog(LOG_ERR, "signal: %m"); 380 #endif 381 382 /* Try to handle urgent data inline */ 383 #if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT) 384 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (void *)&on, 385 sizeof(on)) < 0) 386 syslog(LOG_ERR, "setsockopt: %m"); 387 #endif 388 389 #ifdef F_SETOWN 390 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) 391 syslog(LOG_ERR, "fcntl F_SETOWN: %m"); 392 #endif 393 dolog(his_addr, his_addr_len); 394 /* 395 * Set up default state 396 */ 397 data = -1; 398 type = TYPE_A; 399 form = FORM_N; 400 stru = STRU_F; 401 mode = MODE_S; 402 tmpline[0] = '\0'; 403 404 /* If logins are disabled, print out the message. */ 405 if(show_file(_PATH_NOLOGIN, 530) == 0) { 406 reply(530, "System not available."); 407 exit(0); 408 } 409 show_file(_PATH_FTPWELCOME, 220); 410 /* reply(220,) must follow */ 411 gethostname(hostname, sizeof(hostname)); 412 413 reply(220, "%s FTP server (%s" 414 #ifdef KRB5 415 "+%s" 416 #endif 417 #ifdef KRB4 418 "+%s" 419 #endif 420 ") ready.", hostname, version 421 #ifdef KRB5 422 ,heimdal_version 423 #endif 424 #ifdef KRB4 425 ,krb4_version 426 #endif 427 ); 428 429 setjmp(errcatch); 430 for (;;) 431 yyparse(); 432 /* NOTREACHED */ 433 } 434 435 static RETSIGTYPE 436 lostconn(int signo) 437 { 438 439 if (debug) 440 syslog(LOG_DEBUG, "lost connection"); 441 dologout(-1); 442 } 443 444 /* 445 * Helper function for sgetpwnam(). 446 */ 447 static char * 448 sgetsave(char *s) 449 { 450 char *new = strdup(s); 451 452 if (new == NULL) { 453 perror_reply(421, "Local resource failure: malloc"); 454 dologout(1); 455 /* NOTREACHED */ 456 } 457 return new; 458 } 459 460 /* 461 * Save the result of a getpwnam. Used for USER command, since 462 * the data returned must not be clobbered by any other command 463 * (e.g., globbing). 464 */ 465 static struct passwd * 466 sgetpwnam(char *name) 467 { 468 static struct passwd save; 469 struct passwd *p; 470 471 if ((p = k_getpwnam(name)) == NULL) 472 return (p); 473 if (save.pw_name) { 474 free(save.pw_name); 475 free(save.pw_passwd); 476 free(save.pw_gecos); 477 free(save.pw_dir); 478 free(save.pw_shell); 479 } 480 save = *p; 481 save.pw_name = sgetsave(p->pw_name); 482 save.pw_passwd = sgetsave(p->pw_passwd); 483 save.pw_gecos = sgetsave(p->pw_gecos); 484 save.pw_dir = sgetsave(p->pw_dir); 485 save.pw_shell = sgetsave(p->pw_shell); 486 return (&save); 487 } 488 489 static int login_attempts; /* number of failed login attempts */ 490 static int askpasswd; /* had user command, ask for passwd */ 491 static char curname[10]; /* current USER name */ 492 #ifdef OTP 493 OtpContext otp_ctx; 494 #endif 495 496 /* 497 * USER command. 498 * Sets global passwd pointer pw if named account exists and is acceptable; 499 * sets askpasswd if a PASS command is expected. If logged in previously, 500 * need to reset state. If name is "ftp" or "anonymous", the name is not in 501 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return. 502 * If account doesn't exist, ask for passwd anyway. Otherwise, check user 503 * requesting login privileges. Disallow anyone who does not have a standard 504 * shell as returned by getusershell(). Disallow anyone mentioned in the file 505 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. 506 */ 507 void 508 user(char *name) 509 { 510 char *cp, *shell; 511 512 if(auth_level == 0 && !sec_complete){ 513 reply(530, "No login allowed without authorization."); 514 return; 515 } 516 517 if (logged_in) { 518 if (guest) { 519 reply(530, "Can't change user from guest login."); 520 return; 521 } else if (dochroot) { 522 reply(530, "Can't change user from chroot user."); 523 return; 524 } 525 end_login(); 526 } 527 528 guest = 0; 529 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { 530 if ((auth_level & AUTH_FTP) == 0 || 531 checkaccess("ftp") || 532 checkaccess("anonymous")) 533 reply(530, "User %s access denied.", name); 534 else if ((pw = sgetpwnam("ftp")) != NULL) { 535 guest = 1; 536 defumask = guest_umask; /* paranoia for incoming */ 537 askpasswd = 1; 538 reply(331, "Guest login ok, type your name as password."); 539 } else 540 reply(530, "User %s unknown.", name); 541 if (!askpasswd && logging) { 542 char data_addr[256]; 543 544 if (inet_ntop (his_addr->sa_family, 545 socket_get_address(his_addr), 546 data_addr, sizeof(data_addr)) == NULL) 547 strlcpy (data_addr, "unknown address", 548 sizeof(data_addr)); 549 550 syslog(LOG_NOTICE, 551 "ANONYMOUS FTP LOGIN REFUSED FROM %s(%s)", 552 remotehost, data_addr); 553 } 554 return; 555 } 556 if((auth_level & AUTH_PLAIN) == 0 && !sec_complete){ 557 reply(530, "Only authorized and anonymous login allowed."); 558 return; 559 } 560 if ((pw = sgetpwnam(name))) { 561 if ((shell = pw->pw_shell) == NULL || *shell == 0) 562 shell = _PATH_BSHELL; 563 while ((cp = getusershell()) != NULL) 564 if (strcmp(cp, shell) == 0) 565 break; 566 endusershell(); 567 568 if (cp == NULL || checkaccess(name)) { 569 reply(530, "User %s access denied.", name); 570 if (logging) { 571 char data_addr[256]; 572 573 if (inet_ntop (his_addr->sa_family, 574 socket_get_address(his_addr), 575 data_addr, 576 sizeof(data_addr)) == NULL) 577 strlcpy (data_addr, 578 "unknown address", 579 sizeof(data_addr)); 580 581 syslog(LOG_NOTICE, 582 "FTP LOGIN REFUSED FROM %s(%s), %s", 583 remotehost, 584 data_addr, 585 name); 586 } 587 pw = (struct passwd *) NULL; 588 return; 589 } 590 } 591 if (logging) 592 strlcpy(curname, name, sizeof(curname)); 593 if(sec_complete) { 594 if(sec_userok(name) == 0) 595 do_login(232, name); 596 else 597 reply(530, "User %s access denied.", name); 598 } else { 599 char ss[256]; 600 601 #ifdef OTP 602 if (otp_challenge(&otp_ctx, name, ss, sizeof(ss)) == 0) { 603 reply(331, "Password %s for %s required.", 604 ss, name); 605 askpasswd = 1; 606 } else 607 #endif 608 if ((auth_level & AUTH_OTP) == 0) { 609 reply(331, "Password required for %s.", name); 610 askpasswd = 1; 611 } else { 612 char *s; 613 614 #ifdef OTP 615 if ((s = otp_error (&otp_ctx)) != NULL) 616 lreply(530, "OTP: %s", s); 617 #endif 618 reply(530, 619 "Only authorized, anonymous" 620 #ifdef OTP 621 " and OTP " 622 #endif 623 "login allowed."); 624 } 625 626 } 627 /* 628 * Delay before reading passwd after first failed 629 * attempt to slow down passwd-guessing programs. 630 */ 631 if (login_attempts) 632 sleep(login_attempts); 633 } 634 635 /* 636 * Check if a user is in the file "fname" 637 */ 638 static int 639 checkuser(char *fname, char *name) 640 { 641 FILE *fd; 642 int found = 0; 643 char *p, line[BUFSIZ]; 644 645 if ((fd = fopen(fname, "r")) != NULL) { 646 while (fgets(line, sizeof(line), fd) != NULL) 647 if ((p = strchr(line, '\n')) != NULL) { 648 *p = '\0'; 649 if (line[0] == '#') 650 continue; 651 if (strcmp(line, name) == 0) { 652 found = 1; 653 break; 654 } 655 } 656 fclose(fd); 657 } 658 return (found); 659 } 660 661 662 /* 663 * Determine whether a user has access, based on information in 664 * _PATH_FTPUSERS. The users are listed one per line, with `allow' 665 * or `deny' after the username. If anything other than `allow', or 666 * just nothing, is given after the username, `deny' is assumed. 667 * 668 * If the user is not found in the file, but the pseudo-user `*' is, 669 * the permission is taken from that line. 670 * 671 * This preserves the old semantics where if a user was listed in the 672 * file he was denied, otherwise he was allowed. 673 * 674 * Return 1 if the user is denied, or 0 if he is allowed. */ 675 676 static int 677 match(const char *pattern, const char *string) 678 { 679 return fnmatch(pattern, string, FNM_NOESCAPE); 680 } 681 682 static int 683 checkaccess(char *name) 684 { 685 #define ALLOWED 0 686 #define NOT_ALLOWED 1 687 FILE *fd; 688 int allowed = ALLOWED; 689 char *user, *perm, line[BUFSIZ]; 690 char *foo; 691 692 fd = fopen(_PATH_FTPUSERS, "r"); 693 694 if(fd == NULL) 695 return allowed; 696 697 while (fgets(line, sizeof(line), fd) != NULL) { 698 foo = NULL; 699 user = strtok_r(line, " \t\n", &foo); 700 if (user == NULL || user[0] == '#') 701 continue; 702 perm = strtok_r(NULL, " \t\n", &foo); 703 if (match(user, name) == 0){ 704 if(perm && strcmp(perm, "allow") == 0) 705 allowed = ALLOWED; 706 else 707 allowed = NOT_ALLOWED; 708 break; 709 } 710 } 711 fclose(fd); 712 return allowed; 713 } 714 #undef ALLOWED 715 #undef NOT_ALLOWED 716 717 718 int do_login(int code, char *passwd) 719 { 720 login_attempts = 0; /* this time successful */ 721 if (setegid((gid_t)pw->pw_gid) < 0) { 722 reply(550, "Can't set gid."); 723 return -1; 724 } 725 initgroups(pw->pw_name, pw->pw_gid); 726 727 /* open wtmp before chroot */ 728 ftpd_logwtmp(ttyline, pw->pw_name, remotehost); 729 logged_in = 1; 730 731 dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name); 732 if (guest) { 733 /* 734 * We MUST do a chdir() after the chroot. Otherwise 735 * the old current directory will be accessible as "." 736 * outside the new root! 737 */ 738 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { 739 reply(550, "Can't set guest privileges."); 740 return -1; 741 } 742 } else if (dochroot) { 743 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { 744 reply(550, "Can't change root."); 745 return -1; 746 } 747 } else if (chdir(pw->pw_dir) < 0) { 748 if (chdir("/") < 0) { 749 reply(530, "User %s: can't change directory to %s.", 750 pw->pw_name, pw->pw_dir); 751 return -1; 752 } else 753 lreply(code, "No directory! Logging in with home=/"); 754 } 755 if (seteuid((uid_t)pw->pw_uid) < 0) { 756 reply(550, "Can't set uid."); 757 return -1; 758 } 759 760 if(use_builtin_ls == -1) { 761 struct stat st; 762 /* if /bin/ls exist and is a regular file, use it, otherwise 763 use built-in ls */ 764 if(stat("/bin/ls", &st) == 0 && 765 S_ISREG(st.st_mode)) 766 use_builtin_ls = 0; 767 else 768 use_builtin_ls = 1; 769 } 770 771 /* 772 * Display a login message, if it exists. 773 * N.B. reply(code,) must follow the message. 774 */ 775 show_file(_PATH_FTPLOGINMESG, code); 776 if(show_file(_PATH_ISSUE_NET, code) != 0) 777 show_file(_PATH_ISSUE, code); 778 if (guest) { 779 reply(code, "Guest login ok, access restrictions apply."); 780 #ifdef HAVE_SETPROCTITLE 781 snprintf (proctitle, sizeof(proctitle), 782 "%s: anonymous/%s", 783 remotehost, 784 passwd); 785 setproctitle("%s", proctitle); 786 #endif /* HAVE_SETPROCTITLE */ 787 if (logging) { 788 char data_addr[256]; 789 790 if (inet_ntop (his_addr->sa_family, 791 socket_get_address(his_addr), 792 data_addr, sizeof(data_addr)) == NULL) 793 strlcpy (data_addr, "unknown address", 794 sizeof(data_addr)); 795 796 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s(%s), %s", 797 remotehost, 798 data_addr, 799 passwd); 800 } 801 } else { 802 reply(code, "User %s logged in.", pw->pw_name); 803 #ifdef HAVE_SETPROCTITLE 804 snprintf(proctitle, sizeof(proctitle), "%s: %s", remotehost, pw->pw_name); 805 setproctitle("%s", proctitle); 806 #endif /* HAVE_SETPROCTITLE */ 807 if (logging) { 808 char data_addr[256]; 809 810 if (inet_ntop (his_addr->sa_family, 811 socket_get_address(his_addr), 812 data_addr, sizeof(data_addr)) == NULL) 813 strlcpy (data_addr, "unknown address", 814 sizeof(data_addr)); 815 816 syslog(LOG_INFO, "FTP LOGIN FROM %s(%s) as %s", 817 remotehost, 818 data_addr, 819 pw->pw_name); 820 } 821 } 822 umask(defumask); 823 return 0; 824 } 825 826 /* 827 * Terminate login as previous user, if any, resetting state; 828 * used when USER command is given or login fails. 829 */ 830 static void 831 end_login(void) 832 { 833 834 seteuid((uid_t)0); 835 if (logged_in) 836 ftpd_logwtmp(ttyline, "", ""); 837 pw = NULL; 838 logged_in = 0; 839 guest = 0; 840 dochroot = 0; 841 } 842 843 #ifdef KRB5 844 static int 845 krb5_verify(struct passwd *pwd, char *passwd) 846 { 847 krb5_context context; 848 krb5_ccache id; 849 krb5_principal princ; 850 krb5_error_code ret; 851 852 ret = krb5_init_context(&context); 853 if(ret) 854 return ret; 855 856 ret = krb5_parse_name(context, pwd->pw_name, &princ); 857 if(ret){ 858 krb5_free_context(context); 859 return ret; 860 } 861 ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &id); 862 if(ret){ 863 krb5_free_principal(context, princ); 864 krb5_free_context(context); 865 return ret; 866 } 867 ret = krb5_verify_user(context, 868 princ, 869 id, 870 passwd, 871 1, 872 NULL); 873 krb5_free_principal(context, princ); 874 if (k_hasafs()) { 875 krb5_afslog_uid_home(context, id,NULL, NULL,pwd->pw_uid, pwd->pw_dir); 876 } 877 krb5_cc_destroy(context, id); 878 krb5_free_context (context); 879 if(ret) 880 return ret; 881 return 0; 882 } 883 #endif /* KRB5 */ 884 885 void 886 pass(char *passwd) 887 { 888 int rval; 889 890 /* some clients insists on sending a password */ 891 if (logged_in && askpasswd == 0){ 892 reply(230, "Password not necessary"); 893 return; 894 } 895 896 if (logged_in || askpasswd == 0) { 897 reply(503, "Login with USER first."); 898 return; 899 } 900 askpasswd = 0; 901 rval = 1; 902 if (!guest) { /* "ftp" is only account allowed no password */ 903 if (pw == NULL) 904 rval = 1; /* failure below */ 905 #ifdef OTP 906 else if (otp_verify_user (&otp_ctx, passwd) == 0) { 907 rval = 0; 908 } 909 #endif 910 else if((auth_level & AUTH_OTP) == 0) { 911 #ifdef KRB5 912 rval = krb5_verify(pw, passwd); 913 #endif 914 #ifdef KRB4 915 if (rval) { 916 char realm[REALM_SZ]; 917 if((rval = krb_get_lrealm(realm, 1)) == KSUCCESS) 918 rval = krb_verify_user(pw->pw_name, 919 "", realm, 920 passwd, 921 KRB_VERIFY_SECURE, NULL); 922 if (rval == KSUCCESS ) { 923 chown (tkt_string(), pw->pw_uid, pw->pw_gid); 924 if(k_hasafs()) 925 krb_afslog(0, 0); 926 } 927 } 928 #endif 929 if (rval) 930 rval = unix_verify_user(pw->pw_name, passwd); 931 } else { 932 char *s; 933 934 #ifdef OTP 935 if ((s = otp_error(&otp_ctx)) != NULL) 936 lreply(530, "OTP: %s", s); 937 #endif 938 } 939 memset (passwd, 0, strlen(passwd)); 940 941 /* 942 * If rval == 1, the user failed the authentication 943 * check above. If rval == 0, either Kerberos or 944 * local authentication succeeded. 945 */ 946 if (rval) { 947 char data_addr[256]; 948 949 if (inet_ntop (his_addr->sa_family, 950 socket_get_address(his_addr), 951 data_addr, sizeof(data_addr)) == NULL) 952 strlcpy (data_addr, "unknown address", 953 sizeof(data_addr)); 954 955 reply(530, "Login incorrect."); 956 if (logging) 957 syslog(LOG_NOTICE, 958 "FTP LOGIN FAILED FROM %s(%s), %s", 959 remotehost, 960 data_addr, 961 curname); 962 pw = NULL; 963 if (login_attempts++ >= 5) { 964 syslog(LOG_NOTICE, 965 "repeated login failures from %s(%s)", 966 remotehost, 967 data_addr); 968 exit(0); 969 } 970 return; 971 } 972 } 973 if(!do_login(230, passwd)) 974 return; 975 976 /* Forget all about it... */ 977 end_login(); 978 } 979 980 void 981 retrieve(const char *cmd, char *name) 982 { 983 FILE *fin = NULL, *dout; 984 struct stat st; 985 int (*closefunc) (FILE *); 986 char line[BUFSIZ]; 987 988 989 if (cmd == 0) { 990 fin = fopen(name, "r"); 991 closefunc = fclose; 992 st.st_size = 0; 993 if(fin == NULL){ 994 int save_errno = errno; 995 struct cmds { 996 const char *ext; 997 const char *cmd; 998 const char *rev_cmd; 999 } cmds[] = { 1000 {".tar", "/bin/gtar cPf - %s", NULL}, 1001 {".tar.gz", "/bin/gtar zcPf - %s", NULL}, 1002 {".tar.Z", "/bin/gtar ZcPf - %s", NULL}, 1003 {".gz", "/bin/gzip -c -- %s", "/bin/gzip -c -d -- %s"}, 1004 {".Z", "/bin/compress -c -- %s", "/bin/uncompress -c -- %s"}, 1005 {NULL, NULL} 1006 }; 1007 struct cmds *p; 1008 for(p = cmds; p->ext; p++){ 1009 char *tail = name + strlen(name) - strlen(p->ext); 1010 char c = *tail; 1011 1012 if(strcmp(tail, p->ext) == 0 && 1013 (*tail = 0) == 0 && 1014 access(name, R_OK) == 0){ 1015 snprintf (line, sizeof(line), p->cmd, name); 1016 *tail = c; 1017 break; 1018 } 1019 *tail = c; 1020 if (p->rev_cmd != NULL) { 1021 char *ext; 1022 1023 asprintf(&ext, "%s%s", name, p->ext); 1024 if (ext != NULL) { 1025 if (access(ext, R_OK) == 0) { 1026 snprintf (line, sizeof(line), 1027 p->rev_cmd, ext); 1028 free(ext); 1029 break; 1030 } 1031 free(ext); 1032 } 1033 } 1034 1035 } 1036 if(p->ext){ 1037 fin = ftpd_popen(line, "r", 0, 0); 1038 closefunc = ftpd_pclose; 1039 st.st_size = -1; 1040 cmd = line; 1041 } else 1042 errno = save_errno; 1043 } 1044 } else { 1045 snprintf(line, sizeof(line), cmd, name); 1046 name = line; 1047 fin = ftpd_popen(line, "r", 1, 0); 1048 closefunc = ftpd_pclose; 1049 st.st_size = -1; 1050 } 1051 if (fin == NULL) { 1052 if (errno != 0) { 1053 perror_reply(550, name); 1054 if (cmd == 0) { 1055 LOGCMD("get", name); 1056 } 1057 } 1058 return; 1059 } 1060 byte_count = -1; 1061 if (cmd == 0){ 1062 if(fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) { 1063 reply(550, "%s: not a plain file.", name); 1064 goto done; 1065 } 1066 } 1067 if (restart_point) { 1068 if (type == TYPE_A) { 1069 off_t i, n; 1070 int c; 1071 1072 n = restart_point; 1073 i = 0; 1074 while (i++ < n) { 1075 if ((c=getc(fin)) == EOF) { 1076 perror_reply(550, name); 1077 goto done; 1078 } 1079 if (c == '\n') 1080 i++; 1081 } 1082 } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) { 1083 perror_reply(550, name); 1084 goto done; 1085 } 1086 } 1087 dout = dataconn(name, st.st_size, "w"); 1088 if (dout == NULL) 1089 goto done; 1090 set_buffer_size(fileno(dout), 0); 1091 send_data(fin, dout); 1092 fclose(dout); 1093 data = -1; 1094 pdata = -1; 1095 done: 1096 if (cmd == 0) 1097 LOGBYTES("get", name, byte_count); 1098 (*closefunc)(fin); 1099 } 1100 1101 /* filename sanity check */ 1102 1103 int 1104 filename_check(char *filename) 1105 { 1106 unsigned char *p; 1107 1108 p = (unsigned char *)strrchr(filename, '/'); 1109 if(p) 1110 filename = p + 1; 1111 1112 p = filename; 1113 1114 if(isalnum(*p)){ 1115 p++; 1116 while(*p && (isalnum(*p) || strchr(good_chars, *p))) 1117 p++; 1118 if(*p == '\0') 1119 return 0; 1120 } 1121 lreply(553, "\"%s\" is not an acceptable filename.", filename); 1122 lreply(553, "The filename must start with an alphanumeric " 1123 "character and must only"); 1124 reply(553, "consist of alphanumeric characters or any of the following: %s", 1125 good_chars); 1126 return 1; 1127 } 1128 1129 void 1130 do_store(char *name, char *mode, int unique) 1131 { 1132 FILE *fout, *din; 1133 struct stat st; 1134 int (*closefunc) (FILE *); 1135 1136 if(guest && filename_check(name)) 1137 return; 1138 if (unique && stat(name, &st) == 0 && 1139 (name = gunique(name)) == NULL) { 1140 LOGCMD(*mode == 'w' ? "put" : "append", name); 1141 return; 1142 } 1143 1144 if (restart_point) 1145 mode = "r+"; 1146 fout = fopen(name, mode); 1147 closefunc = fclose; 1148 if (fout == NULL) { 1149 perror_reply(553, name); 1150 LOGCMD(*mode == 'w' ? "put" : "append", name); 1151 return; 1152 } 1153 byte_count = -1; 1154 if (restart_point) { 1155 if (type == TYPE_A) { 1156 off_t i, n; 1157 int c; 1158 1159 n = restart_point; 1160 i = 0; 1161 while (i++ < n) { 1162 if ((c=getc(fout)) == EOF) { 1163 perror_reply(550, name); 1164 goto done; 1165 } 1166 if (c == '\n') 1167 i++; 1168 } 1169 /* 1170 * We must do this seek to "current" position 1171 * because we are changing from reading to 1172 * writing. 1173 */ 1174 if (fseek(fout, 0L, SEEK_CUR) < 0) { 1175 perror_reply(550, name); 1176 goto done; 1177 } 1178 } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) { 1179 perror_reply(550, name); 1180 goto done; 1181 } 1182 } 1183 din = dataconn(name, (off_t)-1, "r"); 1184 if (din == NULL) 1185 goto done; 1186 set_buffer_size(fileno(din), 1); 1187 if (receive_data(din, fout) == 0) { 1188 if((*closefunc)(fout) < 0) 1189 perror_reply(552, name); 1190 else { 1191 if (unique) 1192 reply(226, "Transfer complete (unique file name:%s).", 1193 name); 1194 else 1195 reply(226, "Transfer complete."); 1196 } 1197 } else 1198 (*closefunc)(fout); 1199 fclose(din); 1200 data = -1; 1201 pdata = -1; 1202 done: 1203 LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count); 1204 } 1205 1206 static FILE * 1207 getdatasock(const char *mode) 1208 { 1209 int s, t, tries; 1210 1211 if (data >= 0) 1212 return (fdopen(data, mode)); 1213 seteuid(0); 1214 s = socket(ctrl_addr->sa_family, SOCK_STREAM, 0); 1215 if (s < 0) 1216 goto bad; 1217 socket_set_reuseaddr (s, 1); 1218 /* anchor socket to avoid multi-homing problems */ 1219 socket_set_address_and_port (data_source, 1220 socket_get_address (ctrl_addr), 1221 socket_get_port (data_source)); 1222 1223 for (tries = 1; ; tries++) { 1224 if (bind(s, data_source, 1225 socket_sockaddr_size (data_source)) >= 0) 1226 break; 1227 if (errno != EADDRINUSE || tries > 10) 1228 goto bad; 1229 sleep(tries); 1230 } 1231 seteuid(pw->pw_uid); 1232 #ifdef IPTOS_THROUGHPUT 1233 socket_set_tos (s, IPTOS_THROUGHPUT); 1234 #endif 1235 return (fdopen(s, mode)); 1236 bad: 1237 /* Return the real value of errno (close may change it) */ 1238 t = errno; 1239 seteuid((uid_t)pw->pw_uid); 1240 close(s); 1241 errno = t; 1242 return (NULL); 1243 } 1244 1245 static int 1246 accept_with_timeout(int socket, 1247 struct sockaddr *address, 1248 socklen_t *address_len, 1249 struct timeval *timeout) 1250 { 1251 int ret; 1252 fd_set rfd; 1253 FD_ZERO(&rfd); 1254 FD_SET(socket, &rfd); 1255 ret = select(socket + 1, &rfd, NULL, NULL, timeout); 1256 if(ret < 0) 1257 return ret; 1258 if(ret == 0) { 1259 errno = ETIMEDOUT; 1260 return -1; 1261 } 1262 return accept(socket, address, address_len); 1263 } 1264 1265 static FILE * 1266 dataconn(const char *name, off_t size, const char *mode) 1267 { 1268 char sizebuf[32]; 1269 FILE *file; 1270 int retry = 0; 1271 1272 file_size = size; 1273 byte_count = 0; 1274 if (size >= 0) 1275 snprintf(sizebuf, sizeof(sizebuf), " (%ld bytes)", (long)size); 1276 else 1277 *sizebuf = '\0'; 1278 if (pdata >= 0) { 1279 struct sockaddr_storage from_ss; 1280 struct sockaddr *from = (struct sockaddr *)&from_ss; 1281 struct timeval timeout; 1282 int s; 1283 socklen_t fromlen = sizeof(from_ss); 1284 1285 timeout.tv_sec = 15; 1286 timeout.tv_usec = 0; 1287 s = accept_with_timeout(pdata, from, &fromlen, &timeout); 1288 if (s < 0) { 1289 reply(425, "Can't open data connection."); 1290 close(pdata); 1291 pdata = -1; 1292 return (NULL); 1293 } 1294 close(pdata); 1295 pdata = s; 1296 #if defined(IP_TOS) && defined(HAVE_SETSOCKOPT) 1297 { 1298 int tos = IPTOS_THROUGHPUT; 1299 1300 setsockopt(s, IPPROTO_IP, IP_TOS, (void *)&tos, 1301 sizeof(tos)); 1302 } 1303 #endif 1304 reply(150, "Opening %s mode data connection for '%s'%s.", 1305 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 1306 return (fdopen(pdata, mode)); 1307 } 1308 if (data >= 0) { 1309 reply(125, "Using existing data connection for '%s'%s.", 1310 name, sizebuf); 1311 usedefault = 1; 1312 return (fdopen(data, mode)); 1313 } 1314 if (usedefault) 1315 data_dest = his_addr; 1316 usedefault = 1; 1317 file = getdatasock(mode); 1318 if (file == NULL) { 1319 char data_addr[256]; 1320 1321 if (inet_ntop (data_source->sa_family, 1322 socket_get_address(data_source), 1323 data_addr, sizeof(data_addr)) == NULL) 1324 strlcpy (data_addr, "unknown address", 1325 sizeof(data_addr)); 1326 1327 reply(425, "Can't create data socket (%s,%d): %s.", 1328 data_addr, 1329 socket_get_port (data_source), 1330 strerror(errno)); 1331 return (NULL); 1332 } 1333 data = fileno(file); 1334 while (connect(data, data_dest, 1335 socket_sockaddr_size(data_dest)) < 0) { 1336 if (errno == EADDRINUSE && retry < swaitmax) { 1337 sleep(swaitint); 1338 retry += swaitint; 1339 continue; 1340 } 1341 perror_reply(425, "Can't build data connection"); 1342 fclose(file); 1343 data = -1; 1344 return (NULL); 1345 } 1346 reply(150, "Opening %s mode data connection for '%s'%s.", 1347 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 1348 return (file); 1349 } 1350 1351 /* 1352 * Tranfer the contents of "instr" to "outstr" peer using the appropriate 1353 * encapsulation of the data subject * to Mode, Structure, and Type. 1354 * 1355 * NB: Form isn't handled. 1356 */ 1357 static void 1358 send_data(FILE *instr, FILE *outstr) 1359 { 1360 int c, cnt, filefd, netfd; 1361 static char *buf; 1362 static size_t bufsize; 1363 1364 transflag++; 1365 if (setjmp(urgcatch)) { 1366 transflag = 0; 1367 return; 1368 } 1369 switch (type) { 1370 1371 case TYPE_A: 1372 while ((c = getc(instr)) != EOF) { 1373 byte_count++; 1374 if(c == '\n') 1375 sec_putc('\r', outstr); 1376 sec_putc(c, outstr); 1377 } 1378 sec_fflush(outstr); 1379 transflag = 0; 1380 if (ferror(instr)) 1381 goto file_err; 1382 if (ferror(outstr)) 1383 goto data_err; 1384 reply(226, "Transfer complete."); 1385 return; 1386 1387 case TYPE_I: 1388 case TYPE_L: 1389 #if defined(HAVE_MMAP) && !defined(NO_MMAP) 1390 #ifndef MAP_FAILED 1391 #define MAP_FAILED (-1) 1392 #endif 1393 { 1394 struct stat st; 1395 char *chunk; 1396 int in = fileno(instr); 1397 if(fstat(in, &st) == 0 && S_ISREG(st.st_mode) 1398 && st.st_size > 0) { 1399 /* 1400 * mmap zero bytes has potential of loosing, don't do it. 1401 */ 1402 chunk = mmap(0, st.st_size, PROT_READ, 1403 MAP_SHARED, in, 0); 1404 if((void *)chunk != (void *)MAP_FAILED) { 1405 cnt = st.st_size - restart_point; 1406 sec_write(fileno(outstr), chunk + restart_point, cnt); 1407 if (munmap(chunk, st.st_size) < 0) 1408 warn ("munmap"); 1409 sec_fflush(outstr); 1410 byte_count = cnt; 1411 transflag = 0; 1412 } 1413 } 1414 } 1415 #endif 1416 if(transflag) { 1417 struct stat st; 1418 1419 netfd = fileno(outstr); 1420 filefd = fileno(instr); 1421 buf = alloc_buffer (buf, &bufsize, 1422 fstat(filefd, &st) >= 0 ? &st : NULL); 1423 if (buf == NULL) { 1424 transflag = 0; 1425 perror_reply(451, "Local resource failure: malloc"); 1426 return; 1427 } 1428 while ((cnt = read(filefd, buf, bufsize)) > 0 && 1429 sec_write(netfd, buf, cnt) == cnt) 1430 byte_count += cnt; 1431 sec_fflush(outstr); /* to end an encrypted stream */ 1432 transflag = 0; 1433 if (cnt != 0) { 1434 if (cnt < 0) 1435 goto file_err; 1436 goto data_err; 1437 } 1438 } 1439 reply(226, "Transfer complete."); 1440 return; 1441 default: 1442 transflag = 0; 1443 reply(550, "Unimplemented TYPE %d in send_data", type); 1444 return; 1445 } 1446 1447 data_err: 1448 transflag = 0; 1449 perror_reply(426, "Data connection"); 1450 return; 1451 1452 file_err: 1453 transflag = 0; 1454 perror_reply(551, "Error on input file"); 1455 } 1456 1457 /* 1458 * Transfer data from peer to "outstr" using the appropriate encapulation of 1459 * the data subject to Mode, Structure, and Type. 1460 * 1461 * N.B.: Form isn't handled. 1462 */ 1463 static int 1464 receive_data(FILE *instr, FILE *outstr) 1465 { 1466 int cnt, bare_lfs = 0; 1467 static char *buf; 1468 static size_t bufsize; 1469 struct stat st; 1470 1471 transflag++; 1472 if (setjmp(urgcatch)) { 1473 transflag = 0; 1474 return (-1); 1475 } 1476 1477 buf = alloc_buffer (buf, &bufsize, 1478 fstat(fileno(outstr), &st) >= 0 ? &st : NULL); 1479 if (buf == NULL) { 1480 transflag = 0; 1481 perror_reply(451, "Local resource failure: malloc"); 1482 return -1; 1483 } 1484 1485 switch (type) { 1486 1487 case TYPE_I: 1488 case TYPE_L: 1489 while ((cnt = sec_read(fileno(instr), buf, bufsize)) > 0) { 1490 if (write(fileno(outstr), buf, cnt) != cnt) 1491 goto file_err; 1492 byte_count += cnt; 1493 } 1494 if (cnt < 0) 1495 goto data_err; 1496 transflag = 0; 1497 return (0); 1498 1499 case TYPE_E: 1500 reply(553, "TYPE E not implemented."); 1501 transflag = 0; 1502 return (-1); 1503 1504 case TYPE_A: 1505 { 1506 char *p, *q; 1507 int cr_flag = 0; 1508 while ((cnt = sec_read(fileno(instr), 1509 buf + cr_flag, 1510 bufsize - cr_flag)) > 0){ 1511 byte_count += cnt; 1512 cnt += cr_flag; 1513 cr_flag = 0; 1514 for(p = buf, q = buf; p < buf + cnt;) { 1515 if(*p == '\n') 1516 bare_lfs++; 1517 if(*p == '\r') { 1518 if(p == buf + cnt - 1){ 1519 cr_flag = 1; 1520 p++; 1521 continue; 1522 }else if(p[1] == '\n'){ 1523 *q++ = '\n'; 1524 p += 2; 1525 continue; 1526 } 1527 } 1528 *q++ = *p++; 1529 } 1530 fwrite(buf, q - buf, 1, outstr); 1531 if(cr_flag) 1532 buf[0] = '\r'; 1533 } 1534 if(cr_flag) 1535 putc('\r', outstr); 1536 fflush(outstr); 1537 if (ferror(instr)) 1538 goto data_err; 1539 if (ferror(outstr)) 1540 goto file_err; 1541 transflag = 0; 1542 if (bare_lfs) { 1543 lreply(226, "WARNING! %d bare linefeeds received in ASCII mode\r\n" 1544 " File may not have transferred correctly.\r\n", 1545 bare_lfs); 1546 } 1547 return (0); 1548 } 1549 default: 1550 reply(550, "Unimplemented TYPE %d in receive_data", type); 1551 transflag = 0; 1552 return (-1); 1553 } 1554 1555 data_err: 1556 transflag = 0; 1557 perror_reply(426, "Data Connection"); 1558 return (-1); 1559 1560 file_err: 1561 transflag = 0; 1562 perror_reply(452, "Error writing file"); 1563 return (-1); 1564 } 1565 1566 void 1567 statfilecmd(char *filename) 1568 { 1569 FILE *fin; 1570 int c; 1571 char line[LINE_MAX]; 1572 1573 snprintf(line, sizeof(line), "/bin/ls -la -- %s", filename); 1574 fin = ftpd_popen(line, "r", 1, 0); 1575 lreply(211, "status of %s:", filename); 1576 while ((c = getc(fin)) != EOF) { 1577 if (c == '\n') { 1578 if (ferror(stdout)){ 1579 perror_reply(421, "control connection"); 1580 ftpd_pclose(fin); 1581 dologout(1); 1582 /* NOTREACHED */ 1583 } 1584 if (ferror(fin)) { 1585 perror_reply(551, filename); 1586 ftpd_pclose(fin); 1587 return; 1588 } 1589 putc('\r', stdout); 1590 } 1591 putc(c, stdout); 1592 } 1593 ftpd_pclose(fin); 1594 reply(211, "End of Status"); 1595 } 1596 1597 void 1598 statcmd(void) 1599 { 1600 #if 0 1601 struct sockaddr_in *sin; 1602 u_char *a, *p; 1603 1604 lreply(211, "%s FTP server (%s) status:", hostname, version); 1605 printf(" %s\r\n", version); 1606 printf(" Connected to %s", remotehost); 1607 if (!isdigit(remotehost[0])) 1608 printf(" (%s)", inet_ntoa(his_addr.sin_addr)); 1609 printf("\r\n"); 1610 if (logged_in) { 1611 if (guest) 1612 printf(" Logged in anonymously\r\n"); 1613 else 1614 printf(" Logged in as %s\r\n", pw->pw_name); 1615 } else if (askpasswd) 1616 printf(" Waiting for password\r\n"); 1617 else 1618 printf(" Waiting for user name\r\n"); 1619 printf(" TYPE: %s", typenames[type]); 1620 if (type == TYPE_A || type == TYPE_E) 1621 printf(", FORM: %s", formnames[form]); 1622 if (type == TYPE_L) 1623 #if NBBY == 8 1624 printf(" %d", NBBY); 1625 #else 1626 printf(" %d", bytesize); /* need definition! */ 1627 #endif 1628 printf("; STRUcture: %s; transfer MODE: %s\r\n", 1629 strunames[stru], modenames[mode]); 1630 if (data != -1) 1631 printf(" Data connection open\r\n"); 1632 else if (pdata != -1) { 1633 printf(" in Passive mode"); 1634 sin = &pasv_addr; 1635 goto printaddr; 1636 } else if (usedefault == 0) { 1637 printf(" PORT"); 1638 sin = &data_dest; 1639 printaddr: 1640 a = (u_char *) &sin->sin_addr; 1641 p = (u_char *) &sin->sin_port; 1642 #define UC(b) (((int) b) & 0xff) 1643 printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]), 1644 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 1645 #undef UC 1646 } else 1647 printf(" No data connection\r\n"); 1648 #endif 1649 reply(211, "End of status"); 1650 } 1651 1652 void 1653 fatal(char *s) 1654 { 1655 1656 reply(451, "Error in server: %s\n", s); 1657 reply(221, "Closing connection due to server error."); 1658 dologout(0); 1659 /* NOTREACHED */ 1660 } 1661 1662 static void 1663 int_reply(int, char *, const char *, va_list) 1664 #ifdef __GNUC__ 1665 __attribute__ ((format (printf, 3, 0))) 1666 #endif 1667 ; 1668 1669 static void 1670 int_reply(int n, char *c, const char *fmt, va_list ap) 1671 { 1672 char buf[10240]; 1673 char *p; 1674 p=buf; 1675 if(n){ 1676 snprintf(p, sizeof(buf), "%d%s", n, c); 1677 p+=strlen(p); 1678 } 1679 vsnprintf(p, sizeof(buf) - strlen(p), fmt, ap); 1680 p+=strlen(p); 1681 snprintf(p, sizeof(buf) - strlen(p), "\r\n"); 1682 p+=strlen(p); 1683 sec_fprintf(stdout, "%s", buf); 1684 fflush(stdout); 1685 if (debug) 1686 syslog(LOG_DEBUG, "<--- %s- ", buf); 1687 } 1688 1689 void 1690 reply(int n, const char *fmt, ...) 1691 { 1692 va_list ap; 1693 va_start(ap, fmt); 1694 int_reply(n, " ", fmt, ap); 1695 delete_ftp_command(); 1696 va_end(ap); 1697 } 1698 1699 void 1700 lreply(int n, const char *fmt, ...) 1701 { 1702 va_list ap; 1703 va_start(ap, fmt); 1704 int_reply(n, "-", fmt, ap); 1705 va_end(ap); 1706 } 1707 1708 void 1709 nreply(const char *fmt, ...) 1710 { 1711 va_list ap; 1712 va_start(ap, fmt); 1713 int_reply(0, NULL, fmt, ap); 1714 va_end(ap); 1715 } 1716 1717 static void 1718 ack(char *s) 1719 { 1720 1721 reply(250, "%s command successful.", s); 1722 } 1723 1724 void 1725 nack(char *s) 1726 { 1727 1728 reply(502, "%s command not implemented.", s); 1729 } 1730 1731 /* ARGSUSED */ 1732 void 1733 yyerror(char *s) 1734 { 1735 char *cp; 1736 1737 if ((cp = strchr(cbuf,'\n'))) 1738 *cp = '\0'; 1739 reply(500, "'%s': command not understood.", cbuf); 1740 } 1741 1742 void 1743 do_delete(char *name) 1744 { 1745 struct stat st; 1746 1747 LOGCMD("delete", name); 1748 if (stat(name, &st) < 0) { 1749 perror_reply(550, name); 1750 return; 1751 } 1752 if ((st.st_mode&S_IFMT) == S_IFDIR) { 1753 if (rmdir(name) < 0) { 1754 perror_reply(550, name); 1755 return; 1756 } 1757 goto done; 1758 } 1759 if (unlink(name) < 0) { 1760 perror_reply(550, name); 1761 return; 1762 } 1763 done: 1764 ack("DELE"); 1765 } 1766 1767 void 1768 cwd(char *path) 1769 { 1770 1771 if (chdir(path) < 0) 1772 perror_reply(550, path); 1773 else 1774 ack("CWD"); 1775 } 1776 1777 void 1778 makedir(char *name) 1779 { 1780 1781 LOGCMD("mkdir", name); 1782 if(guest && filename_check(name)) 1783 return; 1784 if (mkdir(name, 0777) < 0) 1785 perror_reply(550, name); 1786 else{ 1787 if(guest) 1788 chmod(name, 0700); /* guest has umask 777 */ 1789 reply(257, "MKD command successful."); 1790 } 1791 } 1792 1793 void 1794 removedir(char *name) 1795 { 1796 1797 LOGCMD("rmdir", name); 1798 if (rmdir(name) < 0) 1799 perror_reply(550, name); 1800 else 1801 ack("RMD"); 1802 } 1803 1804 void 1805 pwd(void) 1806 { 1807 char path[MaxPathLen]; 1808 char *ret; 1809 1810 /* SunOS has a broken getcwd that does popen(pwd) (!!!), this 1811 * failes miserably when running chroot 1812 */ 1813 ret = getcwd(path, sizeof(path)); 1814 if (ret == NULL) 1815 reply(550, "%s.", strerror(errno)); 1816 else 1817 reply(257, "\"%s\" is current directory.", path); 1818 } 1819 1820 char * 1821 renamefrom(char *name) 1822 { 1823 struct stat st; 1824 1825 if (stat(name, &st) < 0) { 1826 perror_reply(550, name); 1827 return NULL; 1828 } 1829 reply(350, "File exists, ready for destination name"); 1830 return (name); 1831 } 1832 1833 void 1834 renamecmd(char *from, char *to) 1835 { 1836 1837 LOGCMD2("rename", from, to); 1838 if(guest && filename_check(to)) 1839 return; 1840 if (rename(from, to) < 0) 1841 perror_reply(550, "rename"); 1842 else 1843 ack("RNTO"); 1844 } 1845 1846 static void 1847 dolog(struct sockaddr *sa, int len) 1848 { 1849 getnameinfo_verified (sa, len, remotehost, sizeof(remotehost), 1850 NULL, 0, 0); 1851 #ifdef HAVE_SETPROCTITLE 1852 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost); 1853 setproctitle("%s", proctitle); 1854 #endif /* HAVE_SETPROCTITLE */ 1855 1856 if (logging) { 1857 char data_addr[256]; 1858 1859 if (inet_ntop (his_addr->sa_family, 1860 socket_get_address(his_addr), 1861 data_addr, sizeof(data_addr)) == NULL) 1862 strlcpy (data_addr, "unknown address", 1863 sizeof(data_addr)); 1864 1865 1866 syslog(LOG_INFO, "connection from %s(%s)", 1867 remotehost, 1868 data_addr); 1869 } 1870 } 1871 1872 /* 1873 * Record logout in wtmp file 1874 * and exit with supplied status. 1875 */ 1876 void 1877 dologout(int status) 1878 { 1879 transflag = 0; 1880 if (logged_in) { 1881 seteuid((uid_t)0); 1882 ftpd_logwtmp(ttyline, "", ""); 1883 #ifdef KRB4 1884 cond_kdestroy(); 1885 #endif 1886 } 1887 /* beware of flushing buffers after a SIGPIPE */ 1888 #ifdef XXX 1889 exit(status); 1890 #else 1891 _exit(status); 1892 #endif 1893 } 1894 1895 void abor(void) 1896 { 1897 } 1898 1899 static void 1900 myoob(int signo) 1901 { 1902 #if 0 1903 char *cp; 1904 #endif 1905 1906 /* only process if transfer occurring */ 1907 if (!transflag) 1908 return; 1909 1910 /* This is all XXX */ 1911 oobflag = 1; 1912 /* if the command resulted in a new command, 1913 parse that as well */ 1914 do{ 1915 yyparse(); 1916 } while(ftp_command); 1917 oobflag = 0; 1918 1919 #if 0 1920 cp = tmpline; 1921 if (ftpd_getline(cp, 7) == NULL) { 1922 reply(221, "You could at least say goodbye."); 1923 dologout(0); 1924 } 1925 upper(cp); 1926 if (strcmp(cp, "ABOR\r\n") == 0) { 1927 tmpline[0] = '\0'; 1928 reply(426, "Transfer aborted. Data connection closed."); 1929 reply(226, "Abort successful"); 1930 longjmp(urgcatch, 1); 1931 } 1932 if (strcmp(cp, "STAT\r\n") == 0) { 1933 if (file_size != (off_t) -1) 1934 reply(213, "Status: %ld of %ld bytes transferred", 1935 (long)byte_count, 1936 (long)file_size); 1937 else 1938 reply(213, "Status: %ld bytes transferred" 1939 (long)byte_count); 1940 } 1941 #endif 1942 } 1943 1944 /* 1945 * Note: a response of 425 is not mentioned as a possible response to 1946 * the PASV command in RFC959. However, it has been blessed as 1947 * a legitimate response by Jon Postel in a telephone conversation 1948 * with Rick Adams on 25 Jan 89. 1949 */ 1950 void 1951 pasv(void) 1952 { 1953 socklen_t len; 1954 char *p, *a; 1955 struct sockaddr_in *sin; 1956 1957 if (ctrl_addr->sa_family != AF_INET) { 1958 reply(425, 1959 "You cannot do PASV with something that's not IPv4"); 1960 return; 1961 } 1962 1963 if(pdata != -1) 1964 close(pdata); 1965 1966 pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0); 1967 if (pdata < 0) { 1968 perror_reply(425, "Can't open passive connection"); 1969 return; 1970 } 1971 pasv_addr->sa_family = ctrl_addr->sa_family; 1972 socket_set_address_and_port (pasv_addr, 1973 socket_get_address (ctrl_addr), 1974 0); 1975 socket_set_portrange(pdata, restricted_data_ports, 1976 pasv_addr->sa_family); 1977 seteuid(0); 1978 if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) { 1979 seteuid(pw->pw_uid); 1980 goto pasv_error; 1981 } 1982 seteuid(pw->pw_uid); 1983 len = sizeof(pasv_addr_ss); 1984 if (getsockname(pdata, pasv_addr, &len) < 0) 1985 goto pasv_error; 1986 if (listen(pdata, 1) < 0) 1987 goto pasv_error; 1988 sin = (struct sockaddr_in *)pasv_addr; 1989 a = (char *) &sin->sin_addr; 1990 p = (char *) &sin->sin_port; 1991 1992 #define UC(b) (((int) b) & 0xff) 1993 1994 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), 1995 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 1996 return; 1997 1998 pasv_error: 1999 close(pdata); 2000 pdata = -1; 2001 perror_reply(425, "Can't open passive connection"); 2002 return; 2003 } 2004 2005 void 2006 epsv(char *proto) 2007 { 2008 socklen_t len; 2009 2010 pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0); 2011 if (pdata < 0) { 2012 perror_reply(425, "Can't open passive connection"); 2013 return; 2014 } 2015 pasv_addr->sa_family = ctrl_addr->sa_family; 2016 socket_set_address_and_port (pasv_addr, 2017 socket_get_address (ctrl_addr), 2018 0); 2019 socket_set_portrange(pdata, restricted_data_ports, 2020 pasv_addr->sa_family); 2021 seteuid(0); 2022 if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) { 2023 seteuid(pw->pw_uid); 2024 goto pasv_error; 2025 } 2026 seteuid(pw->pw_uid); 2027 len = sizeof(pasv_addr_ss); 2028 if (getsockname(pdata, pasv_addr, &len) < 0) 2029 goto pasv_error; 2030 if (listen(pdata, 1) < 0) 2031 goto pasv_error; 2032 2033 reply(229, "Entering Extended Passive Mode (|||%d|)", 2034 ntohs(socket_get_port (pasv_addr))); 2035 return; 2036 2037 pasv_error: 2038 close(pdata); 2039 pdata = -1; 2040 perror_reply(425, "Can't open passive connection"); 2041 return; 2042 } 2043 2044 void 2045 eprt(char *str) 2046 { 2047 char *end; 2048 char sep; 2049 int af; 2050 int ret; 2051 int port; 2052 2053 usedefault = 0; 2054 if (pdata >= 0) { 2055 close(pdata); 2056 pdata = -1; 2057 } 2058 2059 sep = *str++; 2060 if (sep == '\0') { 2061 reply(500, "Bad syntax in EPRT"); 2062 return; 2063 } 2064 af = strtol (str, &end, 0); 2065 if (af == 0 || *end != sep) { 2066 reply(500, "Bad syntax in EPRT"); 2067 return; 2068 } 2069 str = end + 1; 2070 switch (af) { 2071 #ifdef HAVE_IPV6 2072 case 2 : 2073 data_dest->sa_family = AF_INET6; 2074 break; 2075 #endif 2076 case 1 : 2077 data_dest->sa_family = AF_INET; 2078 break; 2079 default : 2080 reply(522, "Network protocol %d not supported, use (1" 2081 #ifdef HAVE_IPV6 2082 ",2" 2083 #endif 2084 ")", af); 2085 return; 2086 } 2087 end = strchr (str, sep); 2088 if (end == NULL) { 2089 reply(500, "Bad syntax in EPRT"); 2090 return; 2091 } 2092 *end = '\0'; 2093 ret = inet_pton (data_dest->sa_family, str, 2094 socket_get_address (data_dest)); 2095 2096 if (ret != 1) { 2097 reply(500, "Bad address syntax in EPRT"); 2098 return; 2099 } 2100 str = end + 1; 2101 port = strtol (str, &end, 0); 2102 if (port == 0 || *end != sep) { 2103 reply(500, "Bad port syntax in EPRT"); 2104 return; 2105 } 2106 socket_set_port (data_dest, htons(port)); 2107 reply(200, "EPRT command successful."); 2108 } 2109 2110 /* 2111 * Generate unique name for file with basename "local". 2112 * The file named "local" is already known to exist. 2113 * Generates failure reply on error. 2114 */ 2115 static char * 2116 gunique(char *local) 2117 { 2118 static char new[MaxPathLen]; 2119 struct stat st; 2120 int count; 2121 char *cp; 2122 2123 cp = strrchr(local, '/'); 2124 if (cp) 2125 *cp = '\0'; 2126 if (stat(cp ? local : ".", &st) < 0) { 2127 perror_reply(553, cp ? local : "."); 2128 return NULL; 2129 } 2130 if (cp) 2131 *cp = '/'; 2132 for (count = 1; count < 100; count++) { 2133 snprintf (new, sizeof(new), "%s.%d", local, count); 2134 if (stat(new, &st) < 0) 2135 return (new); 2136 } 2137 reply(452, "Unique file name cannot be created."); 2138 return (NULL); 2139 } 2140 2141 /* 2142 * Format and send reply containing system error number. 2143 */ 2144 void 2145 perror_reply(int code, const char *string) 2146 { 2147 reply(code, "%s: %s.", string, strerror(errno)); 2148 } 2149 2150 static char *onefile[] = { 2151 "", 2152 0 2153 }; 2154 2155 void 2156 list_file(char *file) 2157 { 2158 if(use_builtin_ls) { 2159 FILE *dout; 2160 dout = dataconn(file, -1, "w"); 2161 if (dout == NULL) 2162 return; 2163 set_buffer_size(fileno(dout), 0); 2164 if(builtin_ls(dout, file) == 0) 2165 reply(226, "Transfer complete."); 2166 else 2167 reply(451, "Requested action aborted. Local error in processing."); 2168 fclose(dout); 2169 data = -1; 2170 pdata = -1; 2171 } else { 2172 #ifdef HAVE_LS_A 2173 const char *cmd = "/bin/ls -lA %s"; 2174 #else 2175 const char *cmd = "/bin/ls -la %s"; 2176 #endif 2177 retrieve(cmd, file); 2178 } 2179 } 2180 2181 void 2182 send_file_list(char *whichf) 2183 { 2184 struct stat st; 2185 DIR *dirp = NULL; 2186 struct dirent *dir; 2187 FILE *dout = NULL; 2188 char **dirlist, *dirname; 2189 int simple = 0; 2190 int freeglob = 0; 2191 glob_t gl; 2192 char buf[MaxPathLen]; 2193 2194 if (strpbrk(whichf, "~{[*?") != NULL) { 2195 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE| 2196 #ifdef GLOB_MAXPATH 2197 GLOB_MAXPATH 2198 #else 2199 GLOB_LIMIT 2200 #endif 2201 ; 2202 2203 memset(&gl, 0, sizeof(gl)); 2204 freeglob = 1; 2205 if (glob(whichf, flags, 0, &gl)) { 2206 reply(550, "not found"); 2207 goto out; 2208 } else if (gl.gl_pathc == 0) { 2209 errno = ENOENT; 2210 perror_reply(550, whichf); 2211 goto out; 2212 } 2213 dirlist = gl.gl_pathv; 2214 } else { 2215 onefile[0] = whichf; 2216 dirlist = onefile; 2217 simple = 1; 2218 } 2219 2220 if (setjmp(urgcatch)) { 2221 transflag = 0; 2222 goto out; 2223 } 2224 while ((dirname = *dirlist++)) { 2225 if (stat(dirname, &st) < 0) { 2226 /* 2227 * If user typed "ls -l", etc, and the client 2228 * used NLST, do what the user meant. 2229 */ 2230 if (dirname[0] == '-' && *dirlist == NULL && 2231 transflag == 0) { 2232 list_file(dirname); 2233 goto out; 2234 } 2235 perror_reply(550, whichf); 2236 if (dout != NULL) { 2237 fclose(dout); 2238 transflag = 0; 2239 data = -1; 2240 pdata = -1; 2241 } 2242 goto out; 2243 } 2244 2245 if (S_ISREG(st.st_mode)) { 2246 if (dout == NULL) { 2247 dout = dataconn("file list", (off_t)-1, "w"); 2248 if (dout == NULL) 2249 goto out; 2250 transflag++; 2251 } 2252 snprintf(buf, sizeof(buf), "%s%s\n", dirname, 2253 type == TYPE_A ? "\r" : ""); 2254 sec_write(fileno(dout), buf, strlen(buf)); 2255 byte_count += strlen(dirname) + 1; 2256 continue; 2257 } else if (!S_ISDIR(st.st_mode)) 2258 continue; 2259 2260 if ((dirp = opendir(dirname)) == NULL) 2261 continue; 2262 2263 while ((dir = readdir(dirp)) != NULL) { 2264 char nbuf[MaxPathLen]; 2265 2266 if (!strcmp(dir->d_name, ".")) 2267 continue; 2268 if (!strcmp(dir->d_name, "..")) 2269 continue; 2270 2271 snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname, dir->d_name); 2272 2273 /* 2274 * We have to do a stat to insure it's 2275 * not a directory or special file. 2276 */ 2277 if (simple || (stat(nbuf, &st) == 0 && 2278 S_ISREG(st.st_mode))) { 2279 if (dout == NULL) { 2280 dout = dataconn("file list", (off_t)-1, "w"); 2281 if (dout == NULL) 2282 goto out; 2283 transflag++; 2284 } 2285 if(strncmp(nbuf, "./", 2) == 0) 2286 snprintf(buf, sizeof(buf), "%s%s\n", nbuf +2, 2287 type == TYPE_A ? "\r" : ""); 2288 else 2289 snprintf(buf, sizeof(buf), "%s%s\n", nbuf, 2290 type == TYPE_A ? "\r" : ""); 2291 sec_write(fileno(dout), buf, strlen(buf)); 2292 byte_count += strlen(nbuf) + 1; 2293 } 2294 } 2295 closedir(dirp); 2296 } 2297 if (dout == NULL) 2298 reply(550, "No files found."); 2299 else if (ferror(dout) != 0) 2300 perror_reply(550, "Data connection"); 2301 else 2302 reply(226, "Transfer complete."); 2303 2304 transflag = 0; 2305 if (dout != NULL){ 2306 sec_write(fileno(dout), buf, 0); /* XXX flush */ 2307 2308 fclose(dout); 2309 } 2310 data = -1; 2311 pdata = -1; 2312 out: 2313 if (freeglob) { 2314 freeglob = 0; 2315 globfree(&gl); 2316 } 2317 } 2318 2319 2320 int 2321 find(char *pattern) 2322 { 2323 char line[1024]; 2324 FILE *f; 2325 2326 snprintf(line, sizeof(line), 2327 "/bin/locate -d %s -- %s", 2328 ftp_rooted("/etc/locatedb"), 2329 pattern); 2330 f = ftpd_popen(line, "r", 1, 1); 2331 if(f == NULL){ 2332 perror_reply(550, "/bin/locate"); 2333 return 1; 2334 } 2335 lreply(200, "Output from find."); 2336 while(fgets(line, sizeof(line), f)){ 2337 if(line[strlen(line)-1] == '\n') 2338 line[strlen(line)-1] = 0; 2339 nreply("%s", line); 2340 } 2341 reply(200, "Done"); 2342 ftpd_pclose(f); 2343 return 0; 2344 } 2345 2346