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