|
|
1.1 ! root 1: /* ftp.c - FTP client */ ! 2: ! 3: #ifndef lint ! 4: static char *rcsid = "$Header: /f/osi/ftam-ftp/RCS/ftp.c,v 7.0 89/11/23 21:55:04 mrose Rel $"; /* from UCB 4.11 7/26/83 */ ! 5: #endif ! 6: ! 7: /* ! 8: * $Header: /f/osi/ftam-ftp/RCS/ftp.c,v 7.0 89/11/23 21:55:04 mrose Rel $ ! 9: * ! 10: * ! 11: * $Log: ftp.c,v $ ! 12: * Revision 7.0 89/11/23 21:55:04 mrose ! 13: * Release 6.0 ! 14: * ! 15: */ ! 16: ! 17: /* ! 18: * NOTICE ! 19: * ! 20: * The MITRE Corporation (hereafter MITRE) makes this software available ! 21: * on an "as is" basis. No guarantees, either explicit or implied, are ! 22: * given as to performance or suitability. ! 23: * ! 24: */ ! 25: ! 26: /* ! 27: * Shamelessly taken from UCB ! 28: */ ! 29: ! 30: #include "config.h" ! 31: #include <sys/param.h> ! 32: #include <sys/ioctl.h> ! 33: #include "internet.h" ! 34: #include <sys/time.h> ! 35: ! 36: #include <arpa/ftp.h> ! 37: ! 38: #include <stdio.h> ! 39: #include <errno.h> ! 40: #include <varargs.h> ! 41: ! 42: #include "ftp_var.h" ! 43: #include "general.h" ! 44: #include "logger.h" ! 45: void advise (); ! 46: ! 47: #ifndef NOTOK ! 48: #define NOTOK (-1) ! 49: #define OK 0 ! 50: #define DONE 1 ! 51: #endif /* NOTOK */ ! 52: ! 53: int verbose = 0; ! 54: ! 55: struct sockaddr_in hisctladdr; ! 56: struct sockaddr_in data_addr; ! 57: int data = -1; ! 58: int connected = 0; ! 59: struct sockaddr_in myctladdr; ! 60: ! 61: FILE *cin, *cout; ! 62: int dataconn(); ! 63: ! 64: ! 65: ftp_init() ! 66: { /* default ftp communication values */ ! 67: ! 68: (void)strcpy(typename, "ascii"), type = TYPE_A; ! 69: (void)strcpy(formname, "non-print"), form = FORM_N; ! 70: (void)strcpy(modename, "stream"), mode = MODE_S; ! 71: (void)strcpy(structname, "file"), stru = STRU_F; ! 72: (void)strcpy(bytename, "8"), bytesize = 8; ! 73: ftp_directory = 0; ! 74: ftp_error = ftp_error_buffer; ! 75: verbose = isatty (fileno (stderr)); ! 76: } ! 77: ! 78: hookup(host, port) ! 79: char *host; ! 80: int port; ! 81: { ! 82: register struct hostent *hp; ! 83: int s, len; ! 84: ! 85: bzero((char *)&hisctladdr, sizeof (hisctladdr)); ! 86: hp = gethostbyname(host); ! 87: if (hp == NULL) { ! 88: #ifdef h_addr ! 89: static char *addrs = NULL; ! 90: #endif ! 91: static struct hostent def; ! 92: static struct in_addr defaddr; ! 93: static char namebuf[128]; ! 94: u_long inet_addr(); ! 95: ! 96: defaddr.s_addr = inet_addr(host); ! 97: if (defaddr.s_addr == -1) { ! 98: (void)sprintf(ftp_error, "%s: Unknown host.", host); ! 99: return (NOTOK); ! 100: } ! 101: (void)strcpy(namebuf, host); ! 102: def.h_name = namebuf; ! 103: hostname = namebuf; ! 104: #ifdef h_addr ! 105: def.h_addr_list = &addrs; ! 106: #endif ! 107: def.h_addr = (char *)&defaddr; ! 108: def.h_length = sizeof (struct in_addr); ! 109: def.h_addrtype = AF_INET; ! 110: def.h_aliases = 0; ! 111: hp = &def; ! 112: } ! 113: hostname = hp->h_name; ! 114: hisctladdr.sin_family = hp->h_addrtype; ! 115: s = socket(hp->h_addrtype, SOCK_STREAM, 0); ! 116: if (s < 0) { ! 117: (void)sprintf(ftp_error,"ftp: socket %s", ! 118: (errno <= sys_nerr)? sys_errlist[errno]:""); ! 119: return (NOTOK); ! 120: } ! 121: if (bind(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) { ! 122: (void)sprintf(ftp_error,"ftp: bind %s", ! 123: (errno <= sys_nerr)? sys_errlist[errno]:""); ! 124: goto bad; ! 125: } ! 126: inaddr_copy (hp, &hisctladdr); ! 127: hisctladdr.sin_port = htons ((u_short) port); ! 128: if (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) { ! 129: (void)sprintf(ftp_error,"ftp: connect %s", ! 130: (errno <= sys_nerr)? sys_errlist[errno]:""); ! 131: goto bad; ! 132: } ! 133: len = sizeof (myctladdr); ! 134: if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) { ! 135: (void)sprintf(ftp_error,"ftp: getsockname %s", ! 136: (errno <= sys_nerr)? sys_errlist[errno]:""); ! 137: goto bad; ! 138: } ! 139: cin = fdopen(s, "r"); ! 140: cout = fdopen(s, "w"); ! 141: if (cin == NULL || cout == NULL) { ! 142: (void)sprintf(ftp_error, "ftp: fdopen failed."); ! 143: if (cin) ! 144: (void)fclose(cin); ! 145: if (cout) ! 146: (void)fclose(cout); ! 147: goto bad; ! 148: } ! 149: (void) getreply(0); /* read startup message from server */ ! 150: connected = 1; ! 151: return (OK); ! 152: bad: ! 153: (void)close(s); ! 154: return (NOTOK); ! 155: } ! 156: ! 157: login(user,pass,acct) ! 158: char *user, *pass, *acct; ! 159: { ! 160: int n; ! 161: ! 162: if (!user){ ! 163: (void)sprintf(ftp_error, "Username required"); ! 164: return(NOTOK); ! 165: } ! 166: n = command("USER %s", user); ! 167: if (n == CONTINUE){ ! 168: if (!pass){ ! 169: (void)sprintf(ftp_error, "Password required"); ! 170: return(NOTOK); ! 171: } ! 172: n = command("PASS %s", pass); ! 173: } ! 174: if (n == CONTINUE) { ! 175: if (!acct){ ! 176: (void)sprintf(ftp_error, "Account required"); ! 177: return(NOTOK); ! 178: } ! 179: n = command("ACCT %s", acct); ! 180: } ! 181: if (n != COMPLETE) { ! 182: (void)sprintf(ftp_error, "Login failed."); ! 183: return (NOTOK); ! 184: } ! 185: return (OK); ! 186: } ! 187: ! 188: #ifndef lint ! 189: command(va_alist) ! 190: va_dcl ! 191: { ! 192: int val; ! 193: va_list ap; ! 194: ! 195: va_start (ap); ! 196: ! 197: val = _command (ap); ! 198: ! 199: va_end (ap); ! 200: ! 201: return val; ! 202: } ! 203: ! 204: _command(ap) ! 205: va_list ap; ! 206: { ! 207: char buffer[BUFSIZ]; ! 208: ! 209: if (cout == NULL) { ! 210: (void)sprintf(ftp_error,"No control connection for command %s", ! 211: (errno <= sys_nerr)? sys_errlist[errno]:""); ! 212: return (NOTOK); ! 213: } ! 214: ! 215: _asprintf (buffer, NULLCP, ap); ! 216: fprintf (cout, "%s\r\n", buffer); ! 217: (void) fflush(cout); ! 218: if (verbose) ! 219: advise (LLOG_DEBUG, NULLCP, "<--- %s", buffer); ! 220: return (getreply(!strcmp(buffer, "QUIT"))); ! 221: } ! 222: #else ! 223: /* VARARGS1 */ ! 224: ! 225: command (fmt) ! 226: char *fmt; ! 227: { ! 228: return command (fmt); ! 229: } ! 230: #endif ! 231: ! 232: #include <ctype.h> ! 233: ! 234: getreply(expecteof) ! 235: int expecteof; ! 236: { ! 237: register int c, n; ! 238: register int code, dig; ! 239: int originalcode = 0, continuation = 0; ! 240: char *mesg; ! 241: ! 242: mesg = ftp_error_buffer; ! 243: for (;;) { ! 244: dig = n = code = 0; ! 245: while ((c = getc(cin)) != '\n') { ! 246: dig++; ! 247: if (c == EOF) { ! 248: if (expecteof) ! 249: return (0); ! 250: lostpeer(); ! 251: advise (LLOG_EXCEPTIONS,NULLCP,"getreply: %s", ! 252: ftp_error_buffer); ! 253: return(1); ! 254: /* exit(1); */ ! 255: } ! 256: if (c != '\r') *mesg++ = c; ! 257: else *mesg = '\0'; ! 258: if (dig < 4 && isdigit(c)) ! 259: code = code * 10 + (c - '0'); ! 260: if (dig == 4 && c == '-') ! 261: continuation++; ! 262: if (n == 0) ! 263: n = c; ! 264: } ! 265: if (continuation && code != originalcode) { ! 266: if (originalcode == 0) ! 267: originalcode = code; ! 268: continue; ! 269: } ! 270: if (verbose) ! 271: advise (LLOG_DEBUG,NULLCP,"---> %s", ! 272: ftp_error_buffer); ! 273: return (n - '0'); ! 274: } ! 275: } ! 276: ! 277: /* ! 278: * sendrequest and recvrequest routines have been modified to send the ! 279: * appropriate remote command then open and return a file descriptor (socket). ! 280: * The FTAM code treats this as though it were a local file (which ! 281: * is about what FTP does) ! 282: */ ! 283: int ! 284: sendrequest(cmd, /* local, */ remote) ! 285: char *cmd, /* *local, */ *remote; ! 286: { ! 287: int dout; ! 288: int expectingreply = 0; ! 289: ! 290: if (initconn()) ! 291: goto bad; ! 292: if (remote) { ! 293: if (command("%s %s", cmd, remote) != PRELIM) ! 294: goto bad; ! 295: } else ! 296: if (command("%s", cmd) != PRELIM) ! 297: goto bad; ! 298: expectingreply++; /* got preliminary reply, expecting final reply */ ! 299: dout = dataconn("w"); ! 300: if (dout == NOTOK) ! 301: goto bad; ! 302: return(dout); ! 303: ! 304: bad: ! 305: if (data >= 0) ! 306: (void) close(data), data = -1; ! 307: if (expectingreply) { ! 308: (void) getreply(0); ! 309: expectingreply = 0; ! 310: } ! 311: return(NOTOK); ! 312: } ! 313: ! 314: int ! 315: recvrequest(cmd, /* local,*/ remote) ! 316: char *cmd, /* *local,*/ *remote; ! 317: { ! 318: int din; ! 319: int expectingreply = 0; ! 320: ! 321: if (initconn()) ! 322: goto bad; ! 323: if (remote) { ! 324: if (command("%s %s", cmd, remote) != PRELIM) ! 325: goto bad; ! 326: } else ! 327: if (command("%s", cmd) != PRELIM) ! 328: goto bad; ! 329: expectingreply++; /* got preliminary reply, expecting final reply */ ! 330: din = dataconn("r"); ! 331: if (din == NOTOK) ! 332: goto bad; ! 333: return(din); ! 334: bad: ! 335: if (data >= 0) ! 336: (void) close(data), data = -1; ! 337: if (expectingreply) { ! 338: (void) getreply(0); ! 339: expectingreply = 0; ! 340: } ! 341: return(NOTOK); ! 342: } ! 343: ! 344: /* ! 345: * Need to start a listen on the data channel ! 346: * before we send the command, otherwise the ! 347: * server's connect may fail. ! 348: */ ! 349: int sendport = -1; ! 350: ! 351: initconn() ! 352: { ! 353: register char *p, *a; ! 354: int result, len; ! 355: #ifdef BSD43 ! 356: int on = 1; ! 357: #endif ! 358: ! 359: noport: ! 360: data_addr = myctladdr; ! 361: if (sendport) ! 362: data_addr.sin_port = 0; /* let system pick one */ ! 363: if (data != -1) ! 364: (void) close (data); ! 365: data = socket(AF_INET, SOCK_STREAM, 0); ! 366: if (data < 0) { ! 367: (void)sprintf(ftp_error,"ftp: socket %s", ! 368: (errno <= sys_nerr)? sys_errlist[errno]:""); ! 369: return (NOTOK); ! 370: } ! 371: if (!sendport) ! 372: #ifndef BSD43 ! 373: if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *) 0, 0) < 0) { ! 374: #else ! 375: if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on) < 0) { ! 376: #endif ! 377: (void)sprintf(ftp_error,"ftp: setsockopt (reuse address) %s", ! 378: (errno <= sys_nerr)? sys_errlist[errno]:""); ! 379: goto bad; ! 380: } ! 381: if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) { ! 382: (void)sprintf(ftp_error,"ftp: bind %s", ! 383: (errno <= sys_nerr)? sys_errlist[errno]:""); ! 384: goto bad; ! 385: } ! 386: if (options & SO_DEBUG && ! 387: #ifndef BSD43 ! 388: setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *) 0, 0) < 0) ! 389: #else ! 390: setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *) &on, on) < 0) ! 391: #endif ! 392: (void)sprintf(ftp_error,"ftp: setsockopt (ignoreg) %s", ! 393: (errno <= sys_nerr)? sys_errlist[errno]:""); ! 394: len = sizeof (data_addr); ! 395: if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) { ! 396: (void)sprintf(ftp_error,"ftp: getsockname %s", ! 397: (errno <= sys_nerr)? sys_errlist[errno]:""); ! 398: goto bad; ! 399: } ! 400: if (listen(data, 1) < 0) { ! 401: (void)sprintf(ftp_error,"ftp: listen %s", ! 402: (errno <= sys_nerr)? sys_errlist[errno]:""); ! 403: goto bad; ! 404: } ! 405: if (sendport) { ! 406: a = (char *)&data_addr.sin_addr; ! 407: p = (char *)&data_addr.sin_port; ! 408: #define UC(b) (((int)b)&0xff) ! 409: result = ! 410: command("PORT %d,%d,%d,%d,%d,%d", ! 411: UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), ! 412: UC(p[0]), UC(p[1])); ! 413: if (result == ERROR && sendport == -1) { ! 414: sendport = 0; ! 415: goto noport; ! 416: } ! 417: return ((result == COMPLETE)?OK:NOTOK); ! 418: } ! 419: return (OK); ! 420: bad: ! 421: (void) close(data), data = -1; ! 422: return (NOTOK); ! 423: } ! 424: ! 425: /*ARGSUSED */ ! 426: int ! 427: dataconn(modeX) ! 428: char *modeX; ! 429: { ! 430: struct sockaddr_in from; ! 431: int s, fromlen = sizeof (from); ! 432: ! 433: s = accept(data, (struct sockaddr *) &from, &fromlen); ! 434: if (s < 0) { ! 435: (void)sprintf(ftp_error,"ftp: accept %s", ! 436: (errno <= sys_nerr)? sys_errlist[errno]:""); ! 437: (void) close(data), data = -1; ! 438: return (NOTOK); ! 439: } ! 440: (void) close(data); ! 441: data = s; ! 442: return (data); ! 443: } ! 444: ! 445: lostpeer() ! 446: { ! 447: ! 448: if (connected) { ! 449: if (cout != NULL) { ! 450: (void)shutdown(fileno(cout), 1+1); ! 451: (void)fclose(cout); ! 452: cout = NULL; ! 453: } ! 454: if (data >= 0) { ! 455: (void) shutdown(data, 1+1); ! 456: (void) close(data); ! 457: data = -1; ! 458: } ! 459: connected = 0; ! 460: } ! 461: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.