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