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