|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)ftpd.c 4.28 (Berkeley) 9/22/83";
3: #endif
4:
5: /*
6: * FTP server.
7: */
8: #include <sys/param.h>
9: #include <sys/stat.h>
10: #include <sys/ioctl.h>
11: #include <sys/file.h>
12: #include <wait.h>
13:
14: #include <sys/inet/in.h>
15:
16: #include "ftp.h"
17:
18: #include <stdio.h>
19: #include <signal.h>
20: #include <pwd.h>
21: #include <setjmp.h>
22: #include <errno.h>
23:
24: /*
25: * File containing login names
26: * NOT to be used on this machine.
27: * Commonly used to disallow uucp.
28: */
29: #define FTPUSERS "/etc/ftpusers"
30:
31: extern int errno;
32: extern char *sys_errlist[];
33: extern char *crypt();
34: extern char version[];
35: extern char *home; /* pointer to home directory for glob */
36: extern FILE *popen(), *fopen();
37: extern int pclose(), fclose();
38:
39: struct socket {
40: unsigned short sport;
41: unsigned short dport;
42: long saddr;
43: long daddr;
44: } his_addr, data_dest, data_source, ctrl_addr;
45:
46: int data;
47: jmp_buf errcatch;
48: int logged_in;
49: struct passwd *pw;
50: int debug;
51: int timeout;
52: int logging;
53: int guest;
54: int type;
55: int form;
56: int stru; /* avoid C keyword */
57: int mode;
58: int usedefault = 1; /* for data transfers */
59: char hostname[32];
60: char remotehost[32];
61:
62:
63: /*
64: * Timeout intervals for retrying connections
65: * to hosts that don't accept PORT cmds. This
66: * is a kludge, but given the problems with TCP...
67: */
68: #define SWAITMAX 90 /* wait at most 90 seconds */
69: #define SWAITINT 5 /* interval between retries */
70:
71: int swaitmax = SWAITMAX;
72: int swaitint = SWAITINT;
73:
74: int lostconn();
75: int reapchild();
76: int getdatasock();
77: FILE *dataconn();
78:
79: main(argc, argv)
80: int argc;
81: char *argv[];
82: {
83: int ctrl, s, options = 0;
84: char *cp;
85: int dev;
86: struct in_service *servp;
87:
88: servp = in_service("ftp", "tcp", 0);
89: if (servp == 0) {
90: fprintf(stderr, "ftpd: ftp/tcp: unknown service\n");
91: exit(1);
92: }
93: ctrl_addr.sport = servp->port;
94: data_source.sport = servp->port - 1;
95: while (argc > 0 && *argv[0] == '-') {
96: for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
97:
98: case 'v':
99: debug = 1;
100: break;
101:
102: case 'd':
103: debug = 1;
104: break;
105:
106: case 'l':
107: logging = 1;
108: break;
109:
110: case 't':
111: timeout = atoi(++cp);
112: goto nextopt;
113: break;
114:
115: default:
116: fprintf(stderr, "Unknown flag -%c ignored.\n", *cp);
117: break;
118: }
119: nextopt:
120: argc--, argv++;
121: }
122: signal(SIGPIPE, SIG_IGN);
123: signal(SIGHUP, SIG_IGN);
124:
125: do {
126: s = tcp_sock();
127: if (s < 0) {
128: perror("ftpd: socket");;
129: sleep(5);
130: continue;
131: }
132: if (tcp_listen(s, servp->port, 0, 0) < 0) {
133: close(s);
134: s = -1;
135: sleep(30);
136: continue;
137: }
138: } while (s < 0);
139:
140: signal(SIGCHLD, reapchild);
141: for (;;) {
142: int ctrl;
143:
144: ctrl = tcp_accept(s, &his_addr.saddr, &his_addr.sport, &dev);
145: fprintf(stderr, "accept req from %s, port %d\n", inet_ntoa(his_addr.saddr), his_addr.sport);
146: if (ctrl < 0) {
147: if (errno == EINTR)
148: continue;
149: perror("ftpd: accept");
150: sleep(1);
151: continue;
152: }
153: switch(fork()) {
154: case -1:
155: printf("Out of processes\n");
156: break;
157: case 0:
158: signal (SIGCHLD, SIG_IGN);
159: dolog(&his_addr);
160: close(s);
161: dup2(ctrl, 0), close(ctrl), dup2(0, 1);
162: /*
163: * Set up default state
164: */
165: logged_in = 0;
166: data = -1;
167: type = TYPE_A;
168: form = FORM_N;
169: stru = STRU_F;
170: mode = MODE_S;
171: /* try to do this equivalently
172: (void) getsockname(0, &ctrl_addr, sizeof (ctrl_addr));
173: gethostname(hostname, sizeof (hostname));
174: */
175: reply(220, "%s FTP server (%s) ready.",
176: hostname, version);
177: for (;;) {
178: setjmp(errcatch);
179: yyparse();
180: }
181: }
182: close(ctrl);
183: }
184: }
185:
186: reapchild()
187: {
188: union wait status;
189:
190: while (wait3(&status, WNOHANG, 0) > 0)
191: ;
192: }
193:
194: lostconn()
195: {
196:
197: if (debug)
198: fprintf(stderr, "Lost connection.\n");
199: dologout(-1);
200: }
201:
202: pass(passwd)
203: char *passwd;
204: {
205: char *xpasswd, *savestr();
206: static struct passwd save;
207:
208: if (logged_in || pw == NULL) {
209: reply(503, "Login with USER first.");
210: return;
211: }
212: if (!guest) { /* "ftp" is only account allowed no password */
213: xpasswd = crypt(passwd, pw->pw_passwd);
214: if (*pw->pw_passwd == '\0' || strcmp(xpasswd, pw->pw_passwd)) {
215: reply(530, "Login incorrect.");
216: pw = NULL;
217: return;
218: }
219: }
220: setegid(pw->pw_gid);
221: /* initgroups(pw->pw_name, pw->pw_gid); */
222: if (chdir(pw->pw_dir)) {
223: reply(550, "User %s: can't change directory to $s.",
224: pw->pw_name, pw->pw_dir);
225: goto bad;
226: }
227: if (guest && chroot(pw->pw_dir) < 0) {
228: reply(550, "Can't set guest privileges.");
229: goto bad;
230: }
231: if (!guest)
232: reply(230, "User %s logged in.", pw->pw_name);
233: else
234: reply(230, "Guest login ok, access restrictions apply.");
235: logged_in = 1;
236: dologin(pw);
237: seteuid(pw->pw_uid);
238: /*
239: * Save everything so globbing doesn't
240: * clobber the fields.
241: */
242: save = *pw;
243: save.pw_name = savestr(pw->pw_name);
244: save.pw_passwd = savestr(pw->pw_passwd);
245: save.pw_comment = savestr(pw->pw_comment);
246: save.pw_gecos = savestr(pw->pw_gecos, &save.pw_gecos);
247: save.pw_dir = savestr(pw->pw_dir);
248: save.pw_shell = savestr(pw->pw_shell);
249: pw = &save;
250: home = pw->pw_dir; /* home dir for globbing */
251: return;
252: bad:
253: seteuid(0);
254: pw = NULL;
255: }
256:
257: char *
258: savestr(s)
259: char *s;
260: {
261: char *malloc();
262: char *new = malloc(strlen(s) + 1);
263:
264: if (new != NULL)
265: strcpy(new, s);
266: return (new);
267: }
268:
269: retrieve(cmd, name)
270: char *cmd, *name;
271: {
272: FILE *fin, *dout;
273: struct stat st;
274: int (*closefunc)();
275:
276: st.st_size = 0;
277: if (cmd == 0 &&
278: (stat(name, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) {
279: reply(550, "%s: not a plain file.", name);
280: goto done;
281: }
282: dout = dataconn(name, st.st_size, "w");
283: if (dout == NULL)
284: goto done;
285: if (cmd == 0) {
286: #ifdef notdef
287: /* no remote command execution -- it's a security hole */
288: if (*name == '|')
289: fin = popen(name + 1, "r"), closefunc = pclose;
290: else
291: #endif
292: fin = fopen(name, "r"), closefunc = fclose;
293: } else {
294: char line[BUFSIZ];
295:
296: sprintf(line, cmd, name), name = line;
297: fin = popen(line, "r"), closefunc = pclose;
298: }
299: if (fin == NULL) {
300: if (errno != 0)
301: reply(550, "%s: %s.", name, sys_errlist[errno]);
302: return;
303: }
304: if (send_data(fin, dout) || ferror(dout))
305: reply(550, "%s: %s.", name, sys_errlist[errno]);
306: else
307: reply(226, "Transfer complete.");
308: fclose(dout), data = -1;
309: done:
310: (*closefunc)(fin);
311: }
312:
313: store(name, mode)
314: char *name, *mode;
315: {
316: FILE *fout, *din;
317: int (*closefunc)(), dochown = 0;
318:
319: din = dataconn(name, (off_t)-1, "r");
320: if (din == NULL)
321: goto done;
322: #ifdef notdef
323: /* no remote command execution -- it's a security hole */
324: if (name[0] == '|')
325: fout = popen(&name[1], "w"), closefunc = pclose;
326: else
327: #endif
328: {
329: struct stat st;
330:
331: if (stat(name, &st) < 0)
332: dochown++;
333: fout = fopen(name, mode), closefunc = fclose;
334: }
335: if (fout == NULL) {
336: reply(550, "%s: %s.", name, sys_errlist[errno]);
337: return;
338: }
339: if (receive_data(din, fout) || ferror(fout))
340: reply(550, "%s: %s.", name, sys_errlist[errno]);
341: else
342: reply(226, "Transfer complete.");
343: fclose(din), data = -1;
344: done:
345: if (dochown)
346: (void) chown(name, pw->pw_uid, -1);
347: (*closefunc)(fout);
348: }
349:
350: getdatasock(mode)
351: char *mode;
352: {
353: int s;
354:
355: if (data >= 0)
356: return (data);
357: data_source.saddr = ctrl_addr.saddr;
358: s = tcp_sock();
359: if (s < 0) {
360: perror("ftpd: socket");;
361: return(NULL);
362: }
363:
364: seteuid(pw->pw_uid);
365: return (s);
366: }
367:
368: FILE *
369: dataconn(name, size, mode)
370: char *name;
371: off_t size;
372: char *mode;
373: {
374: char sizebuf[32];
375: FILE *file;
376: int retry = 0;
377:
378: if (size >= 0)
379: sprintf (sizebuf, " (%ld bytes)", size);
380: else
381: (void) strcpy(sizebuf, "");
382: if (data >= 0) {
383: reply(125, "Using existing data connection for %s%s.",
384: name, sizebuf);
385: usedefault = 1;
386: return (fdopen(data, mode));
387: }
388: if (usedefault)
389: data_dest = his_addr;
390: usedefault = 1;
391: data = getdatasock(mode);
392: if (data < 0) {
393: reply(425, "Can't create data socket (%s,%d): %s.",
394: inet_ntoa(data_source.saddr),
395: ntohs(data_source.sport),
396: sys_errlist[errno]);
397: return (NULL);
398: }
399: reply(150, "Opening data connection for %s (%s,%d)%s.",
400: name,
401: inet_ntoa(data_dest.saddr),
402: data_dest.sport, sizebuf);
403:
404: while (tcp_connect(data, 0, data_dest.saddr, data_dest.sport) < 0) {
405: data = -1;
406: if (retry < swaitmax) {
407: data = getdatasock(mode);
408: sleep(swaitint);
409: retry += swaitint;
410: continue;
411: }
412: reply(425, "Can't build data connection: %s.",
413: sys_errlist[errno]);
414: (void)fclose(file);
415: return (NULL);
416: }
417: return (fdopen(data, mode));
418: }
419:
420: /*
421: * Tranfer the contents of "instr" to
422: * "outstr" peer using the appropriate
423: * encapulation of the date subject
424: * to Mode, Structure, and Type.
425: *
426: * NB: Form isn't handled.
427: */
428: send_data(instr, outstr)
429: FILE *instr, *outstr;
430: {
431: register int c;
432: int netfd, filefd, cnt;
433: char buf[BUFSIZ];
434:
435: switch (type) {
436:
437: case TYPE_A:
438: while ((c = getc(instr)) != EOF) {
439: if (c == '\n') {
440: if (ferror (outstr))
441: return (1);
442: putc('\r', outstr);
443: }
444: putc(c, outstr);
445: if (c == '\r')
446: putc ('\0', outstr);
447: }
448: if (ferror (instr) || ferror (outstr))
449: return (1);
450: return (0);
451:
452: case TYPE_I:
453: case TYPE_L:
454: netfd = fileno(outstr);
455: filefd = fileno(instr);
456:
457: while ((cnt = read(filefd, buf, sizeof (buf))) > 0)
458: if (write(netfd, buf, cnt) < 0)
459: return (1);
460: return (cnt < 0);
461: }
462: reply(504,"Unimplemented TYPE %d in send_data", type);
463: return (1);
464: }
465:
466: /*
467: * Transfer data from peer to
468: * "outstr" using the appropriate
469: * encapulation of the data subject
470: * to Mode, Structure, and Type.
471: *
472: * N.B.: Form isn't handled.
473: */
474: receive_data(instr, outstr)
475: FILE *instr, *outstr;
476: {
477: register int c;
478: int cnt;
479: char buf[BUFSIZ];
480:
481:
482: switch (type) {
483:
484: case TYPE_I:
485: case TYPE_L:
486: while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0)
487: if (write(fileno(outstr), buf, cnt) < 0)
488: return (1);
489: return (cnt < 0);
490:
491: case TYPE_E:
492: reply(504, "TYPE E not implemented.");
493: return (1);
494:
495: case TYPE_A:
496: while ((c = getc(instr)) != EOF) {
497: if (c == '\r') {
498: if (ferror (outstr))
499: return (1);
500: if ((c = getc(instr)) != '\n')
501: putc ('\r', outstr);
502: if (c == '\0')
503: continue;
504: }
505: putc (c, outstr);
506: }
507: if (ferror (instr) || ferror (outstr))
508: return (1);
509: return (0);
510: }
511: fatal("Unknown type in receive_data.");
512: /*NOTREACHED*/
513: }
514:
515: fatal(s)
516: char *s;
517: {
518: reply(451, "Error in server: %s\n", s);
519: reply(221, "Closing connection due to server error.");
520: dologout(0);
521: }
522:
523: reply(n, s, args)
524: int n;
525: char *s;
526: {
527:
528: printf("%d ", n);
529: _doprnt(s, &args, stdout);
530: printf("\r\n");
531: fflush(stdout);
532: if (debug) {
533: fprintf(stderr, "<--- %d ", n);
534: _doprnt(s, &args, stderr);
535: fprintf(stderr, "\n");
536: fflush(stderr);
537: }
538: }
539:
540: lreply(n, s, args)
541: int n;
542: char *s;
543: {
544: printf("%d-", n);
545: _doprnt(s, &args, stdout);
546: printf("\r\n");
547: fflush(stdout);
548: if (debug) {
549: fprintf(stderr, "<--- %d-", n);
550: _doprnt(s, &args, stderr);
551: fprintf(stderr, "\n");
552: }
553: }
554:
555: replystr(s)
556: char *s;
557: {
558: printf("%s\r\n", s);
559: fflush(stdout);
560: if (debug)
561: fprintf(stderr, "<--- %s\n", s);
562: }
563:
564: ack(s)
565: char *s;
566: {
567: reply(200, "%s command okay.", s);
568: }
569:
570: nack(s)
571: char *s;
572: {
573: reply(502, "%s command not implemented.", s);
574: }
575:
576: yyerror()
577: {
578: reply(500, "Command not understood.");
579: }
580:
581: delete(name)
582: char *name;
583: {
584: struct stat st;
585:
586: if (stat(name, &st) < 0) {
587: reply(550, "%s: %s.", name, sys_errlist[errno]);
588: return;
589: }
590: if ((st.st_mode&S_IFMT) == S_IFDIR) {
591: if (rmdir(name) < 0) {
592: reply(550, "%s: %s.", name, sys_errlist[errno]);
593: return;
594: }
595: goto done;
596: }
597: if (unlink(name) < 0) {
598: reply(550, "%s: %s.", name, sys_errlist[errno]);
599: return;
600: }
601: done:
602: ack("DELE");
603: }
604:
605: cwd(path)
606: char *path;
607: {
608:
609: if (chdir(path) < 0) {
610: reply(550, "%s: %s.", path, sys_errlist[errno]);
611: return;
612: }
613: ack("CWD");
614: }
615:
616: makedir(name)
617: char *name;
618: {
619: struct stat st;
620: int dochown = stat(name, &st) < 0;
621:
622: if (mkdir(name, 0777) < 0) {
623: reply(550, "%s: %s.", name, sys_errlist[errno]);
624: return;
625: }
626: if (dochown)
627: (void) chown(name, pw->pw_uid, -1);
628: ack("MKDIR");
629: }
630:
631: removedir(name)
632: char *name;
633: {
634:
635: if (rmdir(name) < 0) {
636: reply(550, "%s: %s.", name, sys_errlist[errno]);
637: return;
638: }
639: ack("RMDIR");
640: }
641:
642: #define MAXPATHLEN 256
643: pwd()
644: {
645: char path[MAXPATHLEN + 1];
646:
647: if (getwd(path) == NULL) {
648: reply(451, "%s.", path);
649: return;
650: }
651: reply(251, "\"%s\" is current directory.", path);
652: }
653:
654: char *
655: renamefrom(name)
656: char *name;
657: {
658: struct stat st;
659:
660: if (stat(name, &st) < 0) {
661: reply(550, "%s: %s.", name, sys_errlist[errno]);
662: return ((char *)0);
663: }
664: reply(350, "File exists, ready for destination name");
665: return (name);
666: }
667:
668: renamecmd(from, to)
669: char *from, *to;
670: {
671:
672: if (rename(from, to) < 0) {
673: reply(550, "rename: %s.", sys_errlist[errno]);
674: return;
675: }
676: ack("RNTO");
677: }
678:
679: dolog(addr)
680: register struct socket *addr;
681: {
682: char *h_name = (char *)in_host(addr->saddr);
683: time_t t;
684:
685: strncpy(remotehost, h_name, sizeof (remotehost));
686: if (!logging)
687: return;
688: t = time(0);
689: fprintf(stderr,"FTPD: connection from %s at %s", remotehost, ctime(&t));
690: fflush(stderr);
691: }
692:
693: #include <utmp.h>
694:
695: #define SCPYN(a, b) strncpy(a, b, sizeof (a))
696: struct utmp utmp;
697:
698: /*
699: * Record login in wtmp file.
700: */
701:
702: #define O_WRONLY 1
703: #define O_APPEND 1
704: dologin(pw)
705: struct passwd *pw;
706: {
707: int wtmp;
708: char line[32];
709:
710: wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
711: if (wtmp >= 0) {
712: /* hack, but must be unique and no tty line */
713: sprintf(line, "ftp%d", getpid());
714: SCPYN(utmp.ut_line, line);
715: SCPYN(utmp.ut_name, pw->pw_name);
716: utmp.ut_time = time(0);
717: (void) write(wtmp, (char *)&utmp, sizeof (utmp));
718: (void) close(wtmp);
719: }
720: }
721:
722: /*
723: * Record logout in wtmp file
724: * and exit with supplied status.
725: */
726: dologout(status)
727: int status;
728: {
729: int wtmp;
730:
731: if (!logged_in)
732: _exit(status);
733: seteuid(0);
734: wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
735: if (wtmp >= 0) {
736: SCPYN(utmp.ut_name, "");
737: utmp.ut_time = time(0);
738: (void) write(wtmp, (char *)&utmp, sizeof (utmp));
739: (void) close(wtmp);
740: }
741: /* beware of flushing buffers after a SIGPIPE */
742: _exit(status);
743: }
744:
745: /*
746: * Special version of popen which avoids
747: * call to shell. This insures noone may
748: * create a pipe to a hidden program as a side
749: * effect of a list or dir command.
750: */
751: #define tst(a,b) (*mode == 'r'? (b) : (a))
752: #define RDR 0
753: #define WTR 1
754: static int popen_pid[5];
755:
756: static char *
757: nextarg(cpp)
758: char *cpp;
759: {
760: register char *cp = cpp;
761:
762: if (cp == 0)
763: return (cp);
764: while (*cp && *cp != ' ' && *cp != '\t')
765: cp++;
766: if (*cp == ' ' || *cp == '\t') {
767: *cp++ = '\0';
768: while (*cp == ' ' || *cp == '\t')
769: cp++;
770: }
771: if (cp == cpp)
772: return ((char *)0);
773: return (cp);
774: }
775:
776: FILE *
777: popen(cmd, mode)
778: char *cmd, *mode;
779: {
780: int p[2], ac, gac;
781: register myside, hisside, pid;
782: char *av[20], *gav[512];
783: register char *cp;
784:
785: if (pipe(p) < 0)
786: return (NULL);
787: cp = cmd, ac = 0;
788: /* break up string into pieces */
789: do {
790: av[ac++] = cp;
791: cp = nextarg(cp);
792: } while (cp && *cp && ac < 20);
793: av[ac] = (char *)0;
794: gav[0] = av[0];
795: /* glob each piece */
796: for (gac = ac = 1; av[ac] != NULL; ac++) {
797: char **pop;
798: extern char **glob();
799:
800: pop = glob(av[ac]);
801: if (pop) {
802: av[ac] = (char *)pop; /* save to free later */
803: while (*pop && gac < 512)
804: gav[gac++] = *pop++;
805: }
806: }
807: gav[gac] = (char *)0;
808: myside = tst(p[WTR], p[RDR]);
809: hisside = tst(p[RDR], p[WTR]);
810: if ((pid = fork()) == 0) {
811: /* myside and hisside reverse roles in child */
812: close(myside);
813: dup2(hisside, tst(0, 1));
814: close(hisside);
815: execv(gav[0], gav);
816: _exit(1);
817: }
818: for (ac = 1; av[ac] != NULL; ac++)
819: blkfree((char **)av[ac]);
820: if (pid == -1)
821: return (NULL);
822: popen_pid[myside] = pid;
823: close(hisside);
824: return (fdopen(myside, mode));
825: }
826:
827: pclose(ptr)
828: FILE *ptr;
829: {
830: register f, r, (*hstat)(), (*istat)(), (*qstat)();
831: int status;
832:
833: f = fileno(ptr);
834: fclose(ptr);
835: istat = signal(SIGINT, SIG_IGN);
836: qstat = signal(SIGQUIT, SIG_IGN);
837: hstat = signal(SIGHUP, SIG_IGN);
838: while ((r = wait(&status)) != popen_pid[f] && r != -1)
839: ;
840: if (r == -1)
841: status = -1;
842: signal(SIGINT, istat);
843: signal(SIGQUIT, qstat);
844: signal(SIGHUP, hstat);
845: return (status);
846: }
847:
848: /*
849: * Check user requesting login priviledges.
850: * Disallow anyone mentioned in the file FTPUSERS
851: * to allow people such as uucp to be avoided.
852: */
853: checkuser(name)
854: register char *name;
855: {
856: char line[BUFSIZ], *index();
857: FILE *fd;
858: int found = 0;
859:
860: fd = fopen(FTPUSERS, "r");
861: if (fd == NULL)
862: return (1);
863: while (fgets(line, sizeof (line), fd) != NULL) {
864: register char *cp = index(line, '\n');
865:
866: if (cp)
867: *cp = '\0';
868: if (strcmp(line, name) == 0) {
869: found++;
870: break;
871: }
872: }
873: fclose(fd);
874: return (!found);
875: }
876: seteuid(uid)
877: {
878: return(setuid(uid));
879: }
880: setegid(gid)
881: {
882: return(setgid(gid));
883: }
884:
885: rename(from, to)
886: {
887: if (-1 == link(from, to))
888: return(-1);
889: return(unlink(from));
890: }
891: inet_ntoa(addr)
892: long addr;
893: {
894: static char b[32];
895: unsigned char *xp = (unsigned char *)&addr;
896:
897: sprintf(b, "%d.%d.%d.%d", xp[3], xp[2], xp[1], xp[0]);
898: return(b);
899: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.