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