|
|
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.