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