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