ftpd.c revision 100486
1189251Ssam/* 2189251Ssam * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994 3189251Ssam * The Regents of the University of California. All rights reserved. 4189251Ssam * 5189251Ssam * Redistribution and use in source and binary forms, with or without 6189251Ssam * modification, are permitted provided that the following conditions 7189251Ssam * are met: 8189251Ssam * 1. Redistributions of source code must retain the above copyright 9189251Ssam * notice, this list of conditions and the following disclaimer. 10189251Ssam * 2. Redistributions in binary form must reproduce the above copyright 11189251Ssam * notice, this list of conditions and the following disclaimer in the 12189251Ssam * documentation and/or other materials provided with the distribution. 13189251Ssam * 3. All advertising materials mentioning features or use of this software 14189251Ssam * must display the following acknowledgement: 15189251Ssam * This product includes software developed by the University of 16189251Ssam * California, Berkeley and its contributors. 17189251Ssam * 4. Neither the name of the University nor the names of its contributors 18189251Ssam * may be used to endorse or promote products derived from this software 19189251Ssam * without specific prior written permission. 20189251Ssam * 21189251Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22189251Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23189251Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24189251Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25189251Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26189251Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27189251Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28189251Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29189251Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30189251Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31189251Ssam * SUCH DAMAGE. 32189251Ssam */ 33189251Ssam 34189251Ssam#if 0 35189251Ssam#ifndef lint 36189251Ssamstatic char copyright[] = 37189251Ssam"@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\ 38189251Ssam The Regents of the University of California. All rights reserved.\n"; 39189251Ssam#endif /* not lint */ 40189251Ssam#endif 41189251Ssam 42189251Ssam#ifndef lint 43189251Ssam#if 0 44189251Ssamstatic char sccsid[] = "@(#)ftpd.c 8.4 (Berkeley) 4/16/94"; 45189251Ssam#endif 46189251Ssamstatic const char rcsid[] = 47189251Ssam "$FreeBSD: head/libexec/ftpd/ftpd.c 100486 2002-07-22 07:41:14Z yar $"; 48189251Ssam#endif /* not lint */ 49189251Ssam 50189251Ssam/* 51189251Ssam * FTP server. 52189251Ssam */ 53189251Ssam#include <sys/param.h> 54189251Ssam#include <sys/ioctl.h> 55189251Ssam#include <sys/mman.h> 56189251Ssam#include <sys/socket.h> 57189251Ssam#include <sys/stat.h> 58189251Ssam#include <sys/time.h> 59189251Ssam#include <sys/wait.h> 60189251Ssam 61189251Ssam#include <netinet/in.h> 62189251Ssam#include <netinet/in_systm.h> 63189251Ssam#include <netinet/ip.h> 64189251Ssam#include <netinet/tcp.h> 65189251Ssam 66189251Ssam#define FTP_NAMES 67189251Ssam#include <arpa/ftp.h> 68189251Ssam#include <arpa/inet.h> 69189251Ssam#include <arpa/telnet.h> 70189251Ssam 71189251Ssam#include <ctype.h> 72189251Ssam#include <dirent.h> 73189251Ssam#include <err.h> 74189251Ssam#include <errno.h> 75189251Ssam#include <fcntl.h> 76189251Ssam#include <glob.h> 77189251Ssam#include <limits.h> 78189251Ssam#include <netdb.h> 79189251Ssam#include <pwd.h> 80189251Ssam#include <grp.h> 81189251Ssam#include <opie.h> 82189251Ssam#include <signal.h> 83189251Ssam#include <stdio.h> 84189251Ssam#include <stdlib.h> 85189251Ssam#include <string.h> 86189251Ssam#include <syslog.h> 87189251Ssam#include <time.h> 88189251Ssam#include <unistd.h> 89189251Ssam#include <libutil.h> 90189251Ssam#ifdef LOGIN_CAP 91189251Ssam#include <login_cap.h> 92189251Ssam#endif 93189251Ssam 94189251Ssam#ifdef USE_PAM 95189251Ssam#include <security/pam_appl.h> 96189251Ssam#endif 97189251Ssam 98189251Ssam#include "pathnames.h" 99189251Ssam#include "extern.h" 100189251Ssam 101189251Ssam#include <stdarg.h> 102189251Ssam 103189251Ssamstatic char version[] = "Version 6.00LS"; 104189251Ssam#undef main 105189251Ssam 106189251Ssamextern off_t restart_point; 107189251Ssamextern char cbuf[]; 108189251Ssam 109189251Ssamunion sockunion server_addr; 110189251Ssamunion sockunion ctrl_addr; 111189251Ssamunion sockunion data_source; 112189251Ssamunion sockunion data_dest; 113189251Ssamunion sockunion his_addr; 114189251Ssamunion sockunion pasv_addr; 115189251Ssam 116189251Ssamint daemon_mode; 117189251Ssamint data; 118189251Ssamint logged_in; 119189251Ssamstruct passwd *pw; 120int ftpdebug; 121int timeout = 900; /* timeout after 15 minutes of inactivity */ 122int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ 123int logging; 124int restricted_data_ports = 1; 125int paranoid = 1; /* be extra careful about security */ 126int anon_only = 0; /* Only anonymous ftp allowed */ 127int guest; 128int dochroot; 129int stats; 130int statfd = -1; 131int type; 132int form; 133int stru; /* avoid C keyword */ 134int mode; 135int usedefault = 1; /* for data transfers */ 136int pdata = -1; /* for passive mode */ 137int readonly=0; /* Server is in readonly mode. */ 138int noepsv=0; /* EPSV command is disabled. */ 139int noretr=0; /* RETR command is disabled. */ 140int noguestretr=0; /* RETR command is disabled for anon users. */ 141int noguestmkd=0; /* MKD command is disabled for anon users. */ 142 143static volatile sig_atomic_t recvurg; 144sig_atomic_t transflag; 145off_t file_size; 146off_t byte_count; 147#if !defined(CMASK) || CMASK == 0 148#undef CMASK 149#define CMASK 027 150#endif 151int defumask = CMASK; /* default umask value */ 152char tmpline[7]; 153char *hostname; 154int epsvall = 0; 155 156#ifdef VIRTUAL_HOSTING 157char *ftpuser; 158 159static struct ftphost { 160 struct ftphost *next; 161 struct addrinfo *hostinfo; 162 char *hostname; 163 char *anonuser; 164 char *statfile; 165 char *welcome; 166 char *loginmsg; 167} *thishost, *firsthost; 168 169#endif 170char remotehost[MAXHOSTNAMELEN]; 171char *ident = NULL; 172 173static char ttyline[20]; 174char *tty = ttyline; /* for klogin */ 175 176#ifdef USE_PAM 177static int auth_pam(struct passwd**, const char*); 178pam_handle_t *pamh = NULL; 179#endif 180 181static struct opie opiedata; 182static char opieprompt[OPIE_CHALLENGE_MAX+1]; 183static int pwok; 184 185char *pid_file = NULL; 186 187/* 188 * Limit number of pathnames that glob can return. 189 * A limit of 0 indicates the number of pathnames is unlimited. 190 */ 191#define MAXGLOBARGS 16384 192# 193 194/* 195 * Timeout intervals for retrying connections 196 * to hosts that don't accept PORT cmds. This 197 * is a kludge, but given the problems with TCP... 198 */ 199#define SWAITMAX 90 /* wait at most 90 seconds */ 200#define SWAITINT 5 /* interval between retries */ 201 202int swaitmax = SWAITMAX; 203int swaitint = SWAITINT; 204 205#ifdef SETPROCTITLE 206#ifdef OLD_SETPROCTITLE 207char **Argv = NULL; /* pointer to argument vector */ 208char *LastArgv = NULL; /* end of argv */ 209#endif /* OLD_SETPROCTITLE */ 210char proctitle[LINE_MAX]; /* initial part of title */ 211#endif /* SETPROCTITLE */ 212 213#define LOGCMD(cmd, file) \ 214 if (logging > 1) \ 215 syslog(LOG_INFO,"%s %s%s", cmd, \ 216 *(file) == '/' ? "" : curdir(), file); 217#define LOGCMD2(cmd, file1, file2) \ 218 if (logging > 1) \ 219 syslog(LOG_INFO,"%s %s%s %s%s", cmd, \ 220 *(file1) == '/' ? "" : curdir(), file1, \ 221 *(file2) == '/' ? "" : curdir(), file2); 222#define LOGBYTES(cmd, file, cnt) \ 223 if (logging > 1) { \ 224 if (cnt == (off_t)-1) \ 225 syslog(LOG_INFO,"%s %s%s", cmd, \ 226 *(file) == '/' ? "" : curdir(), file); \ 227 else \ 228 syslog(LOG_INFO, "%s %s%s = %qd bytes", \ 229 cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \ 230 } 231 232#ifdef VIRTUAL_HOSTING 233static void inithosts(void); 234static void selecthost(union sockunion *); 235#endif 236static void ack(char *); 237static void sigurg(int); 238static void myoob(void); 239static int checkuser(char *, char *, int); 240static FILE *dataconn(char *, off_t, char *); 241static void dolog(struct sockaddr *); 242static char *curdir(void); 243static void end_login(void); 244static FILE *getdatasock(char *); 245static char *gunique(char *); 246static void lostconn(int); 247static void sigquit(int); 248static int receive_data(FILE *, FILE *); 249static int send_data(FILE *, FILE *, off_t, off_t, int); 250static struct passwd * 251 sgetpwnam(char *); 252static char *sgetsave(char *); 253static void reapchild(int); 254static void logxfer(char *, off_t, time_t); 255static char *doublequote(char *); 256 257static char * 258curdir(void) 259{ 260 static char path[MAXPATHLEN+1+1]; /* path + '/' + '\0' */ 261 262 if (getcwd(path, sizeof(path)-2) == NULL) 263 return (""); 264 if (path[1] != '\0') /* special case for root dir. */ 265 strcat(path, "/"); 266 /* For guest account, skip / since it's chrooted */ 267 return (guest ? path+1 : path); 268} 269 270int 271main(int argc, char *argv[], char **envp) 272{ 273 int addrlen, ch, on = 1, tos; 274 char *cp, line[LINE_MAX]; 275 FILE *fd; 276 int error; 277 char *bindname = NULL; 278 int family = AF_UNSPEC; 279 int enable_v4 = 0; 280 struct sigaction sa; 281 282 tzset(); /* in case no timezone database in ~ftp */ 283 sigemptyset(&sa.sa_mask); 284 sa.sa_flags = SA_RESTART; 285 286#ifdef OLD_SETPROCTITLE 287 /* 288 * Save start and extent of argv for setproctitle. 289 */ 290 Argv = argv; 291 while (*envp) 292 envp++; 293 LastArgv = envp[-1] + strlen(envp[-1]); 294#endif /* OLD_SETPROCTITLE */ 295 296 297 while ((ch = getopt(argc, argv, "AdlDESURrt:T:u:vMOoa:p:46")) != -1) { 298 switch (ch) { 299 case 'D': 300 daemon_mode++; 301 break; 302 303 case 'd': 304 ftpdebug++; 305 break; 306 307 case 'E': 308 noepsv = 1; 309 break; 310 311 case 'l': 312 logging++; /* > 1 == extra logging */ 313 break; 314 315 case 'r': 316 readonly = 1; 317 break; 318 319 case 'R': 320 paranoid = 0; 321 break; 322 323 case 'S': 324 stats++; 325 break; 326 327 case 'T': 328 maxtimeout = atoi(optarg); 329 if (timeout > maxtimeout) 330 timeout = maxtimeout; 331 break; 332 333 case 't': 334 timeout = atoi(optarg); 335 if (maxtimeout < timeout) 336 maxtimeout = timeout; 337 break; 338 339 case 'U': 340 restricted_data_ports = 0; 341 break; 342 343 case 'a': 344 bindname = optarg; 345 break; 346 347 case 'p': 348 pid_file = optarg; 349 break; 350 351 case 'u': 352 { 353 long val = 0; 354 355 val = strtol(optarg, &optarg, 8); 356 if (*optarg != '\0' || val < 0) 357 warnx("bad value for -u"); 358 else 359 defumask = val; 360 break; 361 } 362 case 'A': 363 anon_only = 1; 364 break; 365 366 case 'v': 367 ftpdebug = 1; 368 break; 369 370 case '4': 371 enable_v4 = 1; 372 if (family == AF_UNSPEC) 373 family = AF_INET; 374 break; 375 376 case '6': 377 family = AF_INET6; 378 break; 379 380 case 'M': 381 noguestmkd = 1; 382 break; 383 384 case 'O': 385 noguestretr = 1; 386 break; 387 388 case 'o': 389 noretr = 1; 390 break; 391 392 default: 393 warnx("unknown flag -%c ignored", optopt); 394 break; 395 } 396 } 397 398#ifdef VIRTUAL_HOSTING 399 inithosts(); 400#endif 401 (void) freopen(_PATH_DEVNULL, "w", stderr); 402 403 /* 404 * LOG_NDELAY sets up the logging connection immediately, 405 * necessary for anonymous ftp's that chroot and can't do it later. 406 */ 407 openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); 408 409 if (daemon_mode) { 410 int ctl_sock, fd; 411 struct addrinfo hints, *res; 412 413 /* 414 * Detach from parent. 415 */ 416 if (daemon(1, 1) < 0) { 417 syslog(LOG_ERR, "failed to become a daemon"); 418 exit(1); 419 } 420 sa.sa_handler = reapchild; 421 (void)sigaction(SIGCHLD, &sa, NULL); 422 /* init bind_sa */ 423 memset(&hints, 0, sizeof(hints)); 424 425 hints.ai_family = family == AF_UNSPEC ? AF_INET : family; 426 hints.ai_socktype = SOCK_STREAM; 427 hints.ai_protocol = 0; 428 hints.ai_flags = AI_PASSIVE; 429 error = getaddrinfo(bindname, "ftp", &hints, &res); 430 if (error) { 431 if (family == AF_UNSPEC) { 432 hints.ai_family = AF_UNSPEC; 433 error = getaddrinfo(bindname, "ftp", &hints, 434 &res); 435 } 436 } 437 if (error) { 438 syslog(LOG_ERR, "%s", gai_strerror(error)); 439 if (error == EAI_SYSTEM) 440 syslog(LOG_ERR, "%s", strerror(errno)); 441 exit(1); 442 } 443 if (res->ai_addr == NULL) { 444 syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname); 445 exit(1); 446 } else 447 family = res->ai_addr->sa_family; 448 /* 449 * Open a socket, bind it to the FTP port, and start 450 * listening. 451 */ 452 ctl_sock = socket(family, SOCK_STREAM, 0); 453 if (ctl_sock < 0) { 454 syslog(LOG_ERR, "control socket: %m"); 455 exit(1); 456 } 457 if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR, 458 (char *)&on, sizeof(on)) < 0) 459 syslog(LOG_ERR, "control setsockopt: %m"); 460#ifdef IPV6_BINDV6ONLY 461 if (family == AF_INET6 && enable_v4 == 0) { 462 if (setsockopt(ctl_sock, IPPROTO_IPV6, IPV6_BINDV6ONLY, 463 (char *)&on, sizeof (on)) < 0) 464 syslog(LOG_ERR, 465 "control setsockopt(IPV6_BINDV6ONLY): %m"); 466 } 467#endif /* IPV6_BINDV6ONLY */ 468 memcpy(&server_addr, res->ai_addr, res->ai_addr->sa_len); 469 if (bind(ctl_sock, (struct sockaddr *)&server_addr, 470 server_addr.su_len) < 0) { 471 syslog(LOG_ERR, "control bind: %m"); 472 exit(1); 473 } 474 if (listen(ctl_sock, 32) < 0) { 475 syslog(LOG_ERR, "control listen: %m"); 476 exit(1); 477 } 478 /* 479 * Atomically write process ID 480 */ 481 if (pid_file) 482 { 483 int fd; 484 char buf[20]; 485 486 fd = open(pid_file, O_CREAT | O_WRONLY | O_TRUNC 487 | O_NONBLOCK | O_EXLOCK, 0644); 488 if (fd < 0) { 489 if (errno == EAGAIN) 490 errx(1, "%s: file locked", pid_file); 491 else 492 err(1, "%s", pid_file); 493 } 494 snprintf(buf, sizeof(buf), 495 "%lu\n", (unsigned long) getpid()); 496 if (write(fd, buf, strlen(buf)) < 0) 497 err(1, "%s: write", pid_file); 498 /* Leave the pid file open and locked */ 499 } 500 /* 501 * Loop forever accepting connection requests and forking off 502 * children to handle them. 503 */ 504 while (1) { 505 addrlen = server_addr.su_len; 506 fd = accept(ctl_sock, (struct sockaddr *)&his_addr, &addrlen); 507 if (fork() == 0) { 508 /* child */ 509 (void) dup2(fd, 0); 510 (void) dup2(fd, 1); 511 close(ctl_sock); 512 break; 513 } 514 close(fd); 515 } 516 } else { 517 addrlen = sizeof(his_addr); 518 if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { 519 syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); 520 exit(1); 521 } 522 } 523 524 sa.sa_handler = SIG_DFL; 525 (void)sigaction(SIGCHLD, &sa, NULL); 526 527 sa.sa_handler = sigurg; 528 sa.sa_flags = 0; /* don't restart syscalls for SIGURG */ 529 (void)sigaction(SIGURG, &sa, NULL); 530 531 sigfillset(&sa.sa_mask); /* block all signals in handler */ 532 sa.sa_flags = SA_RESTART; 533 sa.sa_handler = sigquit; 534 (void)sigaction(SIGHUP, &sa, NULL); 535 (void)sigaction(SIGINT, &sa, NULL); 536 (void)sigaction(SIGQUIT, &sa, NULL); 537 (void)sigaction(SIGTERM, &sa, NULL); 538 539 sa.sa_handler = lostconn; 540 (void)sigaction(SIGPIPE, &sa, NULL); 541 542 addrlen = sizeof(ctrl_addr); 543 if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { 544 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); 545 exit(1); 546 } 547#ifdef VIRTUAL_HOSTING 548 /* select our identity from virtual host table */ 549 selecthost(&ctrl_addr); 550#endif 551#ifdef IP_TOS 552 if (ctrl_addr.su_family == AF_INET) 553 { 554 tos = IPTOS_LOWDELAY; 555 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) 556 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 557 } 558#endif 559 /* 560 * Disable Nagle on the control channel so that we don't have to wait 561 * for peer's ACK before issuing our next reply. 562 */ 563 if (setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) 564 syslog(LOG_WARNING, "control setsockopt TCP_NODELAY: %m"); 565 566 data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1); 567 568 /* set this here so klogin can use it... */ 569 (void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid()); 570 571 /* Try to handle urgent data inline */ 572#ifdef SO_OOBINLINE 573 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) 574 syslog(LOG_ERR, "setsockopt: %m"); 575#endif 576 577#ifdef F_SETOWN 578 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) 579 syslog(LOG_ERR, "fcntl F_SETOWN: %m"); 580#endif 581 dolog((struct sockaddr *)&his_addr); 582 /* 583 * Set up default state 584 */ 585 data = -1; 586 type = TYPE_A; 587 form = FORM_N; 588 stru = STRU_F; 589 mode = MODE_S; 590 tmpline[0] = '\0'; 591 592 /* If logins are disabled, print out the message. */ 593 if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) { 594 while (fgets(line, sizeof(line), fd) != NULL) { 595 if ((cp = strchr(line, '\n')) != NULL) 596 *cp = '\0'; 597 lreply(530, "%s", line); 598 } 599 (void) fflush(stdout); 600 (void) fclose(fd); 601 reply(530, "System not available."); 602 exit(0); 603 } 604#ifdef VIRTUAL_HOSTING 605 if ((fd = fopen(thishost->welcome, "r")) != NULL) { 606#else 607 if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) { 608#endif 609 while (fgets(line, sizeof(line), fd) != NULL) { 610 if ((cp = strchr(line, '\n')) != NULL) 611 *cp = '\0'; 612 lreply(220, "%s", line); 613 } 614 (void) fflush(stdout); 615 (void) fclose(fd); 616 /* reply(220,) must follow */ 617 } 618#ifndef VIRTUAL_HOSTING 619 if ((hostname = malloc(MAXHOSTNAMELEN)) == NULL) 620 fatalerror("Ran out of memory."); 621 (void) gethostname(hostname, MAXHOSTNAMELEN - 1); 622 hostname[MAXHOSTNAMELEN - 1] = '\0'; 623#endif 624 reply(220, "%s FTP server (%s) ready.", hostname, version); 625 for (;;) 626 (void) yyparse(); 627 /* NOTREACHED */ 628} 629 630static void 631lostconn(int signo) 632{ 633 634 if (ftpdebug) 635 syslog(LOG_DEBUG, "lost connection"); 636 dologout(1); 637} 638 639static void 640sigquit(int signo) 641{ 642 643 syslog(LOG_ERR, "got signal %d", signo); 644 dologout(1); 645} 646 647#ifdef VIRTUAL_HOSTING 648/* 649 * read in virtual host tables (if they exist) 650 */ 651 652static void 653inithosts(void) 654{ 655 int insert; 656 size_t len; 657 FILE *fp; 658 char *cp, *mp, *line; 659 char *hostname; 660 char *vhost, *anonuser, *statfile, *welcome, *loginmsg; 661 struct ftphost *hrp, *lhrp; 662 struct addrinfo hints, *res, *ai; 663 664 /* 665 * Fill in the default host information 666 */ 667 if ((hostname = malloc(MAXHOSTNAMELEN)) == NULL) 668 fatalerror("Ran out of memory."); 669 if (gethostname(hostname, MAXHOSTNAMELEN) < 0) 670 hostname[0] = '\0'; 671 hostname[MAXHOSTNAMELEN - 1] = '\0'; 672 if ((hrp = malloc(sizeof(struct ftphost))) == NULL) 673 fatalerror("Ran out of memory."); 674 hrp->hostname = hostname; 675 hrp->hostinfo = NULL; 676 677 memset(&hints, 0, sizeof(hints)); 678 hints.ai_flags = AI_CANONNAME; 679 hints.ai_family = AF_UNSPEC; 680 getaddrinfo(hrp->hostname, NULL, &hints, &res); 681 if (res) 682 hrp->hostinfo = res; 683 hrp->statfile = _PATH_FTPDSTATFILE; 684 hrp->welcome = _PATH_FTPWELCOME; 685 hrp->loginmsg = _PATH_FTPLOGINMESG; 686 hrp->anonuser = "ftp"; 687 hrp->next = NULL; 688 thishost = firsthost = lhrp = hrp; 689 if ((fp = fopen(_PATH_FTPHOSTS, "r")) != NULL) { 690 int addrsize, error, gothost; 691 void *addr; 692 struct hostent *hp; 693 694 while ((line = fgetln(fp, &len)) != NULL) { 695 int i, hp_error; 696 697 /* skip comments */ 698 if (line[0] == '#') 699 continue; 700 if (line[len - 1] == '\n') { 701 line[len - 1] = '\0'; 702 mp = NULL; 703 } else { 704 if ((mp = malloc(len + 1)) == NULL) 705 fatalerror("Ran out of memory."); 706 memcpy(mp, line, len); 707 mp[len] = '\0'; 708 line = mp; 709 } 710 cp = strtok(line, " \t"); 711 /* skip empty lines */ 712 if (cp == NULL) 713 goto nextline; 714 vhost = cp; 715 716 /* set defaults */ 717 anonuser = "ftp"; 718 statfile = _PATH_FTPDSTATFILE; 719 welcome = _PATH_FTPWELCOME; 720 loginmsg = _PATH_FTPLOGINMESG; 721 722 /* 723 * Preparse the line so we can use its info 724 * for all the addresses associated with 725 * the virtual host name. 726 * Field 0, the virtual host name, is special: 727 * it's already parsed off and will be strdup'ed 728 * later, after we know its canonical form. 729 */ 730 for (i = 1; i < 5 && (cp = strtok(NULL, " \t")); i++) 731 if (*cp != '-' && (cp = strdup(cp))) 732 switch (i) { 733 case 1: /* anon user permissions */ 734 anonuser = cp; 735 break; 736 case 2: /* statistics file */ 737 statfile = cp; 738 break; 739 case 3: /* welcome message */ 740 welcome = cp; 741 break; 742 case 4: /* login message */ 743 loginmsg = cp; 744 break; 745 default: /* programming error */ 746 abort(); 747 /* NOTREACHED */ 748 } 749 750 hints.ai_flags = 0; 751 hints.ai_family = AF_UNSPEC; 752 hints.ai_flags = AI_PASSIVE; 753 error = getaddrinfo(vhost, NULL, &hints, &res); 754 if (error != NULL) 755 goto nextline; 756 for (ai = res; ai != NULL && ai->ai_addr != NULL; 757 ai = ai->ai_next) { 758 759 gothost = 0; 760 for (hrp = firsthost; hrp != NULL; hrp = hrp->next) { 761 struct addrinfo *hi; 762 763 for (hi = hrp->hostinfo; hi != NULL; 764 hi = hi->ai_next) 765 if (hi->ai_addrlen == ai->ai_addrlen && 766 memcmp(hi->ai_addr, 767 ai->ai_addr, 768 ai->ai_addr->sa_len) == 0) { 769 gothost++; 770 break; 771 } 772 if (gothost) 773 break; 774 } 775 if (hrp == NULL) { 776 if ((hrp = malloc(sizeof(struct ftphost))) == NULL) 777 goto nextline; 778 insert = 1; 779 } else 780 insert = 0; /* host already in the chain */ 781 hrp->hostinfo = res; 782 783 /* 784 * determine hostname to use. 785 * force defined name if there is a valid alias 786 * otherwise fallback to primary hostname 787 */ 788 /* XXX: getaddrinfo() can't do alias check */ 789 switch(hrp->hostinfo->ai_family) { 790 case AF_INET: 791 addr = &((struct sockaddr_in *)hrp->hostinfo->ai_addr)->sin_addr; 792 addrsize = sizeof(struct in_addr); 793 break; 794 case AF_INET6: 795 addr = &((struct sockaddr_in6 *)hrp->hostinfo->ai_addr)->sin6_addr; 796 addrsize = sizeof(struct in6_addr); 797 break; 798 default: 799 /* should not reach here */ 800 if (hrp->hostinfo != NULL) 801 freeaddrinfo(hrp->hostinfo); 802 free(hrp); 803 goto nextline; 804 /* NOTREACHED */ 805 } 806 if ((hp = getipnodebyaddr((char*)addr, addrsize, 807 hrp->hostinfo->ai_family, 808 &hp_error)) != NULL) { 809 if (strcmp(vhost, hp->h_name) != 0) { 810 if (hp->h_aliases == NULL) 811 vhost = hp->h_name; 812 else { 813 i = 0; 814 while (hp->h_aliases[i] && 815 strcmp(vhost, hp->h_aliases[i]) != 0) 816 ++i; 817 if (hp->h_aliases[i] == NULL) 818 vhost = hp->h_name; 819 } 820 } 821 } 822 if ((hrp->hostname = strdup(vhost)) == NULL) 823 goto nextline; 824 hrp->anonuser = anonuser; 825 hrp->statfile = statfile; 826 hrp->welcome = welcome; 827 hrp->loginmsg = loginmsg; 828 if (insert) { 829 hrp->next = NULL; 830 lhrp->next = hrp; 831 lhrp = hrp; 832 } 833 if (hp) 834 freehostent(hp); 835 } 836nextline: 837 if (mp) 838 free(mp); 839 } 840 (void) fclose(fp); 841 } 842} 843 844static void 845selecthost(union sockunion *su) 846{ 847 struct ftphost *hrp; 848 u_int16_t port; 849#ifdef INET6 850 struct in6_addr *mapped_in6 = NULL; 851#endif 852 struct addrinfo *hi; 853 854#ifdef INET6 855 /* 856 * XXX IPv4 mapped IPv6 addr consideraton, 857 * specified in rfc2373. 858 */ 859 if (su->su_family == AF_INET6 && 860 IN6_IS_ADDR_V4MAPPED(&su->su_sin6.sin6_addr)) 861 mapped_in6 = &su->su_sin6.sin6_addr; 862#endif 863 864 hrp = thishost = firsthost; /* default */ 865 port = su->su_port; 866 su->su_port = 0; 867 while (hrp != NULL) { 868 for (hi = hrp->hostinfo; hi != NULL; hi = hi->ai_next) { 869 if (memcmp(su, hi->ai_addr, hi->ai_addrlen) == 0) { 870 thishost = hrp; 871 break; 872 } 873#ifdef INET6 874 /* XXX IPv4 mapped IPv6 addr consideraton */ 875 if (hi->ai_addr->sa_family == AF_INET && mapped_in6 != NULL && 876 (memcmp(&mapped_in6->s6_addr[12], 877 &((struct sockaddr_in *)hi->ai_addr)->sin_addr, 878 sizeof(struct in_addr)) == 0)) { 879 thishost = hrp; 880 break; 881 } 882#endif 883 } 884 hrp = hrp->next; 885 } 886 su->su_port = port; 887 /* setup static variables as appropriate */ 888 hostname = thishost->hostname; 889 ftpuser = thishost->anonuser; 890} 891#endif 892 893/* 894 * Helper function for sgetpwnam(). 895 */ 896static char * 897sgetsave(char *s) 898{ 899 char *new = malloc((unsigned) strlen(s) + 1); 900 901 if (new == NULL) { 902 perror_reply(421, "Local resource failure: malloc"); 903 dologout(1); 904 /* NOTREACHED */ 905 } 906 (void) strcpy(new, s); 907 return (new); 908} 909 910/* 911 * Save the result of a getpwnam. Used for USER command, since 912 * the data returned must not be clobbered by any other command 913 * (e.g., globbing). 914 */ 915static struct passwd * 916sgetpwnam(char *name) 917{ 918 static struct passwd save; 919 struct passwd *p; 920 921 if ((p = getpwnam(name)) == NULL) 922 return (p); 923 if (save.pw_name) { 924 free(save.pw_name); 925 free(save.pw_passwd); 926 free(save.pw_gecos); 927 free(save.pw_dir); 928 free(save.pw_shell); 929 } 930 save = *p; 931 save.pw_name = sgetsave(p->pw_name); 932 save.pw_passwd = sgetsave(p->pw_passwd); 933 save.pw_gecos = sgetsave(p->pw_gecos); 934 save.pw_dir = sgetsave(p->pw_dir); 935 save.pw_shell = sgetsave(p->pw_shell); 936 return (&save); 937} 938 939static int login_attempts; /* number of failed login attempts */ 940static int askpasswd; /* had user command, ask for passwd */ 941static char curname[MAXLOGNAME]; /* current USER name */ 942 943/* 944 * USER command. 945 * Sets global passwd pointer pw if named account exists and is acceptable; 946 * sets askpasswd if a PASS command is expected. If logged in previously, 947 * need to reset state. If name is "ftp" or "anonymous", the name is not in 948 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return. 949 * If account doesn't exist, ask for passwd anyway. Otherwise, check user 950 * requesting login privileges. Disallow anyone who does not have a standard 951 * shell as returned by getusershell(). Disallow anyone mentioned in the file 952 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. 953 */ 954void 955user(char *name) 956{ 957 char *cp, *shell; 958 959 if (logged_in) { 960 if (guest) { 961 reply(530, "Can't change user from guest login."); 962 return; 963 } else if (dochroot) { 964 reply(530, "Can't change user from chroot user."); 965 return; 966 } 967 end_login(); 968 } 969 970 guest = 0; 971 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { 972 if (checkuser(_PATH_FTPUSERS, "ftp", 0) || 973 checkuser(_PATH_FTPUSERS, "anonymous", 0)) 974 reply(530, "User %s access denied.", name); 975#ifdef VIRTUAL_HOSTING 976 else if ((pw = sgetpwnam(thishost->anonuser)) != NULL) { 977#else 978 else if ((pw = sgetpwnam("ftp")) != NULL) { 979#endif 980 guest = 1; 981 askpasswd = 1; 982 reply(331, 983 "Guest login ok, send your email address as password."); 984 } else 985 reply(530, "User %s unknown.", name); 986 if (!askpasswd && logging) 987 syslog(LOG_NOTICE, 988 "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost); 989 return; 990 } 991 if (anon_only != 0) { 992 reply(530, "Sorry, only anonymous ftp allowed."); 993 return; 994 } 995 996 if ((pw = sgetpwnam(name))) { 997 if ((shell = pw->pw_shell) == NULL || *shell == 0) 998 shell = _PATH_BSHELL; 999 while ((cp = getusershell()) != NULL) 1000 if (strcmp(cp, shell) == 0) 1001 break; 1002 endusershell(); 1003 1004 if (cp == NULL || checkuser(_PATH_FTPUSERS, name, 1)) { 1005 reply(530, "User %s access denied.", name); 1006 if (logging) 1007 syslog(LOG_NOTICE, 1008 "FTP LOGIN REFUSED FROM %s, %s", 1009 remotehost, name); 1010 pw = (struct passwd *) NULL; 1011 return; 1012 } 1013 } 1014 if (logging) 1015 strncpy(curname, name, sizeof(curname)-1); 1016 1017 pwok = 0; 1018#ifdef USE_PAM 1019 /* XXX Kluge! The conversation mechanism needs to be fixed. */ 1020#endif 1021 if (opiechallenge(&opiedata, name, opieprompt) == 0) { 1022 pwok = (pw != NULL) && 1023 opieaccessfile(remotehost) && 1024 opiealways(pw->pw_dir); 1025 reply(331, "Response to %s %s for %s.", 1026 opieprompt, pwok ? "requested" : "required", name); 1027 } else { 1028 pwok = 1; 1029 reply(331, "Password required for %s.", name); 1030 } 1031 askpasswd = 1; 1032 /* 1033 * Delay before reading passwd after first failed 1034 * attempt to slow down passwd-guessing programs. 1035 */ 1036 if (login_attempts) 1037 sleep((unsigned) login_attempts); 1038} 1039 1040/* 1041 * Check if a user is in the file "fname" 1042 */ 1043static int 1044checkuser(char *fname, char *name, int pwset) 1045{ 1046 FILE *fd; 1047 int found = 0; 1048 size_t len; 1049 char *line, *mp, *p; 1050 1051 if ((fd = fopen(fname, "r")) != NULL) { 1052 while (!found && (line = fgetln(fd, &len)) != NULL) { 1053 /* skip comments */ 1054 if (line[0] == '#') 1055 continue; 1056 if (line[len - 1] == '\n') { 1057 line[len - 1] = '\0'; 1058 mp = NULL; 1059 } else { 1060 if ((mp = malloc(len + 1)) == NULL) 1061 fatalerror("Ran out of memory."); 1062 memcpy(mp, line, len); 1063 mp[len] = '\0'; 1064 line = mp; 1065 } 1066 /* avoid possible leading and trailing whitespace */ 1067 p = strtok(line, " \t"); 1068 /* skip empty lines */ 1069 if (p == NULL) 1070 goto nextline; 1071 /* 1072 * if first chr is '@', check group membership 1073 */ 1074 if (p[0] == '@') { 1075 int i = 0; 1076 struct group *grp; 1077 1078 if ((grp = getgrnam(p+1)) == NULL) 1079 goto nextline; 1080 /* 1081 * Check user's default group 1082 */ 1083 if (pwset && grp->gr_gid == pw->pw_gid) 1084 found = 1; 1085 /* 1086 * Check supplementary groups 1087 */ 1088 while (!found && grp->gr_mem[i]) 1089 found = strcmp(name, 1090 grp->gr_mem[i++]) 1091 == 0; 1092 } 1093 /* 1094 * Otherwise, just check for username match 1095 */ 1096 else 1097 found = strcmp(p, name) == 0; 1098nextline: 1099 if (mp) 1100 free(mp); 1101 } 1102 (void) fclose(fd); 1103 } 1104 return (found); 1105} 1106 1107/* 1108 * Terminate login as previous user, if any, resetting state; 1109 * used when USER command is given or login fails. 1110 */ 1111static void 1112end_login(void) 1113{ 1114#ifdef USE_PAM 1115 int e; 1116#endif 1117 1118 (void) seteuid((uid_t)0); 1119 if (logged_in) 1120 ftpd_logwtmp(ttyline, "", NULL); 1121 pw = NULL; 1122#ifdef LOGIN_CAP 1123 setusercontext(NULL, getpwuid(0), (uid_t)0, 1124 LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK); 1125#endif 1126#ifdef USE_PAM 1127 if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) 1128 syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); 1129 if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS) 1130 syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pamh, e)); 1131 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) 1132 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); 1133 pamh = NULL; 1134#endif 1135 logged_in = 0; 1136 guest = 0; 1137 dochroot = 0; 1138} 1139 1140#ifdef USE_PAM 1141 1142/* 1143 * the following code is stolen from imap-uw PAM authentication module and 1144 * login.c 1145 */ 1146#define COPY_STRING(s) (s ? strdup(s) : NULL) 1147 1148struct cred_t { 1149 const char *uname; /* user name */ 1150 const char *pass; /* password */ 1151}; 1152typedef struct cred_t cred_t; 1153 1154static int 1155auth_conv(int num_msg, const struct pam_message **msg, 1156 struct pam_response **resp, void *appdata) 1157{ 1158 int i; 1159 cred_t *cred = (cred_t *) appdata; 1160 struct pam_response *reply; 1161 1162 reply = calloc(num_msg, sizeof *reply); 1163 if (reply == NULL) 1164 return PAM_BUF_ERR; 1165 1166 for (i = 0; i < num_msg; i++) { 1167 switch (msg[i]->msg_style) { 1168 case PAM_PROMPT_ECHO_ON: /* assume want user name */ 1169 reply[i].resp_retcode = PAM_SUCCESS; 1170 reply[i].resp = COPY_STRING(cred->uname); 1171 /* PAM frees resp. */ 1172 break; 1173 case PAM_PROMPT_ECHO_OFF: /* assume want password */ 1174 reply[i].resp_retcode = PAM_SUCCESS; 1175 reply[i].resp = COPY_STRING(cred->pass); 1176 /* PAM frees resp. */ 1177 break; 1178 case PAM_TEXT_INFO: 1179 case PAM_ERROR_MSG: 1180 reply[i].resp_retcode = PAM_SUCCESS; 1181 reply[i].resp = NULL; 1182 break; 1183 default: /* unknown message style */ 1184 free(reply); 1185 return PAM_CONV_ERR; 1186 } 1187 } 1188 1189 *resp = reply; 1190 return PAM_SUCCESS; 1191} 1192 1193/* 1194 * Attempt to authenticate the user using PAM. Returns 0 if the user is 1195 * authenticated, or 1 if not authenticated. If some sort of PAM system 1196 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this 1197 * function returns -1. This can be used as an indication that we should 1198 * fall back to a different authentication mechanism. 1199 */ 1200static int 1201auth_pam(struct passwd **ppw, const char *pass) 1202{ 1203 pam_handle_t *pamh = NULL; 1204 const char *tmpl_user; 1205 const void *item; 1206 int rval; 1207 int e; 1208 cred_t auth_cred = { (*ppw)->pw_name, pass }; 1209 struct pam_conv conv = { &auth_conv, &auth_cred }; 1210 1211 e = pam_start("ftpd", (*ppw)->pw_name, &conv, &pamh); 1212 if (e != PAM_SUCCESS) { 1213 syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e)); 1214 return -1; 1215 } 1216 1217 e = pam_set_item(pamh, PAM_RHOST, remotehost); 1218 if (e != PAM_SUCCESS) { 1219 syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s", 1220 pam_strerror(pamh, e)); 1221 return -1; 1222 } 1223 1224 e = pam_authenticate(pamh, 0); 1225 switch (e) { 1226 case PAM_SUCCESS: 1227 /* 1228 * With PAM we support the concept of a "template" 1229 * user. The user enters a login name which is 1230 * authenticated by PAM, usually via a remote service 1231 * such as RADIUS or TACACS+. If authentication 1232 * succeeds, a different but related "template" name 1233 * is used for setting the credentials, shell, and 1234 * home directory. The name the user enters need only 1235 * exist on the remote authentication server, but the 1236 * template name must be present in the local password 1237 * database. 1238 * 1239 * This is supported by two various mechanisms in the 1240 * individual modules. However, from the application's 1241 * point of view, the template user is always passed 1242 * back as a changed value of the PAM_USER item. 1243 */ 1244 if ((e = pam_get_item(pamh, PAM_USER, &item)) == 1245 PAM_SUCCESS) { 1246 tmpl_user = (const char *) item; 1247 if (strcmp((*ppw)->pw_name, tmpl_user) != 0) 1248 *ppw = getpwnam(tmpl_user); 1249 } else 1250 syslog(LOG_ERR, "Couldn't get PAM_USER: %s", 1251 pam_strerror(pamh, e)); 1252 rval = 0; 1253 break; 1254 1255 case PAM_AUTH_ERR: 1256 case PAM_USER_UNKNOWN: 1257 case PAM_MAXTRIES: 1258 rval = 1; 1259 break; 1260 1261 default: 1262 syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e)); 1263 rval = -1; 1264 break; 1265 } 1266 1267 if (rval == 0) { 1268 e = pam_acct_mgmt(pamh, 0); 1269 if (e == PAM_NEW_AUTHTOK_REQD) { 1270 e = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); 1271 if (e != PAM_SUCCESS) { 1272 syslog(LOG_ERR, "pam_chauthtok: %s", pam_strerror(pamh, e)); 1273 rval = 1; 1274 } 1275 } else if (e != PAM_SUCCESS) { 1276 rval = 1; 1277 } 1278 } 1279 1280 if (rval != 0) { 1281 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) { 1282 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); 1283 } 1284 pamh = NULL; 1285 } 1286 return rval; 1287} 1288 1289#endif /* USE_PAM */ 1290 1291void 1292pass(char *passwd) 1293{ 1294 int rval; 1295 FILE *fd; 1296#ifdef LOGIN_CAP 1297 login_cap_t *lc = NULL; 1298#endif 1299#ifdef USE_PAM 1300 int e; 1301#endif 1302 char *xpasswd; 1303 1304 if (logged_in || askpasswd == 0) { 1305 reply(503, "Login with USER first."); 1306 return; 1307 } 1308 askpasswd = 0; 1309 if (!guest) { /* "ftp" is only account allowed no password */ 1310 if (pw == NULL) { 1311 rval = 1; /* failure below */ 1312 goto skip; 1313 } 1314#ifdef USE_PAM 1315 rval = auth_pam(&pw, passwd); 1316 if (rval >= 0) { 1317 opieunlock(); 1318 goto skip; 1319 } 1320#endif 1321 if (opieverify(&opiedata, passwd) == 0) 1322 xpasswd = pw->pw_passwd; 1323 else if (pwok) { 1324 xpasswd = crypt(passwd, pw->pw_passwd); 1325 if (passwd[0] == '\0' && pw->pw_passwd[0] != '\0') 1326 xpasswd = ":"; 1327 } else { 1328 rval = 1; 1329 goto skip; 1330 } 1331 rval = strcmp(pw->pw_passwd, xpasswd); 1332 if (pw->pw_expire && time(NULL) >= pw->pw_expire) 1333 rval = 1; /* failure */ 1334skip: 1335 /* 1336 * If rval == 1, the user failed the authentication check 1337 * above. If rval == 0, either PAM or local authentication 1338 * succeeded. 1339 */ 1340 if (rval) { 1341 reply(530, "Login incorrect."); 1342 if (logging) 1343 syslog(LOG_NOTICE, 1344 "FTP LOGIN FAILED FROM %s, %s", 1345 remotehost, curname); 1346 pw = NULL; 1347 if (login_attempts++ >= 5) { 1348 syslog(LOG_NOTICE, 1349 "repeated login failures from %s", 1350 remotehost); 1351 exit(0); 1352 } 1353 return; 1354 } 1355 } 1356 login_attempts = 0; /* this time successful */ 1357 if (setegid((gid_t)pw->pw_gid) < 0) { 1358 reply(550, "Can't set gid."); 1359 return; 1360 } 1361 /* May be overridden by login.conf */ 1362 (void) umask(defumask); 1363#ifdef LOGIN_CAP 1364 if ((lc = login_getpwclass(pw)) != NULL) { 1365 char remote_ip[MAXHOSTNAMELEN]; 1366 1367 getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len, 1368 remote_ip, sizeof(remote_ip) - 1, NULL, 0, 1369 NI_NUMERICHOST); 1370 remote_ip[sizeof(remote_ip) - 1] = 0; 1371 if (!auth_hostok(lc, remotehost, remote_ip)) { 1372 syslog(LOG_INFO|LOG_AUTH, 1373 "FTP LOGIN FAILED (HOST) as %s: permission denied.", 1374 pw->pw_name); 1375 reply(530, "Permission denied.\n"); 1376 pw = NULL; 1377 return; 1378 } 1379 if (!auth_timeok(lc, time(NULL))) { 1380 reply(530, "Login not available right now.\n"); 1381 pw = NULL; 1382 return; 1383 } 1384 } 1385 setusercontext(lc, pw, (uid_t)0, 1386 LOGIN_SETLOGIN|LOGIN_SETGROUP|LOGIN_SETPRIORITY| 1387 LOGIN_SETRESOURCES|LOGIN_SETUMASK); 1388#else 1389 setlogin(pw->pw_name); 1390 (void) initgroups(pw->pw_name, pw->pw_gid); 1391#endif 1392 1393#ifdef USE_PAM 1394 if (pamh) { 1395 if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) { 1396 syslog(LOG_ERR, "pam_open_session: %s", pam_strerror(pamh, e)); 1397 } else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) { 1398 syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); 1399 } 1400 } 1401#endif 1402 1403 /* open wtmp before chroot */ 1404 ftpd_logwtmp(ttyline, pw->pw_name, (struct sockaddr *)&his_addr); 1405 logged_in = 1; 1406 1407 if (guest && stats && statfd < 0) 1408#ifdef VIRTUAL_HOSTING 1409 if ((statfd = open(thishost->statfile, O_WRONLY|O_APPEND)) < 0) 1410#else 1411 if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0) 1412#endif 1413 stats = 0; 1414 1415 dochroot = 1416#ifdef LOGIN_CAP /* Allow login.conf configuration as well */ 1417 login_getcapbool(lc, "ftp-chroot", 0) || 1418#endif 1419 checkuser(_PATH_FTPCHROOT, pw->pw_name, 1); 1420 if (guest) { 1421 /* 1422 * We MUST do a chdir() after the chroot. Otherwise 1423 * the old current directory will be accessible as "." 1424 * outside the new root! 1425 */ 1426 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { 1427 reply(550, "Can't set guest privileges."); 1428 goto bad; 1429 } 1430 } else if (dochroot) { 1431 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { 1432 reply(550, "Can't change root."); 1433 goto bad; 1434 } 1435 } else if (chdir(pw->pw_dir) < 0) { 1436 if (chdir("/") < 0) { 1437 reply(530, "User %s: can't change directory to %s.", 1438 pw->pw_name, pw->pw_dir); 1439 goto bad; 1440 } else 1441 lreply(230, "No directory! Logging in with home=/"); 1442 } 1443 if (seteuid((uid_t)pw->pw_uid) < 0) { 1444 reply(550, "Can't set uid."); 1445 goto bad; 1446 } 1447 1448 /* 1449 * Display a login message, if it exists. 1450 * N.B. reply(230,) must follow the message. 1451 */ 1452#ifdef VIRTUAL_HOSTING 1453 if ((fd = fopen(thishost->loginmsg, "r")) != NULL) { 1454#else 1455 if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) { 1456#endif 1457 char *cp, line[LINE_MAX]; 1458 1459 while (fgets(line, sizeof(line), fd) != NULL) { 1460 if ((cp = strchr(line, '\n')) != NULL) 1461 *cp = '\0'; 1462 lreply(230, "%s", line); 1463 } 1464 (void) fflush(stdout); 1465 (void) fclose(fd); 1466 } 1467 if (guest) { 1468 if (ident != NULL) 1469 free(ident); 1470 ident = strdup(passwd); 1471 if (ident == NULL) 1472 fatalerror("Ran out of memory."); 1473 1474 reply(230, "Guest login ok, access restrictions apply."); 1475#ifdef SETPROCTITLE 1476#ifdef VIRTUAL_HOSTING 1477 if (thishost != firsthost) 1478 snprintf(proctitle, sizeof(proctitle), 1479 "%s: anonymous(%s)/%s", remotehost, hostname, 1480 passwd); 1481 else 1482#endif 1483 snprintf(proctitle, sizeof(proctitle), 1484 "%s: anonymous/%s", remotehost, passwd); 1485 setproctitle("%s", proctitle); 1486#endif /* SETPROCTITLE */ 1487 if (logging) 1488 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s", 1489 remotehost, passwd); 1490 } else { 1491 if (dochroot) 1492 reply(230, "User %s logged in, " 1493 "access restrictions apply.", pw->pw_name); 1494 else 1495 reply(230, "User %s logged in.", pw->pw_name); 1496 1497#ifdef SETPROCTITLE 1498 snprintf(proctitle, sizeof(proctitle), 1499 "%s: user/%s", remotehost, pw->pw_name); 1500 setproctitle("%s", proctitle); 1501#endif /* SETPROCTITLE */ 1502 if (logging) 1503 syslog(LOG_INFO, "FTP LOGIN FROM %s as %s", 1504 remotehost, pw->pw_name); 1505 } 1506#ifdef LOGIN_CAP 1507 login_close(lc); 1508#endif 1509 return; 1510bad: 1511 /* Forget all about it... */ 1512#ifdef LOGIN_CAP 1513 login_close(lc); 1514#endif 1515 end_login(); 1516} 1517 1518void 1519retrieve(char *cmd, char *name) 1520{ 1521 FILE *fin, *dout; 1522 struct stat st; 1523 int (*closefunc)(FILE *); 1524 time_t start; 1525 1526 if (cmd == 0) { 1527 fin = fopen(name, "r"), closefunc = fclose; 1528 st.st_size = 0; 1529 } else { 1530 char line[BUFSIZ]; 1531 1532 (void) snprintf(line, sizeof(line), cmd, name), name = line; 1533 fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose; 1534 st.st_size = -1; 1535 st.st_blksize = BUFSIZ; 1536 } 1537 if (fin == NULL) { 1538 if (errno != 0) { 1539 perror_reply(550, name); 1540 if (cmd == 0) { 1541 LOGCMD("get", name); 1542 } 1543 } 1544 return; 1545 } 1546 byte_count = -1; 1547 if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) { 1548 reply(550, "%s: not a plain file.", name); 1549 goto done; 1550 } 1551 if (restart_point) { 1552 if (type == TYPE_A) { 1553 off_t i, n; 1554 int c; 1555 1556 n = restart_point; 1557 i = 0; 1558 while (i++ < n) { 1559 if ((c=getc(fin)) == EOF) { 1560 perror_reply(550, name); 1561 goto done; 1562 } 1563 if (c == '\n') 1564 i++; 1565 } 1566 } else if (lseek(fileno(fin), restart_point, L_SET) < 0) { 1567 perror_reply(550, name); 1568 goto done; 1569 } 1570 } 1571 dout = dataconn(name, st.st_size, "w"); 1572 if (dout == NULL) 1573 goto done; 1574 time(&start); 1575 send_data(fin, dout, st.st_blksize, st.st_size, 1576 restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)); 1577 if (cmd == 0 && guest && stats) 1578 logxfer(name, st.st_size, start); 1579 (void) fclose(dout); 1580 data = -1; 1581 pdata = -1; 1582done: 1583 if (cmd == 0) 1584 LOGBYTES("get", name, byte_count); 1585 (*closefunc)(fin); 1586} 1587 1588void 1589store(char *name, char *mode, int unique) 1590{ 1591 FILE *fout, *din; 1592 struct stat st; 1593 int (*closefunc)(FILE *); 1594 1595 if ((unique || guest) && stat(name, &st) == 0 && 1596 (name = gunique(name)) == NULL) { 1597 LOGCMD(*mode == 'w' ? "put" : "append", name); 1598 return; 1599 } 1600 1601 if (restart_point) 1602 mode = "r+"; 1603 fout = fopen(name, mode); 1604 closefunc = fclose; 1605 if (fout == NULL) { 1606 perror_reply(553, name); 1607 LOGCMD(*mode == 'w' ? "put" : "append", name); 1608 return; 1609 } 1610 byte_count = -1; 1611 if (restart_point) { 1612 if (type == TYPE_A) { 1613 off_t i, n; 1614 int c; 1615 1616 n = restart_point; 1617 i = 0; 1618 while (i++ < n) { 1619 if ((c=getc(fout)) == EOF) { 1620 perror_reply(550, name); 1621 goto done; 1622 } 1623 if (c == '\n') 1624 i++; 1625 } 1626 /* 1627 * We must do this seek to "current" position 1628 * because we are changing from reading to 1629 * writing. 1630 */ 1631 if (fseeko(fout, (off_t)0, SEEK_CUR) < 0) { 1632 perror_reply(550, name); 1633 goto done; 1634 } 1635 } else if (lseek(fileno(fout), restart_point, L_SET) < 0) { 1636 perror_reply(550, name); 1637 goto done; 1638 } 1639 } 1640 din = dataconn(name, (off_t)-1, "r"); 1641 if (din == NULL) 1642 goto done; 1643 if (receive_data(din, fout) == 0) { 1644 if (unique) 1645 reply(226, "Transfer complete (unique file name:%s).", 1646 name); 1647 else 1648 reply(226, "Transfer complete."); 1649 } 1650 (void) fclose(din); 1651 data = -1; 1652 pdata = -1; 1653done: 1654 LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count); 1655 (*closefunc)(fout); 1656} 1657 1658static FILE * 1659getdatasock(char *mode) 1660{ 1661 int on = 1, s, t, tries; 1662 1663 if (data >= 0) 1664 return (fdopen(data, mode)); 1665 (void) seteuid((uid_t)0); 1666 1667 s = socket(data_dest.su_family, SOCK_STREAM, 0); 1668 if (s < 0) 1669 goto bad; 1670 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 1671 (char *) &on, sizeof(on)) < 0) 1672 goto bad; 1673 /* anchor socket to avoid multi-homing problems */ 1674 data_source = ctrl_addr; 1675 data_source.su_port = htons(20); /* ftp-data port */ 1676 for (tries = 1; ; tries++) { 1677 if (bind(s, (struct sockaddr *)&data_source, 1678 data_source.su_len) >= 0) 1679 break; 1680 if (errno != EADDRINUSE || tries > 10) 1681 goto bad; 1682 sleep(tries); 1683 } 1684 (void) seteuid((uid_t)pw->pw_uid); 1685#ifdef IP_TOS 1686 if (data_source.su_family == AF_INET) 1687 { 1688 on = IPTOS_THROUGHPUT; 1689 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 1690 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 1691 } 1692#endif 1693#ifdef TCP_NOPUSH 1694 /* 1695 * Turn off push flag to keep sender TCP from sending short packets 1696 * at the boundaries of each write(). Should probably do a SO_SNDBUF 1697 * to set the send buffer size as well, but that may not be desirable 1698 * in heavy-load situations. 1699 */ 1700 on = 1; 1701 if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0) 1702 syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m"); 1703#endif 1704#ifdef SO_SNDBUF 1705 on = 65536; 1706 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0) 1707 syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m"); 1708#endif 1709 1710 return (fdopen(s, mode)); 1711bad: 1712 /* Return the real value of errno (close may change it) */ 1713 t = errno; 1714 (void) seteuid((uid_t)pw->pw_uid); 1715 (void) close(s); 1716 errno = t; 1717 return (NULL); 1718} 1719 1720static FILE * 1721dataconn(char *name, off_t size, char *mode) 1722{ 1723 char sizebuf[32]; 1724 FILE *file; 1725 int retry = 0, tos; 1726 1727 file_size = size; 1728 byte_count = 0; 1729 if (size != (off_t) -1) 1730 (void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)", size); 1731 else 1732 *sizebuf = '\0'; 1733 if (pdata >= 0) { 1734 union sockunion from; 1735 int flags; 1736 int s, fromlen = ctrl_addr.su_len; 1737 struct timeval timeout; 1738 fd_set set; 1739 1740 FD_ZERO(&set); 1741 FD_SET(pdata, &set); 1742 1743 timeout.tv_usec = 0; 1744 timeout.tv_sec = 120; 1745 1746 /* 1747 * Granted a socket is in the blocking I/O mode, 1748 * accept() will block after a successful select() 1749 * if the selected connection dies in between. 1750 * Therefore set the non-blocking I/O flag here. 1751 */ 1752 if ((flags = fcntl(pdata, F_GETFL, 0)) == -1 || 1753 fcntl(pdata, F_SETFL, flags | O_NONBLOCK) == -1) 1754 goto pdata_err; 1755 if (select(pdata+1, &set, (fd_set *) 0, (fd_set *) 0, &timeout) <= 0 || 1756 (s = accept(pdata, (struct sockaddr *) &from, &fromlen)) < 0) 1757 goto pdata_err; 1758 (void) close(pdata); 1759 pdata = s; 1760 /* 1761 * Unset the blocking I/O flag on the child socket 1762 * again so stdio can work on it. 1763 */ 1764 if ((flags = fcntl(pdata, F_GETFL, 0)) == -1 || 1765 fcntl(pdata, F_SETFL, flags & ~O_NONBLOCK) == -1) 1766 goto pdata_err; 1767#ifdef IP_TOS 1768 if (from.su_family == AF_INET) 1769 { 1770 tos = IPTOS_THROUGHPUT; 1771 (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, 1772 sizeof(int)); 1773 } 1774#endif 1775 reply(150, "Opening %s mode data connection for '%s'%s.", 1776 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 1777 return (fdopen(pdata, mode)); 1778pdata_err: 1779 reply(425, "Can't open data connection."); 1780 (void) close(pdata); 1781 pdata = -1; 1782 return (NULL); 1783 } 1784 if (data >= 0) { 1785 reply(125, "Using existing data connection for '%s'%s.", 1786 name, sizebuf); 1787 usedefault = 1; 1788 return (fdopen(data, mode)); 1789 } 1790 if (usedefault) 1791 data_dest = his_addr; 1792 usedefault = 1; 1793 file = getdatasock(mode); 1794 if (file == NULL) { 1795 char hostbuf[BUFSIZ], portbuf[BUFSIZ]; 1796 getnameinfo((struct sockaddr *)&data_source, 1797 data_source.su_len, hostbuf, sizeof(hostbuf) - 1, 1798 portbuf, sizeof(portbuf), 1799 NI_NUMERICHOST|NI_NUMERICSERV); 1800 reply(425, "Can't create data socket (%s,%s): %s.", 1801 hostbuf, portbuf, strerror(errno)); 1802 return (NULL); 1803 } 1804 data = fileno(file); 1805 while (connect(data, (struct sockaddr *)&data_dest, 1806 data_dest.su_len) < 0) { 1807 if (errno == EADDRINUSE && retry < swaitmax) { 1808 sleep((unsigned) swaitint); 1809 retry += swaitint; 1810 continue; 1811 } 1812 perror_reply(425, "Can't build data connection"); 1813 (void) fclose(file); 1814 data = -1; 1815 return (NULL); 1816 } 1817 reply(150, "Opening %s mode data connection for '%s'%s.", 1818 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 1819 return (file); 1820} 1821 1822/* 1823 * Tranfer the contents of "instr" to "outstr" peer using the appropriate 1824 * encapsulation of the data subject to Mode, Structure, and Type. 1825 * 1826 * NB: Form isn't handled. 1827 */ 1828static int 1829send_data(FILE *instr, FILE *outstr, off_t blksize, off_t filesize, int isreg) 1830{ 1831 int c, filefd, netfd; 1832 char *buf; 1833 off_t cnt; 1834 1835 transflag++; 1836 switch (type) { 1837 1838 case TYPE_A: 1839 while ((c = getc(instr)) != EOF) { 1840 if (recvurg) 1841 goto got_oob; 1842 byte_count++; 1843 if (c == '\n') { 1844 if (ferror(outstr)) 1845 goto data_err; 1846 (void) putc('\r', outstr); 1847 } 1848 (void) putc(c, outstr); 1849 } 1850 if (recvurg) 1851 goto got_oob; 1852 fflush(outstr); 1853 transflag = 0; 1854 if (ferror(instr)) 1855 goto file_err; 1856 if (ferror(outstr)) 1857 goto data_err; 1858 reply(226, "Transfer complete."); 1859 return (0); 1860 1861 case TYPE_I: 1862 case TYPE_L: 1863 /* 1864 * isreg is only set if we are not doing restart and we 1865 * are sending a regular file 1866 */ 1867 netfd = fileno(outstr); 1868 filefd = fileno(instr); 1869 1870 if (isreg) { 1871 1872 off_t offset; 1873 int err; 1874 1875 err = cnt = offset = 0; 1876 1877 while (err != -1 && filesize > 0) { 1878 err = sendfile(filefd, netfd, offset, 0, 1879 (struct sf_hdtr *) NULL, &cnt, 0); 1880 /* 1881 * Calculate byte_count before OOB processing. 1882 * It can be used in myoob() later. 1883 */ 1884 byte_count += cnt; 1885 if (recvurg) 1886 goto got_oob; 1887 offset += cnt; 1888 filesize -= cnt; 1889 1890 if (err == -1) { 1891 if (!cnt) 1892 goto oldway; 1893 1894 goto data_err; 1895 } 1896 } 1897 1898 transflag = 0; 1899 reply(226, "Transfer complete."); 1900 return (0); 1901 } 1902 1903oldway: 1904 if ((buf = malloc((u_int)blksize)) == NULL) { 1905 transflag = 0; 1906 perror_reply(451, "Local resource failure: malloc"); 1907 return (-1); 1908 } 1909 1910 while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 && 1911 write(netfd, buf, cnt) == cnt) 1912 byte_count += cnt; 1913 transflag = 0; 1914 (void)free(buf); 1915 if (cnt != 0) { 1916 if (cnt < 0) 1917 goto file_err; 1918 goto data_err; 1919 } 1920 reply(226, "Transfer complete."); 1921 return (0); 1922 default: 1923 transflag = 0; 1924 reply(550, "Unimplemented TYPE %d in send_data", type); 1925 return (-1); 1926 } 1927 1928data_err: 1929 transflag = 0; 1930 perror_reply(426, "Data connection"); 1931 return (-1); 1932 1933file_err: 1934 transflag = 0; 1935 perror_reply(551, "Error on input file"); 1936 return (-1); 1937 1938got_oob: 1939 myoob(); 1940 recvurg = 0; 1941 transflag = 0; 1942 return (-1); 1943} 1944 1945/* 1946 * Transfer data from peer to "outstr" using the appropriate encapulation of 1947 * the data subject to Mode, Structure, and Type. 1948 * 1949 * N.B.: Form isn't handled. 1950 */ 1951static int 1952receive_data(FILE *instr, FILE *outstr) 1953{ 1954 int c; 1955 int cnt, bare_lfs; 1956 char buf[BUFSIZ]; 1957 1958 transflag++; 1959 bare_lfs = 0; 1960 1961 switch (type) { 1962 1963 case TYPE_I: 1964 case TYPE_L: 1965 while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) { 1966 if (recvurg) 1967 goto got_oob; 1968 if (write(fileno(outstr), buf, cnt) != cnt) 1969 goto file_err; 1970 byte_count += cnt; 1971 } 1972 if (recvurg) 1973 goto got_oob; 1974 if (cnt < 0) 1975 goto data_err; 1976 transflag = 0; 1977 return (0); 1978 1979 case TYPE_E: 1980 reply(553, "TYPE E not implemented."); 1981 transflag = 0; 1982 return (-1); 1983 1984 case TYPE_A: 1985 while ((c = getc(instr)) != EOF) { 1986 if (recvurg) 1987 goto got_oob; 1988 byte_count++; 1989 if (c == '\n') 1990 bare_lfs++; 1991 while (c == '\r') { 1992 if (ferror(outstr)) 1993 goto data_err; 1994 if ((c = getc(instr)) != '\n') { 1995 (void) putc ('\r', outstr); 1996 if (c == '\0' || c == EOF) 1997 goto contin2; 1998 } 1999 } 2000 (void) putc(c, outstr); 2001 contin2: ; 2002 } 2003 if (recvurg) 2004 goto got_oob; 2005 fflush(outstr); 2006 if (ferror(instr)) 2007 goto data_err; 2008 if (ferror(outstr)) 2009 goto file_err; 2010 transflag = 0; 2011 if (bare_lfs) { 2012 lreply(226, 2013 "WARNING! %d bare linefeeds received in ASCII mode", 2014 bare_lfs); 2015 (void)printf(" File may not have transferred correctly.\r\n"); 2016 } 2017 return (0); 2018 default: 2019 reply(550, "Unimplemented TYPE %d in receive_data", type); 2020 transflag = 0; 2021 return (-1); 2022 } 2023 2024data_err: 2025 transflag = 0; 2026 perror_reply(426, "Data Connection"); 2027 return (-1); 2028 2029file_err: 2030 transflag = 0; 2031 perror_reply(452, "Error writing file"); 2032 return (-1); 2033 2034got_oob: 2035 myoob(); 2036 recvurg = 0; 2037 transflag = 0; 2038 return (-1); 2039} 2040 2041void 2042statfilecmd(char *filename) 2043{ 2044 FILE *fin; 2045 int c; 2046 char line[LINE_MAX]; 2047 2048 (void)snprintf(line, sizeof(line), _PATH_LS " -lgA %s", filename); 2049 fin = ftpd_popen(line, "r"); 2050 lreply(211, "status of %s:", filename); 2051 while ((c = getc(fin)) != EOF) { 2052 if (c == '\n') { 2053 if (ferror(stdout)){ 2054 perror_reply(421, "control connection"); 2055 (void) ftpd_pclose(fin); 2056 dologout(1); 2057 /* NOTREACHED */ 2058 } 2059 if (ferror(fin)) { 2060 perror_reply(551, filename); 2061 (void) ftpd_pclose(fin); 2062 return; 2063 } 2064 (void) putc('\r', stdout); 2065 } 2066 (void) putc(c, stdout); 2067 } 2068 (void) ftpd_pclose(fin); 2069 reply(211, "End of Status"); 2070} 2071 2072void 2073statcmd(void) 2074{ 2075 union sockunion *su; 2076 u_char *a, *p; 2077 char hname[NI_MAXHOST]; 2078 int ispassive; 2079 2080 lreply(211, "%s FTP server status:", hostname, version); 2081 printf(" %s\r\n", version); 2082 printf(" Connected to %s", remotehost); 2083 if (!getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len, 2084 hname, sizeof(hname) - 1, NULL, 0, NI_NUMERICHOST)) { 2085 if (strcmp(hname, remotehost) != 0) 2086 printf(" (%s)", hname); 2087 } 2088 printf("\r\n"); 2089 if (logged_in) { 2090 if (guest) 2091 printf(" Logged in anonymously\r\n"); 2092 else 2093 printf(" Logged in as %s\r\n", pw->pw_name); 2094 } else if (askpasswd) 2095 printf(" Waiting for password\r\n"); 2096 else 2097 printf(" Waiting for user name\r\n"); 2098 printf(" TYPE: %s", typenames[type]); 2099 if (type == TYPE_A || type == TYPE_E) 2100 printf(", FORM: %s", formnames[form]); 2101 if (type == TYPE_L) 2102#if NBBY == 8 2103 printf(" %d", NBBY); 2104#else 2105 printf(" %d", bytesize); /* need definition! */ 2106#endif 2107 printf("; STRUcture: %s; transfer MODE: %s\r\n", 2108 strunames[stru], modenames[mode]); 2109 if (data != -1) 2110 printf(" Data connection open\r\n"); 2111 else if (pdata != -1) { 2112 ispassive = 1; 2113 su = &pasv_addr; 2114 goto printaddr; 2115 } else if (usedefault == 0) { 2116 ispassive = 0; 2117 su = &data_dest; 2118printaddr: 2119#define UC(b) (((int) b) & 0xff) 2120 if (epsvall) { 2121 printf(" EPSV only mode (EPSV ALL)\r\n"); 2122 goto epsvonly; 2123 } 2124 2125 /* PORT/PASV */ 2126 if (su->su_family == AF_INET) { 2127 a = (u_char *) &su->su_sin.sin_addr; 2128 p = (u_char *) &su->su_sin.sin_port; 2129 printf(" %s (%d,%d,%d,%d,%d,%d)\r\n", 2130 ispassive ? "PASV" : "PORT", 2131 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 2132 UC(p[0]), UC(p[1])); 2133 } 2134 2135 /* LPRT/LPSV */ 2136 { 2137 int alen, af, i; 2138 2139 switch (su->su_family) { 2140 case AF_INET: 2141 a = (u_char *) &su->su_sin.sin_addr; 2142 p = (u_char *) &su->su_sin.sin_port; 2143 alen = sizeof(su->su_sin.sin_addr); 2144 af = 4; 2145 break; 2146 case AF_INET6: 2147 a = (u_char *) &su->su_sin6.sin6_addr; 2148 p = (u_char *) &su->su_sin6.sin6_port; 2149 alen = sizeof(su->su_sin6.sin6_addr); 2150 af = 6; 2151 break; 2152 default: 2153 af = 0; 2154 break; 2155 } 2156 if (af) { 2157 printf(" %s (%d,%d,", ispassive ? "LPSV" : "LPRT", 2158 af, alen); 2159 for (i = 0; i < alen; i++) 2160 printf("%d,", UC(a[i])); 2161 printf("%d,%d,%d)\r\n", 2, UC(p[0]), UC(p[1])); 2162 } 2163 } 2164 2165epsvonly:; 2166 /* EPRT/EPSV */ 2167 { 2168 int af; 2169 2170 switch (su->su_family) { 2171 case AF_INET: 2172 af = 1; 2173 break; 2174 case AF_INET6: 2175 af = 2; 2176 break; 2177 default: 2178 af = 0; 2179 break; 2180 } 2181 if (af) { 2182 union sockunion tmp; 2183 2184 tmp = *su; 2185 if (tmp.su_family == AF_INET6) 2186 tmp.su_sin6.sin6_scope_id = 0; 2187 if (!getnameinfo((struct sockaddr *)&tmp, tmp.su_len, 2188 hname, sizeof(hname) - 1, NULL, 0, 2189 NI_NUMERICHOST)) { 2190 printf(" %s |%d|%s|%d|\r\n", 2191 ispassive ? "EPSV" : "EPRT", 2192 af, hname, htons(tmp.su_port)); 2193 } 2194 } 2195 } 2196#undef UC 2197 } else 2198 printf(" No data connection\r\n"); 2199 reply(211, "End of status"); 2200} 2201 2202void 2203fatalerror(char *s) 2204{ 2205 2206 reply(451, "Error in server: %s\n", s); 2207 reply(221, "Closing connection due to server error."); 2208 dologout(0); 2209 /* NOTREACHED */ 2210} 2211 2212void 2213reply(int n, const char *fmt, ...) 2214{ 2215 va_list ap; 2216 2217 va_start(ap, fmt); 2218 (void)printf("%d ", n); 2219 (void)vprintf(fmt, ap); 2220 (void)printf("\r\n"); 2221 (void)fflush(stdout); 2222 if (ftpdebug) { 2223 syslog(LOG_DEBUG, "<--- %d ", n); 2224 vsyslog(LOG_DEBUG, fmt, ap); 2225 } 2226} 2227 2228void 2229lreply(int n, const char *fmt, ...) 2230{ 2231 va_list ap; 2232 2233 va_start(ap, fmt); 2234 (void)printf("%d- ", n); 2235 (void)vprintf(fmt, ap); 2236 (void)printf("\r\n"); 2237 (void)fflush(stdout); 2238 if (ftpdebug) { 2239 syslog(LOG_DEBUG, "<--- %d- ", n); 2240 vsyslog(LOG_DEBUG, fmt, ap); 2241 } 2242} 2243 2244static void 2245ack(char *s) 2246{ 2247 2248 reply(250, "%s command successful.", s); 2249} 2250 2251void 2252nack(char *s) 2253{ 2254 2255 reply(502, "%s command not implemented.", s); 2256} 2257 2258/* ARGSUSED */ 2259void 2260yyerror(char *s) 2261{ 2262 char *cp; 2263 2264 if ((cp = strchr(cbuf,'\n'))) 2265 *cp = '\0'; 2266 reply(500, "'%s': command not understood.", cbuf); 2267} 2268 2269void 2270delete(char *name) 2271{ 2272 struct stat st; 2273 2274 LOGCMD("delete", name); 2275 if (lstat(name, &st) < 0) { 2276 perror_reply(550, name); 2277 return; 2278 } 2279 if ((st.st_mode&S_IFMT) == S_IFDIR) { 2280 if (rmdir(name) < 0) { 2281 perror_reply(550, name); 2282 return; 2283 } 2284 goto done; 2285 } 2286 if (unlink(name) < 0) { 2287 perror_reply(550, name); 2288 return; 2289 } 2290done: 2291 ack("DELE"); 2292} 2293 2294void 2295cwd(char *path) 2296{ 2297 2298 if (chdir(path) < 0) 2299 perror_reply(550, path); 2300 else 2301 ack("CWD"); 2302} 2303 2304void 2305makedir(char *name) 2306{ 2307 2308 LOGCMD("mkdir", name); 2309 if (guest && noguestmkd) 2310 reply(550, "%s: permission denied", name); 2311 else if (mkdir(name, 0777) < 0) 2312 perror_reply(550, name); 2313 else 2314 reply(257, "MKD command successful."); 2315} 2316 2317void 2318removedir(char *name) 2319{ 2320 2321 LOGCMD("rmdir", name); 2322 if (rmdir(name) < 0) 2323 perror_reply(550, name); 2324 else 2325 ack("RMD"); 2326} 2327 2328void 2329pwd(void) 2330{ 2331 char *s, path[MAXPATHLEN + 1]; 2332 2333 if (getwd(path) == (char *)NULL) 2334 reply(550, "%s.", path); 2335 else { 2336 if ((s = doublequote(path)) == NULL) 2337 fatalerror("Ran out of memory."); 2338 reply(257, "\"%s\" is current directory.", s); 2339 free(s); 2340 } 2341} 2342 2343char * 2344renamefrom(char *name) 2345{ 2346 struct stat st; 2347 2348 if (lstat(name, &st) < 0) { 2349 perror_reply(550, name); 2350 return ((char *)0); 2351 } 2352 reply(350, "File exists, ready for destination name"); 2353 return (name); 2354} 2355 2356void 2357renamecmd(char *from, char *to) 2358{ 2359 struct stat st; 2360 2361 LOGCMD2("rename", from, to); 2362 2363 if (guest && (stat(to, &st) == 0)) { 2364 reply(550, "%s: permission denied", to); 2365 return; 2366 } 2367 2368 if (rename(from, to) < 0) 2369 perror_reply(550, "rename"); 2370 else 2371 ack("RNTO"); 2372} 2373 2374static void 2375dolog(struct sockaddr *who) 2376{ 2377 int error; 2378 2379 realhostname_sa(remotehost, sizeof(remotehost) - 1, who, who->sa_len); 2380 2381#ifdef SETPROCTITLE 2382#ifdef VIRTUAL_HOSTING 2383 if (thishost != firsthost) 2384 snprintf(proctitle, sizeof(proctitle), "%s: connected (to %s)", 2385 remotehost, hostname); 2386 else 2387#endif 2388 snprintf(proctitle, sizeof(proctitle), "%s: connected", 2389 remotehost); 2390 setproctitle("%s", proctitle); 2391#endif /* SETPROCTITLE */ 2392 2393 if (logging) { 2394#ifdef VIRTUAL_HOSTING 2395 if (thishost != firsthost) 2396 syslog(LOG_INFO, "connection from %s (to %s)", 2397 remotehost, hostname); 2398 else 2399#endif 2400 { 2401 char who_name[MAXHOSTNAMELEN]; 2402 2403 error = getnameinfo(who, who->sa_len, 2404 who_name, sizeof(who_name) - 1, 2405 NULL, 0, NI_NUMERICHOST); 2406 syslog(LOG_INFO, "connection from %s (%s)", remotehost, 2407 error == 0 ? who_name : ""); 2408 } 2409 } 2410} 2411 2412/* 2413 * Record logout in wtmp file 2414 * and exit with supplied status. 2415 */ 2416void 2417dologout(int status) 2418{ 2419 /* 2420 * Prevent reception of SIGURG from resulting in a resumption 2421 * back to the main program loop. 2422 */ 2423 transflag = 0; 2424 2425 if (logged_in) { 2426 (void) seteuid((uid_t)0); 2427 ftpd_logwtmp(ttyline, "", NULL); 2428 } 2429 /* beware of flushing buffers after a SIGPIPE */ 2430 _exit(status); 2431} 2432 2433static void 2434sigurg(int signo) 2435{ 2436 2437 recvurg = 1; 2438} 2439 2440static void 2441myoob(void) 2442{ 2443 char *cp; 2444 2445 /* only process if transfer occurring */ 2446 if (!transflag) 2447 return; 2448 cp = tmpline; 2449 if (getline(cp, 7, stdin) == NULL) { 2450 reply(221, "You could at least say goodbye."); 2451 dologout(0); 2452 } 2453 upper(cp); 2454 if (strcmp(cp, "ABOR\r\n") == 0) { 2455 tmpline[0] = '\0'; 2456 reply(426, "Transfer aborted. Data connection closed."); 2457 reply(226, "Abort successful"); 2458 } 2459 if (strcmp(cp, "STAT\r\n") == 0) { 2460 tmpline[0] = '\0'; 2461 if (file_size != (off_t) -1) 2462 reply(213, "Status: %qd of %qd bytes transferred", 2463 byte_count, file_size); 2464 else 2465 reply(213, "Status: %qd bytes transferred", byte_count); 2466 } 2467} 2468 2469/* 2470 * Note: a response of 425 is not mentioned as a possible response to 2471 * the PASV command in RFC959. However, it has been blessed as 2472 * a legitimate response by Jon Postel in a telephone conversation 2473 * with Rick Adams on 25 Jan 89. 2474 */ 2475void 2476passive(void) 2477{ 2478 int len; 2479 char *p, *a; 2480 2481 if (pdata >= 0) /* close old port if one set */ 2482 close(pdata); 2483 2484 pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0); 2485 if (pdata < 0) { 2486 perror_reply(425, "Can't open passive connection"); 2487 return; 2488 } 2489 2490 (void) seteuid((uid_t)0); 2491 2492#ifdef IP_PORTRANGE 2493 if (ctrl_addr.su_family == AF_INET) { 2494 int on = restricted_data_ports ? IP_PORTRANGE_HIGH 2495 : IP_PORTRANGE_DEFAULT; 2496 2497 if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE, 2498 (char *)&on, sizeof(on)) < 0) 2499 goto pasv_error; 2500 } 2501#endif 2502#ifdef IPV6_PORTRANGE 2503 if (ctrl_addr.su_family == AF_INET6) { 2504 int on = restricted_data_ports ? IPV6_PORTRANGE_HIGH 2505 : IPV6_PORTRANGE_DEFAULT; 2506 2507 if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE, 2508 (char *)&on, sizeof(on)) < 0) 2509 goto pasv_error; 2510 } 2511#endif 2512 2513 pasv_addr = ctrl_addr; 2514 pasv_addr.su_port = 0; 2515 if (bind(pdata, (struct sockaddr *)&pasv_addr, pasv_addr.su_len) < 0) 2516 goto pasv_error; 2517 2518 (void) seteuid((uid_t)pw->pw_uid); 2519 2520 len = sizeof(pasv_addr); 2521 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) 2522 goto pasv_error; 2523 if (listen(pdata, 1) < 0) 2524 goto pasv_error; 2525 if (pasv_addr.su_family == AF_INET) 2526 a = (char *) &pasv_addr.su_sin.sin_addr; 2527 else if (pasv_addr.su_family == AF_INET6 && 2528 IN6_IS_ADDR_V4MAPPED(&pasv_addr.su_sin6.sin6_addr)) 2529 a = (char *) &pasv_addr.su_sin6.sin6_addr.s6_addr[12]; 2530 else 2531 goto pasv_error; 2532 2533 p = (char *) &pasv_addr.su_port; 2534 2535#define UC(b) (((int) b) & 0xff) 2536 2537 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), 2538 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 2539 return; 2540 2541pasv_error: 2542 (void) seteuid((uid_t)pw->pw_uid); 2543 (void) close(pdata); 2544 pdata = -1; 2545 perror_reply(425, "Can't open passive connection"); 2546 return; 2547} 2548 2549/* 2550 * Long Passive defined in RFC 1639. 2551 * 228 Entering Long Passive Mode 2552 * (af, hal, h1, h2, h3,..., pal, p1, p2...) 2553 */ 2554 2555void 2556long_passive(char *cmd, int pf) 2557{ 2558 int len; 2559 char *p, *a; 2560 2561 if (pdata >= 0) /* close old port if one set */ 2562 close(pdata); 2563 2564 if (pf != PF_UNSPEC) { 2565 if (ctrl_addr.su_family != pf) { 2566 switch (ctrl_addr.su_family) { 2567 case AF_INET: 2568 pf = 1; 2569 break; 2570 case AF_INET6: 2571 pf = 2; 2572 break; 2573 default: 2574 pf = 0; 2575 break; 2576 } 2577 /* 2578 * XXX 2579 * only EPRT/EPSV ready clients will understand this 2580 */ 2581 if (strcmp(cmd, "EPSV") == 0 && pf) { 2582 reply(522, "Network protocol mismatch, " 2583 "use (%d)", pf); 2584 } else 2585 reply(501, "Network protocol mismatch"); /*XXX*/ 2586 2587 return; 2588 } 2589 } 2590 2591 pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0); 2592 if (pdata < 0) { 2593 perror_reply(425, "Can't open passive connection"); 2594 return; 2595 } 2596 2597 (void) seteuid((uid_t)0); 2598 2599 pasv_addr = ctrl_addr; 2600 pasv_addr.su_port = 0; 2601 len = pasv_addr.su_len; 2602 2603#ifdef IP_PORTRANGE 2604 if (ctrl_addr.su_family == AF_INET) { 2605 int on = restricted_data_ports ? IP_PORTRANGE_HIGH 2606 : IP_PORTRANGE_DEFAULT; 2607 2608 if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE, 2609 (char *)&on, sizeof(on)) < 0) 2610 goto pasv_error; 2611 } 2612#endif 2613#ifdef IPV6_PORTRANGE 2614 if (ctrl_addr.su_family == AF_INET6) { 2615 int on = restricted_data_ports ? IPV6_PORTRANGE_HIGH 2616 : IPV6_PORTRANGE_DEFAULT; 2617 2618 if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE, 2619 (char *)&on, sizeof(on)) < 0) 2620 goto pasv_error; 2621 } 2622#endif 2623 2624 if (bind(pdata, (struct sockaddr *)&pasv_addr, len) < 0) 2625 goto pasv_error; 2626 2627 (void) seteuid((uid_t)pw->pw_uid); 2628 2629 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) 2630 goto pasv_error; 2631 if (listen(pdata, 1) < 0) 2632 goto pasv_error; 2633 2634#define UC(b) (((int) b) & 0xff) 2635 2636 if (strcmp(cmd, "LPSV") == 0) { 2637 p = (char *)&pasv_addr.su_port; 2638 switch (pasv_addr.su_family) { 2639 case AF_INET: 2640 a = (char *) &pasv_addr.su_sin.sin_addr; 2641 v4_reply: 2642 reply(228, 2643"Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d)", 2644 4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 2645 2, UC(p[0]), UC(p[1])); 2646 return; 2647 case AF_INET6: 2648 if (IN6_IS_ADDR_V4MAPPED(&pasv_addr.su_sin6.sin6_addr)) { 2649 a = (char *) &pasv_addr.su_sin6.sin6_addr.s6_addr[12]; 2650 goto v4_reply; 2651 } 2652 a = (char *) &pasv_addr.su_sin6.sin6_addr; 2653 reply(228, 2654"Entering Long Passive Mode " 2655"(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)", 2656 6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 2657 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]), 2658 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]), 2659 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]), 2660 2, UC(p[0]), UC(p[1])); 2661 return; 2662 } 2663 } else if (strcmp(cmd, "EPSV") == 0) { 2664 switch (pasv_addr.su_family) { 2665 case AF_INET: 2666 case AF_INET6: 2667 reply(229, "Entering Extended Passive Mode (|||%d|)", 2668 ntohs(pasv_addr.su_port)); 2669 return; 2670 } 2671 } else { 2672 /* more proper error code? */ 2673 } 2674 2675pasv_error: 2676 (void) seteuid((uid_t)pw->pw_uid); 2677 (void) close(pdata); 2678 pdata = -1; 2679 perror_reply(425, "Can't open passive connection"); 2680 return; 2681} 2682 2683/* 2684 * Generate unique name for file with basename "local". 2685 * The file named "local" is already known to exist. 2686 * Generates failure reply on error. 2687 */ 2688static char * 2689gunique(char *local) 2690{ 2691 static char new[MAXPATHLEN]; 2692 struct stat st; 2693 int count; 2694 char *cp; 2695 2696 cp = strrchr(local, '/'); 2697 if (cp) 2698 *cp = '\0'; 2699 if (stat(cp ? local : ".", &st) < 0) { 2700 perror_reply(553, cp ? local : "."); 2701 return ((char *) 0); 2702 } 2703 if (cp) 2704 *cp = '/'; 2705 /* -4 is for the .nn<null> we put on the end below */ 2706 (void) snprintf(new, sizeof(new) - 4, "%s", local); 2707 cp = new + strlen(new); 2708 *cp++ = '.'; 2709 for (count = 1; count < 100; count++) { 2710 (void)sprintf(cp, "%d", count); 2711 if (stat(new, &st) < 0) 2712 return (new); 2713 } 2714 reply(452, "Unique file name cannot be created."); 2715 return (NULL); 2716} 2717 2718/* 2719 * Format and send reply containing system error number. 2720 */ 2721void 2722perror_reply(int code, char *string) 2723{ 2724 2725 reply(code, "%s: %s.", string, strerror(errno)); 2726} 2727 2728static char *onefile[] = { 2729 "", 2730 0 2731}; 2732 2733void 2734send_file_list(char *whichf) 2735{ 2736 struct stat st; 2737 DIR *dirp = NULL; 2738 struct dirent *dir; 2739 FILE *dout = NULL; 2740 char **dirlist, *dirname; 2741 int simple = 0; 2742 int freeglob = 0; 2743 glob_t gl; 2744 2745 if (strpbrk(whichf, "~{[*?") != NULL) { 2746 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; 2747 2748 memset(&gl, 0, sizeof(gl)); 2749 gl.gl_matchc = MAXGLOBARGS; 2750 flags |= GLOB_LIMIT; 2751 freeglob = 1; 2752 if (glob(whichf, flags, 0, &gl)) { 2753 reply(550, "not found"); 2754 goto out; 2755 } else if (gl.gl_pathc == 0) { 2756 errno = ENOENT; 2757 perror_reply(550, whichf); 2758 goto out; 2759 } 2760 dirlist = gl.gl_pathv; 2761 } else { 2762 onefile[0] = whichf; 2763 dirlist = onefile; 2764 simple = 1; 2765 } 2766 2767 while ((dirname = *dirlist++)) { 2768 if (stat(dirname, &st) < 0) { 2769 /* 2770 * If user typed "ls -l", etc, and the client 2771 * used NLST, do what the user meant. 2772 */ 2773 if (dirname[0] == '-' && *dirlist == NULL && 2774 transflag == 0) { 2775 retrieve(_PATH_LS " %s", dirname); 2776 goto out; 2777 } 2778 perror_reply(550, whichf); 2779 if (dout != NULL) { 2780 (void) fclose(dout); 2781 transflag = 0; 2782 data = -1; 2783 pdata = -1; 2784 } 2785 goto out; 2786 } 2787 2788 if (S_ISREG(st.st_mode)) { 2789 if (dout == NULL) { 2790 dout = dataconn("file list", (off_t)-1, "w"); 2791 if (dout == NULL) 2792 goto out; 2793 transflag++; 2794 } 2795 fprintf(dout, "%s%s\n", dirname, 2796 type == TYPE_A ? "\r" : ""); 2797 byte_count += strlen(dirname) + 1; 2798 continue; 2799 } else if (!S_ISDIR(st.st_mode)) 2800 continue; 2801 2802 if ((dirp = opendir(dirname)) == NULL) 2803 continue; 2804 2805 while ((dir = readdir(dirp)) != NULL) { 2806 char nbuf[MAXPATHLEN]; 2807 2808 if (recvurg) { 2809 myoob(); 2810 recvurg = 0; 2811 transflag = 0; 2812 goto out; 2813 } 2814 2815 if (dir->d_name[0] == '.' && dir->d_namlen == 1) 2816 continue; 2817 if (dir->d_name[0] == '.' && dir->d_name[1] == '.' && 2818 dir->d_namlen == 2) 2819 continue; 2820 2821 snprintf(nbuf, sizeof(nbuf), 2822 "%s/%s", dirname, dir->d_name); 2823 2824 /* 2825 * We have to do a stat to insure it's 2826 * not a directory or special file. 2827 */ 2828 if (simple || (stat(nbuf, &st) == 0 && 2829 S_ISREG(st.st_mode))) { 2830 if (dout == NULL) { 2831 dout = dataconn("file list", (off_t)-1, 2832 "w"); 2833 if (dout == NULL) 2834 goto out; 2835 transflag++; 2836 } 2837 if (nbuf[0] == '.' && nbuf[1] == '/') 2838 fprintf(dout, "%s%s\n", &nbuf[2], 2839 type == TYPE_A ? "\r" : ""); 2840 else 2841 fprintf(dout, "%s%s\n", nbuf, 2842 type == TYPE_A ? "\r" : ""); 2843 byte_count += strlen(nbuf) + 1; 2844 } 2845 } 2846 (void) closedir(dirp); 2847 } 2848 2849 if (dout == NULL) 2850 reply(550, "No files found."); 2851 else if (ferror(dout) != 0) 2852 perror_reply(550, "Data connection"); 2853 else 2854 reply(226, "Transfer complete."); 2855 2856 transflag = 0; 2857 if (dout != NULL) 2858 (void) fclose(dout); 2859 data = -1; 2860 pdata = -1; 2861out: 2862 if (freeglob) { 2863 freeglob = 0; 2864 globfree(&gl); 2865 } 2866} 2867 2868void 2869reapchild(int signo) 2870{ 2871 while (wait3(NULL, WNOHANG, NULL) > 0); 2872} 2873 2874#ifdef OLD_SETPROCTITLE 2875/* 2876 * Clobber argv so ps will show what we're doing. (Stolen from sendmail.) 2877 * Warning, since this is usually started from inetd.conf, it often doesn't 2878 * have much of an environment or arglist to overwrite. 2879 */ 2880void 2881setproctitle(const char *fmt, ...) 2882{ 2883 int i; 2884 va_list ap; 2885 char *p, *bp, ch; 2886 char buf[LINE_MAX]; 2887 2888 va_start(ap, fmt); 2889 (void)vsnprintf(buf, sizeof(buf), fmt, ap); 2890 2891 /* make ps print our process name */ 2892 p = Argv[0]; 2893 *p++ = '-'; 2894 2895 i = strlen(buf); 2896 if (i > LastArgv - p - 2) { 2897 i = LastArgv - p - 2; 2898 buf[i] = '\0'; 2899 } 2900 bp = buf; 2901 while (ch = *bp++) 2902 if (ch != '\n' && ch != '\r') 2903 *p++ = ch; 2904 while (p < LastArgv) 2905 *p++ = ' '; 2906} 2907#endif /* OLD_SETPROCTITLE */ 2908 2909static void 2910logxfer(char *name, off_t size, time_t start) 2911{ 2912 char buf[1024]; 2913 char path[MAXPATHLEN + 1]; 2914 time_t now; 2915 2916 if (statfd >= 0 && getwd(path) != NULL) { 2917 time(&now); 2918 snprintf(buf, sizeof(buf), "%.20s!%s!%s!%s/%s!%qd!%ld\n", 2919 ctime(&now)+4, ident, remotehost, 2920 path, name, (long long)size, 2921 (long)(now - start + (now == start))); 2922 write(statfd, buf, strlen(buf)); 2923 } 2924} 2925 2926static char * 2927doublequote(char *s) 2928{ 2929 int n; 2930 char *p, *s2; 2931 2932 for (p = s, n = 0; *p; p++) 2933 if (*p == '"') 2934 n++; 2935 2936 if ((s2 = malloc(p - s + n + 1)) == NULL) 2937 return (NULL); 2938 2939 for (p = s2; *s; s++, p++) { 2940 if ((*p = *s) == '"') 2941 *(++p) = '"'; 2942 } 2943 *p = '\0'; 2944 2945 return (s2); 2946} 2947