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