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