xref: /csrg-svn/libexec/ftpd/ftpd.c (revision 35691)
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.14 (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, "Openning data connection for %s (%s,%d)%s.",
440 		     name, inet_ntoa(from.sin_addr),
441 		     ntohs(from.sin_port), sizebuf);
442 		return(fdopen(pdata, mode));
443 	}
444 	if (data >= 0) {
445 		reply(125, "Using existing data connection for %s%s.",
446 		    name, sizebuf);
447 		usedefault = 1;
448 		return (fdopen(data, mode));
449 	}
450 	if (usedefault)
451 		data_dest = his_addr;
452 	usedefault = 1;
453 	file = getdatasock(mode);
454 	if (file == NULL) {
455 		reply(425, "Can't create data socket (%s,%d): %s.",
456 		    inet_ntoa(data_source.sin_addr),
457 		    ntohs(data_source.sin_port),
458 		    sys_errlist[errno]);
459 		return (NULL);
460 	}
461 	data = fileno(file);
462 	while (connect(data, &data_dest, sizeof (data_dest)) < 0) {
463 		if (errno == EADDRINUSE && retry < swaitmax) {
464 			sleep((unsigned) swaitint);
465 			retry += swaitint;
466 			continue;
467 		}
468 		reply(425, "Can't build data connection: %s.",
469 		    sys_errlist[errno]);
470 		(void) fclose(file);
471 		data = -1;
472 		return (NULL);
473 	}
474 	reply(150, "Opening data connection for %s (%s,%d)%s.",
475 	    name, inet_ntoa(data_dest.sin_addr),
476 	    ntohs(data_dest.sin_port), sizebuf);
477 	return (file);
478 }
479 
480 /*
481  * Tranfer the contents of "instr" to
482  * "outstr" peer using the appropriate
483  * encapulation of the date subject
484  * to Mode, Structure, and Type.
485  *
486  * NB: Form isn't handled.
487  */
488 send_data(instr, outstr)
489 	FILE *instr, *outstr;
490 {
491 	register int c;
492 	int netfd, filefd, cnt;
493 	char buf[BUFSIZ];
494 
495 	transflag++;
496 	if (setjmp(urgcatch)) {
497 		transflag = 0;
498 		return(-1);
499 	}
500 	switch (type) {
501 
502 	case TYPE_A:
503 		while ((c = getc(instr)) != EOF) {
504 			if (c == '\n') {
505 				if (ferror (outstr)) {
506 					transflag = 0;
507 					return (1);
508 				}
509 				(void) putc('\r', outstr);
510 			}
511 			(void) putc(c, outstr);
512 		/*	if (c == '\r')			*/
513 		/*		putc ('\0', outstr);	*/
514 		}
515 		transflag = 0;
516 		if (ferror (instr) || ferror (outstr)) {
517 			return (1);
518 		}
519 		return (0);
520 
521 	case TYPE_I:
522 	case TYPE_L:
523 		netfd = fileno(outstr);
524 		filefd = fileno(instr);
525 
526 		while ((cnt = read(filefd, buf, sizeof (buf))) > 0) {
527 			if (write(netfd, buf, cnt) < 0) {
528 				transflag = 0;
529 				return (1);
530 			}
531 		}
532 		transflag = 0;
533 		return (cnt < 0);
534 	}
535 	reply(550, "Unimplemented TYPE %d in send_data", type);
536 	transflag = 0;
537 	return (-1);
538 }
539 
540 /*
541  * Transfer data from peer to
542  * "outstr" using the appropriate
543  * encapulation of the data subject
544  * to Mode, Structure, and Type.
545  *
546  * N.B.: Form isn't handled.
547  */
548 receive_data(instr, outstr)
549 	FILE *instr, *outstr;
550 {
551 	register int c;
552 	int cnt;
553 	char buf[BUFSIZ];
554 
555 
556 	transflag++;
557 	if (setjmp(urgcatch)) {
558 		transflag = 0;
559 		return(-1);
560 	}
561 	switch (type) {
562 
563 	case TYPE_I:
564 	case TYPE_L:
565 		while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
566 			if (write(fileno(outstr), buf, cnt) < 0) {
567 				transflag = 0;
568 				return (1);
569 			}
570 		}
571 		transflag = 0;
572 		return (cnt < 0);
573 
574 	case TYPE_E:
575 		reply(553, "TYPE E not implemented.");
576 		transflag = 0;
577 		return (-1);
578 
579 	case TYPE_A:
580 		while ((c = getc(instr)) != EOF) {
581 			while (c == '\r') {
582 				if (ferror (outstr)) {
583 					transflag = 0;
584 					return (1);
585 				}
586 				if ((c = getc(instr)) != '\n')
587 					(void) putc ('\r', outstr);
588 			/*	if (c == '\0')			*/
589 			/*		continue;		*/
590 			}
591 			(void) putc (c, outstr);
592 		}
593 		transflag = 0;
594 		if (ferror (instr) || ferror (outstr))
595 			return (1);
596 		return (0);
597 	}
598 	transflag = 0;
599 	fatal("Unknown type in receive_data.");
600 	/*NOTREACHED*/
601 }
602 
603 fatal(s)
604 	char *s;
605 {
606 	reply(451, "Error in server: %s\n", s);
607 	reply(221, "Closing connection due to server error.");
608 	dologout(0);
609 }
610 
611 reply(n, s, p0, p1, p2, p3, p4)
612 	int n;
613 	char *s;
614 {
615 
616 	printf("%d ", n);
617 	printf(s, p0, p1, p2, p3, p4);
618 	printf("\r\n");
619 	(void) fflush(stdout);
620 	if (debug) {
621 		syslog(LOG_DEBUG, "<--- %d ", n);
622 		syslog(LOG_DEBUG, s, p0, p1, p2, p3, p4);
623 	}
624 }
625 
626 lreply(n, s, p0, p1, p2, p3, p4)
627 	int n;
628 	char *s;
629 {
630 	printf("%d-", n);
631 	printf(s, p0, p1, p2, p3, p4);
632 	printf("\r\n");
633 	(void) fflush(stdout);
634 	if (debug) {
635 		syslog(LOG_DEBUG, "<--- %d- ", n);
636 		syslog(LOG_DEBUG, s, p0, p1, p2, p3, p4);
637 	}
638 }
639 
640 ack(s)
641 	char *s;
642 {
643 	reply(250, "%s command successful.", s);
644 }
645 
646 nack(s)
647 	char *s;
648 {
649 	reply(502, "%s command not implemented.", s);
650 }
651 
652 yyerror(s)
653 	char *s;
654 {
655 	char *cp;
656 
657 	cp = index(cbuf,'\n');
658 	*cp = '\0';
659 	reply(500, "'%s': command not understood.",cbuf);
660 }
661 
662 delete(name)
663 	char *name;
664 {
665 	struct stat st;
666 
667 	if (stat(name, &st) < 0) {
668 		reply(550, "%s: %s.", name, sys_errlist[errno]);
669 		return;
670 	}
671 	if ((st.st_mode&S_IFMT) == S_IFDIR) {
672 		if (rmdir(name) < 0) {
673 			reply(550, "%s: %s.", name, sys_errlist[errno]);
674 			return;
675 		}
676 		goto done;
677 	}
678 	if (unlink(name) < 0) {
679 		reply(550, "%s: %s.", name, sys_errlist[errno]);
680 		return;
681 	}
682 done:
683 	ack("DELE");
684 }
685 
686 cwd(path)
687 	char *path;
688 {
689 
690 	if (chdir(path) < 0) {
691 		reply(550, "%s: %s.", path, sys_errlist[errno]);
692 		return;
693 	}
694 	ack("CWD");
695 }
696 
697 makedir(name)
698 	char *name;
699 {
700 	struct stat st;
701 	int dochown = stat(name, &st) < 0;
702 
703 	if (mkdir(name, 0777) < 0) {
704 		reply(550, "%s: %s.", name, sys_errlist[errno]);
705 		return;
706 	}
707 	if (dochown)
708 		(void) chown(name, pw->pw_uid, -1);
709 	reply(257, "MKD command successful.");
710 }
711 
712 removedir(name)
713 	char *name;
714 {
715 
716 	if (rmdir(name) < 0) {
717 		reply(550, "%s: %s.", name, sys_errlist[errno]);
718 		return;
719 	}
720 	ack("RMD");
721 }
722 
723 pwd()
724 {
725 	char path[MAXPATHLEN + 1];
726 
727 	if (getwd(path) == NULL) {
728 		reply(550, "%s.", path);
729 		return;
730 	}
731 	reply(257, "\"%s\" is current directory.", path);
732 }
733 
734 char *
735 renamefrom(name)
736 	char *name;
737 {
738 	struct stat st;
739 
740 	if (stat(name, &st) < 0) {
741 		reply(550, "%s: %s.", name, sys_errlist[errno]);
742 		return ((char *)0);
743 	}
744 	reply(350, "File exists, ready for destination name");
745 	return (name);
746 }
747 
748 renamecmd(from, to)
749 	char *from, *to;
750 {
751 
752 	if (rename(from, to) < 0) {
753 		reply(550, "rename: %s.", sys_errlist[errno]);
754 		return;
755 	}
756 	ack("RNTO");
757 }
758 
759 dolog(sin)
760 	struct sockaddr_in *sin;
761 {
762 	struct hostent *hp = gethostbyaddr(&sin->sin_addr,
763 		sizeof (struct in_addr), AF_INET);
764 	time_t t;
765 	extern char *ctime();
766 
767 	if (hp) {
768 		(void) strncpy(remotehost, hp->h_name, sizeof (remotehost));
769 		endhostent();
770 	} else
771 		(void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
772 		    sizeof (remotehost));
773 	if (!logging)
774 		return;
775 	t = time((time_t *) 0);
776 	syslog(LOG_INFO,"FTPD: connection from %s at %s", remotehost, ctime(&t));
777 }
778 
779 /*
780  * Record logout in wtmp file
781  * and exit with supplied status.
782  */
783 dologout(status)
784 	int status;
785 {
786 	if (logged_in) {
787 		(void) seteuid(0);
788 		logwtmp(ttyline, "", "");
789 	}
790 	/* beware of flushing buffers after a SIGPIPE */
791 	_exit(status);
792 }
793 
794 /*
795  * Check user requesting login priviledges.
796  * Disallow anyone who does not have a standard
797  * shell returned by getusershell() (/etc/shells).
798  * Disallow anyone mentioned in the file FTPUSERS
799  * to allow people such as uucp to be avoided.
800  */
801 checkuser(name)
802 	register char *name;
803 {
804 	register char *cp;
805 	char line[BUFSIZ], *index(), *getusershell();
806 	FILE *fd;
807 	struct passwd *pw;
808 	int found = 0;
809 
810 	pw = getpwnam(name);
811 	if (pw == NULL)
812 		return (0);
813 	if (pw ->pw_shell == NULL || pw->pw_shell[0] == NULL)
814 		pw->pw_shell = "/bin/sh";
815 	while ((cp = getusershell()) != NULL)
816 		if (strcmp(cp, pw->pw_shell) == 0)
817 			break;
818 	endusershell();
819 	if (cp == NULL)
820 		return (0);
821 	fd = fopen(FTPUSERS, "r");
822 	if (fd == NULL)
823 		return (1);
824 	while (fgets(line, sizeof (line), fd) != NULL) {
825 		cp = index(line, '\n');
826 		if (cp)
827 			*cp = '\0';
828 		if (strcmp(line, name) == 0) {
829 			found++;
830 			break;
831 		}
832 	}
833 	(void) fclose(fd);
834 	return (!found);
835 }
836 
837 myoob()
838 {
839 	char *cp;
840 
841 	/* only process if transfer occurring */
842 	if (!transflag) {
843 		return;
844 	}
845 	cp = tmpline;
846 	if (getline(cp, 7, stdin) == NULL) {
847 		reply(221, "You could at least say goodby.");
848 		dologout(0);
849 	}
850 	upper(cp);
851 	if (strcmp(cp, "ABOR\r\n"))
852 		return;
853 	tmpline[0] = '\0';
854 	reply(426,"Transfer aborted. Data connection closed.");
855 	reply(226,"Abort successful");
856 	longjmp(urgcatch, 1);
857 }
858 
859 /*
860  * Note: The 530 reply codes could be 4xx codes, except nothing is
861  * given in the state tables except 421 which implies an exit.  (RFC959)
862  */
863 passive()
864 {
865 	int len;
866 	struct sockaddr_in tmp;
867 	register char *p, *a;
868 
869 	pdata = socket(AF_INET, SOCK_STREAM, 0);
870 	if (pdata < 0) {
871 		reply(530, "Can't open passive connection");
872 		return;
873 	}
874 	tmp = ctrl_addr;
875 	tmp.sin_port = 0;
876 	seteuid(0);
877 	if (bind(pdata, (struct sockaddr *) &tmp, sizeof(tmp)) < 0) {
878 		seteuid(pw->pw_uid);
879 		(void) close(pdata);
880 		pdata = -1;
881 		reply(530, "Can't open passive connection");
882 		return;
883 	}
884 	seteuid(pw->pw_uid);
885 	len = sizeof(tmp);
886 	if (getsockname(pdata, (char *) &tmp, &len) < 0) {
887 		(void) close(pdata);
888 		pdata = -1;
889 		reply(530, "Can't open passive connection");
890 		return;
891 	}
892 	if (listen(pdata, 1) < 0) {
893 		(void) close(pdata);
894 		pdata = -1;
895 		reply(530, "Can't open passive connection");
896 		return;
897 	}
898 	a = (char *) &tmp.sin_addr;
899 	p = (char *) &tmp.sin_port;
900 
901 #define UC(b) (((int) b) & 0xff)
902 
903 	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
904 		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
905 }
906 
907 char *
908 gunique(local)
909 	char *local;
910 {
911 	static char new[MAXPATHLEN];
912 	char *cp = rindex(local, '/');
913 	int d, count=0;
914 	char ext = '1';
915 
916 	if (cp) {
917 		*cp = '\0';
918 	}
919 	d = access(cp ? local : ".", 2);
920 	if (cp) {
921 		*cp = '/';
922 	}
923 	if (d < 0) {
924 		syslog(LOG_ERR, "%s: %m", local);
925 		return((char *) 0);
926 	}
927 	(void) strcpy(new, local);
928 	cp = new + strlen(new);
929 	*cp++ = '.';
930 	while (!d) {
931 		if (++count == 100) {
932 			reply(452, "Unique file name not cannot be created.");
933 			return((char *) 0);
934 		}
935 		*cp++ = ext;
936 		*cp = '\0';
937 		if (ext == '9') {
938 			ext = '0';
939 		}
940 		else {
941 			ext++;
942 		}
943 		if ((d = access(new, 0)) < 0) {
944 			break;
945 		}
946 		if (ext != '0') {
947 			cp--;
948 		}
949 		else if (*(cp - 2) == '.') {
950 			*(cp - 1) = '1';
951 		}
952 		else {
953 			*(cp - 2) = *(cp - 2) + 1;
954 			cp--;
955 		}
956 	}
957 	return(new);
958 }
959