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