|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)ftpd.c 4.28 (Berkeley) 9/22/83"; ! 3: #endif ! 4: ! 5: #define CHOOSE_PORT ! 6: #define DEBUG ! 7: /* ! 8: * FTP server. ! 9: */ ! 10: #include <sys/param.h> ! 11: #include <sys/stat.h> ! 12: #include <sys/file.h> ! 13: #include <wait.h> ! 14: ! 15: #include <sys/inet/in.h> ! 16: #include <sys/inet/tcp_user.h> ! 17: ! 18: #include <stdio.h> ! 19: #include <signal.h> ! 20: #include <pwd.h> ! 21: #include <setjmp.h> ! 22: #include <errno.h> ! 23: #include <utsname.h> ! 24: ! 25: #include <libc.h> ! 26: ! 27: #include "ftp.h" ! 28: ! 29: /* ! 30: * File containing login names ! 31: * NOT to be used on this machine. ! 32: * Commonly used to disallow uucp. ! 33: */ ! 34: #define CTLPORT 21 ! 35: ! 36: extern int errno; ! 37: extern char *sys_errlist[]; ! 38: extern char *crypt(); ! 39: extern FILE *popen(), *fopen(); ! 40: extern int pclose(), fclose(); ! 41: ! 42: char *defdest; ! 43: extern char dest[]; ! 44: ! 45: int data; ! 46: jmp_buf errcatch; ! 47: int logged_in; ! 48: struct passwd *pw; ! 49: int debug; ! 50: int timeout; ! 51: int logging; ! 52: int type; ! 53: int form; ! 54: int stru; /* avoid C keyword */ ! 55: int mode; ! 56: int usedefault = 1; /* for data transfers */ ! 57: char hostname[32]; ! 58: char remotehost[32]; ! 59: int pasv; ! 60: char *home; /* pointer to home directory for glob */ ! 61: ! 62: /* ! 63: * Timeout intervals for retrying connections ! 64: * to hosts that don't accept PORT cmds. This ! 65: * is a kludge, but given the problems with TCP... ! 66: */ ! 67: #define SWAITMAX 90 /* wait at most 90 seconds */ ! 68: #define SWAITINT 5 /* interval between retries */ ! 69: ! 70: int swaitmax = SWAITMAX; ! 71: int swaitint = SWAITINT; ! 72: ! 73: int lostconn(); ! 74: int reapchild(); ! 75: FILE *dataconn(); ! 76: ! 77: main(argc, argv) ! 78: int argc; ! 79: char *argv[]; ! 80: { ! 81: int ctrl, s, options = 0; ! 82: char *cp; ! 83: int dev; ! 84: int status; ! 85: struct utsname uts; ! 86: ! 87: if(argc==2 && strcmp(argv[1], "-d")==0) ! 88: debug = 1; ! 89: ! 90: signal(SIGPIPE, SIG_IGN); /* used to be lostconn */ ! 91: signal(SIGHUP, SIG_IGN); ! 92: signal (SIGCHLD, SIG_IGN); ! 93: ! 94: /* ! 95: * get source address ! 96: */ ! 97: getsource(); ! 98: ! 99: /* ! 100: * Set up default state ! 101: */ ! 102: logged_in = 0; ! 103: data = -1; ! 104: type = TYPE_A; ! 105: form = FORM_N; ! 106: stru = STRU_F; ! 107: mode = MODE_S; ! 108: uname(&uts); ! 109: strcpy(hostname, uts.sysname); ! 110: reply(220, "%s FTP server ready.", hostname); ! 111: for (;;) { ! 112: setjmp(errcatch); ! 113: yyparse(); ! 114: fprintf(stderr, "out of yyparse\n"); ! 115: } ! 116: } ! 117: ! 118: /* ! 119: * parse the source string and extract system and network ! 120: */ ! 121: getsource() ! 122: { ! 123: char *s; ! 124: char *e; ! 125: ! 126: e = getenv("CSOURCE"); ! 127: if(e == 0){ ! 128: fprintf(stderr, "Can't get source address\n"); ! 129: exit(1); ! 130: } ! 131: s = strchr(e, ' '); ! 132: if(s) ! 133: *s = 0; ! 134: defdest = e; ! 135: } ! 136: ! 137: reapchild() ! 138: { ! 139: union wait status; ! 140: ! 141: while (wait3(&status, WNOHANG, 0) > 0) ! 142: ; ! 143: } ! 144: ! 145: lostconn() ! 146: { ! 147: ! 148: if (debug) ! 149: fprintf(stderr, "Lost connection.\n"); ! 150: dologout(-1); ! 151: } ! 152: ! 153: pass(passwd) ! 154: char *passwd; ! 155: { ! 156: char *xpasswd, *savestr(); ! 157: static struct passwd save; ! 158: ! 159: if (logged_in) { ! 160: reply(503, "already logged in."); ! 161: return; ! 162: } ! 163: xpasswd = crypt(passwd, pw->pw_passwd); ! 164: if (*pw->pw_passwd == '\0' || strcmp(xpasswd, pw->pw_passwd)) { ! 165: reply(530, "Login incorrect."); ! 166: pw = NULL; ! 167: return; ! 168: } ! 169: dologin(pw); ! 170: setgid(pw->pw_gid); ! 171: setuid(pw->pw_uid); ! 172: if (chdir(pw->pw_dir)) { ! 173: reply(550, "User %s: can't change directory to $s.", ! 174: pw->pw_name, pw->pw_dir); ! 175: dologout(-1); ! 176: exit(1); ! 177: } ! 178: logged_in = 1; ! 179: /* ! 180: * Save everything so globbing doesn't ! 181: * clobber the fields. ! 182: */ ! 183: save = *pw; ! 184: save.pw_name = savestr(pw->pw_name); ! 185: save.pw_passwd = savestr(pw->pw_passwd); ! 186: save.pw_comment = savestr(pw->pw_comment); ! 187: save.pw_gecos = savestr(pw->pw_gecos, &save.pw_gecos); ! 188: save.pw_dir = savestr(pw->pw_dir); ! 189: save.pw_shell = savestr(pw->pw_shell); ! 190: pw = &save; ! 191: home = pw->pw_dir; /* home dir for globbing */ ! 192: ack("login"); ! 193: return; ! 194: bad: ! 195: pw = NULL; ! 196: } ! 197: ! 198: char * ! 199: savestr(s) ! 200: char *s; ! 201: { ! 202: char *malloc(); ! 203: char *new = malloc(strlen(s) + 1); ! 204: ! 205: if (new != NULL) ! 206: strcpy(new, s); ! 207: return (new); ! 208: } ! 209: ! 210: ! 211: openfile(name) ! 212: char *name; ! 213: { ! 214: reply(550, "%s: can't open", name); ! 215: } ! 216: ! 217: pipette() ! 218: { ! 219: signal(SIGPIPE, pipette); ! 220: } ! 221: ! 222: retrieve(cmd, name) ! 223: char *cmd, *name; ! 224: { ! 225: FILE *fin, *dout; ! 226: struct stat st; ! 227: int (*closefunc)(); ! 228: ! 229: if(!logged_in){ ! 230: reply(550, "%s: login required.", name); ! 231: return; ! 232: } ! 233: if (cmd == 0) { ! 234: fin = fopen(name, "r"), closefunc = fclose; ! 235: } else { ! 236: char line[BUFSIZ]; ! 237: ! 238: sprintf(line, cmd, name), name = line; ! 239: if(debug) ! 240: fprintf(stderr,"cmd is %s\n", line); ! 241: fin = popen(line, "r"), closefunc = pclose; ! 242: } ! 243: if (fin == NULL) { ! 244: if(debug) ! 245: fprintf(stderr, "bad popen()\n"); ! 246: if (errno != 0) ! 247: reply(550, "%s: %s.", name, sys_errlist[errno]); ! 248: return; ! 249: } ! 250: ! 251: st.st_size = 0; ! 252: if (cmd == 0 ! 253: && (stat(name, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) { ! 254: reply(550, "%s: not a plain file.", name); ! 255: goto done; ! 256: } ! 257: dout = dataconn(name, st.st_size, "w"); ! 258: if (dout == NULL) ! 259: goto done; ! 260: if (send_data(fin, dout) || ferror(dout)) ! 261: reply(550, "%s: %s.", name, sys_errlist[errno]); ! 262: ! 263: else { ! 264: fclose(dout); ! 265: delay(timeout); ! 266: reply(226, "Transfer complete."); ! 267: } ! 268: data = -1; ! 269: done: ! 270: (*closefunc)(fin); ! 271: } ! 272: ! 273: store(name, mode) ! 274: char *name, *mode; ! 275: { ! 276: FILE *fout, *din; ! 277: int (*closefunc)(), dochown = 0; ! 278: ! 279: if(!logged_in){ ! 280: reply(550, "%s: login required.", name); ! 281: return; ! 282: } ! 283: fout = fopen(name, mode), closefunc = fclose; ! 284: if (fout == NULL) { ! 285: reply(550, "%s: %s.", name, sys_errlist[errno]); ! 286: return; ! 287: } ! 288: din = dataconn(name, (off_t)-1, "r"); ! 289: if (din == NULL) ! 290: goto done; ! 291: if (receive_data(din, fout) || ferror(fout)) ! 292: reply(550, "%s: %s.", name, sys_errlist[errno]); ! 293: else { ! 294: fflush(fout); ! 295: delay(timeout); ! 296: reply(226, "Transfer complete."); ! 297: } ! 298: fclose(din); ! 299: data = -1; ! 300: done: ! 301: (*closefunc)(fout); ! 302: } ! 303: ! 304: FILE * ! 305: dataconn(name, size, mode) ! 306: char *name; ! 307: off_t size; ! 308: char *mode; ! 309: { ! 310: char sizebuf[32]; ! 311: char dialstr[128]; ! 312: char params[32]; ! 313: FILE *file; ! 314: int retries; ! 315: ! 316: if (size >= 0) ! 317: sprintf (sizebuf, " (%ld bytes)", size); ! 318: else ! 319: (void) strcpy(sizebuf, ""); ! 320: ! 321: if (data >= 0) { ! 322: reply(125, "Using existing data connection for %s%s.", ! 323: name, sizebuf); ! 324: usedefault = 1; ! 325: return (fdopen(data, mode)); ! 326: } ! 327: if (usedefault) ! 328: sprintf(dialstr, "/cs/%s", defdest); ! 329: else ! 330: sprintf(dialstr, "/cs/%s", dest); ! 331: ! 332: /* make the connection */ ! 333: /*sprintf(params, "port=%d", pasv?0:(CTLPORT - 1));/**/ ! 334: for(retries=0; retries<5; retries++){ ! 335: data = ipcopen(dialstr, params); ! 336: if(data>=0) ! 337: break; ! 338: sleep(1); ! 339: } ! 340: if(data<0 || (file=fdopen(data, mode))==NULL){ ! 341: reply(425, "Can't open data socket (%s): %s.", ! 342: dialstr, ! 343: sys_errlist[errno]); ! 344: return (NULL); ! 345: } ! 346: reply(150, "Opening data connection for %s (%s,%d)%s.", ! 347: name, ! 348: dialstr, ! 349: sizebuf); ! 350: return (file); ! 351: } ! 352: ! 353: /* ! 354: * Tranfer the contents of "instr" to ! 355: * "outstr" peer using the appropriate ! 356: * encapulation of the date subject ! 357: * to Mode, Structure, and Type. ! 358: * ! 359: * NB: Form isn't handled. ! 360: */ ! 361: send_data(instr, outstr) ! 362: FILE *instr, *outstr; ! 363: { ! 364: register int c; ! 365: int netfd, filefd, cnt = 0; ! 366: char buf[BUFSIZ]; ! 367: ! 368: signal(SIGPIPE, pipette); ! 369: switch (type) { ! 370: ! 371: case TYPE_A: ! 372: while ((c = getc(instr)) != EOF) { ! 373: if (c == '\n') { ! 374: if (ferror (outstr)) ! 375: return (1); ! 376: putc('\r', outstr); ! 377: } ! 378: putc(c, outstr); ! 379: if (c == '\r') ! 380: putc ('\0', outstr); ! 381: /* cnt++; ! 382: if (!(cnt%1000)) { fprintf(stderr, "%d ", cnt); fflush(stderr); } */ ! 383: } ! 384: if (ferror (instr) || ferror (outstr)) { ! 385: fprintf(stderr,"error: inst %d, outstr %d\n", ferror(instr), ferror(outstr)); ! 386: return (1); ! 387: } ! 388: return (0); ! 389: ! 390: case TYPE_I: ! 391: case TYPE_L: ! 392: netfd = fileno(outstr); ! 393: filefd = fileno(instr); ! 394: ! 395: while ((cnt = read(filefd, buf, sizeof (buf))) > 0) ! 396: if (write(netfd, buf, cnt) < 0) { ! 397: fprintf(stderr, "write error, cnt=%d\n", cnt); ! 398: return (1); ! 399: } ! 400: return (cnt < 0); ! 401: } ! 402: reply(504,"Unimplemented TYPE %d in send_data", type); ! 403: return (1); ! 404: } ! 405: ! 406: /* ! 407: * Transfer data from peer to ! 408: * "outstr" using the appropriate ! 409: * encapulation of the data subject ! 410: * to Mode, Structure, and Type. ! 411: * ! 412: * N.B.: Form isn't handled. ! 413: */ ! 414: receive_data(instr, outstr) ! 415: FILE *instr, *outstr; ! 416: { ! 417: register int c; ! 418: int cnt; ! 419: char buf[BUFSIZ]; ! 420: ! 421: ! 422: signal(SIGPIPE, pipette); ! 423: switch (type) { ! 424: ! 425: case TYPE_I: ! 426: case TYPE_L: ! 427: while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) ! 428: if (write(fileno(outstr), buf, cnt) < 0) ! 429: return (1); ! 430: return (cnt < 0); ! 431: ! 432: case TYPE_E: ! 433: reply(504, "TYPE E not implemented."); ! 434: return (1); ! 435: ! 436: case TYPE_A: ! 437: while ((c = getc(instr)) != EOF) { ! 438: if (c == '\r') { ! 439: if (ferror (outstr)) ! 440: return (1); ! 441: if ((c = getc(instr)) != '\n') ! 442: putc ('\r', outstr); ! 443: if (c == '\0') ! 444: continue; ! 445: } ! 446: putc (c, outstr); ! 447: } ! 448: if (ferror (instr) || ferror (outstr)) ! 449: return (1); ! 450: return (0); ! 451: } ! 452: fatal("Unknown type in receive_data."); ! 453: /*NOTREACHED*/ ! 454: } ! 455: ! 456: fatal(s) ! 457: char *s; ! 458: { ! 459: reply(451, "Error in server: %s\n", s); ! 460: reply(221, "Closing connection due to server error."); ! 461: dologout(0); ! 462: } ! 463: ! 464: reply(n, s, args) ! 465: int n; ! 466: char *s; ! 467: { ! 468: ! 469: printf("%d ", n); ! 470: _doprnt(s, &args, stdout); ! 471: printf("\r\n"); ! 472: fflush(stdout); ! 473: if (debug) { ! 474: fprintf(stderr, "<--- %d ", n); ! 475: _doprnt(s, &args, stderr); ! 476: fprintf(stderr, "\n"); ! 477: fflush(stderr); ! 478: } ! 479: } ! 480: ! 481: lreply(n, s, args) ! 482: int n; ! 483: char *s; ! 484: { ! 485: printf("%d-", n); ! 486: _doprnt(s, &args, stdout); ! 487: printf("\r\n"); ! 488: fflush(stdout); ! 489: if (debug) { ! 490: fprintf(stderr, "<--- %d-", n); ! 491: _doprnt(s, &args, stderr); ! 492: fprintf(stderr, "\n"); ! 493: } ! 494: } ! 495: ! 496: replystr(s) ! 497: char *s; ! 498: { ! 499: printf("%s\r\n", s); ! 500: fflush(stdout); ! 501: if (debug) ! 502: fprintf(stderr, "<--- %s\n", s); ! 503: } ! 504: ! 505: ack(s) ! 506: char *s; ! 507: { ! 508: reply(200, "%s command okay.", s); ! 509: } ! 510: ! 511: nack(s) ! 512: char *s; ! 513: { ! 514: reply(502, "%s command not implemented.", s); ! 515: } ! 516: ! 517: yyerror() ! 518: { ! 519: reply(500, "Command not understood."); ! 520: } ! 521: ! 522: delete(name) ! 523: char *name; ! 524: { ! 525: struct stat st; ! 526: ! 527: if(!logged_in){ ! 528: reply(550, "delete: login required."); ! 529: return; ! 530: } ! 531: if (stat(name, &st) < 0) { ! 532: reply(550, "%s: %s.", name, sys_errlist[errno]); ! 533: return; ! 534: } ! 535: if ((st.st_mode&S_IFMT) == S_IFDIR) { ! 536: if (rmdir(name) < 0) { ! 537: reply(550, "%s: %s.", name, sys_errlist[errno]); ! 538: return; ! 539: } ! 540: goto done; ! 541: } ! 542: if (unlink(name) < 0) { ! 543: reply(550, "%s: %s.", name, sys_errlist[errno]); ! 544: return; ! 545: } ! 546: done: ! 547: ack("DELE"); ! 548: } ! 549: ! 550: cwd(path) ! 551: char *path; ! 552: { ! 553: ! 554: if(!logged_in){ ! 555: reply(550, "cwd: login required."); ! 556: return; ! 557: } ! 558: if (chdir(path) < 0) { ! 559: reply(550, "%s: %s.", path, sys_errlist[errno]); ! 560: return; ! 561: } ! 562: ack("CWD"); ! 563: } ! 564: ! 565: makedir(name) ! 566: char *name; ! 567: { ! 568: struct stat st; ! 569: int dochown = stat(name, &st) < 0; ! 570: ! 571: if(!logged_in){ ! 572: reply(550, "makedir: login required."); ! 573: return; ! 574: } ! 575: if (mkdir(name, 0777) < 0) { ! 576: reply(550, "%s: %s.", name, sys_errlist[errno]); ! 577: return; ! 578: } ! 579: ack("MKDIR"); ! 580: } ! 581: ! 582: removedir(name) ! 583: char *name; ! 584: { ! 585: ! 586: if(!logged_in){ ! 587: reply(550, "removedir: login required."); ! 588: return; ! 589: } ! 590: if (rmdir(name) < 0) { ! 591: reply(550, "%s: %s.", name, sys_errlist[errno]); ! 592: return; ! 593: } ! 594: ack("RMDIR"); ! 595: } ! 596: ! 597: #define MAXPATHLEN 256 ! 598: pwd() ! 599: { ! 600: char path[MAXPATHLEN + 1]; ! 601: ! 602: if (getwd(path) == NULL) { ! 603: reply(451, "%s.", path); ! 604: return; ! 605: } ! 606: reply(251, "\"%s\" is current directory.", path); ! 607: } ! 608: ! 609: char * ! 610: renamefrom(name) ! 611: char *name; ! 612: { ! 613: struct stat st; ! 614: ! 615: if(!logged_in){ ! 616: reply(550, "rename: login required."); ! 617: return; ! 618: } ! 619: if (stat(name, &st) < 0) { ! 620: reply(550, "%s: %s.", name, sys_errlist[errno]); ! 621: return ((char *)0); ! 622: } ! 623: reply(350, "File exists, ready for destination name"); ! 624: return (name); ! 625: } ! 626: ! 627: renamecmd(from, to) ! 628: char *from, *to; ! 629: { ! 630: ! 631: if(!logged_in){ ! 632: reply(550, "rename: login required."); ! 633: return; ! 634: } ! 635: if (rename(from, to) < 0) { ! 636: reply(550, "rename: %s.", sys_errlist[errno]); ! 637: return; ! 638: } ! 639: ack("RNTO"); ! 640: } ! 641: ! 642: #include <utmp.h> ! 643: ! 644: #define SCPYN(a, b) strncpy(a, b, sizeof (a)) ! 645: struct utmp utmp; ! 646: ! 647: /* ! 648: * Record login in wtmp file. ! 649: */ ! 650: ! 651: #define O_WRONLY 1 ! 652: #define O_APPEND 1 ! 653: dologin(pw) ! 654: struct passwd *pw; ! 655: { ! 656: int wtmp; ! 657: char line[32]; ! 658: ! 659: pasv = 0; ! 660: wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND); ! 661: if (wtmp >= 0) { ! 662: /* hack, but must be unique and no tty line */ ! 663: sprintf(line, "ftp%d", getpid()); ! 664: SCPYN(utmp.ut_line, line); ! 665: SCPYN(utmp.ut_name, pw->pw_name); ! 666: utmp.ut_time = time(0); ! 667: (void) write(wtmp, (char *)&utmp, sizeof (utmp)); ! 668: (void) close(wtmp); ! 669: } ! 670: } ! 671: ! 672: /* ! 673: * Record logout in wtmp file ! 674: * and exit with supplied status. ! 675: */ ! 676: dologout(status) ! 677: int status; ! 678: { ! 679: int wtmp; ! 680: ! 681: if (!logged_in) ! 682: _exit(status); ! 683: wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND); ! 684: if (wtmp >= 0) { ! 685: SCPYN(utmp.ut_name, ""); ! 686: utmp.ut_time = time(0); ! 687: (void) write(wtmp, (char *)&utmp, sizeof (utmp)); ! 688: (void) close(wtmp); ! 689: } ! 690: /* beware of flushing buffers after a SIGPIPE */ ! 691: _exit(status); ! 692: } ! 693: ! 694: static char * ! 695: nextarg(cpp) ! 696: char *cpp; ! 697: { ! 698: register char *cp = cpp; ! 699: ! 700: if (cp == 0) ! 701: return (cp); ! 702: while (*cp && *cp != ' ' && *cp != '\t') ! 703: cp++; ! 704: if (*cp == ' ' || *cp == '\t') { ! 705: *cp++ = '\0'; ! 706: while (*cp == ' ' || *cp == '\t') ! 707: cp++; ! 708: } ! 709: if (cp == cpp) ! 710: return ((char *)0); ! 711: return (cp); ! 712: } ! 713: ! 714: rename(from, to) ! 715: { ! 716: if (-1 == link(from, to)) ! 717: return(-1); ! 718: return(unlink(from)); ! 719: } ! 720: inet_ntoa(addr) ! 721: long addr; ! 722: { ! 723: static char b[32]; ! 724: unsigned char *xp = (unsigned char *)&addr; ! 725: ! 726: sprintf(b, "%d.%d.%d.%d", xp[3], xp[2], xp[1], xp[0]); ! 727: return(b); ! 728: } ! 729: delay() ! 730: { ! 731: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.