|
|
1.1 ! root 1: /* ftpd.c - FTAM/FTP gateway */ ! 2: ! 3: #ifndef lint ! 4: static char *rcsid = "$Header: /f/osi/ftp-ftam/RCS/ftpd.c,v 7.0 89/11/23 21:55:21 mrose Rel $"; ! 5: #endif ! 6: ! 7: /* ! 8: * $Header: /f/osi/ftp-ftam/RCS/ftpd.c,v 7.0 89/11/23 21:55:21 mrose Rel $ ! 9: * ! 10: * Author: John A. Scott <[email protected]> ! 11: * The MITRE Corporation ! 12: * Washington C3I Division ! 13: * 7525 Colshire Drive ! 14: * Mclean, Virginia 22102 ! 15: * +1-703-883-5915 ! 16: * ! 17: * $Log: ftpd.c,v $ ! 18: * Revision 7.0 89/11/23 21:55:21 mrose ! 19: * Release 6.0 ! 20: * ! 21: */ ! 22: ! 23: /* ! 24: * NOTICE ! 25: * ! 26: * The MITRE Corporation (hereafter MITRE) makes this software available ! 27: * on an "as is" basis. No guarantees, either explicit or implied, are ! 28: * given as to performance or suitability. ! 29: * ! 30: */ ! 31: ! 32: /* ! 33: * Shamelessly taken from UCB ! 34: */ ! 35: ! 36: /* ! 37: * FTP server. ! 38: */ ! 39: #include "config.h" ! 40: #include <sys/param.h> ! 41: #include <sys/stat.h> ! 42: #include <sys/ioctl.h> ! 43: #include <sys/socket.h> ! 44: #include <sys/file.h> ! 45: ! 46: #include <netinet/in.h> ! 47: ! 48: #include <arpa/ftp.h> ! 49: #include <arpa/inet.h> ! 50: ! 51: #include <stdio.h> ! 52: #include <signal.h> ! 53: #include <pwd.h> ! 54: #include <setjmp.h> ! 55: #include <netdb.h> ! 56: #include <errno.h> ! 57: #include "general.h" ! 58: #include "manifest.h" ! 59: #include "logger.h" ! 60: extern LLog _ftam_log, *ftam_log; ! 61: #include <varargs.h> ! 62: ! 63: char *ctime(); ! 64: time_t time(); ! 65: void adios (), advise (); ! 66: ! 67: /* ! 68: * File containing login names ! 69: * NOT to be used on this machine. ! 70: * Commonly used to disallow uucp. ! 71: */ ! 72: /* ! 73: * This may be rework to provide bridge access control. JAS ! 74: */ ! 75: #define FTPUSERS "/usr/etc/ftpusers" ! 76: ! 77: extern int errno; ! 78: extern char *sys_errlist[]; ! 79: extern char ftam_error[]; ! 80: extern char version[]; ! 81: ! 82: struct sockaddr_in ctrl_addr; ! 83: struct sockaddr_in data_source; ! 84: struct sockaddr_in data_dest; ! 85: struct sockaddr_in his_addr; ! 86: ! 87: int data; ! 88: jmp_buf errcatch; ! 89: int logged_in; ! 90: int debug = 0; ! 91: int watch = 1; ! 92: int timeout; ! 93: int logging = 0; ! 94: int type; ! 95: int form; ! 96: int stru; /* avoid C keyword */ ! 97: int mode; ! 98: int usedefault = 1; /* for data transfers */ ! 99: char hostname[32]; ! 100: char remotehost[32]; ! 101: char *osi_host; ! 102: char *ftp_user; ! 103: char *ftp_account; ! 104: char *ftp_passwd; ! 105: int verbose = 0; ! 106: #define NVEC 100 ! 107: char *vec[NVEC]; ! 108: ! 109: /* ! 110: * Timeout intervals for retrying connections ! 111: * to hosts that don't accept PORT cmds. This ! 112: * is a kludge, but given the problems with TCP... ! 113: */ ! 114: #define SWAITMAX 90 /* wait at most 90 seconds */ ! 115: #define SWAITINT 5 /* interval between retries */ ! 116: ! 117: int swaitmax = SWAITMAX; ! 118: int swaitint = SWAITINT; ! 119: ! 120: SFD lostconn(); ! 121: ! 122: main(argc, argv) ! 123: int argc; ! 124: char *argv[]; ! 125: { ! 126: int addrlen; ! 127: char *ptr, *index(); ! 128: struct servent *sp; ! 129: ! 130: isodetailor (ptr = argv[0], 0); ! 131: argc--, argv++; ! 132: if (verbose = isatty (fileno (stderr))) ! 133: ll_dbinit (ftam_log, ptr); ! 134: else { ! 135: ftam_log -> ll_stat &= ~LLOGCLS; ! 136: ll_hdinit (ftam_log, ptr); ! 137: } ! 138: ! 139: advise (NULLCP, "starting"); ! 140: ! 141: addrlen = sizeof his_addr; ! 142: if (getpeername (0, (struct sockaddr *) &his_addr, &addrlen) == NOTOK) ! 143: adios ("failed", "getpeername"); ! 144: sp = getservbyname("ftp", "tcp"); ! 145: if (sp == 0) { ! 146: advise(NULLCP, "ftp/tcp: unknown service"); ! 147: abort(); ! 148: exit(1); ! 149: } ! 150: ctrl_addr.sin_port = sp->s_port; ! 151: data_source.sin_port = htons(ntohs((u_short) sp->s_port) - 1); ! 152: (void)signal(SIGPIPE, lostconn); ! 153: (void)signal(SIGCHLD, SIG_IGN); ! 154: (void)dup2(0, 1); ! 155: /* do telnet option negotiation here */ ! 156: /* ! 157: * Set up default state ! 158: */ ! 159: rcinit(); /* FTAM state initialize */ ! 160: logged_in = 0; ! 161: data = -1; ! 162: type = TYPE_A; ! 163: form = FORM_N; ! 164: stru = STRU_F; ! 165: mode = MODE_S; ! 166: addrlen = sizeof ctrl_addr; ! 167: if (getsockname(0, (struct sockaddr *) &ctrl_addr, &addrlen) == NOTOK) ! 168: adios ("failed", "getsockname"); ! 169: (void)gethostname(hostname, sizeof (hostname)); ! 170: ptr = index(hostname,'.'); /* strip off domain name */ ! 171: if (ptr) *ptr = '\0'; ! 172: reply(220, "%s FTP/FTAM gateway (%s) ready.", ! 173: hostname, version); ! 174: for (;;) { ! 175: (void)setjmp(errcatch); ! 176: (void)yyparse(); ! 177: } ! 178: } ! 179: ! 180: SFD ! 181: lostconn() ! 182: { ! 183: ! 184: advise (NULLCP,"lost connection"); ! 185: dologout(-1); ! 186: } ! 187: ! 188: char * ! 189: savestr(s) ! 190: char *s; ! 191: { ! 192: char *malloc(); ! 193: char *new = malloc((unsigned) (strlen(s) + 1)); ! 194: ! 195: if (new != NULL) ! 196: (void)strcpy(new, s); ! 197: return (new); ! 198: } ! 199: ! 200: retrieve(name) ! 201: char *name; ! 202: { ! 203: int result; ! 204: ! 205: /* FTAM file retrieval block function. Return values: ! 206: * OK -- file transfered without error ! 207: * NOTOK -- file transfer error ! 208: * DONE -- Problem opening TCP connection for transfer ! 209: * Error response made by dataconn routine. ! 210: */ ! 211: vec[0] = "f_get"; ! 212: vec[1] = name; ! 213: vec[2] = NULL; ! 214: ! 215: if ((result = f_get(vec)) == NOTOK){ ! 216: reply(550, "%s: %s.", name, ftam_error); ! 217: } else if (result == OK) ! 218: reply(226, "Transfer complete."); ! 219: ! 220: data = -1; ! 221: return; ! 222: } ! 223: ! 224: ftp_store(name, modeX) ! 225: char *name, *modeX; ! 226: { ! 227: int result; ! 228: /* ! 229: * f_put is FTAM file storage block function. First arguement ! 230: * controls file overwrite or append selection. ! 231: * OK -- file transfered without error ! 232: * NOTOK -- file transfer error ! 233: * DONE -- Problem opening TCP connection for transfer ! 234: * Error response made by dataconn routine. ! 235: */ ! 236: ! 237: vec[0] = strcmp(modeX,"a") ? "put" : "append"; ! 238: vec[1] = name; ! 239: vec[2] = NULL; ! 240: if ((result = f_put(vec)) == NOTOK) ! 241: reply(550, "%s: %s.", name, ftam_error); ! 242: else if (result == OK) ! 243: reply(226, "Transfer complete."); ! 244: data = -1; ! 245: } ! 246: ! 247: int ! 248: getdatasock() ! 249: { ! 250: /* UCB data socket creation routine */ ! 251: int s; ! 252: #ifdef BSD43 ! 253: int on = 1; ! 254: #endif ! 255: ! 256: if (data >= 0) ! 257: return (data); ! 258: s = socket(AF_INET, SOCK_STREAM, 0); ! 259: if (s < 0) ! 260: return (NOTOK); ! 261: #ifndef BSD43 ! 262: if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) 0, 0) < 0) ! 263: #else ! 264: if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof on) < 0) ! 265: #endif ! 266: goto bad; ! 267: /* anchor socket to avoid multi-homing problems */ ! 268: data_source.sin_family = AF_INET; ! 269: data_source.sin_addr = ctrl_addr.sin_addr; ! 270: if (bind(s, (struct sockaddr *) &data_source, sizeof (data_source)) < 0) ! 271: goto bad; ! 272: return (s); ! 273: bad: ! 274: (void)close(s); ! 275: return (NOTOK); ! 276: } ! 277: ! 278: int ! 279: dataconn(name) ! 280: char *name; ! 281: { ! 282: /* UCB data connection routine */ ! 283: int retry = 0; ! 284: ! 285: if (data >= 0) { ! 286: reply(125, "Using existing data connection for %s.", ! 287: name); ! 288: usedefault = 1; ! 289: return (data); ! 290: } ! 291: if (usedefault) ! 292: data_dest = his_addr; ! 293: usedefault = 1; ! 294: data = getdatasock(); ! 295: if (data == NOTOK){ ! 296: reply(425, "Can't create data socket (%s,%d): %s.", ! 297: inet_ntoa(data_source.sin_addr), ! 298: ntohs(data_source.sin_port), ! 299: sys_errlist[errno]); ! 300: return (NOTOK); ! 301: } ! 302: reply(150, "Opening data connection for %s (%s,%d).", ! 303: name, inet_ntoa(data_dest.sin_addr), ! 304: ntohs(data_dest.sin_port)); ! 305: while (connect(data, (struct sockaddr *)&data_dest, sizeof (data_dest)) < 0) { ! 306: if (errno == EADDRINUSE && retry < swaitmax) { ! 307: sleep((unsigned) swaitint); ! 308: retry += swaitint; ! 309: continue; ! 310: } ! 311: reply(425, "Can't build data connection: %s.", ! 312: sys_errlist[errno]); ! 313: (void) close(data); ! 314: data = -1; ! 315: return (NOTOK); ! 316: } ! 317: return (data); ! 318: } ! 319: ! 320: fatal(s) ! 321: char *s; ! 322: { ! 323: reply(451, "Error in server: %s\n", s); ! 324: /* reply(221, "Closing connection due to server error.");*/ ! 325: dologout(0); ! 326: } ! 327: ! 328: #ifndef lint ! 329: reply(va_alist) ! 330: va_dcl ! 331: { ! 332: int n; ! 333: va_list ap; ! 334: ! 335: va_start (ap); ! 336: ! 337: n = va_arg (ap, int); ! 338: ! 339: _reply (n, ' ', ap); ! 340: ! 341: va_end (ap); ! 342: } ! 343: ! 344: lreply(va_alist) ! 345: va_dcl ! 346: { ! 347: int n; ! 348: va_list ap; ! 349: ! 350: va_start (ap); ! 351: ! 352: n = va_arg (ap, int); ! 353: ! 354: _reply (n, '-', ap); ! 355: ! 356: va_end (ap); ! 357: } ! 358: ! 359: static _reply (n, c, ap) ! 360: int n; ! 361: char c; ! 362: va_list ap; ! 363: { ! 364: char buffer[BUFSIZ]; ! 365: ! 366: _asprintf (buffer, NULLCP, ap); ! 367: ! 368: printf ("%d%c%s\r\n", n, c, buffer); ! 369: (void)fflush (stdout); ! 370: ! 371: if (verbose) ! 372: advise (NULLCP,"<--- %d%c%s", n, c, buffer); ! 373: } ! 374: #else ! 375: /* VARARGS2 */ ! 376: ! 377: reply(n,fmt) ! 378: int n; ! 379: char *fmt; ! 380: { ! 381: reply(n,fmt); ! 382: } ! 383: /* VARARGS2 */ ! 384: ! 385: lreply(n,fmt) ! 386: int n; ! 387: char *fmt; ! 388: { ! 389: lreply(n,fmt); ! 390: } ! 391: #endif ! 392: ! 393: replystr(s) ! 394: char *s; ! 395: { ! 396: printf("%s\r\n", s); ! 397: (void)fflush(stdout); ! 398: if (verbose) ! 399: advise(NULLCP,"<--- %s", s); ! 400: } ! 401: ! 402: ack(s) ! 403: char *s; ! 404: { ! 405: reply(200, "%s command okay.", s); ! 406: } ! 407: ! 408: nack(s) ! 409: char *s; ! 410: { ! 411: reply(502, "%s command not implemented.", s); ! 412: } ! 413: ! 414: /*ARGSUSED*/ ! 415: yyerror(s) ! 416: char *s; ! 417: { ! 418: reply(500, "Command not understood."); ! 419: } ! 420: ! 421: ftp_delete(name) ! 422: char *name; ! 423: { ! 424: /* f_rm is the general purpose FTAM file/directory deletion routine. ! 425: * Change information is formatted in ftam_error. ! 426: */ ! 427: vec[0] = "f_rm"; ! 428: vec[1] = name; ! 429: vec[2] = NULL; ! 430: ! 431: if (f_rm(vec) == NOTOK){ ! 432: reply(550, "%s: %s.", name, ftam_error); ! 433: return; ! 434: } ! 435: ack("DELE"); ! 436: } ! 437: ! 438: makedir(name) ! 439: char *name; ! 440: { ! 441: ! 442: /* f_mkdir is the FTAM directory creation routine */ ! 443: ! 444: vec[0] = "f_mkdir"; ! 445: vec[1] = name; ! 446: vec[2] = NULL; ! 447: ! 448: if (f_mkdir(vec) == NOTOK){ ! 449: reply(550, "%s: %s.", name, ftam_error); ! 450: return; ! 451: } ! 452: ack("MKDIR"); ! 453: } ! 454: ! 455: removedir(name) ! 456: char *name; ! 457: { ! 458: ! 459: /* f_rm is the general purpose FTAM file/directory deletion routine. ! 460: */ ! 461: vec[0] = "f_rm"; ! 462: vec[1] = name; ! 463: vec[2] = NULL; ! 464: ! 465: if (f_rm(vec) == NOTOK){ ! 466: reply(550, "%s: %s.", name, ftam_error); ! 467: return; ! 468: } ! 469: ack("RMDIR"); ! 470: } ! 471: ! 472: char * ! 473: renamefrom(name) ! 474: char *name; ! 475: { ! 476: reply(350, "Ready for destination name"); ! 477: return (name); ! 478: } ! 479: ! 480: renamecmd(from, to) ! 481: char *from, *to; ! 482: { ! 483: ! 484: /* f_mv is FTAM block function to select and change attributes ! 485: * (i.e. file name) ! 486: */ ! 487: vec[0] ="f_mv"; ! 488: vec[1] = from; ! 489: vec[2] = to; ! 490: vec[3] = NULL; ! 491: ! 492: if (f_mv(vec) == NOTOK){ ! 493: reply(550, "rename: %s.", ftam_error); ! 494: return; ! 495: } ! 496: ack("RNTO"); ! 497: } ! 498: ! 499: dolog(sin) ! 500: struct sockaddr_in *sin; ! 501: { ! 502: #ifdef notanymore ! 503: struct hostent *hp = gethostbyaddr((char*)&sin->sin_addr, ! 504: sizeof (struct in_addr), AF_INET); ! 505: #endif ! 506: time_t t; ! 507: ! 508: #ifdef notanymore ! 509: if (hp) { ! 510: (void)strncpy(remotehost, hp->h_name, sizeof (remotehost)); ! 511: endhostent(); ! 512: } else ! 513: #endif ! 514: (void)strncpy(remotehost, inet_ntoa(sin->sin_addr), ! 515: sizeof (remotehost)); ! 516: t = time((time_t*)0); ! 517: if (!logging) ! 518: return; ! 519: advise(NULLCP,"connection from %s at %s", remotehost, ctime(&t)); ! 520: } ! 521: directory(how,name) ! 522: char *how, *name; ! 523: { ! 524: ! 525: int result; ! 526: /* f_ls does a directory contents transfer. The first arguement ! 527: * determines whether a name list (NLST) or long list (LIST) is returned. ! 528: * Results: ! 529: * OK -- list transfered without error ! 530: * NOTOK -- list transfer error ! 531: * DONE -- Problem opening TCP connection for transfer ! 532: * Error response made by dataconn routine. ! 533: */ ! 534: ! 535: vec[0] = strcmp(how,"NLST") ? "dir" : "ls"; ! 536: vec[1] = name; ! 537: vec[2] = NULL; ! 538: ! 539: if ((result = f_ls(vec)) == OK) ! 540: reply(226, "Transfer complete."); ! 541: else if (result == NOTOK) ! 542: reply(500, ftam_error); ! 543: data = -1; ! 544: ! 545: } ! 546: /* ! 547: * Execute FTAM login if all necessary arguements present ! 548: */ ! 549: dologin() ! 550: { ! 551: ! 552: if (!ftp_user) { ! 553: reply(500,"Send USER command first"); ! 554: return(0); ! 555: } ! 556: if (!ftp_passwd) { ! 557: reply(330,"Send PASS command"); ! 558: return(0); ! 559: } ! 560: if (!osi_host){ ! 561: /* Success is returned since most user FTP response scanners ! 562: * are not prepared for a continue at this point. The osi ! 563: * host may be specified by encoding it with the user name ! 564: * (i.e. user@osihost) or using the SITE command (SITE osihost). ! 565: * Gateway users are expected to know if the remote site ! 566: * requires account charging information. The bridge makes ! 567: * ACCT optional. ! 568: */ ! 569: reply(200,"Specify OSI destination with SITE command"); ! 570: return(0); ! 571: } ! 572: vec[0] = "f_open"; ! 573: vec[1] = osi_host; ! 574: vec[2] = ftp_user; ! 575: vec[3] = (ftp_account) ? "" : ftp_account; ! 576: vec[4] = ftp_passwd; ! 577: ! 578: advise (NULLCP, ! 579: "attempting connection with OSI host \"%s\" for user \"%s\"", ! 580: osi_host, ftp_user); ! 581: ! 582: /* f_open performs the FTAM initialization (including login) */ ! 583: if (f_open(vec) == NOTOK){ ! 584: reply(500,"Login failed"); ! 585: return(0); ! 586: } ! 587: ! 588: reply(200,"Logged into %s", osi_host); ! 589: return(1); ! 590: ! 591: } ! 592: ! 593: /* ! 594: * exit with supplied status. ! 595: */ ! 596: dologout(status) ! 597: int status; ! 598: { ! 599: ! 600: vec[0] = "f_close"; ! 601: vec[1] = NULL; ! 602: /* f_close performs the logout sequence and receives charging ! 603: * information ! 604: */ ! 605: (void) f_close(vec); ! 606: if (status>=0) ! 607: reply(221,"Logged off. %s",ftam_error); ! 608: /* beware of flushing buffers after a SIGPIPE */ ! 609: _exit(status); ! 610: } ! 611: ! 612: ! 613: /* ! 614: * Check user requesting login priviledges. ! 615: * Disallow anyone mentioned in the file FTPUSERS ! 616: * to allow people such as uucp to be avoided. ! 617: */ ! 618: checkuser(name) ! 619: register char *name; ! 620: { ! 621: char line[BUFSIZ], *index(); ! 622: FILE *fd, *fopen(); ! 623: int found = 0; ! 624: ! 625: fd = fopen(FTPUSERS, "r"); ! 626: if (fd == NULL) ! 627: return (1); ! 628: while (fgets(line, sizeof (line), fd) != NULL) { ! 629: register char *cp = index(line, '\n'); ! 630: ! 631: if (cp) ! 632: *cp = '\0'; ! 633: if (strcmp(line, name) == 0) { ! 634: found++; ! 635: break; ! 636: } ! 637: } ! 638: (void)fclose(fd); ! 639: return (!found); ! 640: } ! 641:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.