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