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