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