|
|
1.1 root 1: /*
2: * Copyright (c) 1985 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1985 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)ftpd.c 5.7 (Berkeley) 5/28/86";
15: #endif not lint
16:
17: /*
18: * FTP server.
19: */
20: #include <sys/param.h>
21: #include <sys/stat.h>
22: #include <sys/ioctl.h>
23: #include <sys/socket.h>
24: #include <sys/file.h>
25: #include <sys/wait.h>
26:
27: #include <netinet/in.h>
28:
29: #include <arpa/ftp.h>
30: #include <arpa/inet.h>
31: #include <arpa/telnet.h>
32:
33: #include <stdio.h>
34: #include <signal.h>
35: #include <pwd.h>
36: #include <setjmp.h>
37: #include <netdb.h>
38: #include <errno.h>
39: #include <strings.h>
40: #include <syslog.h>
41:
42: /*
43: * File containing login names
44: * NOT to be used on this machine.
45: * Commonly used to disallow uucp.
46: */
47: #define FTPUSERS "/etc/ftpusers"
48:
49: extern int errno;
50: extern char *sys_errlist[];
51: extern char *crypt();
52: extern char version[];
53: extern char *home; /* pointer to home directory for glob */
54: extern FILE *popen(), *fopen(), *freopen();
55: extern int pclose(), fclose();
56: extern char *getline();
57: extern char cbuf[];
58:
59: struct sockaddr_in ctrl_addr;
60: struct sockaddr_in data_source;
61: struct sockaddr_in data_dest;
62: struct sockaddr_in his_addr;
63:
64: int data;
65: jmp_buf errcatch, urgcatch;
66: int logged_in;
67: struct passwd *pw;
68: int debug;
69: int timeout = 900; /* timeout after 15 minutes of inactivity */
70: int logging;
71: int guest;
72: int wtmp;
73: int type;
74: int form;
75: int stru; /* avoid C keyword */
76: int mode;
77: int usedefault = 1; /* for data transfers */
78: int pdata; /* for passive mode */
79: int unique;
80: int transflag;
81: char tmpline[7];
82: char hostname[32];
83: char remotehost[32];
84:
85: /*
86: * Timeout intervals for retrying connections
87: * to hosts that don't accept PORT cmds. This
88: * is a kludge, but given the problems with TCP...
89: */
90: #define SWAITMAX 90 /* wait at most 90 seconds */
91: #define SWAITINT 5 /* interval between retries */
92:
93: int swaitmax = SWAITMAX;
94: int swaitint = SWAITINT;
95:
96: int lostconn();
97: int myoob();
98: FILE *getdatasock(), *dataconn();
99:
100: main(argc, argv)
101: int argc;
102: char *argv[];
103: {
104: int addrlen, on = 1;
105: long pgid;
106: char *cp;
107:
108: addrlen = sizeof (his_addr);
109: if (getpeername(0, &his_addr, &addrlen) < 0) {
110: syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
111: exit(1);
112: }
113: addrlen = sizeof (ctrl_addr);
114: if (getsockname(0, (char *) &ctrl_addr, &addrlen) < 0) {
115: syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
116: exit(1);
117: }
118: data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
119: debug = 0;
120: openlog("ftpd", LOG_PID, LOG_DAEMON);
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: break;
132:
133: case 'l':
134: logging = 1;
135: break;
136:
137: case 't':
138: timeout = atoi(++cp);
139: goto nextopt;
140: break;
141:
142: default:
143: fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n",
144: *cp);
145: break;
146: }
147: nextopt:
148: argc--, argv++;
149: }
150: (void) signal(SIGPIPE, lostconn);
151: (void) signal(SIGCHLD, SIG_IGN);
152: if (signal(SIGURG, myoob) < 0) {
153: syslog(LOG_ERR, "signal: %m");
154: }
155: /* handle urgent data inline */
156: #ifdef SO_OOBINLINE
157: if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) {
158: syslog(LOG_ERR, "setsockopt: %m");
159: }
160: #endif SO_OOBINLINE
161: pgid = getpid();
162: if (ioctl(fileno(stdin), SIOCSPGRP, (char *) &pgid) < 0) {
163: syslog(LOG_ERR, "ioctl: %m");
164: }
165: dolog(&his_addr);
166: /* do telnet option negotiation here */
167: /*
168: * Set up default state
169: */
170: logged_in = 0;
171: data = -1;
172: type = TYPE_A;
173: form = FORM_N;
174: stru = STRU_F;
175: mode = MODE_S;
176: tmpline[0] = '\0';
177: (void) gethostname(hostname, sizeof (hostname));
178: reply(220, "%s FTP server (%s) ready.",
179: hostname, version);
180: for (;;) {
181: (void) setjmp(errcatch);
182: (void) yyparse();
183: }
184: }
185:
186: lostconn()
187: {
188:
189: if (debug)
190: syslog(LOG_DEBUG, "lost connection");
191: dologout(-1);
192: }
193:
194: pass(passwd)
195: char *passwd;
196: {
197: char *xpasswd, *savestr();
198: static struct passwd save;
199:
200: if (logged_in || pw == NULL) {
201: reply(503, "Login with USER first.");
202: return;
203: }
204: if (!guest) { /* "ftp" is only account allowed no password */
205: xpasswd = crypt(passwd, pw->pw_passwd);
206: /* The strcmp does not catch null passwords! */
207: if (*pw->pw_passwd == '\0' || strcmp(xpasswd, pw->pw_passwd)) {
208: reply(530, "Login incorrect.");
209: pw = NULL;
210: return;
211: }
212: }
213: setegid(pw->pw_gid);
214: initgroups(pw->pw_name, pw->pw_gid);
215: if (chdir(pw->pw_dir)) {
216: reply(530, "User %s: can't change directory to %s.",
217: pw->pw_name, pw->pw_dir);
218: goto bad;
219: }
220:
221: /* grab wtmp before chroot */
222: wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
223: if (guest && chroot(pw->pw_dir) < 0) {
224: reply(550, "Can't set guest privileges.");
225: if (wtmp >= 0) {
226: (void) close(wtmp);
227: wtmp = -1;
228: }
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);
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((unsigned) strlen(s) + 1);
263:
264: if (new != NULL)
265: (void) 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)(), tmp;
275:
276: if (cmd == 0) {
277: #ifdef notdef
278: /* no remote command execution -- it's a security hole */
279: if (*name == '|')
280: fin = popen(name + 1, "r"), closefunc = pclose;
281: else
282: #endif
283: fin = fopen(name, "r"), closefunc = fclose;
284: } else {
285: char line[BUFSIZ];
286:
287: (void) sprintf(line, cmd, name), name = line;
288: fin = popen(line, "r"), closefunc = pclose;
289: }
290: if (fin == NULL) {
291: if (errno != 0)
292: reply(550, "%s: %s.", name, sys_errlist[errno]);
293: return;
294: }
295: st.st_size = 0;
296: if (cmd == 0 &&
297: (stat(name, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) {
298: reply(550, "%s: not a plain file.", name);
299: goto done;
300: }
301: dout = dataconn(name, st.st_size, "w");
302: if (dout == NULL)
303: goto done;
304: if ((tmp = send_data(fin, dout)) > 0 || ferror(dout) > 0) {
305: reply(550, "%s: %s.", name, sys_errlist[errno]);
306: }
307: else if (tmp == 0) {
308: reply(226, "Transfer complete.");
309: }
310: (void) fclose(dout);
311: data = -1;
312: pdata = -1;
313: done:
314: (*closefunc)(fin);
315: }
316:
317: store(name, mode)
318: char *name, *mode;
319: {
320: FILE *fout, *din;
321: int (*closefunc)(), dochown = 0, tmp;
322: char *gunique(), *local;
323:
324: #ifdef notdef
325: /* no remote command execution -- it's a security hole */
326: if (name[0] == '|')
327: fout = popen(&name[1], "w"), closefunc = pclose;
328: else
329: #endif
330: {
331: struct stat st;
332:
333: local = name;
334: if (stat(name, &st) < 0) {
335: dochown++;
336: }
337: else if (unique) {
338: if ((local = gunique(name)) == NULL) {
339: return;
340: }
341: dochown++;
342: }
343: fout = fopen(local, mode), closefunc = fclose;
344: }
345: if (fout == NULL) {
346: reply(553, "%s: %s.", local, sys_errlist[errno]);
347: return;
348: }
349: din = dataconn(local, (off_t)-1, "r");
350: if (din == NULL)
351: goto done;
352: if ((tmp = receive_data(din, fout)) > 0 || ferror(fout) > 0) {
353: reply(552, "%s: %s.", local, sys_errlist[errno]);
354: }
355: else if (tmp == 0 && !unique) {
356: reply(226, "Transfer complete.");
357: }
358: else if (tmp == 0 && unique) {
359: reply(226, "Transfer complete (unique file name:%s).", local);
360: }
361: (void) fclose(din);
362: data = -1;
363: pdata = -1;
364: done:
365: if (dochown)
366: (void) chown(local, pw->pw_uid, -1);
367: (*closefunc)(fout);
368: }
369:
370: FILE *
371: getdatasock(mode)
372: char *mode;
373: {
374: int s, on = 1;
375:
376: if (data >= 0)
377: return (fdopen(data, mode));
378: s = socket(AF_INET, SOCK_STREAM, 0);
379: if (s < 0)
380: return (NULL);
381: seteuid(0);
382: if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0)
383: goto bad;
384: /* anchor socket to avoid multi-homing problems */
385: data_source.sin_family = AF_INET;
386: data_source.sin_addr = ctrl_addr.sin_addr;
387: if (bind(s, &data_source, sizeof (data_source)) < 0)
388: goto bad;
389: seteuid(pw->pw_uid);
390: return (fdopen(s, mode));
391: bad:
392: seteuid(pw->pw_uid);
393: (void) close(s);
394: return (NULL);
395: }
396:
397: FILE *
398: dataconn(name, size, mode)
399: char *name;
400: off_t size;
401: char *mode;
402: {
403: char sizebuf[32];
404: FILE *file;
405: int retry = 0;
406:
407: if (size >= 0)
408: (void) sprintf (sizebuf, " (%ld bytes)", size);
409: else
410: (void) strcpy(sizebuf, "");
411: if (pdata > 0) {
412: struct sockaddr_in from;
413: int s, fromlen = sizeof(from);
414:
415: s = accept(pdata, &from, &fromlen);
416: if (s < 0) {
417: reply(425, "Can't open data connection.");
418: (void) close(pdata);
419: pdata = -1;
420: return(NULL);
421: }
422: (void) close(pdata);
423: pdata = s;
424: reply(150, "Openning data connection for %s (%s,%d)%s.",
425: name, inet_ntoa(from.sin_addr),
426: ntohs(from.sin_port), sizebuf);
427: return(fdopen(pdata, mode));
428: }
429: if (data >= 0) {
430: reply(125, "Using existing data connection for %s%s.",
431: name, sizebuf);
432: usedefault = 1;
433: return (fdopen(data, mode));
434: }
435: if (usedefault)
436: data_dest = his_addr;
437: usedefault = 1;
438: file = getdatasock(mode);
439: if (file == NULL) {
440: reply(425, "Can't create data socket (%s,%d): %s.",
441: inet_ntoa(data_source.sin_addr),
442: ntohs(data_source.sin_port),
443: sys_errlist[errno]);
444: return (NULL);
445: }
446: data = fileno(file);
447: while (connect(data, &data_dest, sizeof (data_dest)) < 0) {
448: if (errno == EADDRINUSE && retry < swaitmax) {
449: sleep((unsigned) swaitint);
450: retry += swaitint;
451: continue;
452: }
453: reply(425, "Can't build data connection: %s.",
454: sys_errlist[errno]);
455: (void) fclose(file);
456: data = -1;
457: return (NULL);
458: }
459: reply(150, "Opening data connection for %s (%s,%d)%s.",
460: name, inet_ntoa(data_dest.sin_addr),
461: ntohs(data_dest.sin_port), sizebuf);
462: return (file);
463: }
464:
465: /*
466: * Tranfer the contents of "instr" to
467: * "outstr" peer using the appropriate
468: * encapulation of the date subject
469: * to Mode, Structure, and Type.
470: *
471: * NB: Form isn't handled.
472: */
473: send_data(instr, outstr)
474: FILE *instr, *outstr;
475: {
476: register int c;
477: int netfd, filefd, cnt;
478: char buf[BUFSIZ];
479:
480: transflag++;
481: if (setjmp(urgcatch)) {
482: transflag = 0;
483: return(-1);
484: }
485: switch (type) {
486:
487: case TYPE_A:
488: while ((c = getc(instr)) != EOF) {
489: if (c == '\n') {
490: if (ferror (outstr)) {
491: transflag = 0;
492: return (1);
493: }
494: (void) putc('\r', outstr);
495: }
496: (void) putc(c, outstr);
497: /* if (c == '\r') */
498: /* putc ('\0', outstr); */
499: }
500: transflag = 0;
501: if (ferror (instr) || ferror (outstr)) {
502: return (1);
503: }
504: return (0);
505:
506: case TYPE_I:
507: case TYPE_L:
508: netfd = fileno(outstr);
509: filefd = fileno(instr);
510:
511: while ((cnt = read(filefd, buf, sizeof (buf))) > 0) {
512: if (write(netfd, buf, cnt) < 0) {
513: transflag = 0;
514: return (1);
515: }
516: }
517: transflag = 0;
518: return (cnt < 0);
519: }
520: reply(550, "Unimplemented TYPE %d in send_data", type);
521: transflag = 0;
522: return (-1);
523: }
524:
525: /*
526: * Transfer data from peer to
527: * "outstr" using the appropriate
528: * encapulation of the data subject
529: * to Mode, Structure, and Type.
530: *
531: * N.B.: Form isn't handled.
532: */
533: receive_data(instr, outstr)
534: FILE *instr, *outstr;
535: {
536: register int c;
537: int cnt;
538: char buf[BUFSIZ];
539:
540:
541: transflag++;
542: if (setjmp(urgcatch)) {
543: transflag = 0;
544: return(-1);
545: }
546: switch (type) {
547:
548: case TYPE_I:
549: case TYPE_L:
550: while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
551: if (write(fileno(outstr), buf, cnt) < 0) {
552: transflag = 0;
553: return (1);
554: }
555: }
556: transflag = 0;
557: return (cnt < 0);
558:
559: case TYPE_E:
560: reply(553, "TYPE E not implemented.");
561: transflag = 0;
562: return (-1);
563:
564: case TYPE_A:
565: while ((c = getc(instr)) != EOF) {
566: while (c == '\r') {
567: if (ferror (outstr)) {
568: transflag = 0;
569: return (1);
570: }
571: if ((c = getc(instr)) != '\n')
572: (void) putc ('\r', outstr);
573: /* if (c == '\0') */
574: /* continue; */
575: }
576: (void) putc (c, outstr);
577: }
578: transflag = 0;
579: if (ferror (instr) || ferror (outstr))
580: return (1);
581: return (0);
582: }
583: transflag = 0;
584: fatal("Unknown type in receive_data.");
585: /*NOTREACHED*/
586: }
587:
588: fatal(s)
589: char *s;
590: {
591: reply(451, "Error in server: %s\n", s);
592: reply(221, "Closing connection due to server error.");
593: dologout(0);
594: }
595:
596: /*VARARGS2*/
597: reply(n, s, args)
598: int n;
599: char *s;
600: {
601:
602: printf("%d ", n);
603: _doprnt(s, &args, stdout);
604: printf("\r\n");
605: (void) fflush(stdout);
606: if (debug) {
607: syslog(LOG_DEBUG, "<--- %d ", n);
608: syslog(LOG_DEBUG, s, &args);
609: }
610: }
611:
612: /*VARARGS2*/
613: lreply(n, s, args)
614: int n;
615: char *s;
616: {
617: printf("%d-", n);
618: _doprnt(s, &args, stdout);
619: printf("\r\n");
620: (void) fflush(stdout);
621: if (debug) {
622: syslog(LOG_DEBUG, "<--- %d- ", n);
623: syslog(LOG_DEBUG, s, &args);
624: }
625: }
626:
627: ack(s)
628: char *s;
629: {
630: reply(250, "%s command successful.", s);
631: }
632:
633: nack(s)
634: char *s;
635: {
636: reply(502, "%s command not implemented.", s);
637: }
638:
639: yyerror(s)
640: char *s;
641: {
642: char *cp;
643:
644: cp = index(cbuf,'\n');
645: *cp = '\0';
646: reply(500, "'%s': command not understood.",cbuf);
647: }
648:
649: delete(name)
650: char *name;
651: {
652: struct stat st;
653:
654: if (stat(name, &st) < 0) {
655: reply(550, "%s: %s.", name, sys_errlist[errno]);
656: return;
657: }
658: if ((st.st_mode&S_IFMT) == S_IFDIR) {
659: if (rmdir(name) < 0) {
660: reply(550, "%s: %s.", name, sys_errlist[errno]);
661: return;
662: }
663: goto done;
664: }
665: if (unlink(name) < 0) {
666: reply(550, "%s: %s.", name, sys_errlist[errno]);
667: return;
668: }
669: done:
670: ack("DELE");
671: }
672:
673: cwd(path)
674: char *path;
675: {
676:
677: if (chdir(path) < 0) {
678: reply(550, "%s: %s.", path, sys_errlist[errno]);
679: return;
680: }
681: ack("CWD");
682: }
683:
684: makedir(name)
685: char *name;
686: {
687: struct stat st;
688: int dochown = stat(name, &st) < 0;
689:
690: if (mkdir(name, 0777) < 0) {
691: reply(550, "%s: %s.", name, sys_errlist[errno]);
692: return;
693: }
694: if (dochown)
695: (void) chown(name, pw->pw_uid, -1);
696: reply(257, "MKD command successful.");
697: }
698:
699: removedir(name)
700: char *name;
701: {
702:
703: if (rmdir(name) < 0) {
704: reply(550, "%s: %s.", name, sys_errlist[errno]);
705: return;
706: }
707: ack("RMD");
708: }
709:
710: pwd()
711: {
712: char path[MAXPATHLEN + 1];
713:
714: if (getwd(path) == NULL) {
715: reply(550, "%s.", path);
716: return;
717: }
718: reply(257, "\"%s\" is current directory.", path);
719: }
720:
721: char *
722: renamefrom(name)
723: char *name;
724: {
725: struct stat st;
726:
727: if (stat(name, &st) < 0) {
728: reply(550, "%s: %s.", name, sys_errlist[errno]);
729: return ((char *)0);
730: }
731: reply(350, "File exists, ready for destination name");
732: return (name);
733: }
734:
735: renamecmd(from, to)
736: char *from, *to;
737: {
738:
739: if (rename(from, to) < 0) {
740: reply(550, "rename: %s.", sys_errlist[errno]);
741: return;
742: }
743: ack("RNTO");
744: }
745:
746: dolog(sin)
747: struct sockaddr_in *sin;
748: {
749: struct hostent *hp = gethostbyaddr(&sin->sin_addr,
750: sizeof (struct in_addr), AF_INET);
751: time_t t;
752: extern char *ctime();
753:
754: if (hp) {
755: (void) strncpy(remotehost, hp->h_name, sizeof (remotehost));
756: endhostent();
757: } else
758: (void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
759: sizeof (remotehost));
760: if (!logging)
761: return;
762: t = time((time_t *) 0);
763: syslog(LOG_INFO,"FTPD: connection from %s at %s", remotehost, ctime(&t));
764: }
765:
766: #include <utmp.h>
767:
768: #define SCPYN(a, b) (void) strncpy(a, b, sizeof (a))
769: struct utmp utmp;
770:
771: /*
772: * Record login in wtmp file.
773: */
774: dologin(pw)
775: struct passwd *pw;
776: {
777: char line[32];
778:
779: if (wtmp >= 0) {
780: /* hack, but must be unique and no tty line */
781: (void) sprintf(line, "ftp%d", getpid());
782: SCPYN(utmp.ut_line, line);
783: SCPYN(utmp.ut_name, pw->pw_name);
784: SCPYN(utmp.ut_host, remotehost);
785: utmp.ut_time = (long) time((time_t *) 0);
786: (void) write(wtmp, (char *)&utmp, sizeof (utmp));
787: if (!guest) { /* anon must hang on */
788: (void) close(wtmp);
789: wtmp = -1;
790: }
791: }
792: }
793:
794: /*
795: * Record logout in wtmp file
796: * and exit with supplied status.
797: */
798: dologout(status)
799: int status;
800: {
801:
802: if (logged_in) {
803: (void) seteuid(0);
804: if (wtmp < 0)
805: wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
806: if (wtmp >= 0) {
807: SCPYN(utmp.ut_name, "");
808: SCPYN(utmp.ut_host, "");
809: utmp.ut_time = (long) time((time_t *) 0);
810: (void) write(wtmp, (char *)&utmp, sizeof (utmp));
811: (void) close(wtmp);
812: }
813: }
814: /* beware of flushing buffers after a SIGPIPE */
815: _exit(status);
816: }
817:
818: /*
819: * Special version of popen which avoids
820: * call to shell. This insures noone may
821: * create a pipe to a hidden program as a side
822: * effect of a list or dir command.
823: */
824: #define tst(a,b) (*mode == 'r'? (b) : (a))
825: #define RDR 0
826: #define WTR 1
827: static int popen_pid[5];
828:
829: static char *
830: nextarg(cpp)
831: char *cpp;
832: {
833: register char *cp = cpp;
834:
835: if (cp == 0)
836: return (cp);
837: while (*cp && *cp != ' ' && *cp != '\t')
838: cp++;
839: if (*cp == ' ' || *cp == '\t') {
840: *cp++ = '\0';
841: while (*cp == ' ' || *cp == '\t')
842: cp++;
843: }
844: if (cp == cpp)
845: return ((char *)0);
846: return (cp);
847: }
848:
849: FILE *
850: popen(cmd, mode)
851: char *cmd, *mode;
852: {
853: int p[2], ac, gac;
854: register myside, hisside, pid;
855: char *av[20], *gav[512];
856: register char *cp;
857:
858: if (pipe(p) < 0)
859: return (NULL);
860: cp = cmd, ac = 0;
861: /* break up string into pieces */
862: do {
863: av[ac++] = cp;
864: cp = nextarg(cp);
865: } while (cp && *cp && ac < 20);
866: av[ac] = (char *)0;
867: gav[0] = av[0];
868: /* glob each piece */
869: for (gac = ac = 1; av[ac] != NULL; ac++) {
870: char **pop;
871: extern char **glob(), **copyblk();
872:
873: pop = glob(av[ac]);
874: if (pop == (char **)NULL) { /* globbing failed */
875: char *vv[2];
876:
877: vv[0] = av[ac];
878: vv[1] = 0;
879: pop = copyblk(vv);
880: }
881: av[ac] = (char *)pop; /* save to free later */
882: while (*pop && gac < 512)
883: gav[gac++] = *pop++;
884: }
885: gav[gac] = (char *)0;
886: myside = tst(p[WTR], p[RDR]);
887: hisside = tst(p[RDR], p[WTR]);
888: if ((pid = fork()) == 0) {
889: /* myside and hisside reverse roles in child */
890: (void) close(myside);
891: (void) dup2(hisside, tst(0, 1));
892: (void) close(hisside);
893: execv(gav[0], gav);
894: _exit(1);
895: }
896: for (ac = 1; av[ac] != NULL; ac++)
897: blkfree((char **)av[ac]);
898: if (pid == -1)
899: return (NULL);
900: popen_pid[myside] = pid;
901: (void) close(hisside);
902: return (fdopen(myside, mode));
903: }
904:
905: pclose(ptr)
906: FILE *ptr;
907: {
908: register f, r, (*hstat)(), (*istat)(), (*qstat)();
909: int status;
910:
911: f = fileno(ptr);
912: (void) fclose(ptr);
913: istat = signal(SIGINT, SIG_IGN);
914: qstat = signal(SIGQUIT, SIG_IGN);
915: hstat = signal(SIGHUP, SIG_IGN);
916: while ((r = wait(&status)) != popen_pid[f] && r != -1)
917: ;
918: if (r == -1)
919: status = -1;
920: (void) signal(SIGINT, istat);
921: (void) signal(SIGQUIT, qstat);
922: (void) signal(SIGHUP, hstat);
923: return (status);
924: }
925:
926: /*
927: * Check user requesting login priviledges.
928: * Disallow anyone who does not have a standard
929: * shell returned by getusershell() (/etc/shells).
930: * Disallow anyone mentioned in the file FTPUSERS
931: * to allow people such as uucp to be avoided.
932: */
933: checkuser(name)
934: register char *name;
935: {
936: register char *cp;
937: char line[BUFSIZ], *index(), *getusershell();
938: FILE *fd;
939: struct passwd *pw;
940: int found = 0;
941:
942: pw = getpwnam(name);
943: if (pw == NULL)
944: return (0);
945: while ((cp = getusershell()) != NULL)
946: if (strcmp(cp, pw->pw_shell) == 0)
947: break;
948: endpwent();
949: endusershell();
950: if (cp == NULL)
951: return (0);
952: fd = fopen(FTPUSERS, "r");
953: if (fd == NULL)
954: return (1);
955: while (fgets(line, sizeof (line), fd) != NULL) {
956: cp = index(line, '\n');
957: if (cp)
958: *cp = '\0';
959: if (strcmp(line, name) == 0) {
960: found++;
961: break;
962: }
963: }
964: (void) fclose(fd);
965: return (!found);
966: }
967:
968: myoob()
969: {
970: char *cp;
971:
972: /* only process if transfer occurring */
973: if (!transflag) {
974: return;
975: }
976: cp = tmpline;
977: if (getline(cp, 7, stdin) == NULL) {
978: reply(221, "You could at least say goodby.");
979: dologout(0);
980: }
981: upper(cp);
982: if (strcmp(cp, "ABOR\r\n"))
983: return;
984: tmpline[0] = '\0';
985: reply(426,"Transfer aborted. Data connection closed.");
986: reply(226,"Abort successful");
987: longjmp(urgcatch, 1);
988: }
989:
990: /*
991: * Note: The 530 reply codes could be 4xx codes, except nothing is
992: * given in the state tables except 421 which implies an exit. (RFC959)
993: */
994: passive()
995: {
996: int len;
997: struct sockaddr_in tmp;
998: register char *p, *a;
999:
1000: pdata = socket(AF_INET, SOCK_STREAM, 0);
1001: if (pdata < 0) {
1002: reply(530, "Can't open passive connection");
1003: return;
1004: }
1005: tmp = ctrl_addr;
1006: tmp.sin_port = 0;
1007: seteuid(0);
1008: if (bind(pdata, (struct sockaddr *) &tmp, sizeof(tmp)) < 0) {
1009: seteuid(pw->pw_uid);
1010: (void) close(pdata);
1011: pdata = -1;
1012: reply(530, "Can't open passive connection");
1013: return;
1014: }
1015: seteuid(pw->pw_uid);
1016: len = sizeof(tmp);
1017: if (getsockname(pdata, (char *) &tmp, &len) < 0) {
1018: (void) close(pdata);
1019: pdata = -1;
1020: reply(530, "Can't open passive connection");
1021: return;
1022: }
1023: if (listen(pdata, 1) < 0) {
1024: (void) close(pdata);
1025: pdata = -1;
1026: reply(530, "Can't open passive connection");
1027: return;
1028: }
1029: a = (char *) &tmp.sin_addr;
1030: p = (char *) &tmp.sin_port;
1031:
1032: #define UC(b) (((int) b) & 0xff)
1033:
1034: reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
1035: UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1036: }
1037:
1038: char *
1039: gunique(local)
1040: char *local;
1041: {
1042: static char new[MAXPATHLEN];
1043: char *cp = rindex(local, '/');
1044: int d, count=0;
1045: char ext = '1';
1046:
1047: if (cp) {
1048: *cp = '\0';
1049: }
1050: d = access(cp ? local : ".", 2);
1051: if (cp) {
1052: *cp = '/';
1053: }
1054: if (d < 0) {
1055: syslog(LOG_ERR, "%s: %m", local);
1056: return((char *) 0);
1057: }
1058: (void) strcpy(new, local);
1059: cp = new + strlen(new);
1060: *cp++ = '.';
1061: while (!d) {
1062: if (++count == 100) {
1063: reply(452, "Unique file name not cannot be created.");
1064: return((char *) 0);
1065: }
1066: *cp++ = ext;
1067: *cp = '\0';
1068: if (ext == '9') {
1069: ext = '0';
1070: }
1071: else {
1072: ext++;
1073: }
1074: if ((d = access(new, 0)) < 0) {
1075: break;
1076: }
1077: if (ext != '0') {
1078: cp--;
1079: }
1080: else if (*(cp - 2) == '.') {
1081: *(cp - 1) = '1';
1082: }
1083: else {
1084: *(cp - 2) = *(cp - 2) + 1;
1085: cp--;
1086: }
1087: }
1088: return(new);
1089: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.