xref: /original-bsd/libexec/ftpd/ftpd.c (revision 65ba69af)
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) 06/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 }
1101