1 /* 2 * Copyright (c) 1985, 1988, 1990 Regents of the University of California. 3 * 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 #ifndef lint 35 char copyright[] = 36 "@(#) Copyright (c) 1985, 1988, 1990 Regents of the University of California.\n\ 37 All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 static char sccsid[] = "@(#)ftpd.c 5.40 (Berkeley) 7/2/91"; 42 #endif /* not lint */ 43 44 /* 45 * FTP server. 46 */ 47 #include <sys/param.h> 48 #include <sys/stat.h> 49 #include <sys/ioctl.h> 50 #include <sys/socket.h> 51 #include <sys/wait.h> 52 53 #include <netinet/in.h> 54 #include <netinet/in_systm.h> 55 #include <netinet/ip.h> 56 57 #define FTP_NAMES 58 #include <arpa/ftp.h> 59 #include <arpa/inet.h> 60 #include <arpa/telnet.h> 61 62 #include <signal.h> 63 #include <dirent.h> 64 #include <fcntl.h> 65 #include <time.h> 66 #include <pwd.h> 67 #include <setjmp.h> 68 #include <netdb.h> 69 #include <errno.h> 70 #include <syslog.h> 71 #include <varargs.h> 72 #include <unistd.h> 73 #include <stdio.h> 74 #include <ctype.h> 75 #include <stdlib.h> 76 #include <string.h> 77 #include "pathnames.h" 78 79 /* 80 * File containing login names 81 * NOT to be used on this machine. 82 * Commonly used to disallow uucp. 83 */ 84 extern int errno; 85 extern char *crypt(); 86 extern char version[]; 87 extern char *home; /* pointer to home directory for glob */ 88 extern FILE *ftpd_popen(), *fopen(), *freopen(); 89 extern int ftpd_pclose(), fclose(); 90 extern char *getline(); 91 extern char cbuf[]; 92 extern off_t restart_point; 93 94 struct sockaddr_in ctrl_addr; 95 struct sockaddr_in data_source; 96 struct sockaddr_in data_dest; 97 struct sockaddr_in his_addr; 98 struct sockaddr_in pasv_addr; 99 100 int data; 101 jmp_buf errcatch, urgcatch; 102 int logged_in; 103 struct passwd *pw; 104 int debug; 105 int timeout = 900; /* timeout after 15 minutes of inactivity */ 106 int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ 107 int logging; 108 int guest; 109 int type; 110 int form; 111 int stru; /* avoid C keyword */ 112 int mode; 113 int usedefault = 1; /* for data transfers */ 114 int pdata = -1; /* for passive mode */ 115 int transflag; 116 off_t file_size; 117 off_t byte_count; 118 #if !defined(CMASK) || CMASK == 0 119 #undef CMASK 120 #define CMASK 027 121 #endif 122 int defumask = CMASK; /* default umask value */ 123 char tmpline[7]; 124 char hostname[MAXHOSTNAMELEN]; 125 char remotehost[MAXHOSTNAMELEN]; 126 127 /* 128 * Timeout intervals for retrying connections 129 * to hosts that don't accept PORT cmds. This 130 * is a kludge, but given the problems with TCP... 131 */ 132 #define SWAITMAX 90 /* wait at most 90 seconds */ 133 #define SWAITINT 5 /* interval between retries */ 134 135 int swaitmax = SWAITMAX; 136 int swaitint = SWAITINT; 137 138 void lostconn(), myoob(); 139 FILE *getdatasock(), *dataconn(); 140 141 #ifdef SETPROCTITLE 142 char **Argv = NULL; /* pointer to argument vector */ 143 char *LastArgv = NULL; /* end of argv */ 144 char proctitle[BUFSIZ]; /* initial part of title */ 145 #endif /* SETPROCTITLE */ 146 147 main(argc, argv, envp) 148 int argc; 149 char *argv[]; 150 char **envp; 151 { 152 int addrlen, on = 1, tos; 153 char *cp; 154 155 /* 156 * LOG_NDELAY sets up the logging connection immediately, 157 * necessary for anonymous ftp's that chroot and can't do it later. 158 */ 159 openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_DAEMON); 160 addrlen = sizeof (his_addr); 161 if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { 162 syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); 163 exit(1); 164 } 165 addrlen = sizeof (ctrl_addr); 166 if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { 167 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); 168 exit(1); 169 } 170 #ifdef IP_TOS 171 tos = IPTOS_LOWDELAY; 172 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) 173 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 174 #endif 175 data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); 176 debug = 0; 177 #ifdef SETPROCTITLE 178 /* 179 * Save start and extent of argv for setproctitle. 180 */ 181 Argv = argv; 182 while (*envp) 183 envp++; 184 LastArgv = envp[-1] + strlen(envp[-1]); 185 #endif /* SETPROCTITLE */ 186 187 argc--, argv++; 188 while (argc > 0 && *argv[0] == '-') { 189 for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { 190 191 case 'v': 192 debug = 1; 193 break; 194 195 case 'd': 196 debug = 1; 197 break; 198 199 case 'l': 200 logging = 1; 201 break; 202 203 case 't': 204 timeout = atoi(++cp); 205 if (maxtimeout < timeout) 206 maxtimeout = timeout; 207 goto nextopt; 208 209 case 'T': 210 maxtimeout = atoi(++cp); 211 if (timeout > maxtimeout) 212 timeout = maxtimeout; 213 goto nextopt; 214 215 case 'u': 216 { 217 int val = 0; 218 219 while (*++cp && *cp >= '0' && *cp <= '9') 220 val = val*8 + *cp - '0'; 221 if (*cp) 222 fprintf(stderr, "ftpd: Bad value for -u\n"); 223 else 224 defumask = val; 225 goto nextopt; 226 } 227 228 default: 229 fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n", 230 *cp); 231 break; 232 } 233 nextopt: 234 argc--, argv++; 235 } 236 (void) freopen(_PATH_DEVNULL, "w", stderr); 237 (void) signal(SIGPIPE, lostconn); 238 (void) signal(SIGCHLD, SIG_IGN); 239 if ((int)signal(SIGURG, myoob) < 0) 240 syslog(LOG_ERR, "signal: %m"); 241 242 /* Try to handle urgent data inline */ 243 #ifdef SO_OOBINLINE 244 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) 245 syslog(LOG_ERR, "setsockopt: %m"); 246 #endif 247 248 #ifdef F_SETOWN 249 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) 250 syslog(LOG_ERR, "fcntl F_SETOWN: %m"); 251 #endif 252 dolog(&his_addr); 253 /* 254 * Set up default state 255 */ 256 data = -1; 257 type = TYPE_A; 258 form = FORM_N; 259 stru = STRU_F; 260 mode = MODE_S; 261 tmpline[0] = '\0'; 262 (void) gethostname(hostname, sizeof (hostname)); 263 reply(220, "%s FTP server (%s) ready.", hostname, version); 264 (void) setjmp(errcatch); 265 for (;;) 266 (void) yyparse(); 267 /* NOTREACHED */ 268 } 269 270 void 271 lostconn() 272 { 273 if (debug) 274 syslog(LOG_DEBUG, "lost connection"); 275 dologout(-1); 276 } 277 278 static char ttyline[20]; 279 280 /* 281 * Helper function for sgetpwnam(). 282 */ 283 char * 284 sgetsave(s) 285 char *s; 286 { 287 char *new = malloc((unsigned) strlen(s) + 1); 288 289 if (new == NULL) { 290 perror_reply(421, "Local resource failure: malloc"); 291 dologout(1); 292 /* NOTREACHED */ 293 } 294 (void) strcpy(new, s); 295 return (new); 296 } 297 298 /* 299 * Save the result of a getpwnam. Used for USER command, since 300 * the data returned must not be clobbered by any other command 301 * (e.g., globbing). 302 */ 303 struct passwd * 304 sgetpwnam(name) 305 char *name; 306 { 307 static struct passwd save; 308 register struct passwd *p; 309 char *sgetsave(); 310 311 if ((p = getpwnam(name)) == NULL) 312 return (p); 313 if (save.pw_name) { 314 free(save.pw_name); 315 free(save.pw_passwd); 316 free(save.pw_gecos); 317 free(save.pw_dir); 318 free(save.pw_shell); 319 } 320 save = *p; 321 save.pw_name = sgetsave(p->pw_name); 322 save.pw_passwd = sgetsave(p->pw_passwd); 323 save.pw_gecos = sgetsave(p->pw_gecos); 324 save.pw_dir = sgetsave(p->pw_dir); 325 save.pw_shell = sgetsave(p->pw_shell); 326 return (&save); 327 } 328 329 int login_attempts; /* number of failed login attempts */ 330 int askpasswd; /* had user command, ask for passwd */ 331 332 /* 333 * USER command. 334 * Sets global passwd pointer pw if named account exists and is acceptable; 335 * sets askpasswd if a PASS command is expected. If logged in previously, 336 * need to reset state. If name is "ftp" or "anonymous", the name is not in 337 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return. 338 * If account doesn't exist, ask for passwd anyway. Otherwise, check user 339 * requesting login privileges. Disallow anyone who does not have a standard 340 * shell as returned by getusershell(). Disallow anyone mentioned in the file 341 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. 342 */ 343 user(name) 344 char *name; 345 { 346 register char *cp; 347 char *shell; 348 char *getusershell(); 349 350 if (logged_in) { 351 if (guest) { 352 reply(530, "Can't change user from guest login."); 353 return; 354 } 355 end_login(); 356 } 357 358 guest = 0; 359 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { 360 if (checkuser("ftp") || checkuser("anonymous")) 361 reply(530, "User %s access denied.", name); 362 else if ((pw = sgetpwnam("ftp")) != NULL) { 363 guest = 1; 364 askpasswd = 1; 365 reply(331, "Guest login ok, send ident as password."); 366 } else 367 reply(530, "User %s unknown.", name); 368 return; 369 } 370 if (pw = sgetpwnam(name)) { 371 if ((shell = pw->pw_shell) == NULL || *shell == 0) 372 shell = _PATH_BSHELL; 373 while ((cp = getusershell()) != NULL) 374 if (strcmp(cp, shell) == 0) 375 break; 376 endusershell(); 377 if (cp == NULL || checkuser(name)) { 378 reply(530, "User %s access denied.", name); 379 if (logging) 380 syslog(LOG_NOTICE, 381 "FTP LOGIN REFUSED FROM %s, %s", 382 remotehost, name); 383 pw = (struct passwd *) NULL; 384 return; 385 } 386 } 387 reply(331, "Password required for %s.", name); 388 askpasswd = 1; 389 /* 390 * Delay before reading passwd after first failed 391 * attempt to slow down passwd-guessing programs. 392 */ 393 if (login_attempts) 394 sleep((unsigned) login_attempts); 395 } 396 397 /* 398 * Check if a user is in the file _PATH_FTPUSERS 399 */ 400 checkuser(name) 401 char *name; 402 { 403 register FILE *fd; 404 register char *p; 405 char line[BUFSIZ]; 406 407 if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) { 408 while (fgets(line, sizeof(line), fd) != NULL) 409 if ((p = index(line, '\n')) != NULL) { 410 *p = '\0'; 411 if (line[0] == '#') 412 continue; 413 if (strcmp(line, name) == 0) 414 return (1); 415 } 416 (void) fclose(fd); 417 } 418 return (0); 419 } 420 421 /* 422 * Terminate login as previous user, if any, resetting state; 423 * used when USER command is given or login fails. 424 */ 425 end_login() 426 { 427 428 (void) seteuid((uid_t)0); 429 if (logged_in) 430 logwtmp(ttyline, "", ""); 431 pw = NULL; 432 logged_in = 0; 433 guest = 0; 434 } 435 436 pass(passwd) 437 char *passwd; 438 { 439 char *xpasswd, *salt; 440 441 if (logged_in || askpasswd == 0) { 442 reply(503, "Login with USER first."); 443 return; 444 } 445 askpasswd = 0; 446 if (!guest) { /* "ftp" is only account allowed no password */ 447 if (pw == NULL) 448 salt = "xx"; 449 else 450 salt = pw->pw_passwd; 451 xpasswd = crypt(passwd, salt); 452 /* The strcmp does not catch null passwords! */ 453 if (pw == NULL || *pw->pw_passwd == '\0' || 454 strcmp(xpasswd, pw->pw_passwd)) { 455 reply(530, "Login incorrect."); 456 pw = NULL; 457 if (login_attempts++ >= 5) { 458 syslog(LOG_NOTICE, 459 "repeated login failures from %s", 460 remotehost); 461 exit(0); 462 } 463 return; 464 } 465 } 466 login_attempts = 0; /* this time successful */ 467 (void) setegid((gid_t)pw->pw_gid); 468 (void) initgroups(pw->pw_name, pw->pw_gid); 469 470 /* open wtmp before chroot */ 471 (void)sprintf(ttyline, "ftp%d", getpid()); 472 logwtmp(ttyline, pw->pw_name, remotehost); 473 logged_in = 1; 474 475 if (guest) { 476 /* 477 * We MUST do a chdir() after the chroot. Otherwise 478 * the old current directory will be accessible as "." 479 * outside the new root! 480 */ 481 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { 482 reply(550, "Can't set guest privileges."); 483 goto bad; 484 } 485 } else if (chdir(pw->pw_dir) < 0) { 486 if (chdir("/") < 0) { 487 reply(530, "User %s: can't change directory to %s.", 488 pw->pw_name, pw->pw_dir); 489 goto bad; 490 } else 491 lreply(230, "No directory! Logging in with home=/"); 492 } 493 if (seteuid((uid_t)pw->pw_uid) < 0) { 494 reply(550, "Can't set uid."); 495 goto bad; 496 } 497 if (guest) { 498 reply(230, "Guest login ok, access restrictions apply."); 499 #ifdef SETPROCTITLE 500 sprintf(proctitle, "%s: anonymous/%.*s", remotehost, 501 sizeof(proctitle) - sizeof(remotehost) - 502 sizeof(": anonymous/"), passwd); 503 setproctitle(proctitle); 504 #endif /* SETPROCTITLE */ 505 if (logging) 506 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s", 507 remotehost, passwd); 508 } else { 509 reply(230, "User %s logged in.", pw->pw_name); 510 #ifdef SETPROCTITLE 511 sprintf(proctitle, "%s: %s", remotehost, pw->pw_name); 512 setproctitle(proctitle); 513 #endif /* SETPROCTITLE */ 514 if (logging) 515 syslog(LOG_INFO, "FTP LOGIN FROM %s, %s", 516 remotehost, pw->pw_name); 517 } 518 home = pw->pw_dir; /* home dir for globbing */ 519 (void) umask(defumask); 520 return; 521 bad: 522 /* Forget all about it... */ 523 end_login(); 524 } 525 526 retrieve(cmd, name) 527 char *cmd, *name; 528 { 529 FILE *fin, *dout; 530 struct stat st; 531 int (*closefunc)(); 532 533 if (cmd == 0) { 534 fin = fopen(name, "r"), closefunc = fclose; 535 st.st_size = 0; 536 } else { 537 char line[BUFSIZ]; 538 539 (void) sprintf(line, cmd, name), name = line; 540 fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose; 541 st.st_size = -1; 542 st.st_blksize = BUFSIZ; 543 } 544 if (fin == NULL) { 545 if (errno != 0) 546 perror_reply(550, name); 547 return; 548 } 549 if (cmd == 0 && 550 (fstat(fileno(fin), &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) { 551 reply(550, "%s: not a plain file.", name); 552 goto done; 553 } 554 if (restart_point) { 555 if (type == TYPE_A) { 556 register int i, n, c; 557 558 n = restart_point; 559 i = 0; 560 while (i++ < n) { 561 if ((c=getc(fin)) == EOF) { 562 perror_reply(550, name); 563 goto done; 564 } 565 if (c == '\n') 566 i++; 567 } 568 } else if (lseek(fileno(fin), restart_point, L_SET) < 0) { 569 perror_reply(550, name); 570 goto done; 571 } 572 } 573 dout = dataconn(name, st.st_size, "w"); 574 if (dout == NULL) 575 goto done; 576 send_data(fin, dout, st.st_blksize); 577 (void) fclose(dout); 578 data = -1; 579 pdata = -1; 580 done: 581 (*closefunc)(fin); 582 } 583 584 store(name, mode, unique) 585 char *name, *mode; 586 int unique; 587 { 588 FILE *fout, *din; 589 struct stat st; 590 int (*closefunc)(); 591 char *gunique(); 592 593 if (unique && stat(name, &st) == 0 && 594 (name = gunique(name)) == NULL) 595 return; 596 597 if (restart_point) 598 mode = "r+w"; 599 fout = fopen(name, mode); 600 closefunc = fclose; 601 if (fout == NULL) { 602 perror_reply(553, name); 603 return; 604 } 605 if (restart_point) { 606 if (type == TYPE_A) { 607 register int i, n, c; 608 609 n = restart_point; 610 i = 0; 611 while (i++ < n) { 612 if ((c=getc(fout)) == EOF) { 613 perror_reply(550, name); 614 goto done; 615 } 616 if (c == '\n') 617 i++; 618 } 619 /* 620 * We must do this seek to "current" position 621 * because we are changing from reading to 622 * writing. 623 */ 624 if (fseek(fout, 0L, L_INCR) < 0) { 625 perror_reply(550, name); 626 goto done; 627 } 628 } else if (lseek(fileno(fout), restart_point, L_SET) < 0) { 629 perror_reply(550, name); 630 goto done; 631 } 632 } 633 din = dataconn(name, (off_t)-1, "r"); 634 if (din == NULL) 635 goto done; 636 if (receive_data(din, fout) == 0) { 637 if (unique) 638 reply(226, "Transfer complete (unique file name:%s).", 639 name); 640 else 641 reply(226, "Transfer complete."); 642 } 643 (void) fclose(din); 644 data = -1; 645 pdata = -1; 646 done: 647 (*closefunc)(fout); 648 } 649 650 FILE * 651 getdatasock(mode) 652 char *mode; 653 { 654 int s, on = 1, tries; 655 656 if (data >= 0) 657 return (fdopen(data, mode)); 658 (void) seteuid((uid_t)0); 659 s = socket(AF_INET, SOCK_STREAM, 0); 660 if (s < 0) 661 goto bad; 662 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 663 (char *) &on, sizeof (on)) < 0) 664 goto bad; 665 /* anchor socket to avoid multi-homing problems */ 666 data_source.sin_family = AF_INET; 667 data_source.sin_addr = ctrl_addr.sin_addr; 668 for (tries = 1; ; tries++) { 669 if (bind(s, (struct sockaddr *)&data_source, 670 sizeof (data_source)) >= 0) 671 break; 672 if (errno != EADDRINUSE || tries > 10) 673 goto bad; 674 sleep(tries); 675 } 676 (void) seteuid((uid_t)pw->pw_uid); 677 #ifdef IP_TOS 678 on = IPTOS_THROUGHPUT; 679 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 680 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 681 #endif 682 return (fdopen(s, mode)); 683 bad: 684 (void) seteuid((uid_t)pw->pw_uid); 685 (void) close(s); 686 return (NULL); 687 } 688 689 FILE * 690 dataconn(name, size, mode) 691 char *name; 692 off_t size; 693 char *mode; 694 { 695 char sizebuf[32]; 696 FILE *file; 697 int retry = 0, tos; 698 699 file_size = size; 700 byte_count = 0; 701 if (size != (off_t) -1) 702 (void) sprintf (sizebuf, " (%ld bytes)", size); 703 else 704 (void) strcpy(sizebuf, ""); 705 if (pdata >= 0) { 706 struct sockaddr_in from; 707 int s, fromlen = sizeof(from); 708 709 s = accept(pdata, (struct sockaddr *)&from, &fromlen); 710 if (s < 0) { 711 reply(425, "Can't open data connection."); 712 (void) close(pdata); 713 pdata = -1; 714 return(NULL); 715 } 716 (void) close(pdata); 717 pdata = s; 718 #ifdef IP_TOS 719 tos = IPTOS_LOWDELAY; 720 (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, 721 sizeof(int)); 722 #endif 723 reply(150, "Opening %s mode data connection for %s%s.", 724 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 725 return(fdopen(pdata, mode)); 726 } 727 if (data >= 0) { 728 reply(125, "Using existing data connection for %s%s.", 729 name, sizebuf); 730 usedefault = 1; 731 return (fdopen(data, mode)); 732 } 733 if (usedefault) 734 data_dest = his_addr; 735 usedefault = 1; 736 file = getdatasock(mode); 737 if (file == NULL) { 738 reply(425, "Can't create data socket (%s,%d): %s.", 739 inet_ntoa(data_source.sin_addr), 740 ntohs(data_source.sin_port), strerror(errno)); 741 return (NULL); 742 } 743 data = fileno(file); 744 while (connect(data, (struct sockaddr *)&data_dest, 745 sizeof (data_dest)) < 0) { 746 if (errno == EADDRINUSE && retry < swaitmax) { 747 sleep((unsigned) swaitint); 748 retry += swaitint; 749 continue; 750 } 751 perror_reply(425, "Can't build data connection"); 752 (void) fclose(file); 753 data = -1; 754 return (NULL); 755 } 756 reply(150, "Opening %s mode data connection for %s%s.", 757 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 758 return (file); 759 } 760 761 /* 762 * Tranfer the contents of "instr" to 763 * "outstr" peer using the appropriate 764 * encapsulation of the data subject 765 * to Mode, Structure, and Type. 766 * 767 * NB: Form isn't handled. 768 */ 769 send_data(instr, outstr, blksize) 770 FILE *instr, *outstr; 771 off_t blksize; 772 { 773 register int c, cnt; 774 register char *buf; 775 int netfd, filefd; 776 777 transflag++; 778 if (setjmp(urgcatch)) { 779 transflag = 0; 780 return; 781 } 782 switch (type) { 783 784 case TYPE_A: 785 while ((c = getc(instr)) != EOF) { 786 byte_count++; 787 if (c == '\n') { 788 if (ferror(outstr)) 789 goto data_err; 790 (void) putc('\r', outstr); 791 } 792 (void) putc(c, outstr); 793 } 794 fflush(outstr); 795 transflag = 0; 796 if (ferror(instr)) 797 goto file_err; 798 if (ferror(outstr)) 799 goto data_err; 800 reply(226, "Transfer complete."); 801 return; 802 803 case TYPE_I: 804 case TYPE_L: 805 if ((buf = malloc((u_int)blksize)) == NULL) { 806 transflag = 0; 807 perror_reply(451, "Local resource failure: malloc"); 808 return; 809 } 810 netfd = fileno(outstr); 811 filefd = fileno(instr); 812 while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 && 813 write(netfd, buf, cnt) == cnt) 814 byte_count += cnt; 815 transflag = 0; 816 (void)free(buf); 817 if (cnt != 0) { 818 if (cnt < 0) 819 goto file_err; 820 goto data_err; 821 } 822 reply(226, "Transfer complete."); 823 return; 824 default: 825 transflag = 0; 826 reply(550, "Unimplemented TYPE %d in send_data", type); 827 return; 828 } 829 830 data_err: 831 transflag = 0; 832 perror_reply(426, "Data connection"); 833 return; 834 835 file_err: 836 transflag = 0; 837 perror_reply(551, "Error on input file"); 838 } 839 840 /* 841 * Transfer data from peer to 842 * "outstr" using the appropriate 843 * encapulation of the data subject 844 * to Mode, Structure, and Type. 845 * 846 * N.B.: Form isn't handled. 847 */ 848 receive_data(instr, outstr) 849 FILE *instr, *outstr; 850 { 851 register int c; 852 int cnt, bare_lfs = 0; 853 char buf[BUFSIZ]; 854 855 transflag++; 856 if (setjmp(urgcatch)) { 857 transflag = 0; 858 return (-1); 859 } 860 switch (type) { 861 862 case TYPE_I: 863 case TYPE_L: 864 while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) { 865 if (write(fileno(outstr), buf, cnt) != cnt) 866 goto file_err; 867 byte_count += cnt; 868 } 869 if (cnt < 0) 870 goto data_err; 871 transflag = 0; 872 return (0); 873 874 case TYPE_E: 875 reply(553, "TYPE E not implemented."); 876 transflag = 0; 877 return (-1); 878 879 case TYPE_A: 880 while ((c = getc(instr)) != EOF) { 881 byte_count++; 882 if (c == '\n') 883 bare_lfs++; 884 while (c == '\r') { 885 if (ferror(outstr)) 886 goto data_err; 887 if ((c = getc(instr)) != '\n') { 888 (void) putc ('\r', outstr); 889 if (c == '\0' || c == EOF) 890 goto contin2; 891 } 892 } 893 (void) putc(c, outstr); 894 contin2: ; 895 } 896 fflush(outstr); 897 if (ferror(instr)) 898 goto data_err; 899 if (ferror(outstr)) 900 goto file_err; 901 transflag = 0; 902 if (bare_lfs) { 903 lreply(230, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs); 904 printf(" File may not have transferred correctly.\r\n"); 905 } 906 return (0); 907 default: 908 reply(550, "Unimplemented TYPE %d in receive_data", type); 909 transflag = 0; 910 return (-1); 911 } 912 913 data_err: 914 transflag = 0; 915 perror_reply(426, "Data Connection"); 916 return (-1); 917 918 file_err: 919 transflag = 0; 920 perror_reply(452, "Error writing file"); 921 return (-1); 922 } 923 924 statfilecmd(filename) 925 char *filename; 926 { 927 char line[BUFSIZ]; 928 FILE *fin; 929 int c; 930 931 (void) sprintf(line, "/bin/ls -lgA %s", filename); 932 fin = ftpd_popen(line, "r"); 933 lreply(211, "status of %s:", filename); 934 while ((c = getc(fin)) != EOF) { 935 if (c == '\n') { 936 if (ferror(stdout)){ 937 perror_reply(421, "control connection"); 938 (void) ftpd_pclose(fin); 939 dologout(1); 940 /* NOTREACHED */ 941 } 942 if (ferror(fin)) { 943 perror_reply(551, filename); 944 (void) ftpd_pclose(fin); 945 return; 946 } 947 (void) putc('\r', stdout); 948 } 949 (void) putc(c, stdout); 950 } 951 (void) ftpd_pclose(fin); 952 reply(211, "End of Status"); 953 } 954 955 statcmd() 956 { 957 struct sockaddr_in *sin; 958 u_char *a, *p; 959 960 lreply(211, "%s FTP server status:", hostname, version); 961 printf(" %s\r\n", version); 962 printf(" Connected to %s", remotehost); 963 if (!isdigit(remotehost[0])) 964 printf(" (%s)", inet_ntoa(his_addr.sin_addr)); 965 printf("\r\n"); 966 if (logged_in) { 967 if (guest) 968 printf(" Logged in anonymously\r\n"); 969 else 970 printf(" Logged in as %s\r\n", pw->pw_name); 971 } else if (askpasswd) 972 printf(" Waiting for password\r\n"); 973 else 974 printf(" Waiting for user name\r\n"); 975 printf(" TYPE: %s", typenames[type]); 976 if (type == TYPE_A || type == TYPE_E) 977 printf(", FORM: %s", formnames[form]); 978 if (type == TYPE_L) 979 #if NBBY == 8 980 printf(" %d", NBBY); 981 #else 982 printf(" %d", bytesize); /* need definition! */ 983 #endif 984 printf("; STRUcture: %s; transfer MODE: %s\r\n", 985 strunames[stru], modenames[mode]); 986 if (data != -1) 987 printf(" Data connection open\r\n"); 988 else if (pdata != -1) { 989 printf(" in Passive mode"); 990 sin = &pasv_addr; 991 goto printaddr; 992 } else if (usedefault == 0) { 993 printf(" PORT"); 994 sin = &data_dest; 995 printaddr: 996 a = (u_char *) &sin->sin_addr; 997 p = (u_char *) &sin->sin_port; 998 #define UC(b) (((int) b) & 0xff) 999 printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]), 1000 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 1001 #undef UC 1002 } else 1003 printf(" No data connection\r\n"); 1004 reply(211, "End of status"); 1005 } 1006 1007 fatal(s) 1008 char *s; 1009 { 1010 reply(451, "Error in server: %s\n", s); 1011 reply(221, "Closing connection due to server error."); 1012 dologout(0); 1013 /* NOTREACHED */ 1014 } 1015 1016 /* VARARGS2 */ 1017 reply(n, fmt, p0, p1, p2, p3, p4, p5) 1018 int n; 1019 char *fmt; 1020 { 1021 printf("%d ", n); 1022 printf(fmt, p0, p1, p2, p3, p4, p5); 1023 printf("\r\n"); 1024 (void)fflush(stdout); 1025 if (debug) { 1026 syslog(LOG_DEBUG, "<--- %d ", n); 1027 syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5); 1028 } 1029 } 1030 1031 /* VARARGS2 */ 1032 lreply(n, fmt, p0, p1, p2, p3, p4, p5) 1033 int n; 1034 char *fmt; 1035 { 1036 printf("%d- ", n); 1037 printf(fmt, p0, p1, p2, p3, p4, p5); 1038 printf("\r\n"); 1039 (void)fflush(stdout); 1040 if (debug) { 1041 syslog(LOG_DEBUG, "<--- %d- ", n); 1042 syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5); 1043 } 1044 } 1045 1046 ack(s) 1047 char *s; 1048 { 1049 reply(250, "%s command successful.", s); 1050 } 1051 1052 nack(s) 1053 char *s; 1054 { 1055 reply(502, "%s command not implemented.", s); 1056 } 1057 1058 /* ARGSUSED */ 1059 yyerror(s) 1060 char *s; 1061 { 1062 char *cp; 1063 1064 if (cp = index(cbuf,'\n')) 1065 *cp = '\0'; 1066 reply(500, "'%s': command not understood.", cbuf); 1067 } 1068 1069 delete(name) 1070 char *name; 1071 { 1072 struct stat st; 1073 1074 if (stat(name, &st) < 0) { 1075 perror_reply(550, name); 1076 return; 1077 } 1078 if ((st.st_mode&S_IFMT) == S_IFDIR) { 1079 if (rmdir(name) < 0) { 1080 perror_reply(550, name); 1081 return; 1082 } 1083 goto done; 1084 } 1085 if (unlink(name) < 0) { 1086 perror_reply(550, name); 1087 return; 1088 } 1089 done: 1090 ack("DELE"); 1091 } 1092 1093 cwd(path) 1094 char *path; 1095 { 1096 if (chdir(path) < 0) 1097 perror_reply(550, path); 1098 else 1099 ack("CWD"); 1100 } 1101 1102 makedir(name) 1103 char *name; 1104 { 1105 if (mkdir(name, 0777) < 0) 1106 perror_reply(550, name); 1107 else 1108 reply(257, "MKD command successful."); 1109 } 1110 1111 removedir(name) 1112 char *name; 1113 { 1114 if (rmdir(name) < 0) 1115 perror_reply(550, name); 1116 else 1117 ack("RMD"); 1118 } 1119 1120 pwd() 1121 { 1122 char path[MAXPATHLEN + 1]; 1123 extern char *getwd(); 1124 1125 if (getwd(path) == (char *)NULL) 1126 reply(550, "%s.", path); 1127 else 1128 reply(257, "\"%s\" is current directory.", path); 1129 } 1130 1131 char * 1132 renamefrom(name) 1133 char *name; 1134 { 1135 struct stat st; 1136 1137 if (stat(name, &st) < 0) { 1138 perror_reply(550, name); 1139 return ((char *)0); 1140 } 1141 reply(350, "File exists, ready for destination name"); 1142 return (name); 1143 } 1144 1145 renamecmd(from, to) 1146 char *from, *to; 1147 { 1148 if (rename(from, to) < 0) 1149 perror_reply(550, "rename"); 1150 else 1151 ack("RNTO"); 1152 } 1153 1154 dolog(sin) 1155 struct sockaddr_in *sin; 1156 { 1157 struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr, 1158 sizeof (struct in_addr), AF_INET); 1159 time_t t, time(); 1160 extern char *ctime(); 1161 1162 if (hp) 1163 (void) strncpy(remotehost, hp->h_name, sizeof (remotehost)); 1164 else 1165 (void) strncpy(remotehost, inet_ntoa(sin->sin_addr), 1166 sizeof (remotehost)); 1167 #ifdef SETPROCTITLE 1168 sprintf(proctitle, "%s: connected", remotehost); 1169 setproctitle(proctitle); 1170 #endif /* SETPROCTITLE */ 1171 1172 if (logging) { 1173 t = time((time_t *) 0); 1174 syslog(LOG_INFO, "connection from %s at %s", 1175 remotehost, ctime(&t)); 1176 } 1177 } 1178 1179 /* 1180 * Record logout in wtmp file 1181 * and exit with supplied status. 1182 */ 1183 dologout(status) 1184 int status; 1185 { 1186 if (logged_in) { 1187 (void) seteuid((uid_t)0); 1188 logwtmp(ttyline, "", ""); 1189 } 1190 /* beware of flushing buffers after a SIGPIPE */ 1191 _exit(status); 1192 } 1193 1194 void 1195 myoob() 1196 { 1197 char *cp; 1198 1199 /* only process if transfer occurring */ 1200 if (!transflag) 1201 return; 1202 cp = tmpline; 1203 if (getline(cp, 7, stdin) == NULL) { 1204 reply(221, "You could at least say goodbye."); 1205 dologout(0); 1206 } 1207 upper(cp); 1208 if (strcmp(cp, "ABOR\r\n") == 0) { 1209 tmpline[0] = '\0'; 1210 reply(426, "Transfer aborted. Data connection closed."); 1211 reply(226, "Abort successful"); 1212 longjmp(urgcatch, 1); 1213 } 1214 if (strcmp(cp, "STAT\r\n") == 0) { 1215 if (file_size != (off_t) -1) 1216 reply(213, "Status: %lu of %lu bytes transferred", 1217 byte_count, file_size); 1218 else 1219 reply(213, "Status: %lu bytes transferred", byte_count); 1220 } 1221 } 1222 1223 /* 1224 * Note: a response of 425 is not mentioned as a possible response to 1225 * the PASV command in RFC959. However, it has been blessed as 1226 * a legitimate response by Jon Postel in a telephone conversation 1227 * with Rick Adams on 25 Jan 89. 1228 */ 1229 passive() 1230 { 1231 int len; 1232 register char *p, *a; 1233 1234 pdata = socket(AF_INET, SOCK_STREAM, 0); 1235 if (pdata < 0) { 1236 perror_reply(425, "Can't open passive connection"); 1237 return; 1238 } 1239 pasv_addr = ctrl_addr; 1240 pasv_addr.sin_port = 0; 1241 (void) seteuid((uid_t)0); 1242 if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) { 1243 (void) seteuid((uid_t)pw->pw_uid); 1244 goto pasv_error; 1245 } 1246 (void) seteuid((uid_t)pw->pw_uid); 1247 len = sizeof(pasv_addr); 1248 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) 1249 goto pasv_error; 1250 if (listen(pdata, 1) < 0) 1251 goto pasv_error; 1252 a = (char *) &pasv_addr.sin_addr; 1253 p = (char *) &pasv_addr.sin_port; 1254 1255 #define UC(b) (((int) b) & 0xff) 1256 1257 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), 1258 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 1259 return; 1260 1261 pasv_error: 1262 (void) close(pdata); 1263 pdata = -1; 1264 perror_reply(425, "Can't open passive connection"); 1265 return; 1266 } 1267 1268 /* 1269 * Generate unique name for file with basename "local". 1270 * The file named "local" is already known to exist. 1271 * Generates failure reply on error. 1272 */ 1273 char * 1274 gunique(local) 1275 char *local; 1276 { 1277 static char new[MAXPATHLEN]; 1278 struct stat st; 1279 char *cp = rindex(local, '/'); 1280 int count = 0; 1281 1282 if (cp) 1283 *cp = '\0'; 1284 if (stat(cp ? local : ".", &st) < 0) { 1285 perror_reply(553, cp ? local : "."); 1286 return((char *) 0); 1287 } 1288 if (cp) 1289 *cp = '/'; 1290 (void) strcpy(new, local); 1291 cp = new + strlen(new); 1292 *cp++ = '.'; 1293 for (count = 1; count < 100; count++) { 1294 (void) sprintf(cp, "%d", count); 1295 if (stat(new, &st) < 0) 1296 return(new); 1297 } 1298 reply(452, "Unique file name cannot be created."); 1299 return((char *) 0); 1300 } 1301 1302 /* 1303 * Format and send reply containing system error number. 1304 */ 1305 perror_reply(code, string) 1306 int code; 1307 char *string; 1308 { 1309 reply(code, "%s: %s.", string, strerror(errno)); 1310 } 1311 1312 static char *onefile[] = { 1313 "", 1314 0 1315 }; 1316 1317 send_file_list(whichfiles) 1318 char *whichfiles; 1319 { 1320 struct stat st; 1321 DIR *dirp = NULL; 1322 struct dirent *dir; 1323 FILE *dout = NULL; 1324 register char **dirlist, *dirname; 1325 int simple = 0; 1326 char *strpbrk(); 1327 1328 if (strpbrk(whichfiles, "~{[*?") != NULL) { 1329 extern char **ftpglob(), *globerr; 1330 1331 globerr = NULL; 1332 dirlist = ftpglob(whichfiles); 1333 if (globerr != NULL) { 1334 reply(550, globerr); 1335 return; 1336 } else if (dirlist == NULL) { 1337 errno = ENOENT; 1338 perror_reply(550, whichfiles); 1339 return; 1340 } 1341 } else { 1342 onefile[0] = whichfiles; 1343 dirlist = onefile; 1344 simple = 1; 1345 } 1346 1347 if (setjmp(urgcatch)) { 1348 transflag = 0; 1349 return; 1350 } 1351 while (dirname = *dirlist++) { 1352 if (stat(dirname, &st) < 0) { 1353 /* 1354 * If user typed "ls -l", etc, and the client 1355 * used NLST, do what the user meant. 1356 */ 1357 if (dirname[0] == '-' && *dirlist == NULL && 1358 transflag == 0) { 1359 retrieve("/bin/ls %s", dirname); 1360 return; 1361 } 1362 perror_reply(550, whichfiles); 1363 if (dout != NULL) { 1364 (void) fclose(dout); 1365 transflag = 0; 1366 data = -1; 1367 pdata = -1; 1368 } 1369 return; 1370 } 1371 1372 if ((st.st_mode&S_IFMT) == S_IFREG) { 1373 if (dout == NULL) { 1374 dout = dataconn("file list", (off_t)-1, "w"); 1375 if (dout == NULL) 1376 return; 1377 transflag++; 1378 } 1379 fprintf(dout, "%s%s\n", dirname, 1380 type == TYPE_A ? "\r" : ""); 1381 byte_count += strlen(dirname) + 1; 1382 continue; 1383 } else if ((st.st_mode&S_IFMT) != S_IFDIR) 1384 continue; 1385 1386 if ((dirp = opendir(dirname)) == NULL) 1387 continue; 1388 1389 while ((dir = readdir(dirp)) != NULL) { 1390 char nbuf[MAXPATHLEN]; 1391 1392 if (dir->d_name[0] == '.' && dir->d_namlen == 1) 1393 continue; 1394 if (dir->d_name[0] == '.' && dir->d_name[1] == '.' && 1395 dir->d_namlen == 2) 1396 continue; 1397 1398 sprintf(nbuf, "%s/%s", dirname, dir->d_name); 1399 1400 /* 1401 * We have to do a stat to insure it's 1402 * not a directory or special file. 1403 */ 1404 if (simple || (stat(nbuf, &st) == 0 && 1405 (st.st_mode&S_IFMT) == S_IFREG)) { 1406 if (dout == NULL) { 1407 dout = dataconn("file list", (off_t)-1, 1408 "w"); 1409 if (dout == NULL) 1410 return; 1411 transflag++; 1412 } 1413 if (nbuf[0] == '.' && nbuf[1] == '/') 1414 fprintf(dout, "%s%s\n", &nbuf[2], 1415 type == TYPE_A ? "\r" : ""); 1416 else 1417 fprintf(dout, "%s%s\n", nbuf, 1418 type == TYPE_A ? "\r" : ""); 1419 byte_count += strlen(nbuf) + 1; 1420 } 1421 } 1422 (void) closedir(dirp); 1423 } 1424 1425 if (dout == NULL) 1426 reply(550, "No files found."); 1427 else if (ferror(dout) != 0) 1428 perror_reply(550, "Data connection"); 1429 else 1430 reply(226, "Transfer complete."); 1431 1432 transflag = 0; 1433 if (dout != NULL) 1434 (void) fclose(dout); 1435 data = -1; 1436 pdata = -1; 1437 } 1438 1439 #ifdef SETPROCTITLE 1440 /* 1441 * clobber argv so ps will show what we're doing. 1442 * (stolen from sendmail) 1443 * warning, since this is usually started from inetd.conf, it 1444 * often doesn't have much of an environment or arglist to overwrite. 1445 */ 1446 1447 /*VARARGS1*/ 1448 setproctitle(fmt, a, b, c) 1449 char *fmt; 1450 { 1451 register char *p, *bp, ch; 1452 register int i; 1453 char buf[BUFSIZ]; 1454 1455 (void) sprintf(buf, fmt, a, b, c); 1456 1457 /* make ps print our process name */ 1458 p = Argv[0]; 1459 *p++ = '-'; 1460 1461 i = strlen(buf); 1462 if (i > LastArgv - p - 2) { 1463 i = LastArgv - p - 2; 1464 buf[i] = '\0'; 1465 } 1466 bp = buf; 1467 while (ch = *bp++) 1468 if (ch != '\n' && ch != '\r') 1469 *p++ = ch; 1470 while (p < LastArgv) 1471 *p++ = ' '; 1472 } 1473 #endif /* SETPROCTITLE */ 1474