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