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