xref: /csrg-svn/libexec/ftpd/ftpd.c (revision 28864)
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) 05/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 }
1090