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 36 static 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 44 static char sccsid[] = "@(#)ftpd.c 8.4 (Berkeley) 4/16/94"; 45 #endif 46 static const char rcsid[] = 47 "$Id: ftpd.c,v 1.51 1998/06/03 11:33:44 jb 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 107 static char version[] = "Version 6.00LS"; 108 #undef main 109 #else 110 static char version[] = "Version 6.00"; 111 #endif 112 113 extern off_t restart_point; 114 extern char cbuf[]; 115 116 struct sockaddr_in server_addr; 117 struct sockaddr_in ctrl_addr; 118 struct sockaddr_in data_source; 119 struct sockaddr_in data_dest; 120 struct sockaddr_in his_addr; 121 struct sockaddr_in pasv_addr; 122 123 int daemon_mode; 124 int data; 125 jmp_buf errcatch, urgcatch; 126 int logged_in; 127 struct passwd *pw; 128 int debug; 129 int timeout = 900; /* timeout after 15 minutes of inactivity */ 130 int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ 131 int logging; 132 int restricted_data_ports = 1; 133 int paranoid = 1; /* be extra careful about security */ 134 int anon_only = 0; /* Only anonymous ftp allowed */ 135 int guest; 136 int dochroot; 137 int stats; 138 int statfd = -1; 139 int type; 140 int form; 141 int stru; /* avoid C keyword */ 142 int mode; 143 int usedefault = 1; /* for data transfers */ 144 int pdata = -1; /* for passive mode */ 145 sig_atomic_t transflag; 146 off_t file_size; 147 off_t byte_count; 148 #if !defined(CMASK) || CMASK == 0 149 #undef CMASK 150 #define CMASK 027 151 #endif 152 int defumask = CMASK; /* default umask value */ 153 char tmpline[7]; 154 char *hostname; 155 #ifdef VIRTUAL_HOSTING 156 char *ftpuser; 157 158 static 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 169 char remotehost[MAXHOSTNAMELEN]; 170 char *ident = NULL; 171 172 static char ttyline[20]; 173 char *tty = ttyline; /* for klogin */ 174 175 #ifdef KERBEROS 176 int klogin __P((struct passwd *, char *, char *, char *)); 177 #endif 178 179 struct in_addr bind_address; 180 char *pid_file = NULL; 181 182 #if defined(KERBEROS) 183 int notickets = 1; 184 int noticketsdontcomplain = 1; 185 char *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 196 int swaitmax = SWAITMAX; 197 int swaitint = SWAITINT; 198 199 #ifdef SETPROCTITLE 200 #ifdef OLD_SETPROCTITLE 201 char **Argv = NULL; /* pointer to argument vector */ 202 char *LastArgv = NULL; /* end of argv */ 203 #endif /* OLD_SETPROCTITLE */ 204 char proctitle[LINE_MAX]; /* initial part of title */ 205 #endif /* SETPROCTITLE */ 206 207 #ifdef SKEY 208 int pwok = 0; 209 char 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 232 static void inithosts __P((void)); 233 static void selecthost __P((struct in_addr *)); 234 #endif 235 static void ack __P((char *)); 236 static void myoob __P((int)); 237 static int checkuser __P((char *, char *, int)); 238 static FILE *dataconn __P((char *, off_t, char *)); 239 static void dolog __P((struct sockaddr_in *)); 240 static char *curdir __P((void)); 241 static void end_login __P((void)); 242 static FILE *getdatasock __P((char *)); 243 static char *gunique __P((char *)); 244 static void lostconn __P((int)); 245 static int receive_data __P((FILE *, FILE *)); 246 static void send_data __P((FILE *, FILE *, off_t, off_t, int)); 247 static struct passwd * 248 sgetpwnam __P((char *)); 249 static char *sgetsave __P((char *)); 250 static void reapchild __P((int)); 251 static void logxfer __P((char *, long, long)); 252 253 static char * 254 curdir() 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 266 int 267 main(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 (signal(SIGURG, myoob) == SIG_ERR) 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 554 static void 555 lostconn(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 569 static void 570 inithosts() 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 685 static void 686 selecthost(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 */ 708 static char * 709 sgetsave(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 */ 728 static struct passwd * 729 sgetpwnam(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 753 static int login_attempts; /* number of failed login attempts */ 754 static int askpasswd; /* had user command, ask for passwd */ 755 static 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 */ 768 void 769 user(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", 0) || 788 checkuser(_PATH_FTPUSERS, "anonymous", 0)) 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, 1)) { 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 */ 849 static int 850 checkuser(fname, name, pwset) 851 char *fname; 852 char *name; 853 int pwset; 854 { 855 FILE *fd; 856 int found = 0; 857 char *p, line[BUFSIZ]; 858 859 if ((fd = fopen(fname, "r")) != NULL) { 860 while (!found && fgets(line, sizeof(line), fd) != NULL) 861 if ((p = strchr(line, '\n')) != NULL) { 862 *p = '\0'; 863 if (line[0] == '#') 864 continue; 865 /* 866 * if first chr is '@', check group membership 867 */ 868 if (line[0] == '@') { 869 int i = 0; 870 struct group *grp; 871 872 if ((grp = getgrnam(line+1)) == NULL) 873 continue; 874 /* 875 * Check user's default group 876 */ 877 if (pwset && grp->gr_gid == pw->pw_gid) 878 found = 1; 879 /* 880 * Check supplementary groups 881 */ 882 while (!found && grp->gr_mem[i]) 883 found = strcmp(name, 884 grp->gr_mem[i++]) 885 == 0; 886 } 887 /* 888 * Otherwise, just check for username match 889 */ 890 else 891 found = strcmp(line, name) == 0; 892 } 893 (void) fclose(fd); 894 } 895 return (found); 896 } 897 898 /* 899 * Terminate login as previous user, if any, resetting state; 900 * used when USER command is given or login fails. 901 */ 902 static void 903 end_login() 904 { 905 906 (void) seteuid((uid_t)0); 907 if (logged_in) 908 ftpd_logwtmp(ttyline, "", ""); 909 pw = NULL; 910 #ifdef LOGIN_CAP 911 setusercontext(NULL, getpwuid(0), (uid_t)0, 912 LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK); 913 #endif 914 logged_in = 0; 915 guest = 0; 916 dochroot = 0; 917 } 918 919 void 920 pass(passwd) 921 char *passwd; 922 { 923 int rval; 924 FILE *fd; 925 #ifdef LOGIN_CAP 926 login_cap_t *lc = NULL; 927 #endif 928 929 if (logged_in || askpasswd == 0) { 930 reply(503, "Login with USER first."); 931 return; 932 } 933 askpasswd = 0; 934 if (!guest) { /* "ftp" is only account allowed no password */ 935 if (pw == NULL) { 936 rval = 1; /* failure below */ 937 goto skip; 938 } 939 #if defined(KERBEROS) 940 rval = klogin(pw, "", hostname, passwd); 941 if (rval == 0) 942 goto skip; 943 #endif 944 #ifdef SKEY 945 rval = strcmp(skey_crypt(passwd, pw->pw_passwd, pw, pwok), 946 pw->pw_passwd); 947 pwok = 0; 948 #else 949 rval = strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd); 950 #endif 951 /* The strcmp does not catch null passwords! */ 952 if (*pw->pw_passwd == '\0' || 953 (pw->pw_expire && time(NULL) >= pw->pw_expire)) 954 rval = 1; /* failure */ 955 skip: 956 /* 957 * If rval == 1, the user failed the authentication check 958 * above. If rval == 0, either Kerberos or local authentication 959 * succeeded. 960 */ 961 if (rval) { 962 reply(530, "Login incorrect."); 963 if (logging) 964 syslog(LOG_NOTICE, 965 "FTP LOGIN FAILED FROM %s, %s", 966 remotehost, curname); 967 pw = NULL; 968 if (login_attempts++ >= 5) { 969 syslog(LOG_NOTICE, 970 "repeated login failures from %s", 971 remotehost); 972 exit(0); 973 } 974 return; 975 } 976 } 977 login_attempts = 0; /* this time successful */ 978 if (setegid((gid_t)pw->pw_gid) < 0) { 979 reply(550, "Can't set gid."); 980 return; 981 } 982 /* May be overridden by login.conf */ 983 (void) umask(defumask); 984 #ifdef LOGIN_CAP 985 if ((lc = login_getpwclass(pw)) != NULL) { 986 char remote_ip[MAXHOSTNAMELEN]; 987 988 strncpy(remote_ip, inet_ntoa(his_addr.sin_addr), 989 sizeof(remote_ip) - 1); 990 remote_ip[sizeof(remote_ip) - 1] = 0; 991 if (!auth_hostok(lc, remotehost, remote_ip)) { 992 syslog(LOG_INFO|LOG_AUTH, 993 "FTP LOGIN FAILED (HOST) as %s: permission denied.", 994 pw->pw_name); 995 reply(530, "Permission denied.\n"); 996 pw = NULL; 997 return; 998 } 999 if (!auth_timeok(lc, time(NULL))) { 1000 reply(530, "Login not available right now.\n"); 1001 pw = NULL; 1002 return; 1003 } 1004 } 1005 setusercontext(lc, pw, (uid_t)0, 1006 LOGIN_SETLOGIN|LOGIN_SETGROUP|LOGIN_SETPRIORITY| 1007 LOGIN_SETRESOURCES|LOGIN_SETUMASK); 1008 #else 1009 setlogin(pw->pw_name); 1010 (void) initgroups(pw->pw_name, pw->pw_gid); 1011 #endif 1012 1013 /* open wtmp before chroot */ 1014 ftpd_logwtmp(ttyline, pw->pw_name, remotehost); 1015 logged_in = 1; 1016 1017 if (guest && stats && statfd < 0) 1018 #ifdef VIRTUAL_HOSTING 1019 if ((statfd = open(thishost->statfile, O_WRONLY|O_APPEND)) < 0) 1020 #else 1021 if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0) 1022 #endif 1023 stats = 0; 1024 1025 dochroot = 1026 #ifdef LOGIN_CAP /* Allow login.conf configuration as well */ 1027 login_getcapbool(lc, "ftp-chroot", 0) || 1028 #endif 1029 checkuser(_PATH_FTPCHROOT, pw->pw_name, 1); 1030 if (guest) { 1031 /* 1032 * We MUST do a chdir() after the chroot. Otherwise 1033 * the old current directory will be accessible as "." 1034 * outside the new root! 1035 */ 1036 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { 1037 reply(550, "Can't set guest privileges."); 1038 goto bad; 1039 } 1040 } else if (dochroot) { 1041 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { 1042 reply(550, "Can't change root."); 1043 goto bad; 1044 } 1045 } else if (chdir(pw->pw_dir) < 0) { 1046 if (chdir("/") < 0) { 1047 reply(530, "User %s: can't change directory to %s.", 1048 pw->pw_name, pw->pw_dir); 1049 goto bad; 1050 } else 1051 lreply(230, "No directory! Logging in with home=/"); 1052 } 1053 if (seteuid((uid_t)pw->pw_uid) < 0) { 1054 reply(550, "Can't set uid."); 1055 goto bad; 1056 } 1057 1058 /* 1059 * Display a login message, if it exists. 1060 * N.B. reply(230,) must follow the message. 1061 */ 1062 #ifdef VIRTUAL_HOSTING 1063 if ((fd = fopen(thishost->loginmsg, "r")) != NULL) { 1064 #else 1065 if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) { 1066 #endif 1067 char *cp, line[LINE_MAX]; 1068 1069 while (fgets(line, sizeof(line), fd) != NULL) { 1070 if ((cp = strchr(line, '\n')) != NULL) 1071 *cp = '\0'; 1072 lreply(230, "%s", line); 1073 } 1074 (void) fflush(stdout); 1075 (void) fclose(fd); 1076 } 1077 if (guest) { 1078 if (ident != NULL) 1079 free(ident); 1080 ident = strdup(passwd); 1081 if (ident == NULL) 1082 fatal("Ran out of memory."); 1083 1084 reply(230, "Guest login ok, access restrictions apply."); 1085 #ifdef SETPROCTITLE 1086 #ifdef VIRTUAL_HOSTING 1087 if (thishost != firsthost) 1088 snprintf(proctitle, sizeof(proctitle), 1089 "%s: anonymous(%s)/%.*s", remotehost, hostname, 1090 sizeof(proctitle) - sizeof(remotehost) - 1091 sizeof(": anonymous/"), passwd); 1092 else 1093 #endif 1094 snprintf(proctitle, sizeof(proctitle), 1095 "%s: anonymous/%.*s", remotehost, 1096 sizeof(proctitle) - sizeof(remotehost) - 1097 sizeof(": anonymous/"), passwd); 1098 setproctitle("%s", proctitle); 1099 #endif /* SETPROCTITLE */ 1100 if (logging) 1101 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s", 1102 remotehost, passwd); 1103 } else { 1104 if (dochroot) 1105 reply(230, "User %s logged in, access restrictions apply.", 1106 pw->pw_name); 1107 else 1108 reply(230, "User %s logged in.", pw->pw_name); 1109 1110 #ifdef SETPROCTITLE 1111 snprintf(proctitle, sizeof(proctitle), 1112 "%s: %s", remotehost, pw->pw_name); 1113 setproctitle("%s", proctitle); 1114 #endif /* SETPROCTITLE */ 1115 if (logging) 1116 syslog(LOG_INFO, "FTP LOGIN FROM %s as %s", 1117 remotehost, pw->pw_name); 1118 } 1119 #ifdef LOGIN_CAP 1120 login_close(lc); 1121 #endif 1122 return; 1123 bad: 1124 /* Forget all about it... */ 1125 #ifdef LOGIN_CAP 1126 login_close(lc); 1127 #endif 1128 end_login(); 1129 } 1130 1131 void 1132 retrieve(cmd, name) 1133 char *cmd, *name; 1134 { 1135 FILE *fin, *dout; 1136 struct stat st; 1137 int (*closefunc) __P((FILE *)); 1138 time_t start; 1139 1140 if (cmd == 0) { 1141 fin = fopen(name, "r"), closefunc = fclose; 1142 st.st_size = 0; 1143 } else { 1144 char line[BUFSIZ]; 1145 1146 (void) snprintf(line, sizeof(line), cmd, name), name = line; 1147 fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose; 1148 st.st_size = -1; 1149 st.st_blksize = BUFSIZ; 1150 } 1151 if (fin == NULL) { 1152 if (errno != 0) { 1153 perror_reply(550, name); 1154 if (cmd == 0) { 1155 LOGCMD("get", name); 1156 } 1157 } 1158 return; 1159 } 1160 byte_count = -1; 1161 if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) { 1162 reply(550, "%s: not a plain file.", name); 1163 goto done; 1164 } 1165 if (restart_point) { 1166 if (type == TYPE_A) { 1167 off_t i, n; 1168 int c; 1169 1170 n = restart_point; 1171 i = 0; 1172 while (i++ < n) { 1173 if ((c=getc(fin)) == EOF) { 1174 perror_reply(550, name); 1175 goto done; 1176 } 1177 if (c == '\n') 1178 i++; 1179 } 1180 } else if (lseek(fileno(fin), restart_point, L_SET) < 0) { 1181 perror_reply(550, name); 1182 goto done; 1183 } 1184 } 1185 dout = dataconn(name, st.st_size, "w"); 1186 if (dout == NULL) 1187 goto done; 1188 time(&start); 1189 send_data(fin, dout, st.st_blksize, st.st_size, 1190 restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)); 1191 if (cmd == 0 && guest && stats) 1192 logxfer(name, st.st_size, start); 1193 (void) fclose(dout); 1194 data = -1; 1195 pdata = -1; 1196 done: 1197 if (cmd == 0) 1198 LOGBYTES("get", name, byte_count); 1199 (*closefunc)(fin); 1200 } 1201 1202 void 1203 store(name, mode, unique) 1204 char *name, *mode; 1205 int unique; 1206 { 1207 FILE *fout, *din; 1208 struct stat st; 1209 int (*closefunc) __P((FILE *)); 1210 1211 if ((unique || guest) && stat(name, &st) == 0 && 1212 (name = gunique(name)) == NULL) { 1213 LOGCMD(*mode == 'w' ? "put" : "append", name); 1214 return; 1215 } 1216 1217 if (restart_point) 1218 mode = "r+"; 1219 fout = fopen(name, mode); 1220 closefunc = fclose; 1221 if (fout == NULL) { 1222 perror_reply(553, name); 1223 LOGCMD(*mode == 'w' ? "put" : "append", name); 1224 return; 1225 } 1226 byte_count = -1; 1227 if (restart_point) { 1228 if (type == TYPE_A) { 1229 off_t i, n; 1230 int c; 1231 1232 n = restart_point; 1233 i = 0; 1234 while (i++ < n) { 1235 if ((c=getc(fout)) == EOF) { 1236 perror_reply(550, name); 1237 goto done; 1238 } 1239 if (c == '\n') 1240 i++; 1241 } 1242 /* 1243 * We must do this seek to "current" position 1244 * because we are changing from reading to 1245 * writing. 1246 */ 1247 if (fseek(fout, 0L, L_INCR) < 0) { 1248 perror_reply(550, name); 1249 goto done; 1250 } 1251 } else if (lseek(fileno(fout), restart_point, L_SET) < 0) { 1252 perror_reply(550, name); 1253 goto done; 1254 } 1255 } 1256 din = dataconn(name, (off_t)-1, "r"); 1257 if (din == NULL) 1258 goto done; 1259 if (receive_data(din, fout) == 0) { 1260 if (unique) 1261 reply(226, "Transfer complete (unique file name:%s).", 1262 name); 1263 else 1264 reply(226, "Transfer complete."); 1265 } 1266 (void) fclose(din); 1267 data = -1; 1268 pdata = -1; 1269 done: 1270 LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count); 1271 (*closefunc)(fout); 1272 } 1273 1274 static FILE * 1275 getdatasock(mode) 1276 char *mode; 1277 { 1278 int on = 1, s, t, tries; 1279 1280 if (data >= 0) 1281 return (fdopen(data, mode)); 1282 (void) seteuid((uid_t)0); 1283 s = socket(AF_INET, SOCK_STREAM, 0); 1284 if (s < 0) 1285 goto bad; 1286 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 1287 (char *) &on, sizeof(on)) < 0) 1288 goto bad; 1289 /* anchor socket to avoid multi-homing problems */ 1290 data_source.sin_len = sizeof(struct sockaddr_in); 1291 data_source.sin_family = AF_INET; 1292 data_source.sin_addr = ctrl_addr.sin_addr; 1293 for (tries = 1; ; tries++) { 1294 if (bind(s, (struct sockaddr *)&data_source, 1295 sizeof(data_source)) >= 0) 1296 break; 1297 if (errno != EADDRINUSE || tries > 10) 1298 goto bad; 1299 sleep(tries); 1300 } 1301 (void) seteuid((uid_t)pw->pw_uid); 1302 #ifdef IP_TOS 1303 on = IPTOS_THROUGHPUT; 1304 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 1305 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 1306 #endif 1307 #ifdef TCP_NOPUSH 1308 /* 1309 * Turn off push flag to keep sender TCP from sending short packets 1310 * at the boundaries of each write(). Should probably do a SO_SNDBUF 1311 * to set the send buffer size as well, but that may not be desirable 1312 * in heavy-load situations. 1313 */ 1314 on = 1; 1315 if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0) 1316 syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m"); 1317 #endif 1318 #ifdef SO_SNDBUF 1319 on = 65536; 1320 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0) 1321 syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m"); 1322 #endif 1323 1324 return (fdopen(s, mode)); 1325 bad: 1326 /* Return the real value of errno (close may change it) */ 1327 t = errno; 1328 (void) seteuid((uid_t)pw->pw_uid); 1329 (void) close(s); 1330 errno = t; 1331 return (NULL); 1332 } 1333 1334 static FILE * 1335 dataconn(name, size, mode) 1336 char *name; 1337 off_t size; 1338 char *mode; 1339 { 1340 char sizebuf[32]; 1341 FILE *file; 1342 int retry = 0, tos; 1343 1344 file_size = size; 1345 byte_count = 0; 1346 if (size != (off_t) -1) 1347 (void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)", size); 1348 else 1349 *sizebuf = '\0'; 1350 if (pdata >= 0) { 1351 struct sockaddr_in from; 1352 int s, fromlen = sizeof(from); 1353 struct timeval timeout; 1354 fd_set set; 1355 1356 FD_ZERO(&set); 1357 FD_SET(pdata, &set); 1358 1359 timeout.tv_usec = 0; 1360 timeout.tv_sec = 120; 1361 1362 if (select(pdata+1, &set, (fd_set *) 0, (fd_set *) 0, &timeout) == 0 || 1363 (s = accept(pdata, (struct sockaddr *) &from, &fromlen)) < 0) { 1364 reply(425, "Can't open data connection."); 1365 (void) close(pdata); 1366 pdata = -1; 1367 return (NULL); 1368 } 1369 (void) close(pdata); 1370 pdata = s; 1371 #ifdef IP_TOS 1372 tos = IPTOS_THROUGHPUT; 1373 (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, 1374 sizeof(int)); 1375 #endif 1376 reply(150, "Opening %s mode data connection for '%s'%s.", 1377 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 1378 return (fdopen(pdata, mode)); 1379 } 1380 if (data >= 0) { 1381 reply(125, "Using existing data connection for '%s'%s.", 1382 name, sizebuf); 1383 usedefault = 1; 1384 return (fdopen(data, mode)); 1385 } 1386 if (usedefault) 1387 data_dest = his_addr; 1388 usedefault = 1; 1389 file = getdatasock(mode); 1390 if (file == NULL) { 1391 reply(425, "Can't create data socket (%s,%d): %s.", 1392 inet_ntoa(data_source.sin_addr), 1393 ntohs(data_source.sin_port), strerror(errno)); 1394 return (NULL); 1395 } 1396 data = fileno(file); 1397 while (connect(data, (struct sockaddr *)&data_dest, 1398 sizeof(data_dest)) < 0) { 1399 if (errno == EADDRINUSE && retry < swaitmax) { 1400 sleep((unsigned) swaitint); 1401 retry += swaitint; 1402 continue; 1403 } 1404 perror_reply(425, "Can't build data connection"); 1405 (void) fclose(file); 1406 data = -1; 1407 return (NULL); 1408 } 1409 reply(150, "Opening %s mode data connection for '%s'%s.", 1410 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 1411 return (file); 1412 } 1413 1414 /* 1415 * Tranfer the contents of "instr" to "outstr" peer using the appropriate 1416 * encapsulation of the data subject to Mode, Structure, and Type. 1417 * 1418 * NB: Form isn't handled. 1419 */ 1420 static void 1421 send_data(instr, outstr, blksize, filesize, isreg) 1422 FILE *instr, *outstr; 1423 off_t blksize; 1424 off_t filesize; 1425 int isreg; 1426 { 1427 int c, cnt, filefd, netfd; 1428 char *buf, *bp; 1429 size_t len; 1430 1431 transflag++; 1432 if (setjmp(urgcatch)) { 1433 transflag = 0; 1434 return; 1435 } 1436 switch (type) { 1437 1438 case TYPE_A: 1439 while ((c = getc(instr)) != EOF) { 1440 byte_count++; 1441 if (c == '\n') { 1442 if (ferror(outstr)) 1443 goto data_err; 1444 (void) putc('\r', outstr); 1445 } 1446 (void) putc(c, outstr); 1447 } 1448 fflush(outstr); 1449 transflag = 0; 1450 if (ferror(instr)) 1451 goto file_err; 1452 if (ferror(outstr)) 1453 goto data_err; 1454 reply(226, "Transfer complete."); 1455 return; 1456 1457 case TYPE_I: 1458 case TYPE_L: 1459 /* 1460 * isreg is only set if we are not doing restart and we 1461 * are sending a regular file 1462 */ 1463 netfd = fileno(outstr); 1464 filefd = fileno(instr); 1465 1466 if (isreg && filesize < (off_t)16 * 1024 * 1024) { 1467 buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd, 1468 (off_t)0); 1469 if (buf == MAP_FAILED) { 1470 syslog(LOG_WARNING, "mmap(%lu): %m", 1471 (unsigned long)filesize); 1472 goto oldway; 1473 } 1474 bp = buf; 1475 len = filesize; 1476 do { 1477 cnt = write(netfd, bp, len); 1478 len -= cnt; 1479 bp += cnt; 1480 if (cnt > 0) byte_count += cnt; 1481 } while(cnt > 0 && len > 0); 1482 1483 transflag = 0; 1484 munmap(buf, (size_t)filesize); 1485 if (cnt < 0) 1486 goto data_err; 1487 reply(226, "Transfer complete."); 1488 return; 1489 } 1490 1491 oldway: 1492 if ((buf = malloc((u_int)blksize)) == NULL) { 1493 transflag = 0; 1494 perror_reply(451, "Local resource failure: malloc"); 1495 return; 1496 } 1497 1498 while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 && 1499 write(netfd, buf, cnt) == cnt) 1500 byte_count += cnt; 1501 transflag = 0; 1502 (void)free(buf); 1503 if (cnt != 0) { 1504 if (cnt < 0) 1505 goto file_err; 1506 goto data_err; 1507 } 1508 reply(226, "Transfer complete."); 1509 return; 1510 default: 1511 transflag = 0; 1512 reply(550, "Unimplemented TYPE %d in send_data", type); 1513 return; 1514 } 1515 1516 data_err: 1517 transflag = 0; 1518 perror_reply(426, "Data connection"); 1519 return; 1520 1521 file_err: 1522 transflag = 0; 1523 perror_reply(551, "Error on input file"); 1524 } 1525 1526 /* 1527 * Transfer data from peer to "outstr" using the appropriate encapulation of 1528 * the data subject to Mode, Structure, and Type. 1529 * 1530 * N.B.: Form isn't handled. 1531 */ 1532 static int 1533 receive_data(instr, outstr) 1534 FILE *instr, *outstr; 1535 { 1536 int c; 1537 int cnt, bare_lfs; 1538 char buf[BUFSIZ]; 1539 1540 transflag++; 1541 if (setjmp(urgcatch)) { 1542 transflag = 0; 1543 return (-1); 1544 } 1545 1546 bare_lfs = 0; 1547 1548 switch (type) { 1549 1550 case TYPE_I: 1551 case TYPE_L: 1552 while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) { 1553 if (write(fileno(outstr), buf, cnt) != cnt) 1554 goto file_err; 1555 byte_count += cnt; 1556 } 1557 if (cnt < 0) 1558 goto data_err; 1559 transflag = 0; 1560 return (0); 1561 1562 case TYPE_E: 1563 reply(553, "TYPE E not implemented."); 1564 transflag = 0; 1565 return (-1); 1566 1567 case TYPE_A: 1568 while ((c = getc(instr)) != EOF) { 1569 byte_count++; 1570 if (c == '\n') 1571 bare_lfs++; 1572 while (c == '\r') { 1573 if (ferror(outstr)) 1574 goto data_err; 1575 if ((c = getc(instr)) != '\n') { 1576 (void) putc ('\r', outstr); 1577 if (c == '\0' || c == EOF) 1578 goto contin2; 1579 } 1580 } 1581 (void) putc(c, outstr); 1582 contin2: ; 1583 } 1584 fflush(outstr); 1585 if (ferror(instr)) 1586 goto data_err; 1587 if (ferror(outstr)) 1588 goto file_err; 1589 transflag = 0; 1590 if (bare_lfs) { 1591 lreply(226, 1592 "WARNING! %d bare linefeeds received in ASCII mode", 1593 bare_lfs); 1594 (void)printf(" File may not have transferred correctly.\r\n"); 1595 } 1596 return (0); 1597 default: 1598 reply(550, "Unimplemented TYPE %d in receive_data", type); 1599 transflag = 0; 1600 return (-1); 1601 } 1602 1603 data_err: 1604 transflag = 0; 1605 perror_reply(426, "Data Connection"); 1606 return (-1); 1607 1608 file_err: 1609 transflag = 0; 1610 perror_reply(452, "Error writing file"); 1611 return (-1); 1612 } 1613 1614 void 1615 statfilecmd(filename) 1616 char *filename; 1617 { 1618 FILE *fin; 1619 int c; 1620 char line[LINE_MAX]; 1621 1622 (void)snprintf(line, sizeof(line), _PATH_LS " -lgA %s", filename); 1623 fin = ftpd_popen(line, "r"); 1624 lreply(211, "status of %s:", filename); 1625 while ((c = getc(fin)) != EOF) { 1626 if (c == '\n') { 1627 if (ferror(stdout)){ 1628 perror_reply(421, "control connection"); 1629 (void) ftpd_pclose(fin); 1630 dologout(1); 1631 /* NOTREACHED */ 1632 } 1633 if (ferror(fin)) { 1634 perror_reply(551, filename); 1635 (void) ftpd_pclose(fin); 1636 return; 1637 } 1638 (void) putc('\r', stdout); 1639 } 1640 (void) putc(c, stdout); 1641 } 1642 (void) ftpd_pclose(fin); 1643 reply(211, "End of Status"); 1644 } 1645 1646 void 1647 statcmd() 1648 { 1649 struct sockaddr_in *sin; 1650 u_char *a, *p; 1651 1652 lreply(211, "%s FTP server status:", hostname, version); 1653 printf(" %s\r\n", version); 1654 printf(" Connected to %s", remotehost); 1655 if (!isdigit(remotehost[0])) 1656 printf(" (%s)", inet_ntoa(his_addr.sin_addr)); 1657 printf("\r\n"); 1658 if (logged_in) { 1659 if (guest) 1660 printf(" Logged in anonymously\r\n"); 1661 else 1662 printf(" Logged in as %s\r\n", pw->pw_name); 1663 } else if (askpasswd) 1664 printf(" Waiting for password\r\n"); 1665 else 1666 printf(" Waiting for user name\r\n"); 1667 printf(" TYPE: %s", typenames[type]); 1668 if (type == TYPE_A || type == TYPE_E) 1669 printf(", FORM: %s", formnames[form]); 1670 if (type == TYPE_L) 1671 #if NBBY == 8 1672 printf(" %d", NBBY); 1673 #else 1674 printf(" %d", bytesize); /* need definition! */ 1675 #endif 1676 printf("; STRUcture: %s; transfer MODE: %s\r\n", 1677 strunames[stru], modenames[mode]); 1678 if (data != -1) 1679 printf(" Data connection open\r\n"); 1680 else if (pdata != -1) { 1681 printf(" in Passive mode"); 1682 sin = &pasv_addr; 1683 goto printaddr; 1684 } else if (usedefault == 0) { 1685 printf(" PORT"); 1686 sin = &data_dest; 1687 printaddr: 1688 a = (u_char *) &sin->sin_addr; 1689 p = (u_char *) &sin->sin_port; 1690 #define UC(b) (((int) b) & 0xff) 1691 printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]), 1692 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 1693 #undef UC 1694 } else 1695 printf(" No data connection\r\n"); 1696 reply(211, "End of status"); 1697 } 1698 1699 void 1700 fatal(s) 1701 char *s; 1702 { 1703 1704 reply(451, "Error in server: %s\n", s); 1705 reply(221, "Closing connection due to server error."); 1706 dologout(0); 1707 /* NOTREACHED */ 1708 } 1709 1710 void 1711 #if __STDC__ 1712 reply(int n, const char *fmt, ...) 1713 #else 1714 reply(n, fmt, va_alist) 1715 int n; 1716 char *fmt; 1717 va_dcl 1718 #endif 1719 { 1720 va_list ap; 1721 #if __STDC__ 1722 va_start(ap, fmt); 1723 #else 1724 va_start(ap); 1725 #endif 1726 (void)printf("%d ", n); 1727 (void)vprintf(fmt, ap); 1728 (void)printf("\r\n"); 1729 (void)fflush(stdout); 1730 if (debug) { 1731 syslog(LOG_DEBUG, "<--- %d ", n); 1732 vsyslog(LOG_DEBUG, fmt, ap); 1733 } 1734 } 1735 1736 void 1737 #if __STDC__ 1738 lreply(int n, const char *fmt, ...) 1739 #else 1740 lreply(n, fmt, va_alist) 1741 int n; 1742 char *fmt; 1743 va_dcl 1744 #endif 1745 { 1746 va_list ap; 1747 #if __STDC__ 1748 va_start(ap, fmt); 1749 #else 1750 va_start(ap); 1751 #endif 1752 (void)printf("%d- ", n); 1753 (void)vprintf(fmt, ap); 1754 (void)printf("\r\n"); 1755 (void)fflush(stdout); 1756 if (debug) { 1757 syslog(LOG_DEBUG, "<--- %d- ", n); 1758 vsyslog(LOG_DEBUG, fmt, ap); 1759 } 1760 } 1761 1762 static void 1763 ack(s) 1764 char *s; 1765 { 1766 1767 reply(250, "%s command successful.", s); 1768 } 1769 1770 void 1771 nack(s) 1772 char *s; 1773 { 1774 1775 reply(502, "%s command not implemented.", s); 1776 } 1777 1778 /* ARGSUSED */ 1779 void 1780 yyerror(s) 1781 char *s; 1782 { 1783 char *cp; 1784 1785 if ((cp = strchr(cbuf,'\n'))) 1786 *cp = '\0'; 1787 reply(500, "'%s': command not understood.", cbuf); 1788 } 1789 1790 void 1791 delete(name) 1792 char *name; 1793 { 1794 struct stat st; 1795 1796 LOGCMD("delete", name); 1797 if (stat(name, &st) < 0) { 1798 perror_reply(550, name); 1799 return; 1800 } 1801 if ((st.st_mode&S_IFMT) == S_IFDIR) { 1802 if (rmdir(name) < 0) { 1803 perror_reply(550, name); 1804 return; 1805 } 1806 goto done; 1807 } 1808 if (unlink(name) < 0) { 1809 perror_reply(550, name); 1810 return; 1811 } 1812 done: 1813 ack("DELE"); 1814 } 1815 1816 void 1817 cwd(path) 1818 char *path; 1819 { 1820 1821 if (chdir(path) < 0) 1822 perror_reply(550, path); 1823 else 1824 ack("CWD"); 1825 } 1826 1827 void 1828 makedir(name) 1829 char *name; 1830 { 1831 1832 LOGCMD("mkdir", name); 1833 if (mkdir(name, 0777) < 0) 1834 perror_reply(550, name); 1835 else 1836 reply(257, "MKD command successful."); 1837 } 1838 1839 void 1840 removedir(name) 1841 char *name; 1842 { 1843 1844 LOGCMD("rmdir", name); 1845 if (rmdir(name) < 0) 1846 perror_reply(550, name); 1847 else 1848 ack("RMD"); 1849 } 1850 1851 void 1852 pwd() 1853 { 1854 char path[MAXPATHLEN + 1]; 1855 1856 if (getwd(path) == (char *)NULL) 1857 reply(550, "%s.", path); 1858 else 1859 reply(257, "\"%s\" is current directory.", path); 1860 } 1861 1862 char * 1863 renamefrom(name) 1864 char *name; 1865 { 1866 struct stat st; 1867 1868 if (stat(name, &st) < 0) { 1869 perror_reply(550, name); 1870 return ((char *)0); 1871 } 1872 reply(350, "File exists, ready for destination name"); 1873 return (name); 1874 } 1875 1876 void 1877 renamecmd(from, to) 1878 char *from, *to; 1879 { 1880 struct stat st; 1881 1882 LOGCMD2("rename", from, to); 1883 1884 if (guest && (stat(to, &st) == 0)) { 1885 reply(550, "%s: permission denied", to); 1886 return; 1887 } 1888 1889 if (rename(from, to) < 0) 1890 perror_reply(550, "rename"); 1891 else 1892 ack("RNTO"); 1893 } 1894 1895 static void 1896 dolog(sin) 1897 struct sockaddr_in *sin; 1898 { 1899 struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr, 1900 sizeof(struct in_addr), AF_INET); 1901 1902 if (hp) 1903 (void) strncpy(remotehost, hp->h_name, sizeof(remotehost)); 1904 else 1905 (void) strncpy(remotehost, inet_ntoa(sin->sin_addr), 1906 sizeof(remotehost)); 1907 #ifdef SETPROCTITLE 1908 #ifdef VIRTUAL_HOSTING 1909 if (thishost != firsthost) 1910 snprintf(proctitle, sizeof(proctitle), "%s: connected (to %s)", 1911 remotehost, hostname); 1912 else 1913 #endif 1914 snprintf(proctitle, sizeof(proctitle), "%s: connected", 1915 remotehost); 1916 setproctitle("%s", proctitle); 1917 #endif /* SETPROCTITLE */ 1918 1919 if (logging) { 1920 #ifdef VIRTUAL_HOSTING 1921 if (thishost != firsthost) 1922 syslog(LOG_INFO, "connection from %s (to %s)", 1923 remotehost, hostname); 1924 else 1925 #endif 1926 syslog(LOG_INFO, "connection from %s (%s)", remotehost, 1927 inet_ntoa(sin->sin_addr)); 1928 } 1929 } 1930 1931 /* 1932 * Record logout in wtmp file 1933 * and exit with supplied status. 1934 */ 1935 void 1936 dologout(status) 1937 int status; 1938 { 1939 /* 1940 * Prevent reception of SIGURG from resulting in a resumption 1941 * back to the main program loop. 1942 */ 1943 transflag = 0; 1944 1945 if (logged_in) { 1946 (void) seteuid((uid_t)0); 1947 ftpd_logwtmp(ttyline, "", ""); 1948 #if defined(KERBEROS) 1949 if (!notickets && krbtkfile_env) 1950 unlink(krbtkfile_env); 1951 #endif 1952 } 1953 /* beware of flushing buffers after a SIGPIPE */ 1954 _exit(status); 1955 } 1956 1957 static void 1958 myoob(signo) 1959 int signo; 1960 { 1961 char *cp; 1962 1963 /* only process if transfer occurring */ 1964 if (!transflag) 1965 return; 1966 cp = tmpline; 1967 if (getline(cp, 7, stdin) == NULL) { 1968 reply(221, "You could at least say goodbye."); 1969 dologout(0); 1970 } 1971 upper(cp); 1972 if (strcmp(cp, "ABOR\r\n") == 0) { 1973 tmpline[0] = '\0'; 1974 reply(426, "Transfer aborted. Data connection closed."); 1975 reply(226, "Abort successful"); 1976 longjmp(urgcatch, 1); 1977 } 1978 if (strcmp(cp, "STAT\r\n") == 0) { 1979 if (file_size != (off_t) -1) 1980 reply(213, "Status: %qd of %qd bytes transferred", 1981 byte_count, file_size); 1982 else 1983 reply(213, "Status: %qd bytes transferred", byte_count); 1984 } 1985 } 1986 1987 /* 1988 * Note: a response of 425 is not mentioned as a possible response to 1989 * the PASV command in RFC959. However, it has been blessed as 1990 * a legitimate response by Jon Postel in a telephone conversation 1991 * with Rick Adams on 25 Jan 89. 1992 */ 1993 void 1994 passive() 1995 { 1996 int len; 1997 char *p, *a; 1998 1999 if (pdata >= 0) /* close old port if one set */ 2000 close(pdata); 2001 2002 pdata = socket(AF_INET, SOCK_STREAM, 0); 2003 if (pdata < 0) { 2004 perror_reply(425, "Can't open passive connection"); 2005 return; 2006 } 2007 2008 (void) seteuid((uid_t)0); 2009 2010 #ifdef IP_PORTRANGE 2011 { 2012 int on = restricted_data_ports ? IP_PORTRANGE_HIGH 2013 : IP_PORTRANGE_DEFAULT; 2014 2015 if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE, 2016 (char *)&on, sizeof(on)) < 0) 2017 goto pasv_error; 2018 } 2019 #endif 2020 2021 pasv_addr = ctrl_addr; 2022 pasv_addr.sin_port = 0; 2023 if (bind(pdata, (struct sockaddr *)&pasv_addr, 2024 sizeof(pasv_addr)) < 0) 2025 goto pasv_error; 2026 2027 (void) seteuid((uid_t)pw->pw_uid); 2028 2029 len = sizeof(pasv_addr); 2030 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) 2031 goto pasv_error; 2032 if (listen(pdata, 1) < 0) 2033 goto pasv_error; 2034 a = (char *) &pasv_addr.sin_addr; 2035 p = (char *) &pasv_addr.sin_port; 2036 2037 #define UC(b) (((int) b) & 0xff) 2038 2039 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), 2040 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 2041 return; 2042 2043 pasv_error: 2044 (void) seteuid((uid_t)pw->pw_uid); 2045 (void) close(pdata); 2046 pdata = -1; 2047 perror_reply(425, "Can't open passive connection"); 2048 return; 2049 } 2050 2051 /* 2052 * Generate unique name for file with basename "local". 2053 * The file named "local" is already known to exist. 2054 * Generates failure reply on error. 2055 */ 2056 static char * 2057 gunique(local) 2058 char *local; 2059 { 2060 static char new[MAXPATHLEN]; 2061 struct stat st; 2062 int count; 2063 char *cp; 2064 2065 cp = strrchr(local, '/'); 2066 if (cp) 2067 *cp = '\0'; 2068 if (stat(cp ? local : ".", &st) < 0) { 2069 perror_reply(553, cp ? local : "."); 2070 return ((char *) 0); 2071 } 2072 if (cp) 2073 *cp = '/'; 2074 /* -4 is for the .nn<null> we put on the end below */ 2075 (void) snprintf(new, sizeof(new) - 4, "%s", local); 2076 cp = new + strlen(new); 2077 *cp++ = '.'; 2078 for (count = 1; count < 100; count++) { 2079 (void)sprintf(cp, "%d", count); 2080 if (stat(new, &st) < 0) 2081 return (new); 2082 } 2083 reply(452, "Unique file name cannot be created."); 2084 return (NULL); 2085 } 2086 2087 /* 2088 * Format and send reply containing system error number. 2089 */ 2090 void 2091 perror_reply(code, string) 2092 int code; 2093 char *string; 2094 { 2095 2096 reply(code, "%s: %s.", string, strerror(errno)); 2097 } 2098 2099 static char *onefile[] = { 2100 "", 2101 0 2102 }; 2103 2104 void 2105 send_file_list(whichf) 2106 char *whichf; 2107 { 2108 struct stat st; 2109 DIR *dirp = NULL; 2110 struct dirent *dir; 2111 FILE *dout = NULL; 2112 char **dirlist, *dirname; 2113 int simple = 0; 2114 int freeglob = 0; 2115 glob_t gl; 2116 2117 if (strpbrk(whichf, "~{[*?") != NULL) { 2118 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; 2119 2120 memset(&gl, 0, sizeof(gl)); 2121 freeglob = 1; 2122 if (glob(whichf, flags, 0, &gl)) { 2123 reply(550, "not found"); 2124 goto out; 2125 } else if (gl.gl_pathc == 0) { 2126 errno = ENOENT; 2127 perror_reply(550, whichf); 2128 goto out; 2129 } 2130 dirlist = gl.gl_pathv; 2131 } else { 2132 onefile[0] = whichf; 2133 dirlist = onefile; 2134 simple = 1; 2135 } 2136 2137 if (setjmp(urgcatch)) { 2138 transflag = 0; 2139 goto out; 2140 } 2141 while ((dirname = *dirlist++)) { 2142 if (stat(dirname, &st) < 0) { 2143 /* 2144 * If user typed "ls -l", etc, and the client 2145 * used NLST, do what the user meant. 2146 */ 2147 if (dirname[0] == '-' && *dirlist == NULL && 2148 transflag == 0) { 2149 retrieve(_PATH_LS " %s", dirname); 2150 goto out; 2151 } 2152 perror_reply(550, whichf); 2153 if (dout != NULL) { 2154 (void) fclose(dout); 2155 transflag = 0; 2156 data = -1; 2157 pdata = -1; 2158 } 2159 goto out; 2160 } 2161 2162 if (S_ISREG(st.st_mode)) { 2163 if (dout == NULL) { 2164 dout = dataconn("file list", (off_t)-1, "w"); 2165 if (dout == NULL) 2166 goto out; 2167 transflag++; 2168 } 2169 fprintf(dout, "%s%s\n", dirname, 2170 type == TYPE_A ? "\r" : ""); 2171 byte_count += strlen(dirname) + 1; 2172 continue; 2173 } else if (!S_ISDIR(st.st_mode)) 2174 continue; 2175 2176 if ((dirp = opendir(dirname)) == NULL) 2177 continue; 2178 2179 while ((dir = readdir(dirp)) != NULL) { 2180 char nbuf[MAXPATHLEN]; 2181 2182 if (dir->d_name[0] == '.' && dir->d_namlen == 1) 2183 continue; 2184 if (dir->d_name[0] == '.' && dir->d_name[1] == '.' && 2185 dir->d_namlen == 2) 2186 continue; 2187 2188 snprintf(nbuf, sizeof(nbuf), 2189 "%s/%s", dirname, dir->d_name); 2190 2191 /* 2192 * We have to do a stat to insure it's 2193 * not a directory or special file. 2194 */ 2195 if (simple || (stat(nbuf, &st) == 0 && 2196 S_ISREG(st.st_mode))) { 2197 if (dout == NULL) { 2198 dout = dataconn("file list", (off_t)-1, 2199 "w"); 2200 if (dout == NULL) 2201 goto out; 2202 transflag++; 2203 } 2204 if (nbuf[0] == '.' && nbuf[1] == '/') 2205 fprintf(dout, "%s%s\n", &nbuf[2], 2206 type == TYPE_A ? "\r" : ""); 2207 else 2208 fprintf(dout, "%s%s\n", nbuf, 2209 type == TYPE_A ? "\r" : ""); 2210 byte_count += strlen(nbuf) + 1; 2211 } 2212 } 2213 (void) closedir(dirp); 2214 } 2215 2216 if (dout == NULL) 2217 reply(550, "No files found."); 2218 else if (ferror(dout) != 0) 2219 perror_reply(550, "Data connection"); 2220 else 2221 reply(226, "Transfer complete."); 2222 2223 transflag = 0; 2224 if (dout != NULL) 2225 (void) fclose(dout); 2226 data = -1; 2227 pdata = -1; 2228 out: 2229 if (freeglob) { 2230 freeglob = 0; 2231 globfree(&gl); 2232 } 2233 } 2234 2235 void 2236 reapchild(signo) 2237 int signo; 2238 { 2239 while (wait3(NULL, WNOHANG, NULL) > 0); 2240 } 2241 2242 #ifdef OLD_SETPROCTITLE 2243 /* 2244 * Clobber argv so ps will show what we're doing. (Stolen from sendmail.) 2245 * Warning, since this is usually started from inetd.conf, it often doesn't 2246 * have much of an environment or arglist to overwrite. 2247 */ 2248 void 2249 #if __STDC__ 2250 setproctitle(const char *fmt, ...) 2251 #else 2252 setproctitle(fmt, va_alist) 2253 char *fmt; 2254 va_dcl 2255 #endif 2256 { 2257 int i; 2258 va_list ap; 2259 char *p, *bp, ch; 2260 char buf[LINE_MAX]; 2261 2262 #if __STDC__ 2263 va_start(ap, fmt); 2264 #else 2265 va_start(ap); 2266 #endif 2267 (void)vsnprintf(buf, sizeof(buf), fmt, ap); 2268 2269 /* make ps print our process name */ 2270 p = Argv[0]; 2271 *p++ = '-'; 2272 2273 i = strlen(buf); 2274 if (i > LastArgv - p - 2) { 2275 i = LastArgv - p - 2; 2276 buf[i] = '\0'; 2277 } 2278 bp = buf; 2279 while (ch = *bp++) 2280 if (ch != '\n' && ch != '\r') 2281 *p++ = ch; 2282 while (p < LastArgv) 2283 *p++ = ' '; 2284 } 2285 #endif /* OLD_SETPROCTITLE */ 2286 2287 static void 2288 logxfer(name, size, start) 2289 char *name; 2290 long size; 2291 long start; 2292 { 2293 char buf[1024]; 2294 char path[MAXPATHLEN + 1]; 2295 time_t now; 2296 2297 if (statfd >= 0 && getwd(path) != NULL) { 2298 time(&now); 2299 snprintf(buf, sizeof(buf), "%.20s!%s!%s!%s/%s!%ld!%ld\n", 2300 ctime(&now)+4, ident, remotehost, 2301 path, name, size, now - start + (now == start)); 2302 write(statfd, buf, strlen(buf)); 2303 } 2304 } 2305