xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/ftpd.c (revision 12333:f835be4545bb)
1 /*
2  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /****************************************************************************
6 
7   Copyright (c) 1999,2000,2001 WU-FTPD Development Group.
8   All rights reserved.
9 
10   Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994
11     The Regents of the University of California.
12   Portions Copyright (c) 1993, 1994 Washington University in Saint Louis.
13   Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc.
14   Portions Copyright (c) 1989 Massachusetts Institute of Technology.
15   Portions Copyright (c) 1998 Sendmail, Inc.
16   Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P.  Allman.
17   Portions Copyright (c) 1997 by Stan Barber.
18   Portions Copyright (c) 1997 by Kent Landfield.
19   Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997
20     Free Software Foundation, Inc.
21 
22   Use and distribution of this software and its source code are governed
23   by the terms and conditions of the WU-FTPD Software License ("LICENSE").
24 
25   If you did not receive a copy of the license, it may be obtained online
26   at http://www.wu-ftpd.org/license.html.
27 
28   $Id: ftpd.c,v 1.111 2000/07/01 18:17:39 wuftpd Exp $
29 
30 ****************************************************************************/
31 /* FTP server. */
32 #include "config.h"
33 
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/stat.h>
37 #include <sys/ioctl.h>
38 #include <sys/socket.h>
39 #include <sys/file.h>
40 #include <sys/wait.h>
41 
42 #ifdef AIX
43 #include <sys/id.h>
44 #include <sys/priv.h>
45 #include <netinet/if_ether.h>
46 #include <net/if_dl.h>
47 #endif
48 
49 #ifdef AUX
50 #include <compat.h>
51 #endif
52 
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 
57 #define FTP_NAMES
58 #include <arpa/ftp.h>
59 #include <arpa/inet.h>
60 
61 #include <ctype.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <signal.h>
65 #include <pwd.h>
66 #include <grp.h>
67 #include <setjmp.h>
68 #include <errno.h>
69 #include <string.h>
70 #ifdef INTERNAL_LS
71 #ifdef HAVE_GLOB_H
72 #include <glob.h>
73 #else
74 #include <wuftpd_glob.h>
75 #endif
76 #endif
77 #ifdef HAVE_GRP_H
78 #include <grp.h>
79 #endif
80 #include <sys/stat.h>
81 
82 #define VA_LOCAL_DECL	va_list ap;
83 #define VA_START(f)	va_start(ap, f)
84 #define VA_END		va_end(ap)
85 
86 #include "proto.h"
87 
88 #ifdef HAVE_UFS_QUOTA_H
89 #include <ufs/quota.h>
90 #endif
91 #ifdef HAVE_SYS_FS_UFS_QUOTA_H
92 #include <sys/fs/ufs_quota.h>
93 #endif
94 
95 #ifdef HAVE_SYS_SYSLOG_H
96 #include <sys/syslog.h>
97 #endif
98 #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H))
99 #include <syslog.h>
100 #endif
101 #ifdef TIME_WITH_SYS_TIME
102 #include <time.h>
103 #include <sys/time.h>
104 #else
105 #ifdef HAVE_SYS_TIME_H
106 #include <sys/time.h>
107 #else
108 #include <time.h>
109 #endif
110 #endif
111 
112 #ifdef HAVE_SYS_SENDFILE_H
113 #include <sys/sendfile.h>
114 #endif
115 
116 #include "conversions.h"
117 #include "extensions.h"
118 
119 #ifdef SHADOW_PASSWORD
120 #include <shadow.h>
121 #endif
122 
123 #include "pathnames.h"
124 
125 #ifdef M_UNIX
126 #include <arpa/nameser.h>
127 #include <resolv.h>
128 #endif
129 
130 #if defined(HAVE_FCNTL_H)
131 #include <fcntl.h>
132 #endif
133 
134 #ifdef HAVE_SYSINFO
135 #include <sys/systeminfo.h>
136 #endif
137 
138 #ifdef KERBEROS
139 #include <sys/types.h>
140 #include <auth.h>
141 #include <krb.h>
142 #endif
143 
144 #ifdef ULTRIX_AUTH
145 #include <auth.h>
146 #include <sys/svcinfo.h>
147 #endif
148 
149 #ifndef HAVE_LSTAT
150 #define lstat stat
151 #endif
152 
153 #ifdef AFS_AUTH
154 #include <afs/stds.h>
155 #include <afs/kautils.h>
156 #endif
157 
158 #ifdef DCE_AUTH
159 #include <dce/rpc.h>
160 #include <dce/sec_login.h>
161 #include <dce/dce_error.h>
162 #endif
163 
164 
165 #ifdef HAVE_DIRENT_H
166 #include <dirent.h>
167 #else
168 #include <sys/dir.h>
169 #endif
170 
171 #if defined(USE_LONGJMP)
172 #define wu_longjmp(x, y)	longjmp((x), (y))
173 #define wu_setjmp(x)		setjmp(x)
174 #ifndef JMP_BUF
175 #define JMP_BUF			jmp_buf
176 #endif
177 #else
178 #define wu_longjmp(x, y)	siglongjmp((x), (y))
179 #define wu_setjmp(x)		sigsetjmp((x), 1)
180 #ifndef JMP_BUF
181 #define JMP_BUF			sigjmp_buf
182 #endif
183 #endif
184 
185 #ifndef MAXHOSTNAMELEN
186 #define MAXHOSTNAMELEN 64	/* may be too big */
187 #endif
188 
189 #ifndef TRUE
190 #define  TRUE   1
191 #endif
192 
193 #ifndef FALSE
194 #define  FALSE  !TRUE
195 #endif
196 
197 #ifdef MAIL_ADMIN
198 #define MAILSERVERS 10
199 #define INCMAILS 10
200 int mailservers = 0;
201 char *mailserver[MAILSERVERS];
202 int incmails = 0;
203 char *incmail[INCMAILS];
204 char *mailfrom;
205 char *email(char *full_address);
206 FILE *SockOpen(char *host, int clientPort);
207 char *SockGets(FILE *sockfp, char *buf, int len);
208 int SockWrite(char *buf, int size, int nels, FILE *sockfp);
209 int SockPrintf(FILE *sockfp, char *format,...);
210 int SockPuts(FILE *sockfp, char *buf);
211 int Reply(FILE *sockfp);
212 int Send(FILE *sockfp, char *format,...);
213 #endif /* MAIL_ADMIN */
214 
215 #if defined(_SCO_DS) && !defined(SIGURG)
216 #define SIGURG	SIGUSR1
217 #endif
218 
219 /* File containing login names NOT to be used on this machine. Commonly used
220  * to disallow uucp. */
221 extern int errno;
222 
223 extern char *ctime(const time_t *);
224 #ifndef NO_CRYPT_PROTO
225 extern char *crypt(const char *, const char *);
226 #endif
227 
228 extern char version[];
229 extern char *home;		/* pointer to home directory for glob */
230 extern char cbuf[];
231 extern off_t restart_point;
232 extern int yyerrorcalled;
233 
234 struct SOCKSTORAGE ctrl_addr;
235 struct SOCKSTORAGE data_source;
236 struct SOCKSTORAGE data_dest;
237 struct SOCKSTORAGE his_addr;
238 struct SOCKSTORAGE pasv_addr;
239 struct SOCKSTORAGE vect_addr;
240 int route_vectored = 0;
241 int passive_port_min = 1024;
242 int passive_port_max = 65535;
243 int restricted_user = 0;
244 unsigned short data_port = 0;
245 
246 #ifdef INET6
247 int ctrl_v4mapped = 0;
248 int epsv_all = 0;
249 int listen_v4 = 0;	/* when set, listen on IPv4 socket in standalone mode */
250 #endif
251 
252 #ifdef VIRTUAL
253 char virtual_root[MAXPATHLEN];
254 char virtual_banner[MAXPATHLEN];
255 char virtual_email[MAXPATHLEN];
256 
257 char virtual_hostname[MAXHOSTNAMELEN];
258 char virtual_address[MAXHOSTNAMELEN];
259 
260 extern int virtual_mode;
261 extern int virtual_ftpaccess;
262 #endif
263 
264 #ifdef QUOTA
265 extern struct dqblk quota;
266 #endif
267 
268 #if defined(USE_GSS)
269 #include "gssutil.h"
270 
271 extern gss_info_t gss_info;
272 
273 int allow_ccc = 0;
274 int ccc_ok = 0;
275 extern char *cur_auth_type;
276 #endif /* USE_GSS */
277 
278 int data;
279 jmp_buf errcatch;
280 JMP_BUF urgcatch;
281 int logged_in = 0;
282 struct passwd *pw;
283 char chroot_path[MAXPATHLEN];
284 int debug = 0;
285 int disable_rfc931 = 0;
286 extern unsigned int timeout_idle;
287 extern unsigned int timeout_maxidle;
288 extern unsigned int timeout_data;
289 extern unsigned int timeout_accept;
290 extern unsigned int timeout_connect;
291 
292 /* previously defaulted to 1, and -l or -L set them to 1, so that there was
293    no way to turn them *off*!  Changed so that the manpage reflects common
294    sense.  -L is way noisy; -l we'll change to be "just right".  _H */
295 int logging = 0;
296 int log_commands = 0;
297 int log_security = 0;
298 int syslogmsg = 0;
299 static int wtmp_logging = 1;
300 
301 #ifdef SECUREOSF
302 #define SecureWare		/* Does this mean it works for all SecureWare? */
303 #endif
304 
305 #ifdef HPUX_10_TRUSTED
306 #include <hpsecurity.h>
307 #endif
308 
309 #if defined(SecureWare) || defined(HPUX_10_TRUSTED)
310 #include <prot.h>
311 #endif
312 
313 int anonymous = 1;
314 int guest;
315 int type;
316 int form;
317 int stru;			/* avoid C keyword */
318 int mode;
319 int usedefault = 1;		/* for data transfers */
320 int pdata = -1;			/* for passive mode */
321 int transflag;
322 int ftwflag;
323 off_t file_size;
324 off_t byte_count;
325 int TCPwindowsize = 0;		/* 0 = use system default */
326 size_t sendbufsz;		/* buffer size to use when sending data */
327 size_t recvbufsz;		/* buffer size to use when receiving data */
328 
329 #ifdef TRANSFER_COUNT
330 off_t data_count_total = 0;	/* total number of data bytes */
331 off_t data_count_in = 0;
332 off_t data_count_out = 0;
333 off_t byte_count_total = 0;	/* total number of general traffic */
334 off_t byte_count_in = 0;
335 off_t byte_count_out = 0;
336 int file_count_total = 0;	/* total number of data files */
337 int file_count_in = 0;
338 int file_count_out = 0;
339 int xfer_count_total = 0;	/* total number of transfers */
340 int xfer_count_in = 0;
341 int xfer_count_out = 0;
342 #ifdef TRANSFER_LIMIT
343 int file_limit_raw_in = 0;
344 int file_limit_raw_out = 0;
345 int file_limit_raw_total = 0;
346 int file_limit_data_in = 0;
347 int file_limit_data_out = 0;
348 int file_limit_data_total = 0;
349 off_t data_limit_raw_in = 0;
350 off_t data_limit_raw_out = 0;
351 off_t data_limit_raw_total = 0;
352 off_t data_limit_data_in = 0;
353 off_t data_limit_data_out = 0;
354 off_t data_limit_data_total = 0;
355 #ifdef RATIO /* 1998/08/04 K.Wakui */
356 #define TRUNC_KB(n)   ((n)/1024+(((n)%1024)?1:0))
357 off_t   total_free_dl = 0;
358 int     upload_download_rate = 0;
359 int     freefile;
360 int     is_downloadfree( char * );
361 #endif /* RATIO */
362 #endif
363 #endif
364 
365 int retrieve_is_data = 1;	/* !0=data, 0=general traffic -- for 'ls' */
366 char LastFileTransferred[MAXPATHLEN] = "";
367 
368 static char *RootDirectory = NULL;
369 
370 #if !defined(CMASK) || CMASK == 0
371 #undef CMASK
372 #define CMASK 022
373 #endif
374 mode_t defumask = CMASK;	/* default umask value */
375 #ifdef ALTERNATE_CD
376 char defhome[] = "/";
377 #endif
378 char tmpline[7];
379 char hostname[MAXHOSTNAMELEN];
380 char remotehost[MAXHOSTNAMELEN];
381 char remoteaddr[MAXHOSTNAMELEN];
382 char *remoteident = "[nowhere yet]";
383 int rhlookup = TRUE;		/* when TRUE lookup the remote hosts name */
384 
385 #if defined(SOLARIS_2) && !defined(NAME_SERVICE_DOOR)
386 #define NAME_SERVICE_DOOR "/var/run/name_service_door"
387 #endif
388 
389 #if defined(SOLARIS_2)
390 int close_nsdoor(void *cb_data, int fd);
391 void cleanup_nscd();
392 #endif
393 
394 /* log failures         27-apr-93 ehk/bm */
395 #define MAXUSERNAMELEN	256
396 char the_user[MAXUSERNAMELEN];
397 
398 /* Access control and logging passwords */
399 /* OFF by default.  _H */
400 int use_accessfile = 0;
401 char guestpw[MAXHOSTNAMELEN];
402 char privatepw[MAXHOSTNAMELEN];
403 int nameserved = 0;
404 extern char authuser[];
405 extern int authenticated;
406 extern int keepalive;
407 
408 /* File transfer logging (xferlog) */
409 int xferlog = 0;
410 int log_outbound_xfers = 0;
411 int log_incoming_xfers = 0;
412 char logfile[MAXPATHLEN];
413 
414 /* Allow use of lreply(); this is here since some older FTP clients don't
415  * support continuation messages.  In violation of the RFCs... */
416 int dolreplies = 1;
417 
418 /* Spontaneous reply text.  To be sent along with next reply to user */
419 char *autospout = NULL;
420 int autospout_free = 0;
421 
422 /* allowed on-the-fly file manipulations (compress, tar) */
423 int mangleopts = 0;
424 
425 /* number of login failures before attempts are logged and FTP *EXITS* */
426 int lgi_failure_threshold = 5;
427 
428 /* Timeout intervals for retrying connections to hosts that don't accept PORT
429  * cmds.  This is a kludge, but given the problems with TCP... */
430 #define SWAITMAX    90		/* wait at most 90 seconds */
431 #define SWAITINT    5		/* interval between retries */
432 
433 int swaitmax = SWAITMAX;
434 int swaitint = SWAITINT;
435 
436 SIGNAL_TYPE lostconn(int sig);
437 SIGNAL_TYPE randomsig(int sig);
438 SIGNAL_TYPE myoob(int sig);
439 FILE *getdatasock(char *mode);
440 FILE *dataconn(char *name, off_t size, char *mode);
441 void setproctitle(const char *fmt,...);
442 void initsetproctitle(int, char **, char **);
443 void reply(int, char *fmt,...);
444 void lreply(int, char *fmt,...);
445 
446 #ifndef HAVE_VSNPRINTF
447 extern int vsnprintf(char *, size_t, const char *, va_list);
448 #endif
449 
450 #ifndef HAVE_SNPRINTF
451 extern int snprintf(char *, size_t, const char *,...);
452 #endif
453 
454 #ifdef NEED_SIGFIX
455 extern sigset_t block_sigmask;	/* defined in sigfix.c */
456 #endif
457 
458 char proctitle[BUFSIZ];		/* initial part of title */
459 
460 #if defined(SKEY) && defined(OPIE)
461 #error YOU SHOULD NOT HAVE BOTH SKEY AND OPIE DEFINED!!!!!
462 #endif
463 
464 #ifdef SKEY
465 #include <skey.h>
466 int pwok = 0;
467 #endif
468 
469 #ifdef OPIE
470 #include <opie.h>
471 int pwok = 0;
472 int af_pwok = 0;
473 struct opie opiestate;
474 #endif
475 
476 #ifdef KERBEROS
477 void init_krb();
478 void end_krb();
479 char krb_ticket_name[100];
480 #endif /* KERBEROS */
481 
482 #ifdef ULTRIX_AUTH
483 int ultrix_check_pass(char *passwd, char *xpasswd);
484 #endif
485 
486 #ifdef USE_PAM
487 #if defined(ULTRIX_AUTH) || defined(SECUREOSF) || defined(KERBEROS) || defined(SKEY) || defined (OPIE) || defined (BSD_AUTH)
488 #error No other auth methods are allowed with PAM.
489 #endif
490 #include <security/pam_appl.h>
491 static int pam_check_pass(char *user, char *passwd);
492 pam_handle_t *pamh;
493 #endif
494 
495 #ifndef INTERNAL_LS
496 /* ls program commands and options for lreplies on and off */
497 char ls_long[BUFSIZ * 2];
498 char ls_short[BUFSIZ * 2];
499 char ls_plain[BUFSIZ * 2];
500 #endif
501 
502 #define FTPD_OPTS	":4aAdiIlLoP:qQr:t:T:u:vVwWxX"
503 #if defined(DAEMON)
504 #  define DAEMON_OPTS	"p:sS"
505 #else /* !(defined(DAEMON)) */
506 #  define DAEMON_OPTS
507 #endif /* !(defined(DAEMON)) */
508 #if defined(USE_GSS)
509 #  define GSS_OPTS	"CK"
510 #else /* !(defined(USE_GSS)) */
511 #  define GSS_OPTS
512 #endif /* !(defined(USE_GSS)) */
513 
514 /* Some systems use one format, some another.  This takes care of the garbage */
515 #ifndef L_FORMAT		/* Autoconf detects this... */
516 #if (defined(BSD) && (BSD >= 199103)) && !defined(LONGOFF_T)
517 #define L_FORMAT "qd"
518 #else
519 #ifdef _AIX42
520 #define L_FORMAT "lld"
521 #else
522 #ifdef SOLARIS_2
523 #define L_FORMAT "ld"
524 #else
525 #define L_FORMAT "d"
526 #endif
527 #endif
528 #endif
529 #endif
530 
531 #ifdef DAEMON
532 int be_daemon = 0;		/* Run standalone? */
533 int daemon_port = 0;
534 static void do_daemon(void);
535 #endif
536 int Bypass_PID_Files = 0;
537 
538 #ifdef OTHER_PASSWD
539 #include "getpwnam.h"
540 char _path_passwd[MAXPATHLEN];
541 #ifdef SHADOW_PASSWORD
542 char _path_shadow[MAXPATHLEN];
543 #endif
544 #endif
545 #if defined(USE_PAM) && defined(OTHER_PASSWD)
546 int use_pam = 1;
547 #else
548 int use_pam = 0;
549 #endif
550 
551 void print_copyright(void);
552 char *mapping_getcwd(char *path, size_t size);
553 
554 void dolog(struct SOCKSTORAGE *);
555 
556 #ifdef THROUGHPUT
557 extern void throughput_calc(char *, int *, double *);
558 extern void throughput_adjust(char *);
559 #endif
560 
561 time_t login_time;
562 time_t limit_time = 0;
563 
564 int regexmatch(char *name, char *rgexp);
565 
566 int pasv_allowed(char *remoteaddr);
567 int port_allowed(char *remoteaddr);
568 
569 #if sparc && !__svr4__
570 int fclose(FILE *);
571 #endif
572 
alarm_signal(int sig)573 static SIGNAL_TYPE alarm_signal(int sig)
574 {
575 }
576 
577 static FILE *draconian_FILE = NULL;
578 
draconian_alarm_signal(int sig)579 static SIGNAL_TYPE draconian_alarm_signal(int sig)
580 {
581     if (draconian_FILE != NULL) {
582 	fclose(draconian_FILE);
583 	draconian_FILE = NULL;
584     }
585     (void) signal(SIGALRM, draconian_alarm_signal);
586 }
587 
socket_flush_wait(FILE * file)588 static void socket_flush_wait(FILE *file)
589 {
590     static int flushwait = TRUE;
591     static int first_time = TRUE;
592     char c;
593     int set;
594     int fd = fileno(file);
595     int serrno = errno;
596     struct aclmember *entry;
597 
598     if (first_time) {
599 	entry = NULL;
600 	/* flush-wait yes|no [typelist] */
601 	while (getaclentry("flush-wait", &entry)) {
602 	    if (!ARG0)
603 		continue;
604 	    if (strcasecmp(ARG0, "yes") == 0)
605 		set = TRUE;
606 	    else if (strcasecmp(ARG0, "no") == 0)
607 		set = FALSE;
608 	    else
609 		continue;
610 
611 	    if (!ARG1)
612 		flushwait = set;
613 	    else if (type_match(ARG1)) {
614 		flushwait = set;
615 		break;
616 	    }
617 	}
618 	first_time = FALSE;
619     }
620     if (flushwait) {
621 	if (draconian_FILE != NULL)
622 	    shutdown(fd, 1);
623 	if (draconian_FILE != NULL)
624 	    read(fd, &c, 1);
625     }
626     errno = serrno;
627 /*
628  * GAL - the read() here should be checked to ensure it returned 0 (indicating
629  * EOF) or -1 (an error occurred).  Anything else (real data) is a protocol
630  * error.
631  */
632 }
633 
IPClassOfService(const char * type)634 static int IPClassOfService(const char *type)
635 {
636     int ipcos = -1, value;
637     char *endp;
638     struct aclmember *entry = NULL;
639 
640     /* ipcos control|data <value> [<typelist>] */
641     while (getaclentry("ipcos", &entry)) {
642 	if (ARG0 && ARG1) {
643 	    if (strcasecmp(type, ARG0) == 0) {
644 		if (!ARG2) {
645 		    errno = 0;
646 		    value = (int) strtol(ARG1, &endp, 0);
647 		    if ((errno == 0) && (value >= 0) && (*endp == '\0'))
648 			ipcos = value;
649 		}
650 		else if (type_match(ARG2)) {
651 		    errno = 0;
652 		    value = (int) strtol(ARG1, &endp, 0);
653 		    if ((errno == 0) && (value >= 0) && (*endp == '\0')) {
654 			ipcos = value;
655 			break;
656 		    }
657 		}
658 	    }
659 	}
660     }
661     return ipcos;
662 }
663 
main(int argc,char ** argv,char ** envp)664 int main(int argc, char **argv, char **envp)
665 {
666 #if defined(UNIXWARE) || defined(AIX)
667     size_t addrlen;
668 #else
669     int addrlen;
670 #endif
671     int on = 1;
672     int cos;
673     int c;
674 #ifndef INTERNAL_LS
675     int which;
676 #endif
677     extern int optopt;
678     extern char *optarg;
679     char *hp;
680     struct aclmember *entry;
681 #ifdef VIRTUAL
682 #if defined(UNIXWARE) || defined(AIX)
683     size_t virtual_len;
684 #else
685     int virtual_len;
686 #endif
687     struct SOCKSTORAGE virtual_addr;
688 #endif
689     struct servent *serv;
690 
691 #ifdef AUX
692     setcompat(COMPAT_POSIX | COMPAT_BSDSETUGID);
693 #endif
694 
695     closelog();
696 #ifdef FACILITY
697     openlog("ftpd", LOG_PID | LOG_NDELAY, FACILITY);
698 #else
699     openlog("ftpd", LOG_PID);
700 #endif
701 
702 #ifdef SecureWare
703     setluid(1);			/* make sure there is a valid luid */
704     set_auth_parameters(argc, argv);
705     setreuid(0, 0);
706 #endif
707 #if defined(M_UNIX) && !defined(_M_UNIX)
708     res_init();			/* bug in old (1.1.1) resolver     */
709     _res.retrans = 20;		/* because of fake syslog in 3.2.2 */
710     setlogmask(LOG_UPTO(LOG_INFO));
711 #endif
712 
713     while ((c = getopt(argc, argv, FTPD_OPTS DAEMON_OPTS GSS_OPTS)) != -1) {
714 	switch (c) {
715 
716 	case '4':
717 #ifdef INET6
718 	    listen_v4 = 1;
719 #endif
720 	    break;
721 
722 	case 'a':
723 	    use_accessfile = 1;
724 	    break;
725 
726 	case 'A':
727 	    use_accessfile = 0;
728 	    break;
729 
730 	case 'v':
731 	    debug = 1;
732 	    break;
733 
734 	case 'd':
735 	    debug = 1;
736 	    break;
737 
738 #if defined(USE_GSS)
739 	case 'C':
740 	    gss_info.want_creds = 1;
741 	    break;
742 
743 	case 'K':
744 	    gss_info.must_gss_auth = 1;
745 	    break;
746 #endif /* USE_GSS */
747 
748 	case 'l':
749 	    logging = 1;
750 	    break;
751 
752 	case 'L':
753 	    log_commands = 3;
754 	    break;
755 
756 	case 'i':
757 	    log_incoming_xfers = 3;
758 	    break;
759 
760 	case 'I':
761 	    disable_rfc931 = 1;
762 	    break;
763 
764 	case 'o':
765 	    log_outbound_xfers = 3;
766 	    break;
767 
768 	case 'q':
769 	    Bypass_PID_Files = 0;
770 	    break;
771 
772 	case 'Q':
773 	    Bypass_PID_Files = 1;
774 	    break;
775 
776 	case 'r':
777 	    if ((optarg != NULL) && (optarg[0] != '\0')) {
778 		RootDirectory = malloc(strlen(optarg) + 1);
779 		if (RootDirectory != NULL)
780 		    strcpy(RootDirectory, optarg);
781 	    }
782 	    break;
783 
784 	case 'P':
785 	    data_port = htons(atoi(optarg));
786 	    break;
787 
788 #ifdef DAEMON
789 	case 'p':
790 	    daemon_port = atoi(optarg);
791 	    break;
792 
793 	case 's':
794 	    be_daemon = 1;
795 	    break;
796 
797 	case 'S':
798 	    be_daemon = 2;
799 	    break;
800 #endif /* DAEMON */
801 
802 	case 't':
803 	    timeout_idle = atoi(optarg);
804 	    if (timeout_maxidle < timeout_idle)
805 		timeout_maxidle = timeout_idle;
806 	    break;
807 
808 	case 'T':
809 	    timeout_maxidle = atoi(optarg);
810 	    if (timeout_idle > timeout_maxidle)
811 		timeout_idle = timeout_maxidle;
812 	    break;
813 
814 	case 'u':
815 	    {
816 		unsigned int val = 0;
817 
818 		while (*optarg && *optarg >= '0' && *optarg <= '7')
819 		    val = val * 8 + *optarg++ - '0';
820 		if (*optarg || val > 0777)
821 		    syslog(LOG_ERR, "bad value for -u");
822 		else
823 		    defumask = val;
824 		break;
825 	    }
826 
827 	case 'V':
828 	    print_copyright();
829 	    exit(0);
830 	    /* NOTREACHED */
831 	case 'w':
832 	    wtmp_logging = 1;
833 	    break;
834 
835 	case 'W':
836 	    wtmp_logging = 0;
837 	    break;
838 
839 	case 'x':
840 	    syslogmsg = 2;
841 	    break;
842 
843 	case 'X':
844 	    syslogmsg = 1;
845 	    break;
846 
847 	case ':':
848 	    syslog(LOG_ERR, "option -%c requires an argument", optopt);
849 	    break;
850 
851 	default:
852 	    syslog(LOG_ERR, "unknown option -%c ignored", optopt);
853 	    break;
854 	}
855     }
856     initsetproctitle(argc, argv, envp);
857     (void) freopen(_PATH_DEVNULL, "w", stderr);
858 
859     /* Checking for random signals ... */
860 #ifdef NEED_SIGFIX
861     sigemptyset(&block_sigmask);
862 #endif
863 #ifndef SIG_DEBUG
864 #ifdef SIGHUP
865     (void) signal(SIGHUP, randomsig);
866 #ifdef NEED_SIGFIX
867     sigaddset(&block_sigmask, SIGHUP);
868 #endif
869 #endif
870 #ifdef SIGINT
871     (void) signal(SIGINT, randomsig);
872 #ifdef NEED_SIGFIX
873     sigaddset(&block_sigmask, SIGINT);
874 #endif
875 #endif
876 #ifdef SIGQUIT
877     (void) signal(SIGQUIT, randomsig);
878 #ifdef NEED_SIGFIX
879     sigaddset(&block_sigmask, SIGQUIT);
880 #endif
881 #endif
882 #ifdef SIGILL
883     (void) signal(SIGILL, randomsig);
884 #ifdef NEED_SIGFIX
885     sigaddset(&block_sigmask, SIGILL);
886 #endif
887 #endif
888 #ifdef SIGTRAP
889     (void) signal(SIGTRAP, randomsig);
890 #ifdef NEED_SIGFIX
891     sigaddset(&block_sigmask, SIGTRAP);
892 #endif
893 #endif
894 #ifdef SIGIOT
895     (void) signal(SIGIOT, randomsig);
896 #ifdef NEED_SIGFIX
897     sigaddset(&block_sigmask, SIGIOT);
898 #endif
899 #endif
900 #ifdef SIGEMT
901     (void) signal(SIGEMT, randomsig);
902 #ifdef NEED_SIGFIX
903     sigaddset(&block_sigmask, SIGEMT);
904 #endif
905 #endif
906 #ifdef SIGFPE
907     (void) signal(SIGFPE, randomsig);
908 #ifdef NEED_SIGFIX
909     sigaddset(&block_sigmask, SIGFPE);
910 #endif
911 #endif
912 #ifdef SIGKILL
913     (void) signal(SIGKILL, randomsig);
914 #ifdef NEED_SIGFIX
915     sigaddset(&block_sigmask, SIGKILL);
916 #endif
917 #endif
918 #ifdef SIGBUS
919     (void) signal(SIGBUS, randomsig);
920 #ifdef NEED_SIGFIX
921     sigaddset(&block_sigmask, SIGBUS);
922 #endif
923 #endif
924 #ifdef SIGSEGV
925     (void) signal(SIGSEGV, randomsig);
926 #ifdef NEED_SIGFIX
927     sigaddset(&block_sigmask, SIGSEGV);
928 #endif
929 #endif
930 #ifdef SIGSYS
931     (void) signal(SIGSYS, randomsig);
932 #ifdef NEED_SIGFIX
933     sigaddset(&block_sigmask, SIGSYS);
934 #endif
935 #endif
936 #ifdef SIGALRM
937     (void) signal(SIGALRM, randomsig);
938 #ifdef NEED_SIGFIX
939     sigaddset(&block_sigmask, SIGALRM);
940 #endif
941 #endif
942 #ifdef SIGSTOP
943     (void) signal(SIGSTOP, randomsig);
944 #ifdef NEED_SIGFIX
945     sigaddset(&block_sigmask, SIGSTOP);
946 #endif
947 #endif
948 #ifdef SIGTSTP
949     (void) signal(SIGTSTP, randomsig);
950 #ifdef NEED_SIGFIX
951     sigaddset(&block_sigmask, SIGTSTP);
952 #endif
953 #endif
954 #ifdef SIGTTIN
955     (void) signal(SIGTTIN, randomsig);
956 #ifdef NEED_SIGFIX
957     sigaddset(&block_sigmask, SIGTTIN);
958 #endif
959 #endif
960 #ifdef SIGTTOU
961     (void) signal(SIGTTOU, randomsig);
962 #ifdef NEED_SIGFIX
963     sigaddset(&block_sigmask, SIGTTOU);
964 #endif
965 #endif
966 #ifdef SIGIO
967     (void) signal(SIGIO, randomsig);
968 #ifdef NEED_SIGFIX
969     sigaddset(&block_sigmask, SIGIO);
970 #endif
971 #endif
972 #ifdef SIGXCPU
973     (void) signal(SIGXCPU, randomsig);
974 #ifdef NEED_SIGFIX
975     sigaddset(&block_sigmask, SIGXCPU);
976 #endif
977 #endif
978 #ifdef SIGXFSZ
979     (void) signal(SIGXFSZ, randomsig);
980 #ifdef NEED_SIGFIX
981     sigaddset(&block_sigmask, SIGXFSZ);
982 #endif
983 #endif
984 #ifdef SIGWINCH
985     (void) signal(SIGWINCH, randomsig);
986 #ifdef NEED_SIGFIX
987     sigaddset(&block_sigmask, SIGWINCH);
988 #endif
989 #endif
990 #ifdef SIGVTALRM
991     (void) signal(SIGVTALRM, randomsig);
992 #ifdef NEED_SIGFIX
993     sigaddset(&block_sigmask, SIGVTALRM);
994 #endif
995 #endif
996 #ifdef SIGPROF
997     (void) signal(SIGPROF, randomsig);
998 #ifdef NEED_SIGFIX
999     sigaddset(&block_sigmask, SIGPROF);
1000 #endif
1001 #endif
1002 #ifdef SIGUSR1
1003     (void) signal(SIGUSR1, randomsig);
1004 #ifdef NEED_SIGFIX
1005     sigaddset(&block_sigmask, SIGUSR1);
1006 #endif
1007 #endif
1008 #ifdef SIGUSR2
1009     (void) signal(SIGUSR2, randomsig);
1010 #ifdef NEED_SIGFIX
1011     sigaddset(&block_sigmask, SIGUSR2);
1012 #endif
1013 #endif
1014 
1015 #ifdef SIGPIPE
1016     (void) signal(SIGPIPE, lostconn);
1017 #ifdef NEED_SIGFIX
1018     sigaddset(&block_sigmask, SIGPIPE);
1019 #endif
1020 #endif
1021 #ifdef SIGCHLD
1022     (void) signal(SIGCHLD, SIG_IGN);
1023 #ifdef NEED_SIGFIX
1024     sigaddset(&block_sigmask, SIGCHLD);
1025 #endif
1026 #endif
1027 
1028 #ifdef SIGURG
1029     if (signal(SIGURG, myoob) == SIG_ERR)
1030 	syslog(LOG_ERR, "signal: %m");
1031 #ifdef NEED_SIGFIX
1032     sigaddset(&block_sigmask, SIGURG);
1033 #endif
1034 #endif
1035 #endif /* SIG_DEBUG */
1036 
1037 #ifdef VIRTUAL
1038     virtual_root[0] = '\0';
1039     virtual_banner[0] = '\0';
1040 #endif
1041 
1042     setup_paths();
1043 
1044 #ifdef OTHER_PASSWD
1045     strcpy(_path_passwd, "/etc/passwd");
1046 #ifdef SHADOW_PASSWORD
1047     strcpy(_path_shadow, "/etc/shadow");
1048 #endif
1049 #endif
1050 
1051     access_init();
1052 
1053 #ifdef DAEMON
1054     if (be_daemon != 0)
1055 	do_daemon();
1056     else {
1057 #endif
1058 	addrlen = sizeof(his_addr);
1059 	if (getpeername(0, (struct sockaddr *) &his_addr, &addrlen) < 0) {
1060 	    syslog(LOG_ERR, "getpeername: %m");
1061 #ifndef DEBUG
1062 	    exit(1);
1063 #endif
1064 	}
1065 #ifdef DAEMON
1066     }
1067 #endif
1068     addrlen = sizeof(ctrl_addr);
1069     if (getsockname(0, (struct sockaddr *) &ctrl_addr, &addrlen) < 0) {
1070 	syslog(LOG_ERR, "getsockname: %m");
1071 #ifndef DEBUG
1072 	exit(1);
1073 #endif
1074     }
1075     /* Sanity check */
1076     if ((SOCK_FAMILY(ctrl_addr) != AF_INET)
1077 #ifdef INET6
1078         && (SOCK_FAMILY(ctrl_addr) != AF_INET6)
1079 #endif
1080 	) {
1081 	syslog(LOG_ERR, "control connection address family (%d) not supported.",
1082 	       SOCK_FAMILY(ctrl_addr));
1083 #ifndef DEBUG
1084 	exit(1);
1085 #endif
1086     }
1087 #ifdef SOLARIS_BSM_AUDIT
1088     /* Set audit characteristics */
1089     if (audit_settid(0)) {
1090 	syslog(LOG_ERR, "audit failure");
1091 	exit(1);
1092     }
1093 #endif
1094 #ifdef INET6
1095     /* IP_TOS is an IPv4 socket option */
1096     if (SOCK_FAMILY(ctrl_addr) == AF_INET)
1097 #endif
1098     if ((cos = IPClassOfService("control")) >= 0) {
1099 	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *) &cos, sizeof(int)) < 0)
1100 	    syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1101     }
1102 
1103 #ifdef TCP_NODELAY
1104     /*
1105      * Disable Nagle on the control channel so that we don't have to wait
1106      * for peer's ACK before issuing our next reply.
1107      */
1108     if (setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
1109 	syslog(LOG_WARNING, "control setsockopt TCP_NODELAY: %m");
1110 #endif
1111 
1112     if (keepalive)
1113 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0)
1114 	    syslog(LOG_ERR, "setsockopt SO_KEEPALIVE %m");
1115 
1116     /* Try to handle urgent data inline */
1117 #ifdef SO_OOBINLINE
1118     if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof(int)) < 0)
1119 	    syslog(LOG_ERR, "setsockopt (SO_OOBINLINE): %m");
1120 #endif
1121 
1122 #ifdef  F_SETOWN
1123     if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
1124 	syslog(LOG_ERR, "fcntl F_SETOWN: %m");
1125 #elif defined(SIOCSPGRP)
1126     {
1127 	int pid;
1128 	pid = getpid();
1129 	if (ioctl(fileno(stdin), SIOCSPGRP, &pid) == -1)
1130 	    syslog(LOG_ERR, "ioctl SIOCSPGRP: %m");
1131     }
1132 #endif
1133 
1134 #ifdef INET6
1135     if ((SOCK_FAMILY(ctrl_addr) == AF_INET6) &&
1136 	IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&(ctrl_addr))->sin6_addr))
1137 	ctrl_v4mapped = 1;
1138 #endif
1139 
1140     if (data_port == 0) {
1141 	serv = getservbyname("ftp-data", "tcp");
1142 	if (serv != NULL)
1143 	    data_port = serv->s_port;
1144 	else
1145 	    data_port = htons(ntohs(SOCK_PORT(ctrl_addr)) - 1);
1146     }
1147 
1148     if (RootDirectory != NULL) {
1149 	if ((chroot(RootDirectory) < 0)
1150 	    || (chdir("/") < 0)) {
1151 	    syslog(LOG_ERR, "Cannot chroot to initial directory, aborting.");
1152 	    exit(1);
1153 	}
1154     }
1155 
1156     load_timeouts();
1157 
1158     /* set resolver options */
1159     set_res_options();
1160 
1161     dolog(&his_addr);
1162     /* Set up default state */
1163     data = -1;
1164     type = TYPE_A;
1165     form = FORM_N;
1166     stru = STRU_F;
1167     mode = MODE_S;
1168     tmpline[0] = '\0';
1169     yyerrorcalled = 0;
1170 
1171     entry = (struct aclmember *) NULL;
1172     if ((getaclentry("hostname", &entry)) && ARG0) {
1173 	(void) strncpy(hostname, ARG0, sizeof(hostname));
1174 	hostname[sizeof(hostname) - 1] = '\0';
1175     }
1176     else {
1177 #ifdef HAVE_SYSINFO
1178 	sysinfo(SI_HOSTNAME, hostname, sizeof(hostname));
1179 #else
1180 	(void) gethostname(hostname, sizeof(hostname));
1181 #endif
1182 /* set the FQDN here */
1183 	hp = wu_gethostbyname(hostname);
1184 	if (hp) {
1185 	    (void) strncpy(hostname, hp, sizeof(hostname));
1186 	    hostname[sizeof(hostname) - 1] = '\0';
1187 	}
1188     }
1189     route_vectored = routevector();
1190     conv_init();
1191 
1192 #ifdef MAIL_ADMIN
1193     incmails = 0;
1194     mailfrom = NULL;
1195 #endif /* MAIL_ADMIN */
1196 #ifdef VIRTUAL
1197     /*
1198        ** If virtual_mode is set at this point then an alternate ftpaccess
1199        ** is in use.  Otherwise we need to check the Master ftpaccess file
1200        ** to see if the site is only using the "virtual" directives to
1201        ** specify virtual site directives.
1202        **
1203        ** In this manner an admin can put a virtual site in the ftpservers
1204        ** file if they need expanded configuration support or can use the
1205        ** minimal root/banner/logfile if they do not need any more than that.
1206      */
1207 
1208     if (virtual_mode) {
1209 	/* Get the root of the virtual server directory */
1210 	entry = (struct aclmember *) NULL;
1211 	if (getaclentry("root", &entry)) {
1212 	    if (ARG0)
1213 		strcpy(virtual_root, ARG0);
1214 	}
1215 
1216 	/* Get the logfile to use */
1217 	entry = (struct aclmember *) NULL;
1218 	if (getaclentry("logfile", &entry)) {
1219 	    if (ARG0)
1220 		strcpy(logfile, ARG0);
1221 	}
1222     }
1223     else {
1224 	virtual_hostname[0] = '\0';
1225 	virtual_address[0] = '\0';
1226 	virtual_len = sizeof(virtual_addr);
1227 	if (getsockname(0, (struct sockaddr *) &virtual_addr, &virtual_len) == 0) {
1228 	    strcpy(virtual_address, inet_stop(&virtual_addr));
1229 	    wu_gethostbyaddr(&virtual_addr, virtual_hostname, sizeof(virtual_hostname));
1230 	    entry = (struct aclmember *) NULL;
1231 	    while (getaclentry("virtual", &entry)) {
1232 		if (!ARG0 || !ARG1 || !ARG2)
1233 		    continue;
1234 		if (hostmatch(ARG0, virtual_address, virtual_hostname)) {
1235 		    if (!strcasecmp(ARG1, "root")) {
1236 			if (debug)
1237 			    syslog(LOG_DEBUG, "VirtualFTP Connect to: %s [%s]",
1238 				   virtual_hostname, virtual_address);
1239 			virtual_mode = 1;
1240 			strncpy(virtual_root, ARG2, sizeof(virtual_root));
1241 			virtual_root[sizeof(virtual_root) - 1] = '\0';
1242 			/* reset hostname to this virtual name */
1243 			(void) strcpy(hostname, virtual_hostname);
1244 			virtual_email[0] = '\0';
1245 		    }
1246 		    if (!strcasecmp(ARG1, "banner")) {
1247 			strncpy(virtual_banner, ARG2, sizeof(virtual_banner));
1248 			virtual_banner[sizeof(virtual_banner) - 1] = '\0';
1249 		    }
1250 		    if (!strcasecmp(ARG1, "logfile")) {
1251 			strncpy(logfile, ARG2, sizeof(logfile));
1252 			logfile[sizeof(logfile) - 1] = '\0';
1253 		    }
1254 		    if (!strcasecmp(ARG1, "hostname")) {
1255 			strncpy(hostname, ARG2, sizeof(hostname));
1256 			hostname[sizeof(hostname) - 1] = '\0';
1257 		    }
1258 		    if (!strcasecmp(ARG1, "email")) {
1259 			strncpy(virtual_email, ARG2, sizeof(virtual_email));
1260 			virtual_email[sizeof(virtual_email) - 1] = '\0';
1261 		    }
1262 #ifdef OTHER_PASSWD
1263 		    if (!strcasecmp(ARG1, "passwd")) {
1264 			strncpy(_path_passwd, ARG2, sizeof(_path_passwd));
1265 			_path_passwd[sizeof(_path_passwd) - 1] = '\0';
1266 #ifdef USE_PAM
1267 			use_pam = 0;
1268 #endif
1269 		    }
1270 #ifdef SHADOW_PASSWORD
1271 		    if (!strcasecmp(ARG1, "shadow")) {
1272 			strncpy(_path_shadow, ARG2, sizeof(_path_shadow));
1273 			_path_shadow[sizeof(_path_shadow) - 1] = '\0';
1274 #ifdef USE_PAM
1275 			use_pam = 0;
1276 #endif
1277 		    }
1278 #endif
1279 #endif
1280 #ifdef MAIL_ADMIN
1281 		    if (mailfrom == NULL)
1282 			if (!strcasecmp(ARG1, "mailfrom")) {
1283 			    mailfrom = strdup(ARG2);
1284 			}
1285 		    if (!strcasecmp(ARG1, "incmail")) {
1286 			if (incmails < INCMAILS)
1287 			    incmail[incmails++] = strdup(ARG2);
1288 		    }
1289 #endif
1290 		}
1291 	    }
1292 	    if (!virtual_mode) {
1293 		entry = (struct aclmember *) NULL;
1294 		while (getaclentry("defaultserver", &entry)) {
1295 		    if (!ARG0 || !ARG1)
1296 			continue;
1297 #ifdef MAIL_ADMIN
1298 		    if (mailfrom == NULL)
1299 			if (!strcasecmp(ARG0, "mailfrom")) {
1300 			    mailfrom = strdup(ARG1);
1301 			}
1302 		    if (!strcasecmp(ARG0, "incmail")) {
1303 			if (incmails < INCMAILS)
1304 			    incmail[incmails++] = strdup(ARG1);
1305 		    }
1306 #endif
1307 		}
1308 	    }
1309 	}
1310     }
1311 
1312 #ifdef VIRTUAL_DEBUG
1313     lreply(220, "_path_ftpaccess == %s", _path_ftpaccess);
1314     lreply(220, "_path_ftpusers == %s", _path_ftpusers);
1315     lreply(220, "_path_ftphosts == %s", _path_ftphosts);
1316     lreply(220, "_path_private == %s", _path_private);
1317     lreply(220, "_path_cvt == %s", _path_cvt);
1318     if (virtual_mode) {
1319 	if (virtual_ftpaccess)
1320 	    lreply(220, "VIRTUAL Mode: Using %s specific %s access file",
1321 		   hostname, _path_ftpaccess);
1322 	else
1323 	    lreply(220, "VIRTUAL Mode: Using Master access file %s",
1324 		   _path_ftpaccess);
1325 
1326 	lreply(220, "virtual_root == %s", virtual_root);
1327 	if (!virtual_ftpaccess)
1328 	    lreply(220, "virtual_banner == %s", virtual_banner);
1329     }
1330     lreply(220, "logfile == %s", logfile);
1331 #endif
1332 #endif
1333 
1334     if (is_shutdown(1, 1) != 0) {
1335 	syslog(LOG_INFO, "connection refused (server shut down) from %s",
1336 	       remoteident);
1337 	reply(500, "%s FTP server shut down -- please try again later.",
1338 	      hostname);
1339 	exit(0);
1340     }
1341 
1342 #ifdef OPIE
1343     af_pwok = opieaccessfile(remotehost);
1344 #endif
1345 
1346     /* check permitted access based on name and address lookup of remote host */
1347     if (!check_rhost_reverse()) {
1348 	exit(0);
1349     }
1350     if (!check_rhost_matches()) {
1351 	exit(0);
1352     }
1353 
1354     show_banner(220);
1355 
1356 #ifndef INTERNAL_LS
1357     entry = (struct aclmember *) NULL;
1358     if (getaclentry("lslong", &entry) && ARG0 && (int) strlen(ARG0) > 0) {
1359 	strcpy(ls_long, ARG0);
1360 	for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
1361 	    strcat(ls_long, " ");
1362 	    strcat(ls_long, ARG[which]);
1363 	}
1364     }
1365     else {
1366 #if defined(SVR4) || defined(ISC)
1367 #if defined(AIX) || defined(SOLARIS_2)
1368 	strcpy(ls_long, "/bin/ls -lA");
1369 #else
1370 	strcpy(ls_long, "/bin/ls -la");
1371 #endif
1372 #else
1373 	strcpy(ls_long, "/bin/ls -lgA");
1374 #endif
1375     }
1376     strcat(ls_long, " %s");
1377 
1378     entry = (struct aclmember *) NULL;
1379     if (getaclentry("lsshort", &entry) && ARG0 && (int) strlen(ARG0) > 0) {
1380 	strcpy(ls_short, ARG0);
1381 	for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
1382 	    strcat(ls_short, " ");
1383 	    strcat(ls_short, ARG[which]);
1384 	}
1385     }
1386     else {
1387 #if defined(SVR4) || defined(ISC)
1388 #if defined(AIX) || defined(SOLARIS_2)
1389 	strcpy(ls_short, "/bin/ls -lA");
1390 #else
1391 	strcpy(ls_short, "/bin/ls -la");
1392 
1393 #endif
1394 #else
1395 	strcpy(ls_short, "/bin/ls -lgA");
1396 #endif
1397     }
1398     strcat(ls_short, " %s");
1399 
1400     entry = (struct aclmember *) NULL;
1401     if (getaclentry("lsplain", &entry) && ARG0 && (int) strlen(ARG0) > 0) {
1402 	strcpy(ls_plain, ARG0);
1403 	for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
1404 	    strcat(ls_plain, " ");
1405 	    strcat(ls_plain, ARG[which]);
1406 	}
1407     }
1408     else
1409 	strcpy(ls_plain, "/bin/ls");
1410     strcat(ls_plain, " %s");
1411 #endif /* ! INTERNAL_LS */
1412 #ifdef MAIL_ADMIN
1413     mailservers = 0;
1414     entry = (struct aclmember *) NULL;
1415     while (getaclentry("mailserver", &entry) && ARG0 && mailservers < MAILSERVERS)
1416 	mailserver[mailservers++] = strdup(ARG0);
1417     if (mailservers == 0)
1418 	mailserver[mailservers++] = strdup("localhost");
1419     if (incmails == 0) {
1420 	entry = (struct aclmember *) NULL;
1421 	while (getaclentry("incmail", &entry) && ARG0 && incmails < INCMAILS)
1422 	    incmail[incmails++] = strdup(ARG0);
1423     }
1424     if (mailfrom == NULL) {
1425 	entry = (struct aclmember *) NULL;
1426 	if (getaclentry("mailfrom", &entry) && ARG0)
1427 	    mailfrom = strdup(ARG0);
1428 	else
1429 	    mailfrom = strdup("wu-ftpd");
1430     }
1431 #endif /* MAIL_ADMIN */
1432     {
1433 #define OUTPUT_LEN (BUFSIZ * 2)
1434 	int version_option = 0;
1435 	char output_text[OUTPUT_LEN + 1];
1436 	int which;
1437 
1438 	entry = NULL;
1439 	if (getaclentry("greeting", &entry) && ARG0) {
1440 	    if (!strcasecmp(ARG0, "full"))
1441 		version_option = 0;
1442 	    else if (!strcasecmp(ARG0, "text") && ARG1)
1443 		version_option = 3;
1444 	    else if (!strcasecmp(ARG0, "terse"))
1445 		version_option = 2;
1446 	    else if (!strcasecmp(ARG0, "brief"))
1447 		version_option = 1;
1448 	}
1449 	switch (version_option) {
1450 	default:
1451 	    reply(220, "%s FTP server (%s) ready.", hostname, version);
1452 	    break;
1453 	case 1:
1454 	    reply(220, "%s FTP server ready.", hostname);
1455 	    break;
1456 	case 2:
1457 	    reply(220, "FTP server ready.");
1458 	    break;
1459 	case 3:
1460 	    output_text[0] = '\0';
1461 	    for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
1462 		if (which > 1)
1463 		    (void) strlcat(output_text, " ", sizeof(output_text));
1464 		(void) strlcat(output_text, ARG[which], sizeof(output_text));
1465 	    }
1466 	    reply(220, "%s", output_text);
1467 	    break;
1468 	}
1469     }
1470     (void) setjmp(errcatch);
1471 
1472     for (;;)
1473 	(void) yyparse();
1474     /* NOTREACHED */
1475 }
1476 
1477 
randomsig(int sig)1478 SIGNAL_TYPE randomsig(int sig)
1479 {
1480 #ifdef HAVE_SIGLIST
1481     syslog(LOG_ERR, "exiting on signal %d: %s", sig, sys_siglist[sig]);
1482 #else
1483     syslog(LOG_ERR, "exiting on signal %d", sig);
1484 #endif
1485     chdir("/");
1486     signal(SIGIOT, SIG_DFL);
1487     signal(SIGILL, SIG_DFL);
1488     exit(1);
1489     /* dologout(-1); *//* NOTREACHED */
1490 }
1491 
lostconn(int sig)1492 SIGNAL_TYPE lostconn(int sig)
1493 {
1494 #ifdef VERBOSE_ERROR_LOGING
1495     syslog(LOG_INFO, "lost connection to %s", remoteident);
1496 #else
1497     if (debug)
1498 	syslog(LOG_DEBUG, "lost connection to %s", remoteident);
1499 #endif
1500     dologout(-1);
1501 }
1502 
1503 static char ttyline[20];
1504 
1505 #ifdef MAPPING_CHDIR
1506 /* Keep track of the path the user has chdir'd into and respond with
1507  * that to pwd commands.  This is to avoid having the absolue disk
1508  * path returned, which I want to avoid.
1509  */
1510 char mapped_path[MAXPATHLEN] = "/";
1511 
1512 #if !defined(HAVE_GETCWD)
mapping_getwd(char * path)1513 char *mapping_getwd(char *path)
1514 {
1515     strcpy(path, mapped_path);
1516     return path;
1517 }
1518 #endif /* !defined(HAVE_GETCWD) */
1519 
mapping_getcwd(char * path,size_t size)1520 char *mapping_getcwd(char *path, size_t size)
1521 {
1522     (void) strlcpy(path, mapped_path, size);
1523     return path;
1524 }
1525 
1526 /* Make these globals rather than local to mapping_chdir to avoid stack overflow */
1527 char pathspace[MAXPATHLEN];
1528 char old_mapped_path[MAXPATHLEN];
1529 
do_elem(char * dir)1530 void do_elem(char *dir)
1531 {
1532     /* . */
1533     if (dir[0] == '.' && dir[1] == '\0') {
1534 	/* ignore it */
1535 	return;
1536     }
1537 
1538     /* .. */
1539     if (dir[0] == '.' && dir[1] == '.' && dir[2] == '\0') {
1540 	char *last;
1541 	/* lop the last directory off the path */
1542 	if ((last = strrchr(mapped_path, '/'))) {
1543 	    /* If start of pathname leave the / */
1544 	    if (last == mapped_path)
1545 		last++;
1546 	    *last = '\0';
1547 	}
1548 	return;
1549     }
1550 
1551     /* append the dir part with a leading / unless at root */
1552     if (!(mapped_path[0] == '/' && mapped_path[1] == '\0'))
1553 	(void) strlcat(mapped_path, "/", sizeof(mapped_path));
1554     (void) strlcat(mapped_path, dir, sizeof(mapped_path));
1555 }
1556 
mapping_chdir(char * orig_path)1557 int mapping_chdir(char *orig_path)
1558 {
1559     int ret;
1560     char *sl, *path;
1561 
1562     (void) strlcpy(old_mapped_path, mapped_path, sizeof(old_mapped_path));
1563     (void) strlcpy(pathspace, orig_path, sizeof(pathspace));
1564     path = pathspace;
1565 
1566     /* / at start of path, set the start of the mapped_path to / */
1567     if (path[0] == '/') {
1568 	mapped_path[0] = '/';
1569 	mapped_path[1] = '\0';
1570 	path++;
1571     }
1572 
1573     while ((sl = strchr(path, '/'))) {
1574 	char *dir;
1575 	dir = path;
1576 	*sl = '\0';
1577 	path = sl + 1;
1578 	if (*dir)
1579 	    do_elem(dir);
1580 	if (*path == '\0')
1581 	    break;
1582     }
1583     if (*path)
1584 	do_elem(path);
1585 
1586     if ((ret = chdir(mapped_path)) < 0) {
1587 	(void) strlcpy(mapped_path, old_mapped_path, sizeof(mapped_path));
1588     }
1589 
1590     return ret;
1591 }
1592 /* From now on use the mapping version */
1593 
1594 #define chdir(d) mapping_chdir(d)
1595 #define getwd(d) mapping_getwd(d)
1596 #define getcwd(d,u) mapping_getcwd((d),(u))
1597 
1598 #endif /* MAPPING_CHDIR */
1599 
1600 /* Helper function for sgetpwnam(). */
sgetsave(char * s)1601 char *sgetsave(char *s)
1602 {
1603     char *new;
1604 
1605     new = (char *) malloc(strlen(s) + 1);
1606 
1607     if (new == NULL) {
1608 	perror_reply(421, "Local resource failure: malloc");
1609 	dologout(1);
1610 	/* NOTREACHED */
1611     }
1612     (void) strcpy(new, s);
1613     return (new);
1614 }
1615 
1616 /* Save the result of a getpwnam.  Used for USER command, since the data
1617  * returned must not be clobbered by any other command (e.g., globbing). */
sgetpwnam(char * name)1618 struct passwd *sgetpwnam(char *name)
1619 {
1620     static struct passwd save;
1621     register struct passwd *p;
1622 #ifdef M_UNIX
1623     struct passwd *ret = (struct passwd *) NULL;
1624 #endif
1625     char *sgetsave(char *s);
1626 #ifdef KERBEROS
1627     register struct authorization *q;
1628 #endif /* KERBEROS */
1629 
1630 #if defined(SecureWare) || defined(HPUX_10_TRUSTED)
1631     struct pr_passwd *pr;
1632 #endif
1633 
1634 #ifdef KERBEROS
1635     init_krb();
1636     q = getauthuid(p->pw_uid);
1637     end_krb();
1638 #endif /* KERBEROS */
1639 
1640 #ifdef M_UNIX
1641 #if defined(SecureWare) || defined(HPUX_10_TRUSTED)
1642     if ((pr = getprpwnam(name)) == NULL)
1643 	goto DONE;
1644 #endif /* SecureWare || HPUX_10_TRUSTED */
1645 #ifdef OTHER_PASSWD
1646     if ((p = bero_getpwnam(name, _path_passwd)) == NULL)
1647 #else
1648     if ((p = getpwnam(name)) == NULL)
1649 #endif
1650 	goto DONE;
1651 #else /* M_UNIX */
1652 #if defined(SecureWare) || defined(HPUX_10_TRUSTED)
1653     if ((pr = getprpwnam(name)) == NULL)
1654 	return ((struct passwd *) pr);
1655 #endif /* SecureWare || HPUX_10_TRUSTED */
1656 #ifdef OTHER_PASSWD
1657     if ((p = bero_getpwnam(name, _path_passwd)) == NULL)
1658 #else
1659     if ((p = getpwnam(name)) == NULL)
1660 #endif
1661 	return (p);
1662 #endif /* M_UNIX */
1663 
1664     if (save.pw_name)
1665 	free(save.pw_name);
1666     if (save.pw_gecos)
1667 	free(save.pw_gecos);
1668     if (save.pw_dir)
1669 	free(save.pw_dir);
1670     if (save.pw_shell)
1671 	free(save.pw_shell);
1672     if (save.pw_passwd)
1673 	free(save.pw_passwd);
1674 
1675     save = *p;
1676 
1677     save.pw_name = sgetsave(p->pw_name);
1678 
1679 #ifdef KERBEROS
1680     save.pw_passwd = sgetsave(q->a_password);
1681 #elif defined(SecureWare) || defined(HPUX_10_TRUSTED)
1682     if (pr->uflg.fg_encrypt && pr->ufld.fd_encrypt && *pr->ufld.fd_encrypt)
1683 	save.pw_passwd = sgetsave(pr->ufld.fd_encrypt);
1684     else
1685 	save.pw_passwd = sgetsave("");
1686 #else
1687     save.pw_passwd = sgetsave(p->pw_passwd);
1688 #endif
1689 #ifdef SHADOW_PASSWORD
1690     if (p && (p->pw_passwd==NULL || strlen(p->pw_passwd)<8)) {
1691 	struct spwd *spw;
1692 #ifdef OTHER_PASSWD
1693 	if ((spw = bero_getspnam(p->pw_name, _path_shadow)) != NULL) {
1694 #else
1695 	setspent();
1696 	if ((spw = getspnam(p->pw_name)) != NULL) {
1697 #endif
1698 	    int expired = 0;
1699 	    /*XXX Does this work on all Shadow Password Implementations? */
1700 	    /* it is supposed to work on Solaris 2.x */
1701 	    time_t now;
1702 	    long today;
1703 
1704 	    now = time((time_t *) 0);
1705 	    today = now / (60 * 60 * 24);
1706 
1707 	    if ((spw->sp_expire > 0) && (spw->sp_expire < today))
1708 		expired++;
1709 	    if ((spw->sp_max > 0) && (spw->sp_lstchg > 0) &&
1710 		(spw->sp_lstchg + spw->sp_max < today))
1711 		expired++;
1712 	    free(save.pw_passwd);
1713 	    save.pw_passwd = sgetsave(expired ? "" : spw->sp_pwdp);
1714 	}
1715 /* Don't overwrite the password if the shadow read fails, getpwnam() is NIS
1716    aware but getspnam() is not. */
1717 /* Shadow passwords are optional on Linux.  --marekm */
1718 #if !defined(LINUX) && !defined(UNIXWARE)
1719 	else {
1720 	    free(save.pw_passwd);
1721 	    save.pw_passwd = sgetsave("");
1722 	}
1723 #endif
1724 /* marekm's fix for linux proc file system shadow passwd exposure problem */
1725 #ifndef OTHER_PASSWD
1726 	endspent();
1727 #endif
1728     }
1729 #endif
1730     save.pw_gecos = sgetsave(p->pw_gecos);
1731     save.pw_dir = sgetsave(p->pw_dir);
1732     save.pw_shell = sgetsave(p->pw_shell);
1733 #ifdef M_UNIX
1734     ret = &save;
1735   DONE:
1736     endpwent();
1737 #endif
1738 #if defined(SecureWare) || defined(HPUX_10_TRUSTED)
1739     endprpwent();
1740 #endif
1741 #ifdef M_UNIX
1742     return (ret);
1743 #else
1744     return (&save);
1745 #endif
1746 }
1747 #if defined(SKEY) && !defined(__NetBSD__)
1748 /*
1749  * From Wietse Venema, Eindhoven University of Technology.
1750  */
1751 /* skey_challenge - additional password prompt stuff */
1752 
1753 char *skey_challenge(char *name, struct passwd *pwd, int pwok)
1754 {
1755     static char buf[128];
1756     char sbuf[40];
1757     struct skey skey;
1758 
1759     /* Display s/key challenge where appropriate. */
1760 
1761     if (pwd == NULL || skeychallenge(&skey, pwd->pw_name, sbuf))
1762 	sprintf(buf, "Password required for %s.", name);
1763     else
1764 	sprintf(buf, "%s %s for %s.", sbuf,
1765 		pwok ? "allowed" : "required", name);
1766     return (buf);
1767 }
1768 #endif
1769 
1770 int login_attempts;		/* number of failed login attempts */
1771 int askpasswd;			/* had user command, ask for passwd */
1772 #ifndef HELP_CRACKERS
1773 int DenyLoginAfterPassword;
1774 char DelayedMessageFile[MAXPATHLEN];
1775 extern void pr_mesg(int msgcode, char *msgfile);
1776 #endif
1777 
1778 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
1779 static int defaultserver_allow(const char *username)
1780 {
1781     struct aclmember *entry = NULL;
1782     int which;
1783 
1784     while (getaclentry("defaultserver", &entry))
1785 	if (ARG0 && !strcasecmp(ARG0, "allow"))
1786 	    for (which = 1; (which < MAXARGS) && ARG[which]; which++)
1787 		if (!strcasecmp(username, ARG[which]) || !strcmp("*", ARG[which]))
1788 		    return (1);
1789     return (0);
1790 }
1791 
1792 static int defaultserver_deny(const char *username)
1793 {
1794     struct aclmember *entry = NULL;
1795     int which;
1796 
1797     while (getaclentry("defaultserver", &entry))
1798 	if (ARG0 && !strcasecmp(ARG0, "deny"))
1799 	    for (which = 1; (which < MAXARGS) && ARG[which]; which++)
1800 		if (!strcasecmp(username, ARG[which]) || !strcmp("*", ARG[which]))
1801 		    return (1);
1802     return (0);
1803 }
1804 
1805 static int defaultserver_private(void)
1806 {
1807     struct aclmember *entry = NULL;
1808 
1809     while (getaclentry("defaultserver", &entry))
1810 	if (ARG0 && !strcasecmp(ARG0, "private"))
1811 	    return (1);
1812     return (0);
1813 }
1814 #endif
1815 
1816 /* USER command. Sets global passwd pointer pw if named account exists and is
1817  * acceptable; sets askpasswd if a PASS command is expected.  If logged in
1818  * previously, need to reset state.  If name is "ftp" or "anonymous", the
1819  * name is not in the ftpusers file, and ftp account exists, set anonymous and
1820  * pw, then just return.  If account doesn't exist, ask for passwd anyway.
1821  * Otherwise, check user requesting login privileges.  Disallow anyone who
1822  * does not have a standard shell as returned by getusershell().  Disallow
1823  * anyone mentioned in the ftpusers file to allow people such as root and
1824  * uucp to be avoided. */
1825 
1826 /*
1827    char *getusershell();
1828  */
1829 void user(char *name)
1830 {
1831     char *cp;
1832     char *shell;
1833 #ifdef	BSD_AUTH
1834     char *auth;
1835 #endif
1836 #if defined(USE_GSS)
1837     int gss_need_passwd = 1;
1838 #endif
1839 
1840 /* H* fix: if we're logged in at all, we can't log in again. */
1841     if (logged_in) {
1842 #ifdef VERBOSE_ERROR_LOGING
1843 	syslog(LOG_NOTICE, "FTP LOGIN REFUSED (already logged in as %s) FROM %s, %s",
1844 	       pw->pw_name, remoteident, name);
1845 #endif
1846 	reply(530, "Already logged in.");
1847 	return;
1848     }
1849 #ifndef HELP_CRACKERS
1850     askpasswd = 1;
1851     DenyLoginAfterPassword = 0;
1852     DelayedMessageFile[0] = '\0';
1853 #endif
1854 #ifdef	BSD_AUTH
1855     if ((auth = strchr(name, ':')))
1856 	*auth++ = 0;
1857 #endif
1858 
1859 #ifdef HOST_ACCESS		/* 19-Mar-93    BM              */
1860     if (!rhost_ok(name, remotehost, remoteaddr)) {
1861 #ifndef HELP_CRACKERS
1862 	DenyLoginAfterPassword = 1;
1863 	syslog(LOG_NOTICE, "FTP LOGIN REFUSED (name in %s) FROM %s, %s",
1864 	       _path_ftphosts, remoteident, name);
1865 #else
1866 	reply(530, "User %s access denied.", name);
1867 	syslog(LOG_NOTICE,
1868 	       "FTP LOGIN REFUSED (name in %s) FROM %s, %s",
1869 	       _path_ftphosts, remoteident, name);
1870 	return;
1871 #endif
1872     }
1873 #endif
1874 
1875     strncpy(the_user, name, MAXUSERNAMELEN - 1);
1876 
1877     anonymous = 0;
1878     guest = 0;
1879 
1880     if (!strcasecmp(name, "ftp") || !strcasecmp(name, "anonymous")) {
1881 	struct aclmember *entry = NULL;
1882 	int machineok = 1;
1883 	char guestservername[MAXHOSTNAMELEN];
1884 	guestservername[0] = '\0';
1885 
1886 #ifdef NO_ANONYMOUS_ACCESS
1887 	reply(530, "Anonymous FTP access denied.");
1888 	syslog(LOG_NOTICE, "FTP LOGIN REFUSED (anonymous ftp not supported) FROM %s, %s",
1889 	       remoteident, name);
1890 	return;
1891 #else
1892 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
1893 	if (!virtual_mode && defaultserver_private()) {
1894 #ifndef HELP_CRACKERS
1895 	    DenyLoginAfterPassword = 1;
1896 	    syslog(LOG_NOTICE, "FTP LOGIN REFUSED (anonymous ftp denied on default server) FROM %s, %s",
1897 		   remoteident, name);
1898 #else
1899 	    reply(530, "User %s access denied.", name);
1900 	    syslog(LOG_NOTICE,
1901 		   "FTP LOGIN REFUSED (anonymous ftp denied on default server) FROM %s, %s",
1902 		   remoteident, name);
1903 	    return;
1904 #endif
1905 	}
1906 #endif
1907 	if (checkuser("ftp") || checkuser("anonymous")) {
1908 #ifndef HELP_CRACKERS
1909 	    DenyLoginAfterPassword = 1;
1910 	    syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp in %s) FROM %s, %s",
1911 		   _path_ftpusers, remoteident, name);
1912 #else
1913 	    reply(530, "User %s access denied.", name);
1914 	    syslog(LOG_NOTICE,
1915 		   "FTP LOGIN REFUSED (ftp in %s) FROM %s, %s",
1916 		   _path_ftpusers, remoteident, name);
1917 	    return;
1918 #endif
1919 
1920 	    /*
1921 	       ** Algorithm used:
1922 	       ** - if no "guestserver" directive is present,
1923 	       **     anonymous access is allowed, for backward compatibility.
1924 	       ** - if a "guestserver" directive is present,
1925 	       **     anonymous access is restricted to the machines listed,
1926 	       **     usually the machine whose CNAME on the current domain
1927 	       **     is "ftp"...
1928 	       **
1929 	       ** the format of the "guestserver" line is
1930 	       ** guestserver [<machine1> [<machineN>]]
1931 	       ** that is, "guestserver" will forbid anonymous access on all machines
1932 	       ** while "guestserver ftp inf" will allow anonymous access on
1933 	       ** the two machines whose CNAMES are "ftp.enst.fr" and "inf.enst.fr".
1934 	       **
1935 	       ** if anonymous access is denied on the current machine,
1936 	       ** the user will be asked to use the first machine listed (if any)
1937 	       ** on the "guestserver" line instead:
1938 	       ** 530- Guest login not allowed on this machine,
1939 	       **      connect to ftp.enst.fr instead.
1940 	       **
1941 	       ** -- <Nicolas.Pioch@enst.fr>
1942 	     */
1943 	}
1944 	else if (getaclentry("guestserver", &entry)) {
1945 	    char *tmphost;
1946 
1947 	    /*
1948 	       ** if a "guestserver" line is present,
1949 	       ** default is not to allow guest logins
1950 	     */
1951 	    machineok = 0;
1952 
1953 	    if (hostname[0]
1954 		&& ((tmphost = wu_gethostbyname(hostname)))) {
1955 
1956 		/*
1957 		   ** hostname is the only first part of the FQDN
1958 		   ** this may or may not correspond to the h_name value
1959 		   ** (machines with more than one IP#, CNAMEs...)
1960 		   ** -> need to fix that, calling gethostbyname on hostname
1961 		   **
1962 		   ** WARNING!
1963 		   ** for SunOS 4.x, you need to have a working resolver in the libc
1964 		   ** for CNAMES to work properly.
1965 		   ** If you don't, add "-lresolv" to the libraries before compiling!
1966 		 */
1967 		char dns_localhost[MAXHOSTNAMELEN];
1968 		int machinecount;
1969 
1970 		strncpy(dns_localhost, tmphost, sizeof(dns_localhost));
1971 		dns_localhost[sizeof(dns_localhost) - 1] = '\0';
1972 
1973 		for (machinecount = 0;
1974 		     (machinecount < MAXARGS) && entry->arg[machinecount];
1975 		     machinecount++) {
1976 
1977 		    if ((tmphost = wu_gethostbyname(entry->arg[machinecount]))) {
1978 			/*
1979 			   ** remember the name of the first machine for redirection
1980 			 */
1981 
1982 			if (!machinecount) {
1983 			    strncpy(guestservername, entry->arg[machinecount],
1984 				    sizeof(guestservername));
1985 			    guestservername[sizeof(guestservername) - 1] = '\0';
1986 			}
1987 
1988 			if (!strcasecmp(tmphost, dns_localhost)) {
1989 			    machineok++;
1990 			    break;
1991 			}
1992 		    }
1993 		}
1994 	    }
1995 	}
1996 	if (!machineok) {
1997 	    if (guestservername[0])
1998 		reply(530,
1999 		      "Guest login not allowed on this machine, connect to %s instead.",
2000 		      guestservername);
2001 	    else
2002 		reply(530,
2003 		      "Guest login not allowed on this machine.");
2004 	    syslog(LOG_NOTICE,
2005 	    "FTP LOGIN REFUSED (localhost not in guestservers) FROM %s, %s",
2006 		   remoteident, name);
2007 	    /* End of the big patch -- Nap */
2008 
2009 	    dologout(0);
2010 	}
2011 	else if ((pw = sgetpwnam("ftp")) != NULL) {
2012 	    anonymous = 1;	/* for the access_ok call */
2013 	    if (access_ok(530) < 1) {
2014 #ifndef HELP_CRACKERS
2015 		DenyLoginAfterPassword = 1;
2016 		syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s, %s",
2017 		       remoteident, name);
2018 		reply(331, "Guest login ok, send your complete e-mail address as password.");
2019 #else
2020 		reply(530, "User %s access denied.", name);
2021 		syslog(LOG_NOTICE,
2022 		       "FTP LOGIN REFUSED (access denied) FROM %s, %s",
2023 		       remoteident, name);
2024 		dologout(0);
2025 #endif
2026 	    }
2027 	    else {
2028 		askpasswd = 1;
2029 /* H* fix: obey use_accessfile a little better.  This way, things set on the
2030    command line [like xferlog stuff] don't get stupidly overridden.
2031    XXX: all these checks maybe should be in acl.c and access.c */
2032 		if (use_accessfile)
2033 		    acl_setfunctions();
2034 		reply(331, "Guest login ok, send your complete e-mail address as password.");
2035 	    }
2036 	}
2037 	else {
2038 #ifndef HELP_CRACKERS
2039 	    DenyLoginAfterPassword = 1;
2040 	    reply(331, "Guest login ok, send your complete e-mail address as password.");
2041 	    syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp not in /etc/passwd) FROM %s, %s",
2042 		   remoteident, name);
2043 #else
2044 	    reply(530, "User %s unknown.", name);
2045 	    syslog(LOG_NOTICE,
2046 		   "FTP LOGIN REFUSED (ftp not in /etc/passwd) FROM %s, %s",
2047 		   remoteident, name);
2048 #endif
2049 #ifdef SOLARIS_BSM_AUDIT
2050 	    audit_ftpd_no_anon();
2051 #endif
2052 	}
2053 	return;
2054 #endif
2055     }
2056 #ifdef ANON_ONLY
2057 /* H* fix: define the above to completely DISABLE logins by real users,
2058    despite ftpusers, shells, or any of that rot.  You can always hang your
2059    "real" server off some other port, and access-control it. */
2060 
2061     else {			/* "ftp" or "anon" -- MARK your conditionals, okay?! */
2062 #ifndef HELP_CRACKERS
2063 	DenyLoginAfterPassword = 1;
2064 	syslog(LOG_NOTICE, "FTP LOGIN REFUSED (not anonymous) FROM %s, %s",
2065 	       remoteident, name);
2066 	reply(331, "Password required for %s.", name);
2067 #else
2068 	reply(530, "User %s unknown.", name);
2069 	syslog(LOG_NOTICE,
2070 	       "FTP LOGIN REFUSED (not anonymous) FROM %s, %s",
2071 	       remoteident, name);
2072 #endif
2073 	return;
2074     }
2075 /* fall here if username okay in any case */
2076 #endif /* ANON_ONLY */
2077 
2078 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
2079     if (!virtual_mode && defaultserver_deny(name) && !defaultserver_allow(name)) {
2080 #ifndef HELP_CRACKERS
2081 	DenyLoginAfterPassword = 1;
2082 	syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp denied on default server) FROM %s, %s",
2083 	       remoteident, name);
2084 #else
2085 	reply(530, "User %s access denied.", name);
2086 	syslog(LOG_NOTICE,
2087 	     "FTP LOGIN REFUSED (ftp denied on default server) FROM %s, %s",
2088 	       remoteident, name);
2089 	return;
2090 #endif
2091     }
2092 #endif
2093 
2094 #if defined(USE_GSS)
2095     if (gss_info.must_gss_auth &&
2096 	(!IS_GSSAUTH(cur_auth_type) ||
2097 	!(gss_info.authstate & GSS_ADAT_DONE))) {
2098 	reply(530, "Must perform authentication before identifying USER.");
2099 	return;
2100     }
2101 #endif /* USE_GSS */
2102 
2103     if ((pw = sgetpwnam(name)) != NULL) {
2104 	if ((denieduid(pw->pw_uid) && !alloweduid(pw->pw_uid))
2105 	    || (deniedgid(pw->pw_gid) && !allowedgid(pw->pw_gid))) {
2106 #ifndef HELP_CRACKERS
2107 	    DenyLoginAfterPassword = 1;
2108 	    syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in denied-uid) FROM %s, %s",
2109 		   remoteident, name);
2110 	    reply(331, "Password required for %s.", name);
2111 #else
2112 	    reply(530, "User %s access denied.", name);
2113 	    syslog(LOG_NOTICE,
2114 		   "FTP LOGIN REFUSED (username in denied-uid) FROM %s, %s",
2115 		   remoteident, name);
2116 #endif
2117 	    return;
2118 	}
2119 #if defined(USE_GSS)
2120 	if (IS_GSSAUTH(cur_auth_type) &&
2121 	    (gss_info.authstate & GSS_ADAT_DONE)) {
2122 	    char buf[BUFSIZ];
2123 
2124 	    if (gss_user(pw))
2125 		gss_info.authstate |= GSS_USER_DONE;
2126 
2127 	    if (gss_info.must_gss_auth &&
2128 		!GSSUSERAUTH_OK(gss_info)) {
2129 		reply(530, "User %s access denied", name);
2130 		if (logging)
2131 		    syslog(LOG_NOTICE, "FTP GSSAPI LOGIN REFUSED FROM %s, %s",
2132 			remoteident, name);
2133 		pw = NULL;
2134 		return;
2135 	    }
2136 	    /*
2137 	     * If GSSAPI user auth failed, or it succeeded but creds were
2138 	     * not forwarded as required, prompt for password.
2139 	     */
2140 	    gss_need_passwd = !GSSUSERAUTH_OK(gss_info) ||
2141 		(GSSUSERAUTH_OK(gss_info) &&
2142 		(gss_info.want_creds && !gss_info.have_creds));
2143 	    if (gss_need_passwd) {
2144 		snprintf(buf, sizeof(buf),
2145 		    "GSSAPI user %s is authorized as %s password required",
2146 		    gss_info.display_name, name);
2147 		reply(331, "%s", buf);
2148 		askpasswd = 1;
2149 		syslog(LOG_DEBUG, "%s", buf);
2150 		return;
2151 	    }
2152 	}
2153 #endif /* defined(USE_GSS) */
2154 
2155 #if !defined(USE_PAM) || (defined(USE_PAM) && defined(OTHER_PASSWD)) || defined(SOLARIS_2)	/* PAM should be doing these checks, not ftpd */
2156 #if defined(USE_PAM) && !defined(SOLARIS_2)
2157 	if(!use_pam) {
2158 #endif
2159 	if ((shell = pw->pw_shell) == NULL || *shell == 0)
2160 	    shell = _PATH_BSHELL;
2161 	while ((cp = getusershell()) != NULL)
2162 	    if (strcmp(cp, shell) == 0)
2163 		break;
2164 	endusershell();
2165 	if (cp == NULL || checkuser(name)) {
2166 #ifndef HELP_CRACKERS
2167 	    DenyLoginAfterPassword = 1;
2168 	    if (cp == NULL)
2169 		syslog(LOG_NOTICE, "FTP LOGIN REFUSED (shell not in /etc/shells) FROM %s, %s", remoteident, name);
2170 	    else
2171 		syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in %s) FROM %s, %s", _path_ftpusers, remoteident, name);
2172 	    reply(331, "Password required for %s.", name);
2173 #else
2174 	    reply(530, "User %s access denied.", name);
2175 	    if (cp == NULL)
2176 		syslog(LOG_NOTICE, "FTP LOGIN REFUSED (shell not in /etc/shells) FROM %s, %s", remoteident, name);
2177 	    else
2178 		syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in %s) FROM %s, %s", _path_ftpusers, remoteident, name);
2179 #endif /* HELP_CRACKERS */
2180 	    pw = (struct passwd *) NULL;
2181 	    return;
2182 	}
2183 #if defined(USE_PAM) && !defined(SOLARIS_2)
2184 	} /* if(!use_pam) */
2185 #endif
2186 #endif /* !USE_PAM || (USE_PAM && OTHER_PASSWD) || SOLARIS_2 */
2187 	/* if user is a member of any of the guestgroups, cause a chroot() */
2188 	/* after they log in successfully                                  */
2189 	if (use_accessfile) {	/* see above.  _H */
2190 	    guest = acl_guestgroup(pw);
2191 	    if (guest && acl_realgroup(pw))
2192 		guest = 0;
2193 	}
2194     }
2195     if (access_ok(530) < 1) {
2196 #ifndef HELP_CRACKERS
2197 	DenyLoginAfterPassword = 1;
2198 	syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s, %s",
2199 	       remoteident, name);
2200 	reply(331, "Password required for %s.", name);
2201 #else
2202 	reply(530, "User %s access denied.", name);
2203 	syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s, %s",
2204 	       remoteident, name);
2205 #endif
2206 	return;
2207     }
2208     else if (use_accessfile)	/* see above.  _H */
2209 	acl_setfunctions();
2210 
2211 #ifdef	BSD_AUTH
2212     if ((cp = start_auth(auth, name, pw)) != NULL) {
2213 	char *s;
2214 
2215 	for (;;) {
2216 	    s = strsep(&cp, "\n");
2217 	    if (cp == NULL || *cp == '\0')
2218 		break;
2219 	    lreply(331, "%s", s);
2220 	}
2221 	reply(331, "%s", s);
2222     }
2223     else {
2224 #endif /* BSD_AUTH */
2225 #ifdef SKEY
2226 #ifndef __NetBSD__
2227 #ifdef SKEY_NAME
2228 	/* this is the old way, but freebsd uses it */
2229 	pwok = skeyaccess(name, NULL, remotehost, remoteaddr);
2230 #else
2231 	/* this is the new way */
2232 	pwok = skeyaccess(pw, NULL, remotehost, remoteaddr);
2233 #endif /* SKEY_NAME */
2234 	reply(331, "%s", skey_challenge(name, pw, pwok));
2235 #else
2236 	if (skey_haskey(name) == 0) {
2237 	    char *myskey;
2238 
2239 	    myskey = skey_keyinfo(name);
2240 	    reply(331, "Password [%s] required for %s.",
2241 		  myskey ? myskey : "error getting challenge", name);
2242 	}
2243 	else
2244 	    reply(331, "Password required for %s.", name);
2245 #endif /* __NetBSD__ */
2246 #else
2247 #ifdef OPIE
2248 	{
2249 	    char prompt[OPIE_CHALLENGE_MAX + 1];
2250 	    opiechallenge(&opiestate, name, prompt);
2251 
2252 	    if (askpasswd == -1) {
2253 		syslog(LOG_WARNING, "Invalid FTP user name %s attempted from %s", name, remotehost);
2254 		pwok = 0;
2255 	    }
2256 	    else
2257 		pwok = af_pwok && opiealways(pw->pw_dir);
2258 	    reply(331, "Response to %s %s for %s.",
2259 		  prompt, pwok ? "requested" : "required", name);
2260 	}
2261 #else /* !SKEY */
2262 
2263 #if defined(USE_GSS)
2264 	if (GSSUSERAUTH_OK(gss_info) && !gss_need_passwd) {
2265 	    /*
2266 	     * We got this far, we are allowing the GSSAPI authentication
2267 	     * to succeed without further passwd prompting.  Jump
2268 	     * to "pass" processing.
2269 	     */
2270 	    askpasswd = 0;
2271 	    logged_in = 1;
2272 	    pass("");
2273 	    return;
2274 	}
2275 #endif /* defined(USE_GSS) */
2276 	reply(331, "Password required for %s.", name);
2277 #endif /* OPIE */
2278 #endif /* SKEY */
2279 #ifdef	BSD_AUTH
2280     }
2281 #endif /* BSD_AUTH */
2282 
2283     askpasswd = 1;
2284     /* Delay before reading passwd after first failed attempt to slow down
2285      * passwd-guessing programs. */
2286     if (login_attempts) {
2287 	enable_signaling();	/* we can allow signals once again: kinch */
2288 	sleep((unsigned) login_attempts);
2289     }
2290     return;
2291 }
2292 
2293 /* Check if a user is in the ftpusers file */
2294 int checkuser(char *name)
2295 {
2296     register FILE *fd;
2297     register char *p;
2298     char line[BUFSIZ];
2299 
2300 #ifdef SOLARIS_ETC_FTPUSERS
2301     static int etc_ftpusers = 0;
2302 
2303     if (etc_ftpusers) {
2304 	strcpy(_path_ftpusers, _PATH_FTPUSERS);
2305 	etc_ftpusers = 0;
2306     }
2307 retry:
2308 #endif
2309     if ((fd = fopen(_path_ftpusers, "r")) != NULL) {
2310 	while (fgets(line, sizeof(line), fd) != NULL)
2311 	    if ((p = strchr(line, '\n')) != NULL) {
2312 		*p = '\0';
2313 		if (line[0] == '#')
2314 		    continue;
2315 		if (strcasecmp(line, name) == 0) {
2316 		    (void) fclose(fd);
2317 #ifdef SOLARIS_BSM_AUDIT
2318 		    audit_ftpd_excluded(name);
2319 #endif
2320 #ifdef SOLARIS_ETC_FTPUSERS
2321 		    if (etc_ftpusers)
2322 			syslog(LOG_NOTICE, "%s is deprecated, use %s instead", _path_ftpusers, _PATH_FTPUSERS);
2323 #endif
2324 		    return (1);
2325 		}
2326 	    }
2327 	(void) fclose(fd);
2328     }
2329 #ifdef SOLARIS_ETC_FTPUSERS
2330     if (!etc_ftpusers && (strcmp(_path_ftpusers, _PATH_FTPUSERS) == 0)) {
2331 	strcpy(_path_ftpusers, "/etc/ftpusers");
2332 	etc_ftpusers = 1;
2333 	goto retry;
2334     }
2335 #endif
2336     return (0);
2337 }
2338 
2339 int uid_match(char *keyword, uid_t uid)
2340 {
2341     struct aclmember *entry = NULL;
2342     int which;
2343     char *ptr;
2344     struct passwd *pw;
2345 
2346     /*
2347      * keyword <uid-range> [<uid-range> ...]
2348      *
2349      * uid-range may be a username or begin with '%' and be treated as numeric:
2350      *   %<uid>       A single numeric UID
2351      *   %<uid>+      All UIDs greater or equal to UID
2352      *   %<uid>-      All UIDs greater or equal to UID
2353      *   %-<uid>      All UIDs less or equal to UID
2354      *   %<uid>-<uid> All UIDs between the two (inclusive)
2355      *   *            All UIDs
2356      */
2357     while (getaclentry(keyword, &entry)) {
2358 	for (which = 0; (which < MAXARGS) && ARG[which]; which++) {
2359 	    if (!strcmp(ARG[which], "*"))
2360 		return (1);
2361 	    if (ARG[which][0] == '%') {
2362 		if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) {
2363 		    if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) {
2364 			if (uid == strtoul(ARG[which] + 1, NULL, 0))
2365 			    return (1);
2366 		    }
2367 		    else {
2368 			*ptr++ = '\0';
2369 			if ((ARG[which][1] == '\0')
2370 			    || (uid >= strtoul(ARG[which] + 1, NULL, 0))) {
2371 			    *--ptr = '+';
2372 			    return (1);
2373 			}
2374 			*--ptr = '+';
2375 		    }
2376 		}
2377 		else {
2378 		    *ptr++ = '\0';
2379 		    if (((ARG[which][1] == '\0')
2380 			 || (uid >= strtoul(ARG[which] + 1, NULL, 0)))
2381 			&& ((*ptr == '\0')
2382 			    || (uid <= strtoul(ptr, NULL, 0)))) {
2383 			*--ptr = '-';
2384 			return (1);
2385 		    }
2386 		    *--ptr = '-';
2387 		}
2388 	    }
2389 	    else {
2390 #ifdef OTHER_PASSWD
2391 		pw = bero_getpwnam(ARG[which], _path_passwd);
2392 #else
2393 		pw = getpwnam(ARG[which]);
2394 #endif
2395 		if (pw && (uid == pw->pw_uid))
2396 		    return (1);
2397 	    }
2398 	}
2399     }
2400     return (0);
2401 }
2402 
2403 int gid_match(char *keyword, gid_t gid, char *username)
2404 {
2405     struct aclmember *entry = NULL;
2406     int which;
2407     char *ptr;
2408     struct group *grp;
2409     char **member;
2410 
2411     /*
2412      * keyword <gid-range> [<gid-range> ...]
2413      *
2414      * gid-range may be a groupname or begin with '%' and be treated as numeric:
2415      *   %<gid>       A single GID
2416      *   %<gid>+      All GIDs greater or equal to GID
2417      *   %<gid>-      All GIDs greater or equal to GID
2418      *   %-<gid>      All GIDs less or equal to GID
2419      *   %<gid>-<gid> All GIDs between the two (inclusive)
2420      *   *            All GIDs
2421      */
2422     while (getaclentry(keyword, &entry)) {
2423 	for (which = 0; (which < MAXARGS) && ARG[which]; which++) {
2424 	    if (!strcmp(ARG[which], "*"))
2425 		return (1);
2426 	    if (ARG[which][0] == '%') {
2427 		if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) {
2428 		    if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) {
2429 			if (gid == strtoul(ARG[which] + 1, NULL, 0))
2430 			    return (1);
2431 		    }
2432 		    else {
2433 			*ptr++ = '\0';
2434 			if ((ARG[which][1] == '\0')
2435 			    || (gid >= strtoul(ARG[which] + 1, NULL, 0))) {
2436 			    *--ptr = '+';
2437 			    return (1);
2438 			}
2439 			*--ptr = '+';
2440 		    }
2441 		}
2442 		else {
2443 		    *ptr++ = '\0';
2444 		    if (((ARG[which][1] == '\0')
2445 			 || (gid >= strtoul(ARG[which] + 1, NULL, 0)))
2446 			&& ((*ptr == '\0')
2447 			    || (gid <= strtoul(ptr, NULL, 0)))) {
2448 			*--ptr = '-';
2449 			return (1);
2450 		    }
2451 		    *--ptr = '-';
2452 		}
2453 	    }
2454 	    else {
2455 		if ((grp = getgrnam(ARG[which]))) {
2456 		    if (gid == grp->gr_gid)
2457 			return (1);
2458 		    if (username) {
2459 			for (member = grp->gr_mem; *member; member++)
2460 			    if (!strcasecmp(*member, username))
2461 				return (1);
2462 		    }
2463 		}
2464 	    }
2465 	}
2466     }
2467     return (0);
2468 }
2469 
2470 int denieduid(uid_t uid)
2471 {
2472     return uid_match("deny-uid", uid);
2473 }
2474 
2475 int alloweduid(uid_t uid)
2476 {
2477     return uid_match("allow-uid", uid);
2478 }
2479 
2480 int deniedgid(gid_t gid)
2481 {
2482     return gid_match("deny-gid", gid, NULL);
2483 }
2484 
2485 int allowedgid(gid_t gid)
2486 {
2487     return gid_match("allow-gid", gid, NULL);
2488 }
2489 
2490 /* Terminate login as previous user, if any, resetting state; used when USER
2491  * command is given or login fails. */
2492 
2493 void end_login(void)
2494 {
2495     delay_signaling();		/* we can't allow any signals while euid==0: kinch */
2496     (void) seteuid((uid_t) 0);
2497     if (logged_in) {
2498 	if (wtmp_logging)
2499 	    wu_logwtmp(ttyline, pw->pw_name, remotehost, 0);
2500 #ifdef USE_PAM
2501 	if (!anonymous && pamh) {
2502 	    (void) pam_close_session(pamh, 0);
2503 	    (void) pam_end(pamh, PAM_SUCCESS);
2504 	    pamh = (pam_handle_t *)0;
2505 	}
2506 #endif
2507     }
2508     pw = NULL;
2509 #ifdef AFS_AUTH
2510     ktc_ForgetAllTokens();
2511 #endif
2512     logged_in = 0;
2513     anonymous = 0;
2514     guest = 0;
2515 }
2516 
2517 int validate_eaddr(char *eaddr)
2518 {
2519     int i, host, state;
2520 
2521     for (i = host = state = 0; eaddr[i] != '\0'; i++) {
2522 	switch (eaddr[i]) {
2523 	case '.':
2524 	    if (!host)
2525 		return 0;
2526 	    if (state == 2)
2527 		state = 3;
2528 	    host = 0;
2529 	    break;
2530 	case '@':
2531 	    if (!host || state > 1 || !strncasecmp("ftp", eaddr + i - host, host))
2532 		return 0;
2533 	    state = 2;
2534 	    host = 0;
2535 	    break;
2536 	case '!':
2537 	case '%':
2538 	    if (!host || state > 1)
2539 		return 0;
2540 	    state = 1;
2541 	    host = 0;
2542 	    break;
2543 	case '-':
2544 	    break;
2545 	default:
2546 	    host++;
2547 	}
2548     }
2549     if (((state == 3) && host > 1) || ((state == 1) && host > 1))
2550 	return 1;
2551     else
2552 	return 0;
2553 }
2554 
2555 
2556 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
2557 static int AllowVirtualUser(const char *username)
2558 {
2559     struct aclmember *entry = NULL;
2560     int which;
2561 
2562     while (getaclentry("virtual", &entry))
2563 	if (ARG0 && hostmatch(ARG0, virtual_address, virtual_hostname)
2564 	    && ARG1 && !strcasecmp(ARG1, "allow"))
2565 	    for (which = 2; (which < MAXARGS) && ARG[which]; which++)
2566 		if (!strcasecmp(username, ARG[which]) || !strcmp("*", ARG[which]))
2567 		    return (1);
2568     return (0);
2569 }
2570 
2571 static int DenyVirtualUser(const char *username)
2572 {
2573     struct aclmember *entry = NULL;
2574     int which;
2575 
2576     while (getaclentry("virtual", &entry))
2577 	if (ARG0 && hostmatch(ARG0, virtual_address, virtual_hostname)
2578 	    && ARG1 && !strcasecmp(ARG1, "deny"))
2579 	    for (which = 2; (which < MAXARGS) && ARG[which]; which++)
2580 		if (!strcasecmp(username, ARG[which]) || !strcmp("*", ARG[which]))
2581 		    return (1);
2582     return (0);
2583 }
2584 
2585 static int DenyVirtualAnonymous(void)
2586 {
2587     struct aclmember *entry = NULL;
2588 
2589     while (getaclentry("virtual", &entry))
2590 	if (ARG0 && hostmatch(ARG0, virtual_address, virtual_hostname)
2591 	    && ARG1 && !strcasecmp(ARG1, "private"))
2592 	    return (1);
2593     return (0);
2594 }
2595 #endif
2596 
2597 void pass(char *passwd)
2598 {
2599 
2600 #if !defined(USE_PAM) || (defined(USE_PAM) && defined(OTHER_PASSWD))
2601     char *xpasswd, *salt;
2602 #endif
2603 
2604     int passwarn = 0;
2605     int rval = 1;
2606     int success_code = 230;
2607     int cos;
2608 
2609 #ifdef SECUREOSF
2610     struct pr_passwd *pr;
2611     int crypt_alg = 0;
2612 #endif
2613 
2614 #ifdef BSD_AUTH
2615     extern int ext_auth;
2616     extern char *check_auth();
2617 #endif
2618 
2619 #ifdef ULTRIX_AUTH
2620     int numfails;
2621 #endif /* ULTRIX_AUTH */
2622 
2623 #ifdef HAS_PW_EXPIRE
2624     int set_expired = FALSE;
2625 #endif
2626 
2627 #ifdef AFS_AUTH
2628     char *reason;
2629 #endif /* AFS_AUTH */
2630 
2631 #ifdef DCE_AUTH
2632     sec_passwd_rec_t pwr;
2633     sec_login_handle_t lhdl;
2634     boolean32 rstpwd;
2635     sec_login_auth_src_t asrc;
2636     error_status_t status;
2637 #endif /* DCE_AUTH */
2638 
2639 #if defined(USE_GSS)
2640     /*
2641      * LOGIC:
2642      *   If [ the user presented GSSAPI creds and was authorized ]
2643      *      jump down past the password validation code.
2644      */
2645     if (GSSUSERAUTH_OK(gss_info) && logged_in) {
2646 	/*
2647 	 * We could reply(202, "PASS command superfluous.") here, but
2648 	 * allow this for compat with some clients.
2649 	 */
2650 	success_code = 232;
2651 	goto pwd_validation_done;
2652     }
2653 #endif /* defined(USE_GSS) */
2654 
2655     if (logged_in || askpasswd == 0) {
2656 #ifdef VERBOSE_ERROR_LOGING
2657 	syslog(LOG_NOTICE, "FTP LOGIN REFUSED (PASS before USER) FROM %s",
2658 	       remoteident);
2659 #endif
2660 	reply(503, "Login with USER first.");
2661 	return;
2662     }
2663     askpasswd = 0;
2664 
2665     /* Disable lreply() if the first character of the password is '-' since
2666      * some hosts don't understand continuation messages and hang... */
2667 
2668     if (*passwd == '-')
2669 	dolreplies = 0;
2670     else
2671 	dolreplies = 1;
2672 /* ******** REGULAR/GUEST USER PASSWORD PROCESSING ********** */
2673     if (!anonymous) {		/* "ftp" is only account allowed no password */
2674 #ifndef HELP_CRACKERS
2675 	if (DenyLoginAfterPassword) {
2676 	    pr_mesg(530, DelayedMessageFile);
2677 	    reply(530, "Login incorrect.");
2678 #ifdef SOLARIS_BSM_AUDIT
2679 	    audit_ftpd_failure(the_user);
2680 #endif
2681 	    acl_remove();
2682 	    pw = NULL;
2683 	    if (++login_attempts >= lgi_failure_threshold) {
2684 		syslog(LOG_NOTICE, "repeated login failures from %s",
2685 		       remoteident);
2686 		exit(0);
2687 	    }
2688 	    return;
2689 	}
2690 #endif
2691 	if (*passwd == '-')
2692 	    passwd++;
2693 #ifdef USE_PAM
2694 #ifdef OTHER_PASSWD
2695 	if (use_pam
2696 #if defined(USE_GSS)
2697 	    && !GSSUSERAUTH_OK(gss_info)
2698 #endif
2699 	) {
2700 #endif
2701 	/* PAM authentication
2702 	 * If PAM authenticates a user we know nothing about on the local
2703 	 * system, use the generic guest account credentials. We should make
2704 	 * this somehow a configurable item somewhere; later more on that.
2705 	 *
2706 	 * For now assume the guest (not anonymous) identity, so the site
2707 	 * admins can still differentiate between the truw anonymous user and
2708 	 * a little bit more special ones. Otherwise he wouldn't go the extra
2709 	 * mile to have a different user database, right?
2710 	 *              --gaftonc */
2711 	if (pam_check_pass(the_user, passwd)) {
2712 	    rval = 0;
2713 	    if (pw == NULL) {
2714 		/* assume guest account identity */
2715 		pw = sgetpwnam("ftp");
2716 		anonymous = 0;
2717 		guest = 1;
2718 		/* even go as far as... */
2719 		if (pw != NULL && pw->pw_name != NULL) {
2720 		    free(pw->pw_name);
2721 		    pw->pw_name = sgetsave(the_user);
2722 		}
2723 	    }
2724 	}
2725 #ifdef OTHER_PASSWD
2726 	} else {
2727 #endif
2728 #endif /* USE_PAM */
2729 #if !defined(USE_PAM) || (defined(USE_PAM) && defined(OTHER_PASSWD))
2730 #ifdef BSD_AUTH
2731 	if (ext_auth) {
2732 	    if ((salt = check_auth(the_user, passwd))) {
2733 		reply(530, "%s", salt);
2734 #ifdef LOG_FAILED		/* 27-Apr-93      EHK/BM          */
2735 		/*
2736 		 * To avoid logging passwords mistakenly entered as
2737 		 * usernames, only log the names of users which exist.
2738 		 */
2739 		syslog(LOG_INFO, "failed login from %s, %s", remoteident,
2740 		       (pw == NULL) ? "[unknown]" : the_user);
2741 #endif /* LOG_FAILED */
2742 		acl_remove();
2743 		pw = NULL;
2744 		if (++login_attempts >= lgi_failure_threshold) {
2745 		    syslog(LOG_NOTICE, "repeated login failures from %s",
2746 			   remoteident);
2747 		    exit(0);
2748 		}
2749 		return;
2750 	    }
2751 	}
2752 	else {
2753 #endif /* BSD_AUTH */
2754 	    *guestpw = '\0';
2755 	    if (pw == NULL)
2756 		salt = "xx";
2757 	    else
2758 #ifndef OPIE
2759 		salt = pw->pw_passwd;
2760 #ifdef SECUREOSF
2761 	    if ((pr = getprpwnam(pw->pw_name)) != NULL) {
2762 		if (pr->uflg.fg_newcrypt)
2763 		    crypt_alg = pr->ufld.fd_newcrypt;
2764 		else if (pr->sflg.fg_newcrypt)
2765 		    crypt_alg = pr->sfld.fd_newcrypt;
2766 		else
2767 		    crypt_alg = 0;
2768 	    }
2769 	    else
2770 		crypt_alg = 0;
2771 
2772 	    xpasswd = dispcrypt(passwd, salt, crypt_alg);
2773 #elif defined(SecureWare) || defined(HPUX_10_TRUSTED)
2774 	    xpasswd = bigcrypt(passwd, salt);
2775 #elif defined(KERBEROS)
2776 	    xpasswd = crypt16(passwd, salt);
2777 #elif defined(SKEY)
2778 #ifndef __NetBSD__
2779 	    xpasswd = skey_crypt(passwd, salt, pw, pwok);
2780 	    pwok = 0;
2781 #else
2782 	    if ((pw != NULL) && (pw->pw_name != NULL) && skey_haskey(pw->pw_name) == 0 &&
2783 		skey_passcheck(pw->pw_name, passwd) != -1)
2784 		xpasswd = pw->pw_passwd;
2785 	    else
2786 		xpasswd = crypt(passwd, salt);
2787 #endif
2788 #else /* !SKEY */
2789 	    xpasswd = crypt(passwd, salt);
2790 #endif /* SKEY */
2791 #else /* OPIE */
2792 	    if (!opieverify(&opiestate, passwd))
2793 		rval = 0;
2794 	    xpasswd = crypt(passwd, pw->pw_passwd);
2795 #endif /* OPIE */
2796 #ifdef ULTRIX_AUTH
2797 	    if ((numfails = ultrix_check_pass(passwd, xpasswd)) >= 0) {
2798 #else
2799 	    if (pw != NULL) {
2800 #ifdef AFS_AUTH
2801 		if (strcmp(pw->pw_passwd, "X") == 0)
2802 		    if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION | KA_USERAUTH_DOSETPAG, pw->pw_name, "", 0, passwd, 0, 0, 0, &reason) == 0)
2803 			rval = 0;
2804 		    else
2805 			printf("230-AFS: %s", reason);
2806 		else
2807 #endif /* AFS_AUTH */
2808 		    /* The strcmp does not catch null passwords! */
2809 #ifdef HAS_PW_EXPIRE
2810 		    if(pw->pw_expire != NULL) {
2811 			if(pw->pw_expire && time(NULL) >= pw->pw_expire) {
2812 			    set_expired = TRUE;
2813 			}
2814 		    }
2815 #endif
2816 
2817 		    if (*pw->pw_passwd != '\0' &&
2818 #ifdef HAS_PW_EXPIRE
2819 			!set_expired &&
2820 #endif
2821 			strcmp(xpasswd, pw->pw_passwd) == 0) {
2822 #endif
2823 		    rval = 0;
2824 		}
2825 #ifdef DCE_AUTH
2826 #ifndef ALWAYS_TRY_DCE
2827 		else
2828 #endif /* ALWAYS_TRY_DCE */
2829 		{
2830 		    sec_login_setup_identity((unsigned_char_p_t) pw->pw_name, sec_login_no_flags, &lhdl, &status);
2831 		    if (status == error_status_ok) {
2832 			printf("230-sec_login_setup_identity OK\n");
2833 			pwr.key.tagged_union.plain = (idl_char *) passwd;
2834 			pwr.key.key_type = sec_passwd_plain;
2835 			pwr.pepper = 0;
2836 			pwr.version_number = sec_passwd_c_version_none;
2837 			/* validate password with login context */
2838 			sec_login_valid_and_cert_ident(lhdl, &pwr, &rstpwd, &asrc, &status);
2839 			if (!rstpwd && (asrc == sec_login_auth_src_network) && (status == error_status_ok)) {
2840 			    printf("230-sec_login_valid_and_cert_ident OK\n");
2841 			    sec_login_set_context(lhdl, &status);
2842 			    printf("230-sec_login_set_context finished\n");
2843 			    if (status != error_status_ok) {
2844 				int pstatus;
2845 				dce_error_string_t s;
2846 				printf("230-Error status: %d:\n", status);
2847 				dce_error_inq_text(status, s, &pstatus);
2848 				printf("230-%s\n", s);
2849 				fflush(stderr);
2850 				sec_login_purge_context(lhdl, &status);
2851 			    }
2852 			    else {
2853 				/*sec_login_get_pwent(lhdl, &pw, &status); */
2854 				rval = 0;
2855 			    }
2856 			}
2857 		    }
2858 		}
2859 #endif /* DCE_AUTH */
2860 	    }
2861 #ifdef USE_PAM
2862 	    }
2863 #endif
2864 #endif /* !USE_PAM  || (USE_PAM && OTHER_PASSWD) */
2865 	    if (rval) {
2866 		reply(530, "Login incorrect.");
2867 
2868 #ifdef LOG_FAILED		/* 27-Apr-93    EHK/BM             */
2869 /* H* add-on: yell about attempts to use the trojan.  This may alarm you
2870    if you're "stringsing" the binary and you see "NULL" pop out in just
2871    about the same place as it would have in 2.2c! */
2872 		if (!strcasecmp(passwd, "NULL"))
2873 		    syslog(LOG_NOTICE, "REFUSED \"NULL\" from %s, %s",
2874 			   remoteident, the_user);
2875 		else {
2876 		    /*
2877 		     * To avoid logging passwords mistakenly entered as
2878 		     * usernames, only log the names of users which exist.
2879 		     */
2880 		    syslog(LOG_INFO, "failed login from %s, %s", remoteident,
2881 			   (pw == NULL) ? "[unknown]" : the_user);
2882 		}
2883 #endif
2884 #ifdef SOLARIS_BSM_AUDIT
2885 		audit_ftpd_failure(the_user);
2886 #endif
2887 		acl_remove();
2888 
2889 		pw = NULL;
2890 		if (++login_attempts >= lgi_failure_threshold) {
2891 		    syslog(LOG_NOTICE, "repeated login failures from %s",
2892 			   remoteident);
2893 		    exit(0);
2894 		}
2895 		return;
2896 	    }
2897 #ifdef	BSD_AUTH
2898 	}
2899 #endif
2900 /* ANONYMOUS USER PROCESSING STARTS HERE */
2901     }
2902     else {
2903 	char *pwin, *pwout = guestpw;
2904 	struct aclmember *entry = NULL;
2905 	int valid;
2906 	int enforce = 0;
2907 
2908 	if (getaclentry("passwd-check", &entry) &&
2909 	    ARG0 && strcasecmp(ARG0, "none")) {
2910 
2911 	    if (!strcasecmp(ARG0, "rfc822"))
2912 		valid = validate_eaddr(passwd);
2913 	    else if (!strcasecmp(ARG0, "trivial"))
2914 		valid = (strchr(passwd, '@') == NULL) ? 0 : 1;
2915 	    else
2916 		valid = 1;
2917 	    if (ARG1 && !strcasecmp(ARG1, "enforce"))
2918 		enforce = 1;
2919 	    /* Block off "default" responses like mozilla@ and IE30User@
2920 	     * (at the administrator's discretion).  --AC
2921 	     */
2922 	    entry = NULL;
2923 	    while (getaclentry("deny-email", &entry)) {
2924 		if (ARG0
2925 		    && ((strcasecmp(passwd, ARG0) == 0)
2926 			|| regexmatch(passwd, ARG0)
2927 			|| ((*passwd == '-')
2928 			    && ((strcasecmp(passwd + 1, ARG0) == 0)
2929 				|| regexmatch(passwd + 1, ARG0))))) {
2930 		    valid = 0;
2931 		    break;
2932 		}
2933 	    }
2934 	    if (!valid && enforce) {
2935 		lreply(530, "The response '%s' is not valid", passwd);
2936 		lreply(530, "Please use your e-mail address as your password");
2937 		lreply(530, "   for example: %s@%s%s",
2938 		       authenticated ? authuser : "joe", remotehost,
2939 		       strchr(remotehost, '.') ? "" : ".network");
2940 		reply(530, "Login incorrect.");
2941 #ifdef VERBOSE_ERROR_LOGING
2942 		syslog(LOG_NOTICE, "FTP ACCESS REFUSED (anonymous password not rfc822) from %s",
2943 		       remoteident);
2944 #endif
2945 #ifdef SOLARIS_BSM_AUDIT
2946 		audit_ftpd_bad_pw(the_user);
2947 #endif
2948 		acl_remove();
2949 		if (++login_attempts >= lgi_failure_threshold) {
2950 		    syslog(LOG_NOTICE, "repeated login failures from %s",
2951 			   remoteident);
2952 		    exit(0);
2953 		}
2954 		return;
2955 	    }
2956 	    else if (!valid)
2957 		passwarn = 1;
2958 	}
2959 	if (!*passwd) {
2960 	    strcpy(guestpw, "[none_given]");
2961 	}
2962 	else {
2963 	    int cnt = sizeof(guestpw) - 2;
2964 
2965 	    for (pwin = passwd; *pwin && cnt--; pwin++)
2966 		if (!isgraph(*pwin))
2967 		    *pwout++ = '_';
2968 		else
2969 		    *pwout++ = *pwin;
2970 	}
2971 #ifndef HELP_CRACKERS
2972 	if (DenyLoginAfterPassword) {
2973 	    pr_mesg(530, DelayedMessageFile);
2974 	    reply(530, "Login incorrect.");
2975 #ifdef SOLARIS_BSM_AUDIT
2976 	    audit_ftpd_failure(the_user);
2977 #endif
2978 	    acl_remove();
2979 	    pw = NULL;
2980 	    if (++login_attempts >= lgi_failure_threshold) {
2981 		syslog(LOG_NOTICE, "repeated login failures from %s",
2982 		       remoteident);
2983 		exit(0);
2984 	    }
2985 	    return;
2986 	}
2987 #endif
2988     }
2989 
2990 #if defined(USE_GSS)
2991 pwd_validation_done:
2992 #endif /* USE_GSS */
2993     /* if logging is enabled, open logfile before chroot or set group ID */
2994     if ((log_outbound_xfers || log_incoming_xfers) && (syslogmsg != 1)) {
2995 	mode_t oldmask;
2996 	oldmask = umask(0);
2997 	xferlog = open(logfile, O_WRONLY | O_APPEND | O_CREAT, 0640);
2998 	(void) umask(oldmask);
2999 	if (xferlog < 0) {
3000 	    syslog(LOG_ERR, "cannot open logfile %s: %s", logfile,
3001 		   strerror(errno));
3002 	    xferlog = 0;
3003 	}
3004     }
3005 
3006 #ifdef DEBUG
3007 /* I had a lot of trouble getting xferlog working, because of two factors:
3008    acl_setfunctions making stupid assumptions, and sprintf LOSING.  _H */
3009 /*
3010  * Actually, sprintf was not losing, but the rules changed... next release
3011  * this will be fixed the correct way, but right now, it works well enough
3012  * -- sob
3013  */
3014     syslog(LOG_INFO, "-i %d,-o %d,xferlog %s: %d",
3015 	   log_incoming_xfers, log_outbound_xfers, logfile, xferlog);
3016 #endif
3017     enable_signaling();		/* we can allow signals once again: kinch */
3018     /* if autogroup command applies to user's class change pw->pw_gid */
3019     if (anonymous && use_accessfile) {	/* see above.  _H */
3020 	(void) acl_autogroup(pw);
3021 	guest = acl_guestgroup(pw);	/* the new group may be a guest */
3022 	if (guest && acl_realgroup(pw))
3023 	    guest = 0;
3024 	anonymous = !guest;
3025     }
3026 /* END AUTHENTICATION */
3027 
3028 /* SET GROUP ID STARTS HERE */
3029 #ifndef AIX
3030     (void) setegid((gid_t) pw->pw_gid);
3031 #else
3032     (void) setgid((gid_t) pw->pw_gid);
3033 #endif
3034     (void) initgroups(pw->pw_name, pw->pw_gid);
3035 #ifdef DEBUG
3036     syslog(LOG_DEBUG, "initgroups has been called");
3037 #endif
3038 /* WTMP PROCESSING STARTS HERE */
3039     if (wtmp_logging) {
3040 	/* open wtmp before chroot */
3041 #if ((defined(BSD) && (BSD >= 199103)) || defined(sun))
3042 	(void) sprintf(ttyline, "ftp%ld", (long) getpid());
3043 #else
3044 	(void) sprintf(ttyline, "ftpd%d", getpid());
3045 #endif
3046 #ifdef DEBUG
3047 	syslog(LOG_DEBUG, "about to call wtmp");
3048 #endif
3049 	wu_logwtmp(ttyline, pw->pw_name, remotehost, 1);
3050     }
3051     logged_in = 1;
3052 
3053     expand_id();
3054 
3055 #ifdef QUOTA
3056     memset(&quota, 0, sizeof(quota));
3057     get_quota(pw->pw_dir, pw->pw_uid);
3058 #endif
3059 
3060     restricted_user = 0;
3061     if (!anonymous)
3062 	if ((restricteduid(pw->pw_uid) && !unrestricteduid(pw->pw_uid))
3063 	    || (restrictedgid(pw->pw_gid) && !unrestrictedgid(pw->pw_gid)))
3064 	    restricted_user = 1;
3065     if (anonymous || guest) {
3066 	char *sp;
3067 	/* We MUST do a chdir() after the chroot. Otherwise the old current
3068 	 * directory will be accessible as "." outside the new root! */
3069 #ifdef ALTERNATE_CD
3070 	home = defhome;
3071 #endif
3072 #ifdef VIRTUAL
3073 	if (virtual_mode && !guest) {
3074 #ifdef CLOSED_VIRTUAL_SERVER
3075 	    if (DenyVirtualAnonymous()) {
3076 #ifdef VERBOSE_ERROR_LOGING
3077 		syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host anonymous access denied) for %s",
3078 		       remoteident);
3079 #endif
3080 		reply(530, "Login incorrect.");
3081 		if (++login_attempts >= lgi_failure_threshold) {
3082 		    syslog(LOG_NOTICE, "repeated login failures from %s", remoteident);
3083 		    dologout(0);
3084 		}
3085 		goto bad;
3086 	    }
3087 #endif
3088 	    /* Anonymous user in virtual_mode */
3089 	    if (pw->pw_dir)
3090 		free(pw->pw_dir);
3091 	    pw->pw_dir = sgetsave(virtual_root);
3092 	}
3093 	else
3094 #endif
3095 
3096 	    /*
3097 	       *  New chroot logic.
3098 	       *
3099 	       *  If VIRTUAL is supported, the chroot for anonymous users on the
3100 	       *  virtual host has already been determined.  Otherwise the logic
3101 	       *  below applies:
3102 	       *
3103 	       *  If this is an anonymous user, the chroot directory is determined
3104 	       *  by the "anonymous-root" clause and the home directory is taken
3105 	       *  from the etc/passwd file found after chroot'ing.
3106 	       *
3107 	       *  If this a guest user, the chroot directory is determined by the
3108 	       *  "guest-root" clause and the home directory is taken from the
3109 	       *  etc/passwd file found after chroot'ing.
3110 	       *
3111 	       *  The effect of this logic is that the entire chroot environment
3112 	       *  is under the control of the ftpaccess file and the supporting
3113 	       *  files in the ftp environment.  The system-wide passwd file is
3114 	       *  used only to authenticate the user.
3115 	     */
3116 
3117 	{
3118 	    struct aclmember *entry = NULL;
3119 	    char *root_path = NULL;
3120 
3121 	    if (anonymous) {
3122 		char class[BUFSIZ];
3123 
3124 		(void) acl_getclass(class);
3125 		while (getaclentry("anonymous-root", &entry) && ARG0) {
3126 		    if (!ARG1) {
3127 			if (!root_path)
3128 			    root_path = ARG0;
3129 		    }
3130 		    else {
3131 			int which;
3132 
3133 			for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
3134 			    if (!strcmp(ARG[which], "*")) {
3135 				if (!root_path)
3136 				    root_path = ARG0;
3137 			    }
3138 			    else {
3139 				if (!strcasecmp(ARG[which], class))
3140 				    root_path = ARG0;
3141 			    }
3142 			}
3143 		    }
3144 		}
3145 	    }
3146 	    else {		/* (guest) */
3147 		while (getaclentry("guest-root", &entry) && ARG0) {
3148 		    if (!ARG1) {
3149 			if (!root_path)
3150 			    root_path = ARG0;
3151 		    }
3152 		    else {
3153 			int which;
3154 			char *ptr;
3155 
3156 			for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
3157 			    if (!strcmp(ARG[which], "*")) {
3158 				if (!root_path)
3159 				    root_path = ARG0;
3160 			    }
3161 			    else {
3162 				if (ARG[which][0] == '%') {
3163 				    if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) {
3164 					if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) {
3165 					    if (pw->pw_uid == strtoul(ARG[which] + 1, NULL, 0))
3166 						root_path = ARG0;
3167 					}
3168 					else {
3169 					    *ptr++ = '\0';
3170 					    if ((ARG[which][1] == '\0')
3171 						|| (pw->pw_uid >= strtoul(ARG[which] + 1, NULL, 0)))
3172 						root_path = ARG0;
3173 					    *--ptr = '+';
3174 					}
3175 				    }
3176 				    else {
3177 					*ptr++ = '\0';
3178 					if (((ARG[which][1] == '\0')
3179 					     || (pw->pw_uid >= strtoul(ARG[which] + 1, NULL, 0)))
3180 					    && ((*ptr == '\0')
3181 						|| (pw->pw_uid <= strtoul(ptr, NULL, 0))))
3182 					    root_path = ARG0;
3183 					*--ptr = '-';
3184 				    }
3185 				}
3186 				else {
3187 #ifdef OTHER_PASSWD
3188 				    struct passwd *guest_pw = bero_getpwnam(ARG[which], _path_passwd);
3189 #else
3190 				    struct passwd *guest_pw = getpwnam(ARG[which]);
3191 #endif
3192 				    if (guest_pw && (pw->pw_uid == guest_pw->pw_uid))
3193 					root_path = ARG0;
3194 				}
3195 			    }
3196 			}
3197 		    }
3198 		}
3199 	    }
3200 
3201 	    if (root_path) {
3202 		struct passwd *chroot_pw = NULL;
3203 
3204 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
3205 		if (virtual_mode && strcmp(root_path, virtual_root) && !(AllowVirtualUser(pw->pw_name) && !DenyVirtualUser(pw->pw_name))) {
3206 #ifdef VERBOSE_ERROR_LOGING
3207 		    syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host access denied) for %s, %s",
3208 			   remoteident, pw->pw_name);
3209 #endif
3210 		    reply(530, "Login incorrect.");
3211 		    if (++login_attempts >= lgi_failure_threshold) {
3212 			syslog(LOG_NOTICE, "repeated login failures from %s", remoteident);
3213 			dologout(0);
3214 		    }
3215 		    goto bad;
3216 		}
3217 #endif
3218 		(void) strncpy(chroot_path, root_path, sizeof(chroot_path));
3219 		chroot_path[sizeof(chroot_path) - 1] = '\0';
3220 		if (pw->pw_dir)
3221 		    free(pw->pw_dir);
3222 		pw->pw_dir = sgetsave(chroot_path);
3223 #if defined(SOLARIS_2)
3224 		cleanup_nscd();
3225 #endif
3226 		if (chroot(root_path) < 0 || chdir("/") < 0) {
3227 #ifdef VERBOSE_ERROR_LOGING
3228 		    syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set guest privileges) for %s, %s",
3229 			   remoteident, pw->pw_name);
3230 #endif
3231 		    reply(530, "Can't set guest privileges.");
3232 		    goto bad;
3233 		}
3234 #ifdef OTHER_PASSWD
3235 		if ((chroot_pw = bero_getpwuid(pw->pw_uid, _path_passwd)) != NULL)
3236 #else
3237 		if ((chroot_pw = getpwuid(pw->pw_uid)) != NULL)
3238 #endif
3239 		    if (chdir(chroot_pw->pw_dir) >= 0)
3240 			home = sgetsave(chroot_pw->pw_dir);
3241 		goto slimy_hack;	/* onea these days I'll make this structured code, honest ... */
3242 	    }
3243 	}
3244 
3245 	/* determine root and home directory */
3246 
3247 	if ((sp = strstr(pw->pw_dir, "/./")) == NULL) {
3248 	    (void) strncpy(chroot_path, pw->pw_dir, sizeof(chroot_path));
3249 	    chroot_path[sizeof(chroot_path) - 1] = '\0';
3250 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
3251 	    if (virtual_mode && strcmp(chroot_path, virtual_root) && !(AllowVirtualUser(pw->pw_name) && !DenyVirtualUser(pw->pw_name))) {
3252 #ifdef VERBOSE_ERROR_LOGING
3253 		syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host access denied) for %s, %s",
3254 		       remoteident, pw->pw_name);
3255 #endif
3256 		reply(530, "Login incorrect.");
3257 		if (++login_attempts >= lgi_failure_threshold) {
3258 		    syslog(LOG_NOTICE, "repeated login failures from %s", remoteident);
3259 		    dologout(0);
3260 		}
3261 		goto bad;
3262 	    }
3263 #endif
3264 #if defined(SOLARIS_2)
3265 	    cleanup_nscd();
3266 #endif
3267 	    if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
3268 #ifdef VERBOSE_ERROR_LOGING
3269 		syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set guest privileges) for %s, %s",
3270 		       remoteident, pw->pw_name);
3271 #endif
3272 		reply(530, "Can't set guest privileges.");
3273 		goto bad;
3274 	    }
3275 	}
3276 	else {
3277 	    *sp++ = '\0';
3278 	    (void) strncpy(chroot_path, pw->pw_dir, sizeof(chroot_path));
3279 	    chroot_path[sizeof(chroot_path) - 1] = '\0';
3280 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
3281 	    if (virtual_mode && strcmp(chroot_path, virtual_root) && !(AllowVirtualUser(pw->pw_name) && !DenyVirtualUser(pw->pw_name))) {
3282 #ifdef VERBOSE_ERROR_LOGING
3283 		syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host access denied) for %s, %s",
3284 		       remoteident, pw->pw_name);
3285 #endif
3286 		reply(530, "Login incorrect.");
3287 		if (++login_attempts >= lgi_failure_threshold) {
3288 		    syslog(LOG_NOTICE, "repeated login failures from %s", remoteident);
3289 		    dologout(0);
3290 		}
3291 		goto bad;
3292 	    }
3293 #endif
3294 #if defined(SOLARIS_2)
3295 	    cleanup_nscd();
3296 #endif
3297 	    if (chroot(pw->pw_dir) < 0 || chdir(++sp) < 0) {
3298 #ifdef VERBOSE_ERROR_LOGING
3299 		syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set guest privileges) for %s, %s",
3300 		       remoteident, pw->pw_name);
3301 #endif
3302 		reply(550, "Can't set guest privileges.");
3303 		goto bad;
3304 	    }
3305 #ifdef ALTERNATE_CD
3306 	    home = sp;
3307 #endif
3308 	}
3309       slimy_hack:
3310 	/* shut up you stupid compiler! */  {
3311 	    int i = 0;
3312 	    i++;
3313 	}
3314     }
3315 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
3316     else if (virtual_mode && !(AllowVirtualUser(pw->pw_name) && !DenyVirtualUser(pw->pw_name))) {
3317 #ifdef VERBOSE_ERROR_LOGING
3318 	syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host access denied) for %s, %s",
3319 	       remoteident, pw->pw_name);
3320 #endif
3321 	reply(530, "Login incorrect.");
3322 	if (++login_attempts >= lgi_failure_threshold) {
3323 	    syslog(LOG_NOTICE, "repeated login failures from %s", remoteident);
3324 	    dologout(0);
3325 	}
3326 	goto bad;
3327     }
3328 #endif
3329 #ifdef AIX
3330     {
3331 	/* AIX 3 lossage.  Don't ask.  It's undocumented.  */
3332 	priv_t priv;
3333 
3334 	priv.pv_priv[0] = 0;
3335 	priv.pv_priv[1] = 0;
3336 /*       setgroups(NULL, NULL); */
3337 	if (setpriv(PRIV_SET | PRIV_INHERITED | PRIV_EFFECTIVE | PRIV_BEQUEATH,
3338 		    &priv, sizeof(priv_t)) < 0 ||
3339 	    setuidx(ID_REAL | ID_EFFECTIVE, (uid_t) pw->pw_uid) < 0 ||
3340 	    seteuid((uid_t) pw->pw_uid) < 0) {
3341 #ifdef VERBOSE_ERROR_LOGING
3342 	    syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set uid) for %s, %s",
3343 		   remoteident, pw->pw_name);
3344 #endif
3345 	    reply(530, "Can't set uid (AIX3).");
3346 	    goto bad;
3347 	}
3348     }
3349 #ifdef UID_DEBUG
3350     lreply(success_code, "ruid=%d, euid=%d, suid=%d, luid=%d", getuidx(ID_REAL),
3351 	   getuidx(ID_EFFECTIVE), getuidx(ID_SAVED), getuidx(ID_LOGIN));
3352     lreply(success_code, "rgid=%d, egid=%d, sgid=%d, lgid=%d", getgidx(ID_REAL),
3353 	   getgidx(ID_EFFECTIVE), getgidx(ID_SAVED), getgidx(ID_LOGIN));
3354 #endif
3355 #else /* AIX */
3356 #ifdef HAVE_SETREUID
3357     if (setreuid(-1, (uid_t) pw->pw_uid) < 0) {
3358 #else
3359     if (seteuid((uid_t) pw->pw_uid) < 0) {
3360 #endif
3361 #ifdef VERBOSE_ERROR_LOGING
3362 	syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set uid) for %s, %s",
3363 	       remoteident, pw->pw_name);
3364 #endif
3365 	reply(530, "Can't set uid.");
3366 	goto bad;
3367     }
3368 #endif /* AIX */
3369     if (!anonymous && !guest) {
3370 	if (chdir(pw->pw_dir) < 0) {
3371 #ifdef PARANOID
3372 #ifdef VERBOSE_ERROR_LOGING
3373 	    syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot chdir) for %s, %s",
3374 		   remoteident, pw->pw_name);
3375 #endif
3376 	    reply(530, "User %s: can't change directory to %s.",
3377 		  pw->pw_name, pw->pw_dir);
3378 	    goto bad;
3379 #else /* PARANOID */
3380 	    if (restricted_user || chdir("/") < 0) {
3381 #ifdef VERBOSE_ERROR_LOGING
3382 		syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot chdir) for %s, %s",
3383 		       remoteident, pw->pw_name);
3384 #endif
3385 		reply(530, "User %s: can't change directory to %s.",
3386 		      pw->pw_name, pw->pw_dir);
3387 		goto bad;
3388 	    }
3389 	    else {
3390 		lreply(success_code, "No directory! Logging in with home=/");
3391 #ifdef ALTERNATE_CD
3392 		home = defhome;
3393 #endif
3394 	    }
3395 #endif /* PARANOID */
3396 	}
3397     }
3398 
3399     if (passwarn) {
3400 	lreply(success_code, "The response '%s' is not valid", passwd);
3401 	lreply(success_code,
3402 	       "Next time please use your e-mail address as your password");
3403 	lreply(success_code, "   for example: %s@%s%s",
3404 	       authenticated ? authuser : "joe", remotehost,
3405 	       strchr(remotehost, '.') ? "" : ".network");
3406     }
3407 
3408     login_attempts = 0;		/* this time successful */
3409 
3410     /* following two lines were inside the next scope... */
3411 
3412     show_message(success_code, LOG_IN);
3413     show_message(success_code, C_WD);
3414     show_readme(success_code, LOG_IN);
3415     show_readme(success_code, C_WD);
3416 
3417 #ifdef ULTRIX_AUTH
3418     if (!anonymous && numfails > 0) {
3419 	lreply(success_code,
3420 	   "There have been %d unsuccessful login attempts on your account",
3421 	       numfails);
3422     }
3423 #endif /* ULTRIX_AUTH */
3424 
3425     (void) is_shutdown(0, 0);	/* display any shutdown messages now */
3426 
3427     if (anonymous) {
3428 
3429 	reply(success_code, "Guest login ok, access restrictions apply.");
3430 	sprintf(proctitle, "%s: anonymous/%.*s", remotehost,
3431 		(int) (sizeof(proctitle) - sizeof(remotehost) -
3432 		       sizeof(": anonymous/")), passwd);
3433 	setproctitle("%s", proctitle);
3434 	if (logging)
3435 	    syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
3436 		   remoteident, passwd);
3437     }
3438     else {
3439 	reply(success_code, "User %s logged in.%s", pw->pw_name, guest ?
3440 	      "  Access restrictions apply." : "");
3441 	sprintf(proctitle, "%s: %s", remotehost, pw->pw_name);
3442 	setproctitle("%s", proctitle);
3443 	if (logging)
3444 	    syslog(LOG_INFO, "FTP LOGIN FROM %s, %s", remoteident, pw->pw_name);
3445 /* H* mod: if non-anonymous user, copy it to "authuser" so everyone can
3446    see it, since whoever he was @foreign-host is now largely irrelevant.
3447    NMM mod: no, it isn't!  Think about accounting for the transfers from or
3448    to a shared account. */
3449 	/* strcpy (authuser, pw->pw_name); */
3450     }				/* anonymous */
3451 #ifdef ALTERNATE_CD
3452     if (!home)
3453 #endif
3454 	home = pw->pw_dir;	/* home dir for globbing */
3455     (void) umask(defumask);
3456     time(&login_time);
3457     {
3458 	struct aclmember *entry;
3459 	entry = NULL;
3460 	while (getaclentry("limit-time", &entry) && ARG0 && ARG1)
3461 	    if ((anonymous && strcasecmp(ARG0, "anonymous") == 0)
3462 		|| (guest && strcasecmp(ARG0, "guest") == 0)
3463 		|| ((guest | anonymous) && strcmp(ARG0, "*") == 0))
3464 		limit_time = strtoul(ARG1, NULL, 0);
3465     }
3466 
3467     /* Need to reset here as user type/class now known */
3468 #ifdef INET6
3469     /* IP_TOS is an IPv4 socket option */
3470     if (SOCK_FAMILY(ctrl_addr) == AF_INET)
3471 #endif
3472     if ((cos = IPClassOfService("control")) >= 0) {
3473 	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *) &cos, sizeof(int)) < 0)
3474 	    syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
3475     }
3476 
3477 #ifdef SOLARIS_BSM_AUDIT
3478     audit_ftpd_success(the_user);
3479 #endif
3480     init_privs(pw->pw_name);
3481     return;
3482   bad:
3483     /* Forget all about it... */
3484     if (xferlog)
3485 	close(xferlog);
3486     xferlog = 0;
3487     acl_remove();
3488 #ifdef SOLARIS_BSM_AUDIT
3489     audit_ftpd_failure(the_user);
3490 #endif
3491     end_login();
3492     return;
3493 }
3494 
3495 int restricteduid(uid_t uid)
3496 {
3497     return uid_match("restricted-uid", uid);
3498 }
3499 
3500 int unrestricteduid(uid_t uid)
3501 {
3502     return uid_match("unrestricted-uid", uid);
3503 }
3504 
3505 int restrictedgid(gid_t gid)
3506 {
3507     return gid_match("restricted-gid", gid, NULL);
3508 }
3509 
3510 int unrestrictedgid(gid_t gid)
3511 {
3512     return gid_match("unrestricted-gid", gid, NULL);
3513 }
3514 
3515 char *opt_string(int options)
3516 {
3517     static char buf[100];
3518     char *ptr = buf;
3519 
3520     if ((options & O_COMPRESS) != 0)	/* debian fixes: NULL -> 0 */
3521 	*ptr++ = 'C';
3522     if ((options & O_TAR) != 0)
3523 	*ptr++ = 'T';
3524     if ((options & O_UNCOMPRESS) != 0)
3525 	*ptr++ = 'U';
3526     if (options == 0)
3527 	*ptr++ = '_';
3528     *ptr++ = '\0';
3529     return (buf);
3530 }
3531 
3532 #ifdef INTERNAL_LS
3533 char *rpad(char *s, unsigned int len)
3534 {
3535     char *a;
3536     a = (char *) malloc(len + 1);
3537     memset(a, ' ', len);
3538     a[len] = 0;
3539     if (strlen(s) <= len)
3540 	memcpy(a, s, strlen(s));
3541     else
3542 	strncpy(a, s, len);
3543     return a;
3544 }
3545 
3546 char *ls_file(const char *file, int nameonly, char remove_path, char classify)
3547 {
3548     static const char month[12][4] =
3549     {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
3550      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
3551 
3552     char *permissions;
3553     struct stat s;
3554     struct tm *t;
3555     char *ls_entry;
3556     char *owner, *ownerg;
3557     char *rpowner, *rpownerg;
3558     char *link;
3559 #ifndef LS_NUMERIC_UIDS
3560     struct passwd *pw;
3561     struct group *gr;
3562 #endif
3563     link = NULL;
3564     owner = NULL;
3565     ownerg = NULL;
3566     if (lstat(file, &s) != 0)	/* File doesn't exist, or is not readable by user */
3567 	return NULL;
3568     ls_entry = (char *) malloc(312);
3569     memset(ls_entry, 0, 312);
3570     permissions = strdup("----------");
3571     if (S_ISLNK(s.st_mode)) {
3572 	permissions[0] = 'l';
3573 	if (classify)
3574 	    classify = '@';
3575     }
3576     else if (S_ISDIR(s.st_mode)) {
3577 	permissions[0] = 'd';
3578 	if (classify)
3579 	    classify = '/';
3580     }
3581     else if (S_ISBLK(s.st_mode))
3582 	permissions[0] = 'b';
3583     else if (S_ISCHR(s.st_mode))
3584 	permissions[0] = 'c';
3585     else if (S_ISFIFO(s.st_mode)) {
3586 	permissions[0] = 'p';
3587 	if (classify == 1)
3588 	    classify = '=';
3589     }
3590 #ifdef S_ISSOCK
3591     else if (S_ISSOCK(s.st_mode))
3592 	permissions[0] = 's';
3593 #endif
3594     if ((s.st_mode & S_IRUSR) == S_IRUSR)
3595 	permissions[1] = 'r';
3596     if ((s.st_mode & S_IWUSR) == S_IWUSR)
3597 	permissions[2] = 'w';
3598     if ((s.st_mode & S_IXUSR) == S_IXUSR) {
3599 	permissions[3] = 'x';
3600 	if (classify == 1)
3601 	    classify = '*';
3602 #ifndef HIDE_SETUID
3603 	if ((s.st_mode & S_ISUID) == S_ISUID)
3604 	    permissions[3] = 's';
3605 #endif
3606     }
3607 #ifndef HIDE_SETUID
3608     else if ((s.st_mode & S_ISUID) == S_ISUID)
3609 	permissions[3] = 'S';
3610 #endif
3611     if ((s.st_mode & S_IRGRP) == S_IRGRP)
3612 	permissions[4] = 'r';
3613     if ((s.st_mode & S_IWGRP) == S_IWGRP)
3614 	permissions[5] = 'w';
3615     if ((s.st_mode & S_IXGRP) == S_IXGRP) {
3616 	permissions[6] = 'x';
3617 	if (classify == 1)
3618 	    classify = '*';
3619 #ifndef HIDE_SETUID
3620 	if ((s.st_mode & S_ISGID) == S_ISGID)
3621 	    permissions[6] = 's';
3622 #endif
3623     }
3624 #ifndef HIDE_SETUID
3625     else if ((s.st_mode & S_ISGID) == S_ISGID)
3626 	permissions[6] = 'S';
3627 #endif
3628     if ((s.st_mode & S_IROTH) == S_IROTH)
3629 	permissions[7] = 'r';
3630     if ((s.st_mode & S_IWOTH) == S_IWOTH)
3631 	permissions[8] = 'w';
3632     if ((s.st_mode & S_IXOTH) == S_IXOTH) {
3633 	permissions[9] = 'x';
3634 	if (classify == 1)
3635 	    classify = '*';
3636 #ifndef HIDE_SETUID
3637 	if ((s.st_mode & S_ISVTX) == S_ISVTX)
3638 	    permissions[9] = 't';
3639 #endif
3640     }
3641 #ifndef HIDE_SETUID
3642     else if ((s.st_mode & S_ISVTX) == S_ISVTX)
3643 	permissions[9] = 'T';
3644 #endif
3645     t = localtime(&s.st_mtime);
3646 #ifndef LS_NUMERIC_UIDS
3647 #ifdef OTHER_PASSWD
3648     pw = bero_getpwuid(s.st_uid, _path_passwd);
3649 #else
3650     pw = getpwuid(s.st_uid);
3651 #endif
3652     if (pw != NULL)
3653 	owner = strdup(pw->pw_name);
3654     gr = getgrgid(s.st_gid);
3655     if (gr != NULL)
3656 	ownerg = strdup(gr->gr_name);
3657 #endif
3658     if (owner == NULL) {	/* Can't figure out username (or don't want to) */
3659 	if (s.st_uid == 0)
3660 	    owner = strdup("root");
3661 	else {
3662 	    owner = (char *) malloc(9);
3663 	    memset(owner, 0, 9);
3664 #ifdef SOLARIS_2
3665 	    snprintf(owner, 8, "%lu", s.st_uid);
3666 #else
3667 	    snprintf(owner, 8, "%u", s.st_uid);
3668 #endif
3669 	}
3670     }
3671     if (ownerg == NULL) {	/* Can't figure out groupname (or don't want to) */
3672 	if (s.st_gid == 0)
3673 	    ownerg = strdup("root");
3674 	else {
3675 	    ownerg = (char *) malloc(9);
3676 	    memset(ownerg, 0, 9);
3677 #ifdef SOLARIS_2
3678 	    snprintf(ownerg, 8, "%lu", s.st_gid);
3679 #else
3680 	    snprintf(ownerg, 8, "%u", s.st_gid);
3681 #endif
3682 	}
3683     }
3684 
3685 #ifdef HAVE_LSTAT
3686     if (S_ISLNK(s.st_mode)) {
3687 	link = (char *) malloc(MAXPATHLEN);
3688 	memset(link, 0, MAXPATHLEN);
3689 	if (readlink(file, link, MAXPATHLEN) == -1) {
3690 	    free(link);
3691 	    link = NULL;
3692 	}
3693     }
3694 #endif
3695 
3696     if (remove_path != 0 && strchr(file, '/'))
3697 	file = strrchr(file, '/') + 1;
3698 
3699     rpowner = rpad(owner, 8);
3700     rpownerg = rpad(ownerg, 8);
3701 
3702 #ifdef SOLARIS_2
3703 #define N_FORMAT "lu"
3704 #else
3705 #if defined(__FreeBSD__) || defined(__bsdi__)
3706 #define N_FORMAT "u"
3707 #else
3708 #define N_FORMAT "u"
3709 #endif
3710 #endif
3711 
3712     if (nameonly) {
3713 	sprintf(ls_entry, "%s", file);
3714 	if (link != NULL)
3715 	    free(link);
3716     }
3717     else {
3718 	if ((time(NULL) - s.st_mtime) > 6307200) {	/* File is older than 6 months */
3719 	    if (link == NULL)
3720 		snprintf(ls_entry, 311, "%s %3" N_FORMAT " %s %s %8" L_FORMAT " %s %2u %5u %s", permissions, s.st_nlink, rpowner, rpownerg, s.st_size, month[t->tm_mon], t->tm_mday, 1900 + t->tm_year, file);
3721 	    else {
3722 		snprintf(ls_entry, 311, "%s %3" N_FORMAT " %s %s %8" L_FORMAT " %s %2u %5u %s -> %s", permissions, s.st_nlink, rpowner, rpownerg, s.st_size, month[t->tm_mon], t->tm_mday, 1900 + t->tm_year, file, link);
3723 		free(link);
3724 	    }
3725 	}
3726 	else if (link == NULL)
3727 	    snprintf(ls_entry, 311, "%s %3" N_FORMAT " %s %s %8" L_FORMAT " %s %2u %02u:%02u %s", permissions, s.st_nlink, rpowner, rpownerg, s.st_size, month[t->tm_mon], t->tm_mday, t->tm_hour, t->tm_min, file);
3728 	else {
3729 	    snprintf(ls_entry, 311, "%s %3" N_FORMAT " %s %s %8" L_FORMAT " %s %2u %02u:%02u %s -> %s", permissions, s.st_nlink, rpowner, rpownerg, s.st_size, month[t->tm_mon], t->tm_mday, t->tm_hour, t->tm_min, file, link);
3730 	    free(link);
3731 	}
3732     }
3733     free(rpowner);
3734     free(rpownerg);
3735     free(owner);
3736     free(ownerg);
3737     if (classify > 1)
3738 	sprintf(ls_entry + strlen(ls_entry), "%c", classify);
3739     strcat(ls_entry, "\r\n");
3740     free(permissions);
3741     return ls_entry;
3742 }
3743 
3744 void ls_dir(char *d, char ls_a, char ls_F, char ls_l, char ls_R, char omit_total, FILE *out)
3745 {
3746     int total;
3747     char *realdir;		/* fixed up value to pass to glob() */
3748     char **subdirs;		/* Subdirs to be scanned for ls -R  */
3749     int numSubdirs = 0;
3750     glob_t g;
3751     char isDir;			/* 0: d is a file; 1: d is some files; 2: d is dir */
3752     struct stat s;
3753     char *dirlist;
3754     unsigned long dl_size, dl_used;
3755     char *c;
3756     char *lsentry;
3757     int i;
3758 #ifndef GLOB_PERIOD
3759     char *dperiod;
3760 #endif
3761 
3762     isDir = 0;
3763     realdir = (char *) malloc(strlen(d) + 3);
3764     memset(realdir, 0, strlen(d) + 3);
3765     strcpy(realdir, d);
3766     if (strcmp(realdir, ".") == 0)
3767 	realdir[0] = '*';
3768     if (strcmp(realdir + strlen(realdir) - 2, "/.") == 0)
3769 	realdir[strlen(realdir) - 1] = '*';
3770     if (realdir[strlen(realdir) - 1] == '/')
3771 	strcat(realdir, "*");
3772     if (strchr(realdir, '*') || strchr(realdir, '?'))
3773 	isDir = 1;
3774     if (strcmp(realdir, "*") == 0 || strcmp(realdir + strlen(realdir) - 2, "/*") == 0)
3775 	isDir = 2;
3776     else {
3777 	if (lstat(realdir, &s) == 0) {
3778 	    if (S_ISDIR(s.st_mode)) {
3779 		strcat(realdir, "/*");
3780 		isDir = 2;
3781 	    }
3782 	}
3783     }
3784 
3785     if (isDir == 0) {
3786 	if (ls_l) {
3787 	    lsentry = ls_file(realdir, 0, 0, ls_F);
3788 	    if (lsentry != NULL) {
3789 		if (draconian_FILE != NULL) {
3790 		    (void) signal(SIGALRM, draconian_alarm_signal);
3791 		    alarm(timeout_data);
3792 #if defined(USE_GSS)
3793 		    sec_fprintf(out, "%s", lsentry);
3794 #else
3795 		    fputs(lsentry, out);
3796 #endif /* defined(USE_GSS) */
3797 		    (void) signal(SIGALRM, SIG_DFL);
3798 		}
3799 		free(lsentry);
3800 	    }
3801 	}
3802 	else {
3803 	    if (draconian_FILE != NULL) {
3804 		(void) signal(SIGALRM, draconian_alarm_signal);
3805 		alarm(timeout_data);
3806 #if defined(USE_GSS)
3807 		sec_fprintf(out, "%s", realdir);
3808 #else
3809 		fputs(realdir, out);
3810 #endif /* defined(USE_GSS) */
3811 		(void) signal(SIGALRM, SIG_DFL);
3812 	    }
3813 	}
3814 	free(realdir);
3815     }
3816     else {
3817 	if (ls_R) {
3818 	    numSubdirs = 0;
3819 	    subdirs = (char **) malloc(200 * sizeof(char *));
3820 	    memset(subdirs, 0, 200 * sizeof(char *));
3821 	}
3822 
3823 	dl_size = 65536;
3824 	dirlist = (char *) malloc(65536);
3825 	memset(dirlist, 0, 65536);
3826 	dl_used = 0;
3827 
3828 	total = 0;
3829 	memset(&g, 0, sizeof(g));
3830 	if (ls_a) {
3831 #ifdef GLOB_PERIOD
3832 	    if (glob(realdir, GLOB_ERR | GLOB_PERIOD, NULL, &g) != 0)
3833 		g.gl_pathc = 0;
3834 #else
3835 	    dperiod = (char *) malloc(strlen(realdir) + 2);
3836 	    memset(dperiod, 0, strlen(realdir) + 2);
3837 	    strcpy(dperiod, ".");
3838 	    strcat(dperiod, realdir);
3839 	    if (glob(dperiod, GLOB_ERR, NULL, &g) != 0)
3840 		g.gl_pathc = 0;
3841 	    glob(realdir, GLOB_ERR | GLOB_APPEND, NULL, &g);
3842 	    free(dperiod);
3843 #endif
3844 	}
3845 	else if (glob(realdir, GLOB_ERR, NULL, &g) != 0)
3846 	    g.gl_pathc = 0;
3847 	free(realdir);
3848 	for (i = 0; i < g.gl_pathc; i++) {
3849 	    c = g.gl_pathv[i];
3850 	    if (lstat(c, &s) != -1) {
3851 		if (ls_l) {
3852 		    total += s.st_blocks;
3853 		    lsentry = ls_file(c, 0, 1, ls_F);
3854 		    if (lsentry != NULL) {
3855 			/* This can actually happen even though the lstat() worked -
3856 			   if someone deletes the file between the lstat() and ls_file()
3857 			   calls. Unlikely, but better safe than sorry... */
3858 			int flag = snprintf(dirlist + dl_used, dl_size - dl_used, "%s", lsentry);
3859 			dl_used += (flag == -1 ? dl_size - dl_used : flag);
3860 			free(lsentry);
3861 		    }
3862 		}
3863 		else {
3864 		    int flag;
3865 		    lsentry = ls_file(c, 1, 1, ls_F);
3866 		    if (lsentry != NULL) {
3867 		        flag = snprintf(dirlist + dl_used, dl_size - dl_used, "%s", lsentry);
3868 		        dl_used += (flag == -1 ? dl_size - dl_used : flag);
3869 			free(lsentry);
3870 		    }
3871 		}
3872 		if ((ls_R != 0) && (S_ISDIR(s.st_mode))
3873 		    && (strcmp(c, "..") != 0) && (strcmp(c, ".") != 0)
3874 		&& !(strlen(c) > 3 && strcmp(c + strlen(c) - 3, "/..") == 0)
3875 		    && !(strlen(c) > 2 && strcmp(c + strlen(c) - 2, "/.") == 0)) {
3876 		    subdirs[numSubdirs++] = strdup(c);
3877 		    if ((numSubdirs % 200) == 0)
3878 			subdirs = (char **) realloc(subdirs, (numSubdirs + 200) * sizeof(char *));
3879 		}
3880 	    }
3881 	    if (dl_used + 512 >= dl_size) {
3882 		dl_size += 65536;
3883 		dirlist = (char *) realloc(dirlist, dl_size);
3884 	    }
3885 	}
3886 	globfree(&g);
3887 	if (ls_l && isDir == 2 && omit_total == 0) {
3888 	    if (draconian_FILE != NULL) {
3889 		(void) signal(SIGALRM, draconian_alarm_signal);
3890 		alarm(timeout_data);
3891 #if defined(USE_GSS)
3892 		sec_fprintf(out, "total %u\r\n", total);
3893 #else
3894 		fprintf(out, "total %u\r\n", total);
3895 #endif /* defined(USE_GSS) */
3896 	    }
3897 	}
3898 	if (draconian_FILE != NULL) {
3899 	    (void) signal(SIGALRM, draconian_alarm_signal);
3900 	    alarm(timeout_data);
3901 #if defined(USE_GSS)
3902 	    sec_fprintf(out, "%s", dirlist);
3903 #else
3904 	    fputs(dirlist, out);
3905 #endif /* defined(USE_GSS) */
3906 	}
3907 	free(dirlist);
3908 	if (ls_R) {
3909 	    for (i = 0; i < numSubdirs; i++) {
3910 		if (draconian_FILE != NULL) {
3911 		    (void) signal(SIGALRM, draconian_alarm_signal);
3912 		    alarm(timeout_data);
3913 #if defined(USE_GSS)
3914 		    sec_fprintf(out, "\r\n%s:\r\n", subdirs[i]);
3915 #else
3916 		    fprintf(out, "\r\n%s:\r\n", subdirs[i]);
3917 #endif /* defined(USE_GSS) */
3918 		    ls_dir(subdirs[i], ls_a, ls_F, ls_l, ls_R, 0, out);
3919 		}
3920 		free(subdirs[i]);
3921 	    }
3922 	    free(subdirs);
3923 	}
3924     }
3925 }
3926 
3927 void ls(char *file, char nlst)
3928 {
3929     FILE *out;
3930     char free_file = 0;
3931     char ls_l = 0, ls_a = 0, ls_R = 0, ls_F = 0;
3932 
3933     if (nlst == 0)
3934 	ls_l = 1;		/* LIST defaults to ls -l */
3935     if (file == NULL) {
3936 	file = strdup(".");
3937 	free_file = 1;
3938     }
3939     if (strcmp(file, "*") == 0)
3940 	file[0] = '.';
3941 
3942     if (file[0] == '-') {	/* options... */
3943 	if (strchr(file, ' ') == 0) {
3944 	    if (strchr(file, 'l'))
3945 		ls_l = 1;
3946 	    if (strchr(file, 'a'))
3947 		ls_a = 1;
3948 	    if (strchr(file, 'R'))
3949 		ls_R = 1;
3950 	    if (strchr(file, 'F'))
3951 		ls_F = 1;
3952 	    file = strdup(".");
3953 	    free_file = 1;
3954 	}
3955 	else {
3956 	    if (strchr(file, 'l') != NULL && strchr(file, 'l') < strchr(file, ' '))
3957 		ls_l = 1;
3958 	    if (strchr(file, 'a') != NULL && strchr(file, 'a') < strchr(file, ' '))
3959 		ls_a = 1;
3960 	    if (strchr(file, 'R') != NULL && strchr(file, 'R') < strchr(file, ' '))
3961 		ls_R = 1;
3962 	    if (strchr(file, 'F') != NULL && strchr(file, 'F') < strchr(file, ' '))
3963 		ls_F = 1;
3964 	    file = strchr(file, ' ');
3965 	}
3966     }
3967     while (file[0] == ' ')	/* ignore additional whitespaces between parameters */
3968 	file++;
3969     if (strlen(file) == 0) {
3970 	file = strdup(".");
3971 	free_file = 1;
3972     }
3973 
3974     out = dataconn("directory listing", -1, "w");
3975     draconian_FILE = out;
3976 
3977     transflag++;
3978 
3979     fixpath(file);
3980     if (file[0] == '\0') {
3981 	if (free_file != 0)
3982 	    free(file);
3983 	file = strdup(".");
3984 	free_file = 1;
3985     }
3986 
3987     ls_dir(file, ls_a, ls_F, ls_l, ls_R, 0, out);
3988     data = -1;
3989     pdata = -1;
3990     if (draconian_FILE != NULL) {
3991 	(void) signal(SIGALRM, draconian_alarm_signal);
3992 	alarm(timeout_data);
3993 #if defined(USE_GSS)
3994 	if (sec_fflush(out) < 0) {
3995 	    draconian_FILE = NULL;
3996 	    alarm(0);
3997 	    transflag = 0;
3998 	    perror_reply(550, "Data connection");
3999 	    fclose(out);
4000 	    goto ls_done;
4001 	}
4002 #else
4003 	fflush(out);
4004 #endif /* defined(USE_GSS) */
4005     }
4006     if (draconian_FILE != NULL) {
4007 	(void) signal(SIGALRM, draconian_alarm_signal);
4008 	alarm(timeout_data);
4009 	socket_flush_wait(out);
4010     }
4011     if (draconian_FILE != NULL) {
4012 	(void) signal(SIGALRM, draconian_alarm_signal);
4013 	alarm(timeout_data);
4014 	fclose(out);
4015 	draconian_FILE = NULL;
4016     }
4017     alarm(0);
4018     transflag = 0;
4019     reply(226, "Transfer complete.");
4020   ls_done:
4021     if (free_file != 0)
4022 	free(file);
4023 }
4024 #endif /* INTERNAL_LS */
4025 
4026 void retrieve(char *cmd, char *name)
4027 {
4028     FILE *fin = NULL, *dout;
4029     struct stat st, junk;
4030     int (*closefunc) () = NULL;
4031     int options = 0;
4032     int ThisRetrieveIsData = retrieve_is_data;
4033     time_t start_time = time(NULL);
4034     char *logname;
4035     char namebuf[MAXPATHLEN];
4036     char fnbuf[MAXPATHLEN];
4037     static int TransferComplete;	/* static as retrieve can call itself */
4038     struct convert *cptr;
4039     char realname[MAXPATHLEN];
4040     int stat_ret = -1;
4041     size_t buffersize;
4042 
4043     TransferComplete = 0;
4044     wu_realpath(name, realname, chroot_path);
4045 
4046     if (cmd == NULL && (stat_ret = stat(name, &st)) == 0)
4047 	/* there isn't a command and the file exists */
4048 	if (use_accessfile && checknoretrieve(name)) {	/* see above.  _H */
4049 	    if (log_security)
4050 		if (anonymous)
4051 		    syslog(LOG_NOTICE, "anonymous(%s) of %s tried to download %s (noretrieve)",
4052 			   guestpw, remoteident, realname);
4053 		else
4054 		    syslog(LOG_NOTICE, "%s of %s tried to download %s (noretrieve)",
4055 			   pw->pw_name, remoteident, realname);
4056 	    return;
4057 	}
4058 
4059 #ifdef TRANSFER_COUNT
4060 #ifdef TRANSFER_LIMIT
4061     if (retrieve_is_data)
4062 	if (((file_limit_data_out > 0) && (file_count_out >= file_limit_data_out))
4063 	    || ((file_limit_data_total > 0) && (file_count_total >= file_limit_data_total))
4064 	    || ((data_limit_data_out > 0) && (data_count_out >= data_limit_data_out))
4065 	    || ((data_limit_data_total > 0) && (data_count_total >= data_limit_data_total))) {
4066 	    if (log_security)
4067 		if (anonymous)
4068 		    syslog(LOG_NOTICE, "anonymous(%s) of %s tried to retrieve %s (Transfer limits exceeded)",
4069 			   guestpw, remoteident, realname);
4070 		else
4071 		    syslog(LOG_NOTICE, "%s of %s tried to retrieve %s (Transfer limits exceeded)",
4072 			   pw->pw_name, remoteident, realname);
4073 	    reply(553, "Permission denied on server. (Transfer limits exceeded)");
4074 	    return;
4075 	}
4076     if (((file_limit_raw_out > 0) && (xfer_count_out >= file_limit_raw_out))
4077 	|| ((file_limit_raw_total > 0) && (xfer_count_total >= file_limit_raw_total))
4078 	|| ((data_limit_raw_out > 0) && (byte_count_out >= data_limit_raw_out))
4079 	|| ((data_limit_raw_total > 0) && (byte_count_total >= data_limit_raw_total))) {
4080 	if (log_security)
4081 	    if (anonymous)
4082 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to retrieve %s (Transfer limits exceeded)",
4083 		       guestpw, remoteident, realname);
4084 	    else
4085 		syslog(LOG_NOTICE, "%s of %s tried to retrieve %s (Transfer limits exceeded)",
4086 		       pw->pw_name, remoteident, realname);
4087 	reply(553, "Permission denied on server. (Transfer limits exceeded)");
4088 	return;
4089     }
4090 #ifdef RATIO
4091     if (retrieve_is_data && (upload_download_rate > 0) )
4092 	if( freefile = is_downloadfree(name) ) {
4093 	    syslog(LOG_INFO, "%s is download free.", name );
4094 	}
4095 	else {
4096 	    if ((cmd == NULL) && ((data_count_in * upload_download_rate) < (data_count_out - total_free_dl))) {
4097 		reply(550, "%s: Upload/Download ratio exceeded", name);
4098 		goto done;
4099 	    }
4100 	}
4101 #endif /* RATIO */
4102 #endif
4103 #endif
4104 
4105     logname = (char *) NULL;
4106     if (cmd == NULL && stat_ret != 0) {		/* file does not exist */
4107 	char *ptr;
4108 
4109 	for (cptr = cvtptr; cptr != NULL; cptr = cptr->next) {
4110 	    if (!(mangleopts & O_COMPRESS) && (cptr->options & O_COMPRESS))
4111 		continue;
4112 	    if (!(mangleopts & O_UNCOMPRESS) && (cptr->options & O_UNCOMPRESS))
4113 		continue;
4114 	    if (!(mangleopts & O_TAR) && (cptr->options & O_TAR))
4115 		continue;
4116 
4117 	    if ((cptr->stripfix) && (cptr->postfix)) {
4118 		int pfxlen = strlen(cptr->postfix);
4119 		int sfxlen = strlen(cptr->stripfix);
4120 		int namelen = strlen(name);
4121 
4122 		if (namelen <= pfxlen)
4123 		    continue;
4124 		if (((namelen - pfxlen + sfxlen) >= sizeof(fnbuf)) ||
4125 		    (namelen >= sizeof(fnbuf)))
4126 		    continue;
4127 
4128 		(void) strcpy(fnbuf, name);
4129 		if (strcmp(fnbuf + namelen - pfxlen, cptr->postfix))
4130 		    continue;
4131 		*(fnbuf + namelen - pfxlen) = '\0';
4132 		(void) strcat(fnbuf, cptr->stripfix);
4133 		if (stat(fnbuf, &st) != 0)
4134 		    continue;
4135 	    }
4136 	    else if (cptr->postfix) {
4137 		int pfxlen = strlen(cptr->postfix);
4138 		int namelen = strlen(name);
4139 
4140 		if ((namelen <= pfxlen) || (namelen >= sizeof(fnbuf)))
4141 		    continue;
4142 		(void) strcpy(fnbuf, name);
4143 		if (strcmp(fnbuf + namelen - pfxlen, cptr->postfix))
4144 		    continue;
4145 		*(fnbuf + namelen - pfxlen) = (char) NULL;
4146 		if (stat(fnbuf, &st) != 0)
4147 		    continue;
4148 	    }
4149 	    else if (cptr->stripfix) {
4150 		if (strlen(name) + strlen(cptr->stripfix) >= sizeof(fnbuf))
4151 		    continue;
4152 		(void) strcpy(fnbuf, name);
4153 		(void) strcat(fnbuf, cptr->stripfix);
4154 		if (stat(fnbuf, &st) != 0)
4155 		    continue;
4156 	    }
4157 	    else {
4158 		continue;
4159 	    }
4160 
4161 	    if (S_ISDIR(st.st_mode)) {
4162 		if (!cptr->types || !(cptr->types & T_DIR)) {
4163 		    reply(550, "Cannot %s directories.", cptr->name);
4164 		    return;
4165 		}
4166 		if ((cptr->options & O_TAR)) {
4167 		    strcpy(namebuf, fnbuf);
4168 		    if (strlcat(namebuf, "/.notar", sizeof(namebuf)) >=
4169 			sizeof(namebuf))
4170 			continue;
4171 		    if (stat(namebuf, &junk) == 0) {
4172 			if (log_security)
4173 			    if (anonymous)
4174 				syslog(LOG_NOTICE, "anonymous(%s) of %s tried to tar %s (.notar)",
4175 				       guestpw, remoteident, realname);
4176 			    else
4177 				syslog(LOG_NOTICE, "%s of %s tried to tar %s (.notar)",
4178 				       pw->pw_name, remoteident, realname);
4179 			reply(550, "Sorry, you may not TAR that directory.");
4180 			return;
4181 		    }
4182 		}
4183 	    }
4184 /* XXX: checknoretrieve() test is weak in that if I can't get /etc/passwd
4185    but I can tar /etc or /, I still win.  Be careful out there... _H*
4186    but you could put .notar in / and /etc and stop that ! */
4187 	    if (use_accessfile && checknoretrieve(fnbuf)) {
4188 		if (log_security)
4189 		    if (anonymous)
4190 			syslog(LOG_NOTICE, "anonymous(%s) of %s tried to download %s (noretrieve)",
4191 			       guestpw, remoteident, realname);
4192 		    else
4193 			syslog(LOG_NOTICE, "%s of %s tried to download %s (noretrieve)",
4194 			       pw->pw_name, remoteident, realname);
4195 		return;
4196 	    }
4197 
4198 	    if (S_ISREG(st.st_mode) && (!cptr->types || (cptr->types & T_REG) == 0)) {
4199 		reply(550, "Cannot %s plain files.", cptr->name);
4200 		return;
4201 	    }
4202 	    if (S_ISREG(st.st_mode) != 0 && S_ISDIR(st.st_mode) != 0) {
4203 		reply(550, "Cannot %s special files.", cptr->name);
4204 		return;
4205 	    }
4206 	    if ((!cptr->types || !(cptr->types & T_ASCII)) && deny_badasciixfer(550, ""))
4207 		return;
4208 
4209 	    logname = &fnbuf[0];
4210 	    options |= cptr->options;
4211 
4212 	    strcpy(namebuf, cptr->external_cmd);
4213 	    if ((ptr = strchr(namebuf, ' ')) != NULL)
4214 		*ptr = '\0';
4215 	    if (stat(namebuf, &junk) != 0) {
4216 		syslog(LOG_ERR, "external command %s not found", namebuf);
4217 		reply(550,
4218 		"Local error: conversion program not found. Cannot %s file.",
4219 		      cptr->name);
4220 		return;
4221 	    }
4222 	    (void) retrieve(cptr->external_cmd, logname);
4223 
4224 	    goto logresults;	/* transfer of converted file completed */
4225 	}
4226     }
4227 
4228     if (cmd == NULL) {		/* no command */
4229 	fin = fopen(name, "r"), closefunc = fclose;
4230 	st.st_size = 0;
4231     }
4232     else {			/* run command */
4233 	static char line[BUFSIZ];
4234 
4235 	(void) snprintf(line, sizeof(line), cmd, name), name = line;
4236 	fin = ftpd_popen(line, "r", 1), closefunc = ftpd_pclose;
4237 	st.st_size = -1;
4238 #ifdef HAVE_ST_BLKSIZE
4239 	st.st_blksize = BUFSIZ;
4240 #endif
4241     }
4242     if (fin == NULL) {
4243 	if (errno != 0)
4244 	    perror_reply(550, name);
4245 	if ((errno == EACCES) || (errno == EPERM))
4246 	    if (log_security)
4247 		if (anonymous)
4248 		    syslog(LOG_NOTICE, "anonymous(%s) of %s tried to download %s (file permissions)",
4249 			   guestpw, remoteident, realname);
4250 		else
4251 		    syslog(LOG_NOTICE, "%s of %s tried to download %s (file permissions)",
4252 			   pw->pw_name, remoteident, realname);
4253 	return;
4254     }
4255     if (cmd == NULL &&
4256 	(fstat(fileno(fin), &st) < 0 || (st.st_mode & S_IFMT) != S_IFREG)) {
4257 	reply(550, "%s: not a plain file.", name);
4258 	goto done;
4259     }
4260     if (restart_point) {
4261 	if (type == TYPE_A) {
4262 	    register int c;
4263 	    off_t i;
4264 
4265 	    i = 0;
4266 	    while (i++ < restart_point) {
4267 		if ((c = getc(fin)) == EOF) {
4268 		    perror_reply(550, name);
4269 		    goto done;
4270 		}
4271 		if (c == '\n')
4272 		    i++;
4273 	    }
4274 	}
4275 	else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
4276 	    perror_reply(550, name);
4277 	    goto done;
4278 	}
4279     }
4280 
4281     dout = dataconn(name, st.st_size, "w");
4282     if (dout == NULL)
4283 	goto done;
4284 
4285     if (sendbufsz > 0) {
4286 	buffersize = sendbufsz;
4287     }
4288     else {
4289 #ifdef BUFFER_SIZE
4290 	buffersize = BUFFER_SIZE;
4291 #elif HAVE_ST_BLKSIZE
4292 	buffersize = st.st_blksize * 2;
4293 #else
4294 	buffersize = BUFSIZ * 16;
4295 #endif
4296     }
4297 
4298 #ifdef THROUGHPUT
4299     TransferComplete = send_data(name, fin, dout, buffersize);
4300 #else
4301     TransferComplete = send_data(fin, dout, buffersize);
4302 #endif
4303 #ifdef SIGPIPE
4304     (void) signal(SIGPIPE, SIG_IGN);
4305 #endif
4306     (void) fclose(dout);
4307 #ifdef SIGPIPE
4308     (void) signal(SIGPIPE, lostconn);
4309 #endif
4310 
4311   logresults:
4312     if (ThisRetrieveIsData)
4313 	fb_realpath((logname != NULL) ? logname : name, LastFileTransferred);
4314 
4315     if (log_outbound_xfers && (xferlog || syslogmsg) && (cmd == NULL)) {
4316 	char msg[MAXXFERSTRLEN];	/* see extensions.h */
4317 	int xfertime = time(NULL) - start_time;
4318 	size_t msglen;
4319 
4320 	if (!xfertime)
4321 	    xfertime++;
4322 
4323 	/* Gather transfer statistics */
4324 	xfervalues.filename = (logname != NULL) ? logname : name;
4325 	xfervalues.filesize = st.st_size;
4326 	xfervalues.transfer_bytes = byte_count;
4327 	xfervalues.transfer_direction = 'o';
4328 	xfervalues.transfer_type = (type == TYPE_A) ? 'a' : 'b';
4329 	xfervalues.transfer_time = xfertime;
4330 	xfervalues.restart_offset = restart_point;
4331 	strlcpy(xfervalues.special_action, opt_string(options), MAXSPACTCHARS);
4332 	xfervalues.access_mode = anonymous ? 'a' : (guest ? 'g' : 'r');
4333 	xfervalues.auth = authenticated;
4334 	xfervalues.completion = TransferComplete ? 'c' : 'i';
4335 
4336 	xferdone = 1;
4337 	msg_massage(xferlog_format, msg, sizeof(msg));
4338 	xferdone = 0;
4339 
4340 	/* Ensure msg always ends with '\n' */
4341 	msglen = strlen(msg);
4342 	if (msglen == sizeof(msg) - 1) {
4343 	    msg[sizeof(msg) - 2] = '\n';
4344 	    msg[sizeof(msg) - 1] = '\0';
4345 	}
4346 	else {
4347 	    msg[msglen] = '\n';
4348 	    msg[msglen + 1] = '\0';
4349 	}
4350 
4351 	if (syslogmsg != 1)
4352 	    write(xferlog, msg, strlen(msg));
4353 	if (syslogmsg != 0) {
4354 	    char *msgp = msg;
4355 	    /*
4356 	     * To preserve the behavior when the xferlog format was fixed, skip
4357 	     * over the time string if the message starts with the local time.
4358 	     */
4359 	    if (strncmp(xferlog_format, "%T ", 3) == 0)
4360 		msgp += 25;
4361 	    syslog(LOG_INFO, "xferlog (send): %s", msgp);
4362 	}
4363     }
4364     data = -1;
4365     pdata = -1;
4366   done:
4367     if (closefunc)
4368 	(*closefunc) (fin);
4369 }
4370 
4371 void store(char *name, char *mode, int unique)
4372 {
4373     FILE *fout, *din;
4374     struct stat st;
4375     int TransferIncomplete = 1;
4376     char *gunique(char *local);
4377     time_t start_time = time(NULL);
4378 
4379     struct aclmember *entry = NULL;
4380 
4381     int fdout;
4382     char realname[MAXPATHLEN];
4383 
4384 #ifdef OVERWRITE
4385     int overwrite = 1;
4386     int exists = 0;
4387 
4388 #endif /* OVERWRITE */
4389 
4390     int open_flags = 0;
4391 
4392 #ifdef UPLOAD
4393     mode_t oldmask;
4394     uid_t uid;
4395     gid_t gid;
4396     uid_t oldid;
4397     int f_mode = -1, match_value = -1;
4398     int valid = 0;
4399     int ret, serrno;
4400     open_flags = (O_RDWR | O_CREAT |
4401 		  ((mode != NULL && *mode == 'a') ? O_APPEND : O_TRUNC));
4402 #endif /* UPLOAD */
4403 
4404     wu_realpath(name, realname, chroot_path);
4405 
4406 #ifdef TRANSFER_COUNT
4407 #ifdef TRANSFER_LIMIT
4408     if (((file_limit_data_in > 0) && (file_count_in >= file_limit_data_in))
4409 	|| ((file_limit_data_total > 0) && (file_count_total >= file_limit_data_total))
4410       || ((data_limit_data_in > 0) && (data_count_in >= data_limit_data_in))
4411 	|| ((data_limit_data_total > 0) && (data_count_total >= data_limit_data_total))) {
4412 	if (log_security)
4413 	    if (anonymous)
4414 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to upload %s (Transfer limits exceeded)",
4415 		       guestpw, remoteident, realname);
4416 	    else
4417 		syslog(LOG_NOTICE, "%s of %s tried to upload %s (Transfer limits exceeded)",
4418 		       pw->pw_name, remoteident, realname);
4419 	reply(553, "Permission denied on server. (Transfer limits exceeded)");
4420 	return;
4421     }
4422     if (((file_limit_raw_in > 0) && (xfer_count_in >= file_limit_raw_in))
4423 	|| ((file_limit_raw_total > 0) && (xfer_count_total >= file_limit_raw_total))
4424 	|| ((data_limit_raw_in > 0) && (byte_count_in >= data_limit_raw_in))
4425 	|| ((data_limit_raw_total > 0) && (byte_count_total >= data_limit_raw_total))) {
4426 	if (log_security)
4427 	    if (anonymous)
4428 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to upload %s (Transfer limits exceeded)",
4429 		       guestpw, remoteident, realname);
4430 	    else
4431 		syslog(LOG_NOTICE, "%s of %s tried to upload %s (Transfer limits exceeded)",
4432 		       pw->pw_name, remoteident, realname);
4433 	reply(553, "Permission denied on server. (Transfer limits exceeded)");
4434 	return;
4435     }
4436 #endif
4437 #endif
4438 
4439     if (unique && stat(name, &st) == 0 &&
4440 	(name = gunique(name)) == NULL)
4441 	return;
4442 
4443     /*
4444      * check the filename, is it legal?
4445      */
4446     if ((fn_check(name)) <= 0) {
4447 	if (log_security)
4448 	    if (anonymous)
4449 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to upload \"%s\" (path-filter)",
4450 		       guestpw, remoteident, realname);
4451 	    else
4452 		syslog(LOG_NOTICE, "%s of %s tried to upload \"%s\" (path-filter)",
4453 		       pw->pw_name, remoteident, realname);
4454 	return;
4455     }
4456 
4457 #ifdef OVERWRITE
4458     /* if overwrite permission denied and file exists... then deny the user
4459      * permission to write the file. */
4460     while (getaclentry("overwrite", &entry) && ARG0 && ARG1 != NULL) {
4461 	if (type_match(ARG1))
4462 	    if (strcasecmp(ARG0, "yes") != 0) {
4463 		overwrite = 0;
4464 		open_flags |= O_EXCL;
4465 	    }
4466     }
4467 
4468 #ifdef PARANOID
4469     overwrite = 0;
4470 #endif
4471     if (!stat(name, &st))
4472 	exists = 1;
4473 
4474     if (!overwrite && exists) {
4475 	if (log_security)
4476 	    if (anonymous)
4477 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to overwrite %s",
4478 		       guestpw, remoteident, realname);
4479 	    else
4480 		syslog(LOG_NOTICE, "%s of %s tried to overwrite %s",
4481 		       pw->pw_name, remoteident, realname);
4482 	reply(553, "%s: Permission denied on server. (Overwrite)", name);
4483 	return;
4484     }
4485 #endif /* OVERWRITE */
4486 
4487 #ifdef UPLOAD
4488     if ((match_value = upl_check(name, &uid, &gid, &f_mode, &valid)) < 0) {
4489 	if (log_security)
4490 	    if (anonymous)
4491 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to upload %s (upload denied)",
4492 		       guestpw, remoteident, realname);
4493 	    else
4494 		syslog(LOG_NOTICE, "%s of %s tried to upload %s (upload denied)",
4495 		       pw->pw_name, remoteident, realname);
4496 	return;
4497     }
4498 
4499     /* do not truncate the file if we are restarting */
4500     if (restart_point)
4501 	open_flags &= ~O_TRUNC;
4502 
4503     /* if the user has an explicit new file mode, than open the file using
4504      * that mode.  We must take care to not let the umask affect the file
4505      * mode.
4506      *
4507      * else open the file and let the default umask determine the file mode. */
4508     if (f_mode >= 0) {
4509 	oldmask = umask(0000);
4510 	fdout = open(name, open_flags, f_mode);
4511 	umask(oldmask);
4512     }
4513     else
4514 	fdout = open(name, open_flags, 0666);
4515 
4516     if (fdout < 0) {
4517 	if (log_security)
4518 	    if (anonymous)
4519 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to upload %s (permissions)",
4520 		       guestpw, remoteident, realname);
4521 	    else
4522 		syslog(LOG_NOTICE, "%s of %s tried to upload %s (permissions)",
4523 		       pw->pw_name, remoteident, realname);
4524 	perror_reply(553, name);
4525 	return;
4526     }
4527     /* if we have a uid and gid, then use them. */
4528 
4529 #ifdef OVERWRITE
4530     if (!exists)
4531 #endif
4532 	if (valid > 0) {
4533 	    oldid = geteuid();
4534 	    if (uid != 0)
4535 		(void) seteuid((uid_t) uid);
4536 	    if ((uid == 0) || ((fchown(fdout, uid, gid)) < 0)) {
4537 		chown_priv_on(0);
4538 		ret = fchown(fdout, uid, gid);
4539 		serrno = errno;
4540 		chown_priv_off(oldid);
4541 		if (ret < 0) {
4542 		    errno = serrno;
4543 		    perror_reply(550, "fchown");
4544 		    return;
4545 		}
4546 	    }
4547 	    else
4548 		(void) seteuid(oldid);
4549 	}
4550 #endif /* UPLOAD */
4551 
4552     if (restart_point && (open_flags & O_APPEND) == 0)
4553 	mode = "r+";
4554 
4555 #ifdef UPLOAD
4556     fout = fdopen(fdout, mode);
4557 #else
4558     fout = fopen(name, mode);
4559 #endif /* UPLOAD */
4560 
4561     if (fout == NULL) {
4562 	if (log_security)
4563 	    if (anonymous)
4564 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to upload %s (permissions)",
4565 		       guestpw, remoteident, realname);
4566 	    else
4567 		syslog(LOG_NOTICE, "%s of %s tried to upload %s (permissions)",
4568 		       pw->pw_name, remoteident, realname);
4569 	perror_reply(553, name);
4570 	return;
4571     }
4572     if (restart_point && (open_flags & O_APPEND) == 0) {
4573 	if (type == TYPE_A) {
4574 	    register int c;
4575 	    off_t i;
4576 
4577 	    i = 0;
4578 	    while (i++ < restart_point) {
4579 		if ((c = getc(fout)) == EOF) {
4580 		    perror_reply(550, name);
4581 		    goto done;
4582 		}
4583 		if (c == '\n')
4584 		    i++;
4585 	    }
4586 	    /* We must do this seek to "current" position because we are
4587 	     * changing from reading to writing. */
4588 #if _FILE_OFFSET_BITS == 64
4589 	    if (fseeko(fout, 0L, SEEK_CUR) < 0) {
4590 #else
4591 	    if (fseek(fout, 0L, SEEK_CUR) < 0) {
4592 #endif
4593 		perror_reply(550, name);
4594 		goto done;
4595 	    }
4596 	}
4597 	else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
4598 	    perror_reply(550, name);
4599 	    goto done;
4600 	}
4601     }
4602     din = dataconn(name, (off_t) - 1, "r");
4603     if (din == NULL)
4604 	goto done;
4605     TransferIncomplete = receive_data(din, fout);
4606 
4607     if (fstat(fileno(fout), &st) != 0) {
4608 	/* shouldn't fail, but just in case */
4609 	st.st_size = -1;
4610     }
4611     (void) fclose(din);
4612     if (TransferIncomplete == 0) {
4613 	if (unique)
4614 	    reply(226, "Transfer complete (unique file name:%s).", name);
4615 	else
4616 	    reply(226, "Transfer complete.");
4617     }
4618 
4619     fb_realpath(name, LastFileTransferred);
4620 
4621 #ifdef MAIL_ADMIN
4622     if (anonymous && incmails > 0) {
4623 	FILE *sck = NULL;
4624 
4625 	unsigned char temp = 0, temp2 = 0;
4626 	char pathname[MAXPATHLEN];
4627 	while ((temp < mailservers) && (sck == NULL))
4628 	    sck = SockOpen(mailserver[temp++], 25);
4629 	if (sck == NULL) {
4630 	    syslog(LOG_ERR, "Can't connect to a mailserver.");
4631 	    goto mailfail;
4632 	}
4633 	if (Reply(sck) != 220) {
4634 	    syslog(LOG_ERR, "Mailserver failed to initiate contact.");
4635 	    goto mailfail;
4636 	}
4637 	if (Send(sck, "HELO localhost\r\n") != 250) {
4638 	    syslog(LOG_ERR, "Mailserver doesn't understand HELO.");
4639 	    goto mailfail;
4640 	}
4641 	if (Send(sck, "MAIL FROM: <%s>\r\n", email(mailfrom)) != 250) {
4642 	    syslog(LOG_ERR, "Mailserver didn't accept MAIL FROM.");
4643 	    goto mailfail;
4644 	}
4645 	for (temp = 0; temp < incmails; temp++) {
4646 	    if (Send(sck, "RCPT TO: <%s>\r\n", email(incmail[temp])) == 250)
4647 		temp2++;
4648 	}
4649 	if (temp2 == 0) {
4650 	    syslog(LOG_ERR, "Mailserver didn't accept any RCPT TO.");
4651 	    goto mailfail;
4652 	}
4653 	if (Send(sck, "DATA\r\n") != 354) {
4654 	    syslog(LOG_ERR, "Mailserver didn't accept DATA.");
4655 	    goto mailfail;
4656 	}
4657 	SockPrintf(sck, "From: wu-ftpd <%s>\r\n", mailfrom);
4658 	SockPrintf(sck, "Subject: New file uploaded: %s\r\n\r\n", name);
4659 	fb_realpath(name, pathname);
4660 	SockPrintf(sck, "%s uploaded %s from %s.\r\nFile size is %" L_FORMAT ".\r\nPlease move the file where it belongs.\r\n", guestpw, pathname, remotehost, st.st_size);
4661 	if (Send(sck, ".\r\n") != 250)
4662 	    syslog(LOG_ERR, "Message rejected by mailserver.");
4663 	if (Send(sck, "QUIT\r\n") != 221)
4664 	    syslog(LOG_ERR, "Mailserver didn't accept QUIT.");
4665       mailfail:
4666 	if (sck != NULL)
4667 	    fclose(sck);
4668     }
4669 #endif /* MAIL_ADMIN */
4670 
4671     if (log_incoming_xfers && (xferlog || syslogmsg)) {
4672 	char msg[MAXXFERSTRLEN];	/* see extensions.h */
4673 	int xfertime = time(NULL) - start_time;
4674 	size_t msglen;
4675 
4676 	if (!xfertime)
4677 	    xfertime++;
4678 
4679 	/* Gather transfer statistics */
4680 	xfervalues.filename = name;
4681 	xfervalues.filesize = st.st_size;
4682 	xfervalues.transfer_bytes = byte_count;
4683 	xfervalues.transfer_direction = 'i';
4684 	xfervalues.transfer_type = (type == TYPE_A) ? 'a' : 'b';
4685 	xfervalues.transfer_time = xfertime;
4686 	xfervalues.restart_offset = restart_point;
4687 	strlcpy(xfervalues.special_action, opt_string(0), MAXSPACTCHARS);
4688 	xfervalues.access_mode = anonymous ? 'a' : (guest ? 'g' : 'r');
4689 	xfervalues.auth = authenticated;
4690 	xfervalues.completion = TransferIncomplete ? 'i' : 'c';
4691 
4692 	xferdone = 1;
4693 	msg_massage(xferlog_format, msg, sizeof(msg));
4694 	xferdone = 0;
4695 
4696 	/* Ensure msg always ends with '\n' */
4697 	msglen = strlen(msg);
4698 	if (msglen == sizeof(msg) - 1) {
4699 	    msg[sizeof(msg) - 2] = '\n';
4700 	    msg[sizeof(msg) - 1] = '\0';
4701 	}
4702 	else {
4703 	    msg[msglen] = '\n';
4704 	    msg[msglen + 1] = '\0';
4705 	}
4706 
4707 	if (syslogmsg != 1)
4708 	    write(xferlog, msg, strlen(msg));
4709 	if (syslogmsg != 0) {
4710 	    char *msgp = msg;
4711 	    /*
4712 	     * To preserve the behavior when the xferlog format was fixed, skip
4713 	     * over the time string if the message starts with the local time.
4714 	     */
4715 	    if (strncmp(xferlog_format, "%T ", 3) == 0)
4716 		msgp += 25;
4717 	    syslog(LOG_INFO, "xferlog (recv): %s", msgp);
4718 	}
4719     }
4720     data = -1;
4721     pdata = -1;
4722   done:
4723     (void) fclose(fout);
4724 }
4725 
4726 FILE *getdatasock(char *mode)
4727 {
4728     int s, on = 1, tries;
4729 
4730     if (data >= 0)
4731 	return (fdopen(data, mode));
4732     port_priv_on(0);
4733     s = socket(SOCK_FAMILY(data_dest), SOCK_STREAM, 0);
4734     if (s < 0)
4735 	goto bad;
4736     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
4737 		   (char *) &on, sizeof(on)) < 0)
4738 	goto bad;
4739     if (keepalive)
4740 	(void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on));
4741     if (TCPwindowsize)
4742 	(void) setsockopt(s, SOL_SOCKET, (*mode == 'w' ? SO_SNDBUF : SO_RCVBUF),
4743 			  (char *) &TCPwindowsize, sizeof(TCPwindowsize));
4744     /* anchor socket to avoid multi-homing problems */
4745 #ifdef INET6
4746     if (SOCK_FAMILY(data_dest) == SOCK_FAMILY(ctrl_addr))
4747 	data_source = ctrl_addr;
4748     else if ((SOCK_FAMILY(data_dest) == AF_INET) && ctrl_v4mapped) {
4749 	struct sockaddr_in6 *ctrl_sin6 = (struct sockaddr_in6 *)&ctrl_addr;
4750 	struct sockaddr_in *data_sin = (struct sockaddr_in *)&data_source;
4751 
4752 	SET_SOCK_FAMILY(data_source, AF_INET);
4753 	memcpy(&data_sin->sin_addr, &ctrl_sin6->sin6_addr.s6_addr[12],
4754 	       sizeof(struct in_addr));
4755     }
4756     else {
4757 	memset(&data_source, 0, sizeof(struct sockaddr_in6));
4758 	SET_SOCK_FAMILY(data_source, SOCK_FAMILY(data_dest));
4759 	SET_SOCK_ADDR_ANY(data_source);
4760     }
4761 #else
4762     data_source = ctrl_addr;
4763 #endif
4764     SET_SOCK_PORT(data_source, data_port);
4765 
4766 #if defined(VIRTUAL) && defined(CANT_BIND)	/* can't bind to virtual address */
4767     SET_SOCK_ADDR_ANY(data_source);
4768 #endif
4769     for (tries = 1;; tries++) {
4770 	if (bind(s, (struct sockaddr *) &data_source, SOCK_LEN(data_source)) >= 0)
4771 	    break;
4772 	if (errno != EADDRINUSE || tries > 10)
4773 	    goto bad;
4774 	sleep(tries);
4775     }
4776 #if defined(M_UNIX) && !defined(_M_UNIX)	/* bug in old TCP/IP release */
4777     {
4778 	struct linger li;
4779 	li.l_onoff = 1;
4780 	li.l_linger = 900;
4781 	if (setsockopt(s, SOL_SOCKET, SO_LINGER,
4782 		       (char *) &li, sizeof(struct linger)) < 0) {
4783 	    syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
4784 	    goto bad;
4785 	}
4786     }
4787 #endif
4788     port_priv_off((uid_t) pw->pw_uid);
4789 
4790 #ifdef INET6
4791     /* IP_TOS is an IPv4 socket option */
4792     if (SOCK_FAMILY(data_source) == AF_INET)
4793 #endif
4794     if ((on = IPClassOfService("data")) >= 0) {
4795 	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *) &on, sizeof(int)) < 0)
4796 	    syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
4797     }
4798 #ifdef TCP_NOPUSH
4799     /*
4800      * Turn off push flag to keep sender TCP from sending short packets
4801      * at the boundaries of each write().  Should probably do a SO_SNDBUF
4802      * to set the send buffer size as well, but that may not be desirable
4803      * in heavy-load situations.
4804      */
4805     on = 1;
4806     if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *) &on, sizeof on) < 0)
4807 	syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
4808 #endif
4809 
4810     return (fdopen(s, mode));
4811   bad:
4812     on = errno;			/* hold errno for return */
4813     port_priv_off((uid_t) pw->pw_uid);
4814     if (s != -1)
4815 	(void) close(s);
4816     errno = on;
4817     return (NULL);
4818 }
4819 
4820 FILE *dataconn(char *name, off_t size, char *mode)
4821 {
4822     char sizebuf[32];
4823     FILE *file;
4824     int retry = 0;
4825     int on = 1;
4826     int cval, serrno;
4827     int cos;
4828 #ifdef THROUGHPUT
4829     int bps;
4830     double bpsmult;
4831 #endif
4832 
4833     file_size = size;
4834     byte_count = 0;
4835     if (size != (off_t) - 1)
4836 	(void) sprintf(sizebuf, " (%" L_FORMAT " bytes)", size);
4837     else
4838 	(void) strcpy(sizebuf, "");
4839     if (pdata >= 0) {
4840 	struct SOCKSTORAGE from;
4841 	char dataaddr[MAXHOSTNAMELEN];
4842 #if defined(UNIXWARE) || defined(AIX)
4843 	size_t fromlen = sizeof(from);
4844 #else
4845 	int fromlen = sizeof(from);
4846 #endif
4847 	int s;
4848 #ifdef FD_ZERO
4849 	int rv;
4850 #endif
4851 
4852 	if (keepalive)
4853 	    (void) setsockopt(pdata, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on));
4854 	if (TCPwindowsize)
4855 	    (void) setsockopt(pdata, SOL_SOCKET, (*mode == 'w' ? SO_SNDBUF : SO_RCVBUF),
4856 			    (char *) &TCPwindowsize, sizeof(TCPwindowsize));
4857 #ifdef FD_ZERO
4858 	do {
4859 	    struct timeval timeout;
4860 	    fd_set set;
4861 
4862 	    FD_ZERO(&set);
4863 	    FD_SET(pdata, &set);
4864 
4865 	    timeout.tv_usec = 0;
4866 	    timeout.tv_sec = timeout_accept;
4867 #ifdef HPUX_SELECT
4868 	    rv = select(pdata + 1, (int *) &set, NULL, NULL, &timeout);
4869 #else
4870 	    rv = select(pdata + 1, &set, (fd_set *) 0, (fd_set *) 0,
4871 			(struct timeval *) &timeout);
4872 #endif
4873 	} while ((rv == -1) && (errno == EINTR));
4874 	if ((rv != -1) && (rv != 0))
4875 	    s = accept(pdata, (struct sockaddr *) &from, &fromlen);
4876 	else
4877 	    s = -1;
4878 #else /* FD_ZERO */
4879 	(void) signal(SIGALRM, alarm_signal);
4880 	alarm(timeout_accept);
4881 	s = accept(pdata, (struct sockaddr *) &from, &fromlen);
4882 	alarm(0);
4883 #endif
4884 	if (s == -1) {
4885 	    reply(425, "Can't open data connection.");
4886 	    (void) close(pdata);
4887 	    pdata = -1;
4888 	    return (NULL);
4889 	}
4890 	(void) close(pdata);
4891 	pdata = s;
4892 #ifdef INET6
4893 	/* IP_TOS is an IPv4 socket option */
4894 	if (SOCK_FAMILY(from) == AF_INET)
4895 #endif
4896 	if ((cos = IPClassOfService("data")) >= 0)
4897 	    (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&cos, sizeof(int));
4898 	(void) strncpy(dataaddr, inet_stop(&from), sizeof(dataaddr));
4899 	if (!pasv_allowed(dataaddr))
4900 	    if (strcasecmp(dataaddr, remoteaddr) != 0) {
4901 		/*
4902 		 * This will log when data connection comes from an address different
4903 		 * than the control connection.
4904 		 */
4905 #ifdef FIGHT_PASV_PORT_RACE
4906 		syslog(LOG_ERR, "%s of %s: data connect from %s for %s%s",
4907 		       anonymous ? guestpw : pw->pw_name, remoteident,
4908 		       dataaddr, name, sizebuf);
4909 		reply(425, "Possible PASV port theft, cannot open data connection.");
4910 		(void) close(pdata);
4911 		pdata = -1;
4912 		return (NULL);
4913 #else
4914 		syslog(LOG_NOTICE, "%s of %s: data connect from %s for %s%s",
4915 		       anonymous ? guestpw : pw->pw_name, remoteident,
4916 		       dataaddr, name, sizebuf);
4917 #endif
4918 	    }
4919 #ifdef THROUGHPUT
4920 	throughput_calc(name, &bps, &bpsmult);
4921 	if (bps != -1) {
4922 	    lreply(150, "Opening %s mode data connection for %s%s.",
4923 		   type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
4924 	    reply(150, "Restricting network throughput to %d bytes/s.", bps);
4925 	}
4926 	else
4927 #endif
4928 	    reply(150, "Opening %s mode data connection for %s%s.",
4929 		  type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
4930 	return (fdopen(pdata, mode));
4931     }
4932     if (data >= 0) {
4933 	reply(125, "Using existing data connection for %s%s.",
4934 	      name, sizebuf);
4935 	usedefault = 1;
4936 	return (fdopen(data, mode));
4937     }
4938     if (usedefault)
4939 	data_dest = his_addr;
4940     if (SOCK_PORT(data_dest) == 0) {
4941 	reply(500, "Can't build data connection: no PORT specified");
4942 	return (NULL);
4943     }
4944     usedefault = 1;
4945     do {
4946 	file = getdatasock(mode);
4947 	if (file == NULL) {
4948 	    reply(425, "Can't create data socket (%s,%d): %s.",
4949 		  inet_stop(&data_source), ntohs(SOCK_PORT(data_source)),
4950 			    strerror(errno));
4951 	    return (NULL);
4952 	}
4953 	data = fileno(file);
4954 	(void) signal(SIGALRM, alarm_signal);
4955 	alarm(timeout_connect);
4956 	cval = connect(data, (struct sockaddr *) &data_dest,
4957 		       SOCK_LEN(data_dest));
4958 	serrno = errno;
4959 	alarm(0);
4960 	if (cval == -1) {
4961 	    /*
4962 	     * When connect fails, the state of the socket is unspecified so
4963 	     * it should be closed and a new socket created for each connection
4964 	     * attempt. This also prevents denial of service problems when
4965 	     * running on operating systems that only allow one non-connected
4966 	     * socket bound to the same local address.
4967 	     */
4968 	    (void) fclose(file);
4969 	    data = -1;
4970 	    errno = serrno;
4971 	    if ((errno == EADDRINUSE || errno == EINTR) && retry < swaitmax) {
4972 		sleep((unsigned) swaitint);
4973 		retry += swaitint;
4974 	    }
4975 	    else {
4976 		perror_reply(425, "Can't build data connection");
4977 		return (NULL);
4978 	    }
4979 	}
4980     } while (cval == -1);
4981     if (keepalive)
4982 	(void) setsockopt(data, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on));
4983     if (TCPwindowsize)
4984 	(void) setsockopt(data, SOL_SOCKET, (*mode == 'w' ? SO_SNDBUF : SO_RCVBUF),
4985 			  (char *) &TCPwindowsize, sizeof(TCPwindowsize));
4986 #ifdef THROUGHPUT
4987     throughput_calc(name, &bps, &bpsmult);
4988     if (bps != -1) {
4989 	lreply(150, "Opening %s mode data connection for %s%s.",
4990 	       type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
4991 	reply(150, "Restricting network throughput to %d bytes/s.", bps);
4992     }
4993     else
4994 #endif
4995 	reply(150, "Opening %s mode data connection for %s%s.",
4996 	      type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
4997     return (file);
4998 }
4999 
5000 /* Tranfer the contents of "instr" to "outstr" peer using the appropriate
5001  * encapsulation of the data subject to Mode, Structure, and Type.
5002  *
5003  * NB: Form isn't handled. */
5004 
5005 int
5006 #ifdef THROUGHPUT
5007     send_data(char *name, FILE *instr, FILE *outstr, size_t blksize)
5008 #else
5009     send_data(FILE *instr, FILE *outstr, size_t blksize)
5010 #endif
5011 {
5012     register int c, cnt = 0;
5013     static char *buf;
5014     int netfd, filefd;
5015 #ifdef THROUGHPUT
5016     int bps;
5017     double bpsmult;
5018     time_t t1, t2;
5019 #endif
5020 #ifdef SENDFILE
5021     int use_sf = 0;
5022     size_t xferred;
5023     struct stat st;
5024     struct sendfilevec sfv;
5025 #endif
5026 
5027     buf = NULL;
5028     if (wu_setjmp(urgcatch)) {
5029 	draconian_FILE = NULL;
5030 	alarm(0);
5031 	transflag = 0;
5032 #ifdef SIGPIPE
5033 	(void) signal(SIGPIPE, lostconn);
5034 #endif
5035 	if (buf)
5036 	    (void) free(buf);
5037 	retrieve_is_data = 1;
5038 	return (0);
5039     }
5040     transflag++;
5041 
5042 #ifdef THROUGHPUT
5043     throughput_calc(name, &bps, &bpsmult);
5044 #endif
5045 
5046     switch (type) {
5047 
5048     case TYPE_A:
5049 #ifdef SIGPIPE
5050 	/*
5051 	 * Ignore SIGPIPE while sending data, necessary so lostconn() isn't
5052 	 * called if we write to the data connection after the client has
5053 	 * closed it.
5054 	 */
5055 	(void) signal(SIGPIPE, SIG_IGN);
5056 #endif
5057 	draconian_FILE = outstr;
5058 	(void) signal(SIGALRM, draconian_alarm_signal);
5059 	alarm(timeout_data);
5060 #ifdef THROUGHPUT
5061 	if (bps != -1)
5062 	    t1 = time(NULL);
5063 #endif
5064 	while ((draconian_FILE != NULL) && ((c = getc(instr)) != EOF)) {
5065 	    if (++byte_count % 4096 == 0)
5066 		alarm(timeout_data);
5067 	    if (c == '\n') {
5068 		if (ferror(outstr))
5069 		    goto data_err;
5070 		if (++byte_count % 4096 == 0)
5071 		    alarm(timeout_data);
5072 #if defined(USE_GSS)
5073 		if (sec_putc('\r', outstr) != '\r')
5074 		    goto data_err;
5075 #else
5076 		(void) putc('\r', outstr);
5077 #endif
5078 #ifdef TRANSFER_COUNT
5079 		if (retrieve_is_data) {
5080 		    data_count_total++;
5081 		    data_count_out++;
5082 		}
5083 		byte_count_total++;
5084 		byte_count_out++;
5085 #endif
5086 	    }
5087 #if defined(USE_GSS)
5088 	    if (sec_putc(c, outstr) != c)
5089 		goto data_err;
5090 #else
5091 	    (void) putc(c, outstr);
5092 #endif
5093 
5094 #ifdef TRANSFER_COUNT
5095 	    if (retrieve_is_data) {
5096 		data_count_total++;
5097 		data_count_out++;
5098 	    }
5099 	    byte_count_total++;
5100 	    byte_count_out++;
5101 #endif
5102 #ifdef THROUGHPUT
5103 	    if (bps > 0 && (byte_count % bps) == 0) {
5104 		t2 = time(NULL);
5105 		if (t2 == t1)
5106 		    sleep(1);
5107 		t1 = time(NULL);
5108 	    }
5109 #endif
5110 	}
5111 #ifdef THROUGHPUT
5112 	if (bps != -1)
5113 	    throughput_adjust(name);
5114 #endif
5115 	if (draconian_FILE != NULL) {
5116 	    alarm(timeout_data);
5117 #if defined(USE_GSS)
5118 	    if (sec_fflush(outstr) < 0)
5119 		goto data_err;
5120 #else
5121 	    fflush(outstr);
5122 #endif /* defined(USE_GSS) */
5123 	}
5124 	if (draconian_FILE != NULL) {
5125 	    alarm(timeout_data);
5126 	    socket_flush_wait(outstr);
5127 	}
5128 	transflag = 0;
5129 	if (ferror(instr))
5130 	    goto file_err;
5131 	if ((draconian_FILE == NULL) || ferror(outstr))
5132 	    goto data_err;
5133 	draconian_FILE = NULL;
5134 	alarm(0);
5135 #ifdef SIGPIPE
5136 	(void) signal(SIGPIPE, lostconn);
5137 #endif
5138 	reply(226, "Transfer complete.");
5139 #ifdef TRANSFER_COUNT
5140 	if (retrieve_is_data) {
5141 	    file_count_total++;
5142 	    file_count_out++;
5143 	}
5144 	xfer_count_total++;
5145 	xfer_count_out++;
5146 #endif
5147 	retrieve_is_data = 1;
5148 	return (1);
5149 
5150     case TYPE_I:
5151     case TYPE_L:
5152 #ifdef THROUGHPUT
5153 	if (bps != -1)
5154 	    blksize = bps;
5155 #endif
5156 	netfd = fileno(outstr);
5157 	filefd = fileno(instr);
5158 #ifdef SENDFILE
5159 	/* check the input file is a regular file */
5160 	if ((fstat(filefd, &st) == 0) && ((st.st_mode & S_IFMT) == S_IFREG)) {
5161 #if defined(USE_GSS)
5162 	    if (gss_info.data_prot == PROT_C || !IS_GSSAUTH(cur_auth_type) ||
5163 		!(gss_info.authstate & GSS_ADAT_DONE))
5164 #endif /* defined(USE_GSS) */
5165 	    {
5166 		use_sf = 1;
5167 		/*
5168 		 * Use a private sfv_flag SFV_NOWAIT to tell sendfilev(),
5169 		 * when zero-copy is enabled, not to wait for all data to be
5170 		 * ACKed before returning. This is important for throughput
5171 		 * performance when sendfilev() is called to send small piece
5172 		 * at a time.
5173 		 */
5174 		sfv.sfv_flag = SFV_NOWAIT;
5175 		sfv.sfv_fd = filefd;
5176 		sfv.sfv_off = restart_point;
5177 		sfv.sfv_len = blksize;
5178 	    }
5179 	}
5180 	if (use_sf == 0)
5181 #endif
5182 	if ((buf = (char *) malloc(blksize)) == NULL) {
5183 	    transflag = 0;
5184 	    perror_reply(451, "Local resource failure: malloc");
5185 	    retrieve_is_data = 1;
5186 	    return (0);
5187 	}
5188 #ifdef SIGPIPE
5189 	/*
5190 	 * Ignore SIGPIPE while sending data, necessary so lostconn() isn't
5191 	 * called if we write to the data connection after the client has
5192 	 * closed it.
5193 	 */
5194 	(void) signal(SIGPIPE, SIG_IGN);
5195 #endif
5196 	draconian_FILE = outstr;
5197 	(void) signal(SIGALRM, draconian_alarm_signal);
5198 	alarm(timeout_data);
5199 #ifdef THROUGHPUT
5200 	if (bps != -1)
5201 	    t1 = time(NULL);
5202 #endif
5203 	while ((draconian_FILE != NULL) && (
5204 #ifdef SENDFILE
5205 	       (use_sf && (cnt = sendfilev(netfd, &sfv, 1, &xferred)) > 0)
5206 	       || (!use_sf &&
5207 #endif
5208 		   ((cnt = read(filefd, buf, blksize)) > 0 &&
5209 #if defined(USE_GSS)
5210 		    sec_write(netfd, buf, cnt) == cnt)
5211 #else
5212 		    write(netfd, buf, cnt) == cnt)
5213 #endif /* defined(USE_GSS) */
5214 #ifdef SENDFILE
5215 		  )
5216 #endif
5217 	)) {
5218 	    alarm(timeout_data);
5219 #ifdef SENDFILE
5220 	    sfv.sfv_off += cnt;
5221 #endif
5222 	    byte_count += cnt;
5223 #ifdef TRANSFER_COUNT
5224 	    if (retrieve_is_data) {
5225 #ifdef RATIO
5226 		if( freefile ) {
5227 		    total_free_dl += cnt;
5228 		}
5229 #endif /* RATIO */
5230 		data_count_total += cnt;
5231 		data_count_out += cnt;
5232 	    }
5233 	    byte_count_total += cnt;
5234 	    byte_count_out += cnt;
5235 #endif
5236 #ifdef THROUGHPUT
5237 	    if (bps != -1) {
5238 		t2 = time(NULL);
5239 		if (t2 == t1)
5240 		    sleep(1);
5241 		t1 = time(NULL);
5242 	    }
5243 #endif /* THROUGHPUT */
5244 	}
5245 #ifdef THROUGHPUT
5246 	if (bps != -1)
5247 	    throughput_adjust(name);
5248 #endif
5249 #if defined(USE_GSS)
5250 	if (sec_fflush(outstr) < 0)
5251 	    goto data_err;
5252 #endif
5253 	transflag = 0;
5254 	if (buf)
5255 	    (void) free(buf);
5256 	if (draconian_FILE != NULL) {
5257 	    alarm(timeout_data);
5258 	    socket_flush_wait(outstr);
5259 	}
5260 	if (cnt != 0) {
5261 #ifdef SENDFILE
5262 	    if (use_sf && cnt < 0 && errno == EPIPE)
5263 		goto data_err;
5264 #endif
5265 	    if (cnt < 0)
5266 		goto file_err;
5267 	    goto data_err;
5268 	}
5269 	if (draconian_FILE == NULL)
5270 	    goto data_err;
5271 	draconian_FILE = NULL;
5272 	alarm(0);
5273 #ifdef SIGPIPE
5274 	(void) signal(SIGPIPE, lostconn);
5275 #endif
5276 	reply(226, "Transfer complete.");
5277 #ifdef TRANSFER_COUNT
5278 	if (retrieve_is_data) {
5279 	    file_count_total++;
5280 	    file_count_out++;
5281 	}
5282 	xfer_count_total++;
5283 	xfer_count_out++;
5284 #endif
5285 	retrieve_is_data = 1;
5286 	return (1);
5287     default:
5288 	transflag = 0;
5289 	reply(550, "Unimplemented TYPE %d in send_data", type);
5290 	retrieve_is_data = 1;
5291 	return (0);
5292     }
5293 
5294   data_err:
5295     draconian_FILE = NULL;
5296     alarm(0);
5297     transflag = 0;
5298 #ifdef SIGPIPE
5299     (void) signal(SIGPIPE, lostconn);
5300 #endif
5301     perror_reply(426, "Data connection");
5302     retrieve_is_data = 1;
5303     return (0);
5304 
5305   file_err:
5306     draconian_FILE = NULL;
5307     alarm(0);
5308     transflag = 0;
5309 #ifdef SIGPIPE
5310     (void) signal(SIGPIPE, lostconn);
5311 #endif
5312     perror_reply(551, "Error on input file");
5313     retrieve_is_data = 1;
5314     return (0);
5315 }
5316 
5317 /* Transfer data from peer to "outstr" using the appropriate encapulation of
5318  * the data subject to Mode, Structure, and Type.
5319  *
5320  * N.B.: Form isn't handled. */
5321 
5322 int receive_data(FILE *instr, FILE *outstr)
5323 {
5324     register int c;
5325     int rcnt = 0, n = 0, bare_lfs = 0;
5326     static char *buf;
5327     int netfd, filefd, wcnt;
5328 #ifdef BUFFER_SIZE
5329     size_t buffer_size = BUFFER_SIZE;
5330 #else
5331     size_t buffer_size = BUFSIZ * 16;
5332 #endif
5333 
5334     buf = NULL;
5335     if (wu_setjmp(urgcatch)) {
5336 	alarm(0);
5337 	transflag = 0;
5338 	if (buf)
5339 	    (void) free(buf);
5340 	return (-1);
5341     }
5342     transflag++;
5343     switch (type) {
5344 
5345     case TYPE_I:
5346     case TYPE_L:
5347 #if defined(USE_GSS)
5348 	if (GSSUSERAUTH_OK(gss_info))
5349 	    buffer_size = gss_getinbufsz();
5350 	else
5351 #endif
5352 	if (recvbufsz > 0)
5353 	    buffer_size = recvbufsz;
5354 	if ((buf = (char *) malloc(buffer_size)) == NULL) {
5355 	    transflag = 0;
5356 	    perror_reply(451, "Local resource failure: malloc");
5357 	    return (-1);
5358 	}
5359 	netfd = fileno(instr);
5360 	filefd = fileno(outstr);
5361 	draconian_FILE = instr;
5362 	(void) signal(SIGALRM, draconian_alarm_signal);
5363 	alarm(timeout_data);
5364 
5365 	while ((draconian_FILE != NULL) &&
5366 #if defined(USE_GSS)
5367 	    (rcnt = sec_read(netfd, buf, buffer_size)) > 0) {
5368 #else
5369 	    (rcnt = read(netfd, buf, buffer_size)) > 0) {
5370 #endif
5371 	    for (wcnt = 0; wcnt < rcnt; wcnt += n) {
5372 		if ((n = write(filefd, &buf[wcnt], rcnt - wcnt)) == -1)
5373 		    break;
5374 	    }
5375 	    byte_count += wcnt;
5376 #ifdef TRANSFER_COUNT
5377 	    data_count_total += wcnt;
5378 	    data_count_in += wcnt;
5379 	    byte_count_total += wcnt;
5380 	    byte_count_in += wcnt;
5381 #endif
5382 	    if (n == -1)
5383 		break;
5384 	    alarm(timeout_data);
5385 	}
5386 	transflag = 0;
5387 	(void) free(buf);
5388 	if ((rcnt == -1) || (draconian_FILE == NULL))
5389 	    goto data_err;
5390 	if (n == -1)
5391 	    goto file_err;
5392 	draconian_FILE = NULL;
5393 	alarm(0);
5394 #ifdef TRANSFER_COUNT
5395 	file_count_total++;
5396 	file_count_in++;
5397 	xfer_count_total++;
5398 	xfer_count_in++;
5399 #endif
5400 	return (0);
5401 
5402     case TYPE_E:
5403 	reply(553, "TYPE E not implemented.");
5404 	transflag = 0;
5405 	return (-1);
5406 
5407     case TYPE_A:
5408 	draconian_FILE = instr;
5409 	(void) signal(SIGALRM, draconian_alarm_signal);
5410 	alarm(timeout_data);
5411 	while ((draconian_FILE != NULL) &&
5412 #if defined(USE_GSS)
5413 	    ((c = sec_getc(instr)) != EOF)
5414 #else
5415 	    ((c = getc(instr)) != EOF)
5416 #endif
5417 	) {
5418 	    if (++byte_count % 4096 == 0)
5419 		alarm(timeout_data);
5420 	    if (c == '\n')
5421 		bare_lfs++;
5422 	    while (c == '\r') {
5423 		if (ferror(outstr))
5424 		    goto file_err;
5425 		alarm(timeout_data);
5426 		if (draconian_FILE != NULL) {
5427 #if defined(USE_GSS)
5428 		    if ((c = sec_getc(instr)) != '\n')
5429 #else
5430 		    if ((c = getc(instr)) != '\n')
5431 #endif
5432 			(void) putc('\r', outstr);
5433 #ifdef TRANSFER_COUNT
5434 		    data_count_total++;
5435 		    data_count_in++;
5436 		    byte_count_total++;
5437 		    byte_count_in++;
5438 #endif
5439 		    if (c == EOF)	/* null byte fix, noid@cyborg.larc.nasa.gov */
5440 			goto contin2;
5441 		    if (++byte_count % 4096 == 0)
5442 			alarm(timeout_data);
5443 		}
5444 	    }
5445 	    (void) putc(c, outstr);
5446 #ifdef TRANSFER_COUNT
5447 	    data_count_total++;
5448 	    data_count_in++;
5449 	    byte_count_total++;
5450 	    byte_count_in++;
5451 #endif
5452 	  contin2:;
5453 	}
5454 	fflush(outstr);
5455 	if ((draconian_FILE == NULL) || ferror(instr))
5456 	    goto data_err;
5457 	if (ferror(outstr))
5458 	    goto file_err;
5459 	transflag = 0;
5460 	draconian_FILE = NULL;
5461 	alarm(0);
5462 	if (bare_lfs) {
5463 	    lreply(226, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs);
5464 	    lreply(0, "   File may not have transferred correctly.");
5465 	}
5466 #ifdef TRANSFER_COUNT
5467 	file_count_total++;
5468 	file_count_in++;
5469 	xfer_count_total++;
5470 	xfer_count_in++;
5471 #endif
5472 	return (0);
5473     default:
5474 	reply(550, "Unimplemented TYPE %d in receive_data", type);
5475 	transflag = 0;
5476 	return (-1);
5477     }
5478 
5479   data_err:
5480     draconian_FILE = NULL;
5481     alarm(0);
5482     transflag = 0;
5483     perror_reply(426, "Data Connection");
5484     return (-1);
5485 
5486   file_err:
5487     draconian_FILE = NULL;
5488     alarm(0);
5489     transflag = 0;
5490     perror_reply(452, "Error writing file");
5491     return (-1);
5492 }
5493 
5494 void statfilecmd(char *filename)
5495 {
5496 #ifndef INTERNAL_LS
5497     char line[BUFSIZ * 2], *ptr;
5498     FILE *fin;
5499     int c;
5500 #endif /* ! INTERNAL_LS */
5501 
5502     fixpath(filename);
5503     if (filename[0] == '\0')
5504 	filename = ".";
5505 #ifndef INTERNAL_LS
5506     if (anonymous && dolreplies)
5507 	(void) snprintf(line, sizeof(line), ls_long, filename);
5508     else
5509 	(void) snprintf(line, sizeof(line), ls_short, filename);
5510     fin = ftpd_popen(line, "r", 0);
5511 #endif /* ! INTERNAL_LS */
5512     lreply(213, "status of %s:", filename);
5513 #ifndef INTERNAL_LS
5514     /*
5515        while ((c = getc(fin)) != EOF) {
5516        if (c == '\n') {
5517        if (ferror(stdout)) {
5518        perror_reply(421, "control connection");
5519        (void) ftpd_pclose(fin);
5520        dologout(1);
5521        / * NOTREACHED * /
5522        }
5523        if (ferror(fin)) {
5524        perror_reply(551, filename);
5525        (void) ftpd_pclose(fin);
5526        return;
5527        }
5528        (void) putc('\r', stdout);
5529        }
5530        (void) putc(c, stdout);
5531        }
5532      */
5533     while (fgets(line, sizeof(line), fin) != NULL) {
5534 	if ((ptr = strchr(line, '\n')))		/* clip out unnecessary newline */
5535 	    *ptr = '\0';
5536 	lreply(0, "%s", line);
5537     }
5538     (void) ftpd_pclose(fin);
5539 #else /* INTERNAL_LS */
5540     ls_dir(filename, 1, 0, 1, 0, 1, stdout);
5541 #endif /* INTERNAL_LS */
5542     reply(213, "End of Status");
5543 }
5544 
5545 void statcmd(void)
5546 {
5547     struct SOCKSTORAGE *sin;
5548     u_char *a, *p;
5549     unsigned short port;
5550 #ifdef INET6
5551     int isv4 = 0;
5552 #endif
5553 
5554     lreply(211, "%s FTP server status:", hostname);
5555     lreply(0, "     %s", version);
5556     if (nameserved)
5557 	lreply(0, "     Connected to %s (%s)", remotehost, remoteaddr);
5558     else
5559 	lreply(0, "     Connected to %s", remotehost);
5560 
5561     if (logged_in) {
5562 	if (anonymous)
5563 	    lreply(0, "     Logged in anonymously");
5564 	else
5565 	    lreply(0, "     Logged in as %s", pw->pw_name);
5566     }
5567     else if (askpasswd)
5568 	lreply(0, "     Waiting for password");
5569     else
5570 	lreply(0, "     Waiting for user name");
5571 
5572     if (type == TYPE_L)
5573 #ifdef NBBY
5574 	lreply(0, "     TYPE: %s %d; STRUcture: %s; transfer MODE: %s",
5575 	       typenames[type], NBBY, strunames[stru], modenames[mode]);
5576 #else
5577 	lreply(0, "     TYPE: %s %d; STRUcture: %s; transfer MODE: %s",
5578 	       typenames[type], bytesize, strunames[stru], modenames[mode]);
5579 #endif /* NBBY */
5580     else
5581 	lreply(0, "     TYPE: %s%s%s; STRUcture: %s; transfer MODE: %s",
5582 	       typenames[type], (type == TYPE_A || type == TYPE_E) ?
5583 	       ", FORM: " : "", (type == TYPE_A || type == TYPE_E) ?
5584 	       formnames[form] : "", strunames[stru], modenames[mode]);
5585     if (data != -1)
5586 	lreply(0, "     Data connection open");
5587     else if (pdata != -1 || usedefault == 0) {
5588 	if (usedefault == 0) {
5589 	    sin = &data_dest;
5590 	    port = SOCK_PORT(data_dest);
5591 	}
5592 	else {
5593 	    port = SOCK_PORT(pasv_addr);
5594 	    if (route_vectored)
5595 		sin = &vect_addr;
5596 	    else
5597 		sin = &pasv_addr;
5598 	}
5599 	a = (u_char *) SOCK_ADDR(*sin);
5600 	p = (u_char *) &port;
5601 #define UC(b) (((int) b) & 0xff)
5602 #ifdef INET6
5603 	if (SOCK_FAMILY(*sin) == AF_INET)
5604 	    isv4 = 1;
5605 	else if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sin)->sin6_addr))
5606 	{
5607 	    isv4 = 1;
5608 	    a += 12; /* move to the IPv4 part of an IPv4-mapped IPv6 address */
5609 	}
5610 	if (epsv_all)
5611 	    lreply(0, "     EPSV only mode (EPSV ALL)");
5612 	if (isv4 && !epsv_all)
5613 #endif
5614 	    lreply(0, "     %s (%d,%d,%d,%d,%d,%d)",
5615 		   usedefault == 0 ? "PORT" : "PASV",
5616 		   UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
5617 #ifdef INET6
5618 	lreply(0, "     %s (|%d|%s|%d|)", usedefault == 0 ? "EPRT" : "EPSV",
5619 	       isv4 ? 1 : 2, inet_stop(sin), ntohs(port));
5620 	if (!epsv_all)
5621 	    if (isv4)
5622 		lreply(0, "     %s (4,4,%d,%d,%d,%d,2,%d,%d)",
5623 		       usedefault == 0 ? "LPRT" : "LPSV",
5624 		       UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
5625 		       UC(p[0]), UC(p[1]));
5626 	    else
5627 		lreply(0, "     %s (6,16,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
5628 		       "%d,%d,%d,%d,2,%d,%d)",
5629 		       usedefault == 0 ? "LPRT" : "LPSV",
5630 		       UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
5631 		       UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
5632 		       UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
5633 		       UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
5634 		       UC(p[0]), UC(p[1]));
5635 #endif
5636 #undef UC
5637     }
5638     else
5639 	lreply(0, "     No data connection");
5640 #ifdef TRANSFER_COUNT
5641     lreply(0, "     %" L_FORMAT " data bytes received in %d files", data_count_in, file_count_in);
5642     lreply(0, "     %" L_FORMAT " data bytes transmitted in %d files", data_count_out, file_count_out);
5643     lreply(0, "     %" L_FORMAT " data bytes total in %d files", data_count_total, file_count_total);
5644     lreply(0, "     %" L_FORMAT " traffic bytes received in %d transfers", byte_count_in, xfer_count_in);
5645     lreply(0, "     %" L_FORMAT " traffic bytes transmitted in %d transfers", byte_count_out, xfer_count_out);
5646     lreply(0, "     %" L_FORMAT " traffic bytes total in %d transfers", byte_count_total, xfer_count_total);
5647 #endif
5648     reply(211, "End of status");
5649 }
5650 
5651 void fatal(char *s)
5652 {
5653     reply(451, "Error in server: %s\n", s);
5654     reply(221, "Closing connection due to server error.");
5655     dologout(0);
5656     /* NOTREACHED */
5657 }
5658 
5659 #define USE_REPLY_NOTFMT	(1<<1)	/* fmt is not a printf fmt (KLUDGE) */
5660 #define USE_REPLY_LONG		(1<<2)	/* this is a long reply; use a - */
5661 
5662 void vreply(long flags, int n, char *fmt, va_list ap)
5663 {
5664     char buf[BUFSIZ * 16];
5665 
5666     flags &= USE_REPLY_NOTFMT | USE_REPLY_LONG;
5667 
5668     if (n)	/* if numeric is 0, don't output one; use n==0 in place of printf's */
5669 	sprintf(buf, "%03d%c", n, flags & USE_REPLY_LONG ? '-' : ' ');
5670 
5671     /* This is somewhat of a kludge for autospout.  I personally think that
5672      * autospout should be done differently, but that's not my department. -Kev
5673      */
5674     if (flags & USE_REPLY_NOTFMT)
5675 	snprintf(buf + (n ? 4 : 0), n ? sizeof(buf) - 4 : sizeof(buf), "%s", fmt);
5676     else
5677 	vsnprintf(buf + (n ? 4 : 0), n ? sizeof(buf) - 4 : sizeof(buf), fmt, ap);
5678 
5679 #if defined(USE_GSS)
5680     if (IS_GSSAUTH(cur_auth_type) &&
5681 	(gss_info.authstate & GSS_ADAT_DONE) &&
5682 	gss_info.ctrl_prot != PROT_C) {
5683 	if (buf[strlen(buf)-1] != '\n')
5684 		strlcat(buf, "\r\n", sizeof(buf));
5685 	(void) sec_reply(buf, sizeof(buf), n);
5686     }
5687 #endif
5688 
5689     if (debug)			/* debugging output :) */
5690 	syslog(LOG_DEBUG, "<--- %s", buf);
5691 
5692     /* Yes, you want the debugging output before the client output; wrapping
5693      * stuff goes here, you see, and you want to log the cleartext and send
5694      * the wrapped text to the client.
5695      */
5696 
5697     printf("%s\r\n", buf);	/* and send it to the client */
5698 #ifdef TRANSFER_COUNT
5699     byte_count_total += strlen(buf);
5700     byte_count_out += strlen(buf);
5701 #endif
5702     /*
5703      * We dont need to worry about "sec_fflush" here since "sec_reply"
5704      * already wrapped the reply if necessary.
5705      */
5706     fflush(stdout);
5707 }
5708 
5709 void reply(int n, char *fmt,...)
5710 {
5711     VA_LOCAL_DECL
5712 
5713 	if (autospout != NULL) {	/* deal with the autospout stuff... */
5714 	char *p, *ptr = autospout;
5715 
5716 	while (*ptr) {
5717 	    if ((p = strchr(ptr, '\n')) != NULL)	/* step through line by line */
5718 		*p = '\0';
5719 
5720 	    /* send a line...(note that this overrides dolreplies!) */
5721 	    vreply(USE_REPLY_LONG | USE_REPLY_NOTFMT, n, ptr, ap);
5722 
5723 	    if (p)
5724 		ptr = p + 1;	/* set to the next line... (\0 is handled in the while) */
5725 	    else
5726 		break;		/* oh, we're done; drop out of the loop */
5727 	}
5728 
5729 	if (autospout_free) {	/* free autospout if necessary */
5730 	    (void) free(autospout);
5731 	    autospout_free = 0;
5732 	}
5733 	autospout = 0;		/* clear the autospout */
5734     }
5735 
5736     VA_START(fmt);
5737 
5738     /* send the reply */
5739     vreply(0L, n, fmt, ap);
5740 
5741     VA_END;
5742 }
5743 
5744 void lreply(int n, char *fmt,...)
5745 {
5746     VA_LOCAL_DECL
5747 
5748     if (!dolreplies)	/* prohibited from doing long replies? */
5749 	return;
5750 
5751     VA_START(fmt);
5752 
5753     /* send the reply */
5754     vreply(USE_REPLY_LONG, n, fmt, ap);
5755 
5756     VA_END;
5757 }
5758 
5759 void ack(char *s)
5760 {
5761     reply(250, "%s command successful.", s);
5762 }
5763 
5764 void nack(char *s)
5765 {
5766     reply(502, "%s command not implemented.", s);
5767 }
5768 
5769 void yyerror(char *s)
5770 {
5771     char *cp;
5772     if (s == NULL || yyerrorcalled != 0)
5773 	return;
5774     if ((cp = strchr(cbuf, '\n')) != NULL)
5775 	*cp = '\0';
5776     reply(500, "'%s': command not understood.", cbuf);
5777     yyerrorcalled = 1;
5778     return;
5779 }
5780 
5781 void delete(char *name)
5782 {
5783     struct stat st;
5784     char realname[MAXPATHLEN];
5785 
5786     /*
5787      * delete permission?
5788      */
5789 
5790     wu_realpath(name, realname, chroot_path);
5791 
5792     if ((del_check(name)) == 0) {
5793 	if (log_security)
5794 	    if (anonymous)
5795 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to delete %s",
5796 		       guestpw, remoteident, realname);
5797 	    else
5798 		syslog(LOG_NOTICE, "%s of %s tried to delete %s",
5799 		       pw->pw_name, remoteident, realname);
5800 	return;
5801     }
5802 
5803     if (lstat(name, &st) < 0) {
5804 	perror_reply(550, name);
5805 	return;
5806     }
5807     if ((st.st_mode & S_IFMT) == S_IFDIR) {
5808 	uid_t uid;
5809 	gid_t gid;
5810 	int d_mode;
5811 	int valid;
5812 
5813 	/*
5814 	 * check the directory, can we rmdir here?
5815 	 */
5816 	if ((dir_check(name, &uid, &gid, &d_mode, &valid)) <= 0) {
5817 	    if (log_security)
5818 		if (anonymous)
5819 		    syslog(LOG_NOTICE, "anonymous(%s) of %s tried to delete directory %s",
5820 			   guestpw, remoteident, realname);
5821 		else
5822 		    syslog(LOG_NOTICE, "%s of %s tried to delete directory %s",
5823 			   pw->pw_name, remoteident, realname);
5824 	    return;
5825 	}
5826 
5827 	if (rmdir(name) < 0) {
5828 	    if (log_security)
5829 		if (anonymous)
5830 		    syslog(LOG_NOTICE, "anonymous(%s) of %s tried to delete directory %s (permissions)",
5831 			   guestpw, remoteident, realname);
5832 		else
5833 		    syslog(LOG_NOTICE, "%s of %s tried to delete directory %s (permissions)",
5834 			   pw->pw_name, remoteident, realname);
5835 	    perror_reply(550, name);
5836 	    return;
5837 	}
5838 	goto done;
5839     }
5840     if (unlink(name) < 0) {
5841 	if (log_security)
5842 	    if (anonymous)
5843 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to delete %s (permissions)",
5844 		       guestpw, remoteident, realname);
5845 	    else
5846 		syslog(LOG_NOTICE, "%s of %s tried to delete %s (permissions)",
5847 		       pw->pw_name, remoteident, realname);
5848 	perror_reply(550, name);
5849 	return;
5850     }
5851   done:
5852     {
5853 	char path[MAXPATHLEN];
5854 
5855 	wu_realpath(name, path, chroot_path);
5856 
5857 	if (log_security)
5858 	    if ((st.st_mode & S_IFMT) == S_IFDIR)
5859 		if (anonymous) {
5860 		    syslog(LOG_NOTICE, "%s of %s deleted directory %s", guestpw, remoteident, path);
5861 		}
5862 		else {
5863 		    syslog(LOG_NOTICE, "%s of %s deleted directory %s", pw->pw_name,
5864 			   remoteident, path);
5865 		}
5866 	    else if (anonymous) {
5867 		syslog(LOG_NOTICE, "%s of %s deleted %s", guestpw,
5868 		       remoteident, path);
5869 	    }
5870 	    else {
5871 		syslog(LOG_NOTICE, "%s of %s deleted %s", pw->pw_name,
5872 		       remoteident, path);
5873 	    }
5874     }
5875 
5876     ack("DELE");
5877 }
5878 
5879 void cwd(char *path)
5880 {
5881     struct aclmember *entry = NULL;
5882     char cdpath[MAXPATHLEN];
5883 
5884     if (chdir(path) < 0) {
5885 	/* alias checking */
5886 	while (getaclentry("alias", &entry) && ARG0 && ARG1 != NULL) {
5887 	    if (!strcasecmp(ARG0, path)) {
5888 		if (chdir(ARG1) < 0)
5889 		    perror_reply(550, path);
5890 		else {
5891 		    show_message(250, C_WD);
5892 		    show_readme(250, C_WD);
5893 		    ack("CWD");
5894 		}
5895 		return;
5896 	    }
5897 	}
5898 	/* check for "cdpath" directories. */
5899 	entry = (struct aclmember *) NULL;
5900 	while (getaclentry("cdpath", &entry) && ARG0 != NULL) {
5901 	    snprintf(cdpath, sizeof cdpath, "%s/%s", ARG0, path);
5902 	    if (chdir(cdpath) >= 0) {
5903 		show_message(250, C_WD);
5904 		show_readme(250, C_WD);
5905 		ack("CWD");
5906 		return;
5907 	    }
5908 	}
5909 	perror_reply(550, path);
5910     }
5911     else {
5912 	show_message(250, C_WD);
5913 	show_readme(250, C_WD);
5914 	ack("CWD");
5915     }
5916 }
5917 
5918 void makedir(char *name)
5919 {
5920     uid_t uid;
5921     gid_t gid;
5922     int d_mode;
5923     mode_t oldumask;
5924     int valid;
5925     int ret, serrno;
5926     uid_t oldid;
5927     char path[MAXPATHLEN + 1];	/* for realpath() later  - cky */
5928     char realname[MAXPATHLEN];
5929 
5930     wu_realpath(name, realname, chroot_path);
5931     /*
5932      * check the directory, can we mkdir here?
5933      */
5934     if ((dir_check(name, &uid, &gid, &d_mode, &valid)) <= 0) {
5935 	if (log_security)
5936 	    if (anonymous)
5937 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to create directory %s",
5938 		       guestpw, remoteident, realname);
5939 	    else
5940 		syslog(LOG_NOTICE, "%s of %s tried to create directory %s",
5941 		       pw->pw_name, remoteident, realname);
5942 	return;
5943     }
5944 
5945     /*
5946      * check the filename, is it legal?
5947      */
5948     if ((fn_check(name)) <= 0) {
5949 	if (log_security)
5950 	    if (anonymous)
5951 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to create directory %s (path-filter)",
5952 		       guestpw, remoteident, realname);
5953 	    else
5954 		syslog(LOG_NOTICE, "%s of %s tried to create directory %s (path-filter)",
5955 		       pw->pw_name, remoteident, realname);
5956 	return;
5957     }
5958 
5959     oldumask = umask(0000);
5960     if (valid <= 0) {
5961 	d_mode = 0777;
5962 	umask(oldumask);
5963     }
5964 
5965     if (mkdir(name, d_mode) < 0) {
5966 	if (errno == EEXIST) {
5967 	    if (log_security)
5968 		if (anonymous)
5969 		    syslog(LOG_NOTICE, "anonymous(%s) of %s tried to create directory %s (exists)",
5970 			   guestpw, remoteident, realname);
5971 		else
5972 		    syslog(LOG_NOTICE, "%s of %s tried to create directory %s (exists)",
5973 			   pw->pw_name, remoteident, realname);
5974 	    fb_realpath(name, path);
5975 	    reply(521, "\"%s\" directory exists", path);
5976 	}
5977 	else {
5978 	    if (log_security)
5979 		if (anonymous)
5980 		    syslog(LOG_NOTICE, "anonymous(%s) of %s tried to create directory %s (permissions)",
5981 			   guestpw, remoteident, realname);
5982 		else
5983 		    syslog(LOG_NOTICE, "%s of %s tried to create directory %s (permissions)",
5984 			   pw->pw_name, remoteident, realname);
5985 	    perror_reply(550, name);
5986 	}
5987 	umask(oldumask);
5988 	return;
5989     }
5990     umask(oldumask);
5991     if (valid > 0) {
5992 	oldid = geteuid();
5993 	if (uid != 0)
5994 	    (void) seteuid((uid_t) uid);
5995 	if ((uid == 0) || ((chown(name, uid, gid)) < 0)) {
5996 	    chown_priv_on(0);
5997 	    ret = chown(name, uid, gid);
5998 	    serrno = errno;
5999 	    chown_priv_off(oldid);
6000 	    if (ret < 0) {
6001 		errno = serrno;
6002 		perror_reply(550, "chown");
6003 		return;
6004 	    }
6005 	}
6006 	else
6007 	    (void) seteuid(oldid);
6008     }
6009     wu_realpath(name, path, chroot_path);
6010     if (log_security)
6011 	if (anonymous) {
6012 	    syslog(LOG_NOTICE, "%s of %s created directory %s", guestpw, remoteident, path);
6013 	}
6014 	else {
6015 	    syslog(LOG_NOTICE, "%s of %s created directory %s", pw->pw_name,
6016 		   remoteident, path);
6017 	}
6018     fb_realpath(name, path);
6019     /* According to RFC 959:
6020      *   The 257 reply to the MKD command must always contain the
6021      *   absolute pathname of the created directory.
6022      * This is implemented here using similar code to the PWD command.
6023      * XXX - still need to do `quote-doubling'.
6024      */
6025     reply(257, "\"%s\" new directory created.", path);
6026 }
6027 
6028 void removedir(char *name)
6029 {
6030     uid_t uid;
6031     gid_t gid;
6032     int d_mode;
6033     int valid;
6034     char realname[MAXPATHLEN];
6035 
6036     wu_realpath(name, realname, chroot_path);
6037 
6038     /*
6039      * delete permission?
6040      */
6041 
6042     if ((del_check(name)) == 0)
6043 	return;
6044     /*
6045      * check the directory, can we rmdir here?
6046      */
6047     if ((dir_check(name, &uid, &gid, &d_mode, &valid)) <= 0) {
6048 	if (log_security)
6049 	    if (anonymous)
6050 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to remove directory %s",
6051 		       guestpw, remoteident, realname);
6052 	    else
6053 		syslog(LOG_NOTICE, "%s of %s tried to remove directory %s",
6054 		       pw->pw_name, remoteident, realname);
6055 	return;
6056     }
6057 
6058     if (rmdir(name) < 0) {
6059 	if (errno == EBUSY)
6060 	    perror_reply(450, name);
6061 	else {
6062 	    if (log_security)
6063 		if (anonymous)
6064 		    syslog(LOG_NOTICE, "anonymous(%s) of %s tried to remove directory %s (permissions)",
6065 			   guestpw, remoteident, realname);
6066 		else
6067 		    syslog(LOG_NOTICE, "%s of %s tried to remove directory %s (permissions)",
6068 			   pw->pw_name, remoteident, realname);
6069 	    perror_reply(550, name);
6070 	}
6071     }
6072     else {
6073 	char path[MAXPATHLEN];
6074 
6075 	wu_realpath(name, path, chroot_path);
6076 
6077 	if (log_security)
6078 	    if (anonymous) {
6079 		syslog(LOG_NOTICE, "%s of %s deleted directory %s", guestpw, remoteident, path);
6080 	    }
6081 	    else {
6082 		syslog(LOG_NOTICE, "%s of %s deleted directory %s", pw->pw_name,
6083 		       remoteident, path);
6084 	    }
6085 	ack("RMD");
6086     }
6087 }
6088 
6089 void pwd(void)
6090 {
6091     char path[MAXPATHLEN + 1];
6092     char rhome[MAXPATHLEN + 1];
6093     char *rpath = path;		/* Path to return to client */
6094     int pathlen;
6095 #ifndef MAPPING_CHDIR
6096 #ifdef HAVE_GETCWD
6097     extern char *getcwd();
6098 #else
6099     extern char *getwd(char *);
6100 #endif
6101 #endif /* MAPPING_CHDIR */
6102 
6103 #ifdef HAVE_GETCWD
6104     if (getcwd(path, MAXPATHLEN) == (char *) NULL)
6105 #else
6106     if (getwd(path) == (char *) NULL)
6107 #endif
6108 /* Dink!  If you couldn't get the path and the buffer is now likely to
6109    be undefined, why are you trying to PRINT it?!  _H*
6110    reply(550, "%s.", path); */
6111     {
6112 	fb_realpath(".", path);	/* realpath_on_steroids can deal */
6113     }
6114     /* relative to home directory if restricted_user */
6115     if (restricted_user) {
6116 	/*
6117 	 * Re-adjust real path because previous call to getXwd() did
6118 	 * not resolve symlink.
6119 	 */
6120 	fb_realpath(".", path);
6121 	fb_realpath(home, rhome);
6122 	pathlen = strlen(rhome);
6123 	if (pathlen && rhome[pathlen - 1] == '/')
6124 	    pathlen--;
6125 	rpath = rpath + pathlen;
6126 	if (!*rpath)
6127 	    strcpy(rpath, "/");
6128     }
6129     reply(257, "\"%s\" is current directory.", rpath);
6130 }
6131 
6132 char *renamefrom(char *name)
6133 {
6134     struct stat st;
6135 
6136     if (lstat(name, &st) < 0) {
6137 	perror_reply(550, name);
6138 	return ((char *) 0);
6139     }
6140     reply(350, "File exists, ready for destination name");
6141     return (name);
6142 }
6143 
6144 void renamecmd(char *from, char *to)
6145 {
6146     int allowed = (anonymous ? 0 : 1);
6147     char realfrom[MAXPATHLEN];
6148     char realto[MAXPATHLEN];
6149     struct aclmember *entry = NULL;
6150 #ifdef PARANOID
6151     struct stat st;
6152 #endif
6153     wu_realpath(from, realfrom, chroot_path);
6154     wu_realpath(to, realto, chroot_path);
6155     /*
6156      * check the filename, is it legal?
6157      */
6158     if ((fn_check(to)) == 0) {
6159 	if (log_security)
6160 	    if (anonymous)
6161 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to rename %s to \"%s\" (path-filter)",
6162 		       guestpw, remoteident, realfrom, realto);
6163 	    else
6164 		syslog(LOG_NOTICE, "%s of %s tried to rename %s to \"%s\" (path-filter)",
6165 		       pw->pw_name, remoteident, realfrom, realto);
6166 	return;
6167     }
6168 
6169     /*
6170      * if rename permission denied and file exists... then deny the user
6171      * permission to rename the file.
6172      */
6173     while (getaclentry("rename", &entry) && ARG0 && ARG1 != NULL) {
6174 	if (type_match(ARG1))
6175 	    if (anonymous) {
6176 		if (*ARG0 == 'y')
6177 		    allowed = 1;
6178 	    }
6179 	    else if (*ARG0 == 'n')
6180 		allowed = 0;
6181     }
6182     if (!allowed) {
6183 	if (log_security)
6184 	    if (anonymous)
6185 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to rename %s to %s",
6186 		       guestpw, remoteident, realfrom, realto);
6187 	    else
6188 		syslog(LOG_NOTICE, "%s of %s tried to rename %s to %s",
6189 		       pw->pw_name, remoteident, realfrom, realto);
6190 	reply(553, "%s: Permission denied on server. (rename)", from);
6191 	return;
6192     }
6193 
6194 
6195 #ifdef PARANOID
6196 /* Almost forgot about this.  Don't allow renaming TO existing files --
6197    otherwise someone can rename "trivial" to "warez", and "warez" is gone!
6198    XXX: This part really should do the same "overwrite" check as store(). */
6199     if (!stat(to, &st)) {
6200 	if (log_security)
6201 	    if (anonymous)
6202 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to rename %s to %s",
6203 		       guestpw, remoteident, realfrom, realto);
6204 	    else
6205 		syslog(LOG_NOTICE, "%s of %s tried to rename %s to %s",
6206 		       pw->pw_name, remoteident, realfrom, realto);
6207 	reply(550, "%s: Permission denied on server. (rename)", to);
6208 	return;
6209     }
6210 #endif
6211     if (rename(from, to) < 0) {
6212 	if (log_security)
6213 	    if (anonymous)
6214 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to rename %s to %s",
6215 		       guestpw, remoteident, realfrom, realto);
6216 	    else
6217 		syslog(LOG_NOTICE, "%s of %s tried to rename %s to %s",
6218 		       pw->pw_name, remoteident, realfrom, realto);
6219 	perror_reply(550, "rename");
6220     }
6221     else {
6222 	char frompath[MAXPATHLEN];
6223 	char topath[MAXPATHLEN];
6224 
6225 	wu_realpath(from, frompath, chroot_path);
6226 	wu_realpath(to, topath, chroot_path);
6227 
6228 	if (log_security)
6229 	    if (anonymous) {
6230 		syslog(LOG_NOTICE, "%s of %s renamed %s to %s", guestpw, remoteident, frompath, topath);
6231 	    }
6232 	    else {
6233 		syslog(LOG_NOTICE, "%s of %s renamed %s to %s", pw->pw_name,
6234 		       remoteident, frompath, topath);
6235 	    }
6236 	ack("RNTO");
6237     }
6238 }
6239 
6240 void dolog(struct SOCKSTORAGE *sin)
6241 {
6242     char *blah;
6243     int rval;
6244 
6245     blah = inet_stop(sin);
6246     (void) strncpy(remoteaddr, blah, sizeof(remoteaddr));
6247     nameserved = 0;
6248     (void) strncpy(remotehost, remoteaddr, sizeof(remotehost));
6249 
6250     rhlookup = rhostlookup(remoteaddr);
6251     if (rhlookup) {
6252 	if (!strcasecmp(remoteaddr, "0.0.0.0")) {
6253 	    nameserved = 1;
6254 	    strncpy(remotehost, "localhost", sizeof(remotehost));
6255 	}
6256 	else {
6257 #ifdef DNS_TRYAGAIN
6258 	    int num_dns_tries = 0;
6259 	    /*
6260 	     * 27-Apr-93    EHK/BM
6261 	     * far away connections might take some time to get their IP address
6262 	     * resolved. That's why we try again -- maybe our DNS cache has the
6263 	     * PTR-RR now. This code is sloppy. Far better is to check what the
6264 	     * resolver returned so that in case of error, there's no need to
6265 	     * try again.
6266 	     */
6267   dns_again:
6268 #endif /* DNS_TRYAGAIN */
6269 
6270 	    rval = wu_gethostbyaddr(sin, remotehost, sizeof(remotehost));
6271 
6272 #ifdef DNS_TRYAGAIN
6273 	    if (!rval && ++num_dns_tries <= 1) {
6274 		sleep(3);
6275 		goto dns_again;		/* try DNS lookup once more     */
6276 	    }
6277 #endif /* DNS_TRYAGAIN */
6278 
6279 	    if (rval)
6280 		nameserved = 1;
6281 	}
6282     }
6283 
6284     remotehost[sizeof(remotehost) - 1] = '\0';
6285     sprintf(proctitle, "%s: connected", remotehost);
6286     setproctitle("%s", proctitle);
6287 
6288     wu_authenticate();
6289 /* Create a composite source identification string, to improve the logging
6290  * when RFC 931 is being used. */
6291     {
6292 	int n = 20 + strlen(remotehost) + strlen(remoteaddr) +
6293 	(authenticated ? strlen(authuser + 5) : 0);
6294 	if ((remoteident = malloc(n)) == NULL) {
6295 	    syslog(LOG_ERR, "malloc: %m");
6296 #ifndef DEBUG
6297 	    exit(1);
6298 #endif
6299 	}
6300 	else if (authenticated)
6301 	    sprintf(remoteident, "%s @ %s [%s]",
6302 		    authuser, remotehost, remoteaddr);
6303 	else
6304 	    sprintf(remoteident, "%s [%s]", remotehost, remoteaddr);
6305     }
6306 #ifdef DAEMON
6307     if (be_daemon && logging)
6308 	syslog(LOG_INFO, "connection from %s", remoteident);
6309 #else
6310 #if 0				/* this is redundant unless the caller doesn't do *anything*, and
6311 				   tcpd will pick it up and deal with it better anyways. _H */
6312     if (logging)
6313 	syslog(LOG_INFO, "connection from %s", remoteident);
6314 #endif
6315 #endif
6316 }
6317 
6318 /* Record logout in wtmp file and exit with supplied status. */
6319 
6320 void dologout(int status)
6321 {
6322     /*
6323      * Prevent reception of SIGURG from resulting in a resumption
6324      * back to the main program loop.
6325      */
6326     transflag = 0;
6327 
6328     /*
6329      * Cancel any pending alarm request, reception of SIGALRM would cause
6330      * dologout() to be called again from the SIGALRM handler toolong().
6331      */
6332     (void) alarm(0);
6333 
6334     if (logged_in) {
6335 	delay_signaling();	/* we can't allow any signals while euid==0: kinch */
6336 #if defined(SOLARIS_BSM_AUDIT) && !defined(SOLARIS_NO_AUDIT_FTPD_LOGOUT)
6337 	audit_ftpd_logout();
6338 #endif
6339 	(void) seteuid((uid_t) 0);
6340 	if (wtmp_logging)
6341 	    wu_logwtmp(ttyline, pw->pw_name, remotehost, 0);
6342 #ifdef USE_PAM
6343 	if (!anonymous && pamh) {
6344 	    (void) pam_close_session(pamh, 0);
6345 	    (void) pam_end(pamh, PAM_SUCCESS);
6346 	    pamh = (pam_handle_t *)0;
6347 	}
6348 #endif
6349     }
6350     if (logging)
6351 	syslog(LOG_INFO, "FTP session closed");
6352     if (xferlog)
6353 	close(xferlog);
6354     acl_remove();
6355     if (data >= 0)
6356 	close(data);
6357     if (pdata >= 0)
6358 	close(pdata);
6359 #ifdef AFS_AUTH
6360     ktc_ForgetAllTokens();
6361 #endif
6362     /* beware of flushing buffers after a SIGPIPE */
6363     _exit(status);
6364 }
6365 
6366 SIGNAL_TYPE myoob(int sig)
6367 {
6368     char *cp;
6369 #ifdef SIGPIPE
6370     void (*pipe_handler)();
6371 #endif
6372 
6373     /* only process if transfer occurring */
6374     if (!transflag) {
6375 #ifdef SIGURG
6376 	(void) signal(SIGURG, myoob);
6377 #endif
6378 	return;
6379     }
6380 #ifdef SIGPIPE
6381     pipe_handler = signal(SIGPIPE, lostconn);
6382 #endif
6383     cp = tmpline;
6384     if (wu_getline(cp, sizeof(tmpline) - 1, stdin) == NULL) {
6385 	reply(221, "You could at least say goodbye.");
6386 	dologout(0);
6387     }
6388     upper(cp);
6389     if (strcasecmp(cp, "ABOR\r\n") == 0) {
6390 	tmpline[0] = '\0';
6391 	reply(426, "Transfer aborted. Data connection closed.");
6392 	reply(226, "Abort successful");
6393 #ifdef SIGPIPE
6394 	(void) signal(SIGPIPE, pipe_handler);
6395 #endif
6396 #ifdef SIGURG
6397 	(void) signal(SIGURG, myoob);
6398 #endif
6399 	if (ftwflag > 0) {
6400 	    ftwflag++;
6401 	    return;
6402 	}
6403 	wu_longjmp(urgcatch, 1);
6404     }
6405     if (strcasecmp(cp, "STAT\r\n") == 0) {
6406 	tmpline[0] = '\0';
6407 	if (file_size != (off_t) - 1)
6408 	    reply(213, "Status: %" L_FORMAT " of %" L_FORMAT " bytes transferred",
6409 		  byte_count, file_size);
6410 	else
6411 	    reply(213, "Status: %" L_FORMAT " bytes transferred", byte_count);
6412     }
6413 #ifdef SIGPIPE
6414     (void) signal(SIGPIPE, pipe_handler);
6415 #endif
6416 #ifdef SIGURG
6417     (void) signal(SIGURG, myoob);
6418 #endif
6419 }
6420 
6421 /* Note: a response of 425 is not mentioned as a possible response to the
6422  * PASV command in RFC959. However, it has been blessed as a legitimate
6423  * response by Jon Postel in a telephone conversation with Rick Adams on 25
6424  * Jan 89. */
6425 
6426 void passive(int passive_mode, int proto)
6427 {
6428     /* First prime number after 2^n where 4 <= n <= 16 */
6429     static int primes[] = {17,37,67,131,257,521,1031,2053,4099,8209,16411,32771,65537,0};
6430     static int prime = 0;
6431     static int range;
6432 #if defined(UNIXWARE) || defined(AIX)
6433     size_t len;
6434 #else
6435     int len;
6436 #endif
6437     int bind_error, serrno;
6438     int on = 1;
6439     int i, j, inc, val;
6440     unsigned short port;
6441     register char *p, *a;
6442     struct SOCKSTORAGE *reply_addr;
6443     struct timeval tv;
6444 #ifdef INET6
6445     int isv4 = 0;
6446 #endif
6447 
6448 /* H* fix: if we already *have* a passive socket, close it first.  Prevents
6449    a whole variety of entertaining clogging attacks. */
6450     if (pdata >= 0) {
6451 	close(pdata);
6452 	pdata = -1;
6453     }
6454     if (!logged_in) {
6455 	reply(530, "Login with USER first.");
6456 	return;
6457     }
6458 #ifdef INET6
6459     switch (proto) {
6460     case 0:
6461 	if ((passive_mode == TYPE_PASV) && (SOCK_FAMILY(ctrl_addr) == AF_INET6)
6462 	    && !ctrl_v4mapped) {
6463 	    reply(501, "Network protocol mismatch");
6464 	    return;
6465 	}
6466 	else
6467 	    pasv_addr = ctrl_addr;
6468 	break;
6469     case 1:
6470 	if (SOCK_FAMILY(ctrl_addr) == AF_INET)
6471 	    pasv_addr = ctrl_addr;
6472 	else if (ctrl_v4mapped) {
6473 	    struct sockaddr_in6 *ctrl_sin6 = (struct sockaddr_in6 *)&ctrl_addr;
6474 	    struct sockaddr_in *pasv_sin = (struct sockaddr_in *)&pasv_addr;
6475 
6476 	    SET_SOCK_FAMILY(pasv_addr, AF_INET);
6477 	    memcpy(&pasv_sin->sin_addr, &ctrl_sin6->sin6_addr.s6_addr[12],
6478 		   sizeof(struct in_addr));
6479 	}
6480 	else {
6481 	    reply(522, "Network protocol mismatch, use (2)");
6482 	    return;
6483 	}
6484 	break;
6485     case 2:
6486 	if ((SOCK_FAMILY(ctrl_addr) == AF_INET6) && !ctrl_v4mapped)
6487 	    pasv_addr = ctrl_addr;
6488 	else {
6489 	    reply(522, "Network protocol mismatch, use (1)");
6490 	    return;
6491 	}
6492 	break;
6493     default:
6494 	reply(522, "Network protocol not supported, use (1,2)");
6495 	return;
6496     }
6497 #else
6498     pasv_addr = ctrl_addr;
6499 #endif
6500 
6501     if (passive_port_min == 0 && passive_port_max == 0) {
6502 	/* let the kernel allocate the port */
6503 	SET_SOCK_PORT(pasv_addr, 0);
6504     }
6505     else if (prime == 0) {
6506 	range = passive_port_max - passive_port_min + 1;
6507 
6508 	/* find the first prime greater than the range in the primes list */
6509 	for (i = 0; primes[i] != 0 && range >= primes[i]; i++)
6510 	    ;
6511 	/* shouldn't happen, but check just in case */
6512 	if (primes[i] == 0) {
6513 	    syslog(LOG_ERR, "passive ports range too large %d-%d", passive_port_min, passive_port_max);
6514 	    /* let the kernel allocate the port */
6515 	    SET_SOCK_PORT(pasv_addr, 0);
6516 	}
6517 	else
6518 	    prime = primes[i];
6519     }
6520     len = SOCK_LEN(pasv_addr);
6521 
6522     port_priv_on(0);	/* necessary as port can be < 1024 */
6523     pdata = socket(SOCK_FAMILY(pasv_addr), SOCK_STREAM, 0);
6524     if (pdata < 0) {
6525 	serrno = errno;
6526 	port_priv_off((uid_t) pw->pw_uid);
6527 	errno = serrno;
6528 	perror_reply(425, "Can't open passive connection");
6529 	return;
6530     }
6531     if (keepalive)
6532 	(void) setsockopt(pdata, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on));
6533     if (TCPwindowsize) {
6534 	(void) setsockopt(pdata, SOL_SOCKET, SO_SNDBUF, (char *) &TCPwindowsize, sizeof(TCPwindowsize));
6535 	(void) setsockopt(pdata, SOL_SOCKET, SO_RCVBUF, (char *) &TCPwindowsize, sizeof(TCPwindowsize));
6536     }
6537 
6538     bind_error = -1;
6539     errno = EADDRINUSE;
6540 
6541     /* try each port in the specified range a maximum of 3 times */
6542     for (i = 0; i < 3 && bind_error != 0 && \
6543 	((errno == EADDRINUSE) || (errno == EACCES)); i++) {
6544 	if (i > 0)
6545 	    sleep(i);
6546 	if (SOCK_PORT(pasv_addr) == 0)
6547 	    bind_error = bind(pdata, (struct sockaddr *) &pasv_addr, len);
6548 	else {
6549 	    gettimeofday(&tv, NULL);
6550 	    srand(tv.tv_usec + tv.tv_sec);
6551 	    inc = 1 + (int) ((1.0 * (prime - 1) * rand()) / (RAND_MAX + 1.0));
6552 	    val = (int) ((1.0 * range * rand()) / (RAND_MAX + 1.0));
6553 	    /*
6554 	     * Using the modulus operator with a prime number allows us to
6555 	     * try each port in the range once.
6556 	     */
6557 	    for (j = 0; j < range && bind_error != 0 && \
6558 		((errno == EADDRINUSE) || (errno == EACCES)); j++) {
6559 		while ((val = ((val + inc) % prime)) >= range)
6560 		    ;
6561 		SET_SOCK_PORT(pasv_addr, htons(val + passive_port_min));
6562 		bind_error = bind(pdata, (struct sockaddr *) &pasv_addr, len);
6563 	    }
6564 	}
6565     }
6566     serrno = errno;
6567     port_priv_off((uid_t) pw->pw_uid);
6568     if (bind_error != 0) {
6569 	errno = serrno;
6570 	goto pasv_error;
6571     }
6572 
6573     /* if the kernel allocated the port, find out which one */
6574     if ((SOCK_PORT(pasv_addr) == 0) &&
6575 	(getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0))
6576 	goto pasv_error;
6577 
6578     if (listen(pdata, 1) < 0)
6579 	goto pasv_error;
6580     usedefault = 1;
6581     if (route_vectored)
6582 	reply_addr = &vect_addr;
6583     else
6584 	reply_addr = &pasv_addr;
6585     a = (char *) SOCK_ADDR(*reply_addr);
6586     port = SOCK_PORT(pasv_addr);
6587     p = (char *) &port;
6588 
6589 #define UC(b) (((int) b) & 0xff)
6590 
6591     if (debug) {
6592 	char *s = calloc(128 + strlen(remoteident), sizeof(char));
6593 	if (s) {
6594 	    int i = ntohs(port);
6595 	    sprintf(s, "PASV port %i assigned to %s", i, remoteident);
6596 	    syslog(LOG_DEBUG, "%s", s);
6597 	    free(s);
6598 	}
6599     }
6600 #ifdef INET6
6601     if (SOCK_FAMILY(*reply_addr) == AF_INET)
6602 	isv4 = 1;
6603     else if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)reply_addr)->sin6_addr)) {
6604 	    isv4 = 1;
6605 	    a += 12; /* move to the IPv4 part of an IPv4-mapped IPv6 address */
6606     }
6607     switch (passive_mode) {
6608     case TYPE_PASV:
6609 	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)",
6610 	      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
6611 	return;
6612     case TYPE_EPSV:
6613 	reply(229, "Entering Extended Passive Mode (|||%d|)", ntohs(port));
6614 	return;
6615     case TYPE_LPSV:
6616 	if (isv4) {
6617 	    reply(228, "Entering Long Passive Mode "
6618 		  "(%d,%d,%d,%d,%d,%d,%d,%d,%d)",
6619 		  4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
6620 		  2, UC(p[0]), UC(p[1]));
6621 	}
6622 	else {
6623 	    reply(228, "Entering Long Passive Mode "
6624 		  "(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
6625 		  "%d,%d,%d,%d,%d)", 6, 16,
6626 		  UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
6627 		  UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
6628 		  UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
6629 		  UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
6630 		  2, UC(p[0]), UC(p[1]));
6631 	}
6632 	return;
6633      }
6634 #else
6635     reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
6636 	  UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
6637     return;
6638 #endif /* INET6 */
6639 
6640   pasv_error:
6641     perror_reply(425, "Can't open passive connection");
6642     (void) close(pdata);
6643     pdata = -1;
6644     if (debug) {
6645 	char *s = calloc(128 + strlen(remoteident), sizeof(char));
6646 	if (s) {
6647 	    sprintf(s, "PASV port assignment assigned for %s", remoteident);
6648 	    syslog(LOG_DEBUG, "%s", s);
6649 	    free(s);
6650 	}
6651     }
6652     return;
6653 }
6654 
6655 /*
6656  * Generate unique name for file with basename "local". The file named
6657  * "local" is already known to exist. Generates failure reply on error.
6658  */
6659 char *gunique(char *local)
6660 {
6661     static char new[MAXPATHLEN];
6662     struct stat st;
6663     char *cp = strrchr(local, '/');
6664     int count = 0;
6665 
6666     if (cp)
6667 	*cp = '\0';
6668     if (stat(cp ? local : ".", &st) < 0) {
6669 	perror_reply(553, cp ? local : ".");
6670 	return ((char *) 0);
6671     }
6672     if (cp)
6673 	*cp = '/';
6674     (void) strncpy(new, local, (sizeof new) - 3);
6675     new[sizeof(new) - 3] = '\0';
6676     cp = new + strlen(new);
6677     *cp++ = '.';
6678     for (count = 1; count < 100; count++) {
6679 	if (count == 10) {
6680 	    cp -= 2;
6681 	    *cp++ = '.';
6682 	}
6683 	(void) sprintf(cp, "%d", count);
6684 	if (stat(new, &st) < 0)
6685 	    return (new);
6686     }
6687     reply(452, "Unique file name cannot be created.");
6688     return ((char *) 0);
6689 }
6690 
6691 /* Format and send reply containing system error number. */
6692 
6693 void perror_reply(int code, char *string)
6694 {
6695     /*
6696      * If restricted user and string starts with home dir path, strip it off
6697      * and return only the relative path.
6698      */
6699     if (restricted_user && (home != NULL) && (home[0] != '\0')) {
6700 	size_t len = strlen (home);
6701 	if (strncmp (home, string, len) == 0) {
6702 	    if (string[len - 1] == '/')
6703 		string += len - 1;
6704 	    else if (string[len] == '/')
6705 		string += len;
6706 	    else if (string[len] == '\0')
6707 		string = "/";
6708 	}
6709     }
6710     reply(code, "%s: %s.", string, strerror(errno));
6711 }
6712 
6713 static char *onefile[] =
6714 {"", 0};
6715 
6716 extern char **ftpglob(register char *v, boolean_t check_ncargs);
6717 extern char *globerr;
6718 
6719 void send_file_list(char *whichfiles)
6720 {
6721     /* static so not clobbered by longjmp(), volatile would also work */
6722     static FILE *dout;
6723     static DIR *dirp;
6724     static char **sdirlist;
6725     static char *wildcard = NULL;
6726 
6727     struct stat st;
6728 
6729     register char **dirlist, *dirname;
6730     int simple = 0;
6731     int statret;
6732     /* This is ANSI/ISO C .. strpbrk should be in <string.h> which we've
6733        ** already included so we don't need the following line.  'sides, it
6734        ** breaks the GNU EGCS C compiler
6735        ** extern char *strpbrk(const char *, const char *);
6736      */
6737 
6738 #ifdef TRANSFER_COUNT
6739 #ifdef TRANSFER_LIMIT
6740     if (((file_limit_raw_out > 0) && (xfer_count_out >= file_limit_raw_out))
6741 	|| ((file_limit_raw_total > 0) && (xfer_count_total >= file_limit_raw_total))
6742      || ((data_limit_raw_out > 0) && (byte_count_out >= data_limit_raw_out))
6743 	|| ((data_limit_raw_total > 0) && (byte_count_total >= data_limit_raw_total))) {
6744 	if (log_security)
6745 	    if (anonymous)
6746 		syslog(LOG_NOTICE, "anonymous(%s) of %s tried to list files (Transfer limits exceeded)",
6747 		       guestpw, remoteident);
6748 	    else
6749 		syslog(LOG_NOTICE, "%s of %s tried to list files (Transfer limits exceeded)",
6750 		       pw->pw_name, remoteident);
6751 	reply(553, "Permission denied on server. (Transfer limits exceeded)");
6752 	return;
6753     }
6754 #endif
6755 #endif
6756 
6757     draconian_FILE = NULL;
6758     dout = NULL;
6759     dirp = NULL;
6760     sdirlist = NULL;
6761     wildcard = NULL;
6762     if (strpbrk(whichfiles, "~{[*?") == NULL) {
6763 	if (whichfiles[0] == '\0') {
6764 	    wildcard = strdup("*");
6765 	    if (wildcard == NULL) {
6766 		reply(550, "Memory allocation error");
6767 		goto globfree;
6768 	    }
6769 	    whichfiles = wildcard;
6770 	}
6771 	else {
6772 	    if (statret=stat(whichfiles, &st) < 0)
6773 	       statret=lstat(whichfiles, &st); /* Check if it's a dangling symlink */
6774 	    if (statret >= 0) {
6775 	       if ((st.st_mode & S_IFMT) == S_IFDIR) {
6776 		   wildcard = malloc(strlen(whichfiles) + 3);
6777 		   if (wildcard == NULL) {
6778 		       reply(550, "Memory allocation error");
6779 		       goto globfree;
6780 		   }
6781 		   strcpy(wildcard, whichfiles);
6782 		   strcat(wildcard, "/*");
6783 		   whichfiles = wildcard;
6784 	       }
6785 	    }
6786 	}
6787     }
6788     if (strpbrk(whichfiles, "~{[*?") != NULL) {
6789 	globerr = NULL;
6790 	dirlist = ftpglob(whichfiles, B_FALSE);
6791 	sdirlist = dirlist;	/* save to free later */
6792 	if (globerr != NULL) {
6793 	    reply(550, "%s", globerr);
6794 	    goto globfree;
6795 	}
6796 	else if (dirlist == NULL) {
6797 	    errno = ENOENT;
6798 	    perror_reply(550, whichfiles);
6799 	    goto globfree;
6800 	}
6801     }
6802     else {
6803 	onefile[0] = whichfiles;
6804 	dirlist = onefile;
6805 	simple = 1;
6806     }
6807 
6808     if (wu_setjmp(urgcatch)) {
6809 	transflag = 0;
6810 	if (dout != NULL)
6811 	    (void) fclose(dout);
6812 	if (dirp != NULL)
6813 	    (void) closedir(dirp);
6814 	data = -1;
6815 	pdata = -1;
6816 	goto globfree;
6817     }
6818     while ((dirname = *dirlist++) != NULL) {
6819 	statret=stat(dirname, &st);
6820 	if (statret < 0)
6821 	   statret=lstat(dirname, &st); /* Could be a dangling symlink */
6822 	if (statret < 0) {
6823 	    /* If user typed "ls -l", etc, and the client used NLST, do what
6824 	     * the user meant. */
6825 	    if (dirname[0] == '-' && *dirlist == NULL && transflag == 0) {
6826 		retrieve_is_data = 0;
6827 #ifndef INTERNAL_LS
6828 		retrieve(ls_plain, dirname);
6829 #else
6830 		ls(dirname, 1);
6831 #endif
6832 		retrieve_is_data = 1;
6833 		goto globfree;
6834 	    }
6835 	    perror_reply(550, dirname);
6836 	    if (dout != NULL) {
6837 		(void) fclose(dout);
6838 		transflag = 0;
6839 		data = -1;
6840 		pdata = -1;
6841 	    }
6842 	    goto globfree;
6843 	}
6844 #ifndef NLST_SHOWS_DIRS
6845 	if ((st.st_mode & S_IFMT) != S_IFDIR)
6846 #endif
6847 	{
6848 	    if (dout == NULL) {
6849 		dout = dataconn("file list", (off_t) - 1, "w");
6850 		if (dout == NULL)
6851 		    goto globfree;
6852 		transflag++;
6853 		draconian_FILE = dout;
6854 	    }
6855 	    if (draconian_FILE != NULL) {
6856 		(void) signal(SIGALRM, draconian_alarm_signal);
6857 		alarm(timeout_data);
6858 #if defined(USE_GSS)
6859 		(void) sec_fprintf(dout, "%s%s\n", dirname,
6860 				type == TYPE_A ? "\r" : "");
6861 #else
6862 		fprintf(dout, "%s%s\n", dirname,
6863 			type == TYPE_A ? "\r" : "");
6864 #endif /* USE_GSS */
6865 	    }
6866 	    byte_count += strlen(dirname) + 1;
6867 #ifdef TRANSFER_COUNT
6868 	    byte_count_total += strlen(dirname) + 1;
6869 	    byte_count_out += strlen(dirname) + 1;
6870 	    if (type == TYPE_A) {
6871 		byte_count_total++;
6872 		byte_count_out++;
6873 	    }
6874 #endif
6875 	}
6876     }
6877 
6878     if (dout != NULL) {
6879 	if (draconian_FILE != NULL) {
6880 	    (void) signal(SIGALRM, draconian_alarm_signal);
6881 	    alarm(timeout_data);
6882 #if defined(USE_GSS)
6883 	    if (sec_fflush(dout) < 0) {
6884 		alarm(0);
6885 		perror_reply(550, "Data connection");
6886 		goto sfl_cleanup; /* send file list cleanup */
6887 	    }
6888 #else
6889 	    fflush(dout);
6890 #endif /* USE_GSS */
6891 	}
6892 	if (draconian_FILE != NULL) {
6893 	    (void) signal(SIGALRM, draconian_alarm_signal);
6894 	    alarm(timeout_data);
6895 	    socket_flush_wait(dout);
6896 	}
6897     }
6898     if (dout == NULL)
6899 	reply(550, "No files found.");
6900     else if ((draconian_FILE == NULL) || ferror(dout) != 0) {
6901 	alarm(0);
6902 	perror_reply(550, "Data connection");
6903     }
6904     else {
6905 #ifdef TRANSFER_COUNT
6906 	xfer_count_total++;
6907 	xfer_count_out++;
6908 #endif
6909 	alarm(0);
6910 	reply(226, "Transfer complete.");
6911     }
6912   sfl_cleanup:
6913     transflag = 0;
6914     if ((dout != NULL) && (draconian_FILE != NULL))
6915 	(void) fclose(dout);
6916     data = -1;
6917     pdata = -1;
6918   globfree:
6919     if (wildcard != NULL) {
6920 	free(wildcard);
6921 	wildcard = NULL;
6922     }
6923     if (sdirlist) {
6924 	blkfree(sdirlist);
6925 	free((char *) sdirlist);
6926     }
6927 }
6928 
6929 /*
6930    **  SETPROCTITLE -- set process title for ps
6931    **
6932    **   Parameters:
6933    **           fmt -- a printf style format string.
6934    **           a, b, c -- possible parameters to fmt.
6935    **
6936    **   Returns:
6937    **           none.
6938    **
6939    **   Side Effects:
6940    **           Clobbers argv of our main procedure so ps(1) will
6941    **           display the title.
6942  */
6943 
6944 #define SPT_NONE	0	/* don't use it at all */
6945 #define SPT_REUSEARGV	1	/* cover argv with title information */
6946 #define SPT_BUILTIN	2	/* use libc builtin */
6947 #define SPT_PSTAT	3	/* use pstat(PSTAT_SETCMD, ...) */
6948 #define SPT_PSSTRINGS	4	/* use PS_STRINGS->... */
6949 #define SPT_SYSMIPS	5	/* use sysmips() supported by NEWS-OS 6 */
6950 #define SPT_SCO		6	/* write kernel u. area */
6951 #define SPT_CHANGEARGV	7	/* write our own strings into argv[] */
6952 #define MAXLINE      2048	/* max line length for setproctitle */
6953 #define SPACELEFT(buf, ptr)  (sizeof buf - ((ptr) - buf))
6954 
6955 #ifndef SPT_TYPE
6956 #define SPT_TYPE	SPT_REUSEARGV
6957 #endif
6958 
6959 #if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN
6960 
6961 #if SPT_TYPE == SPT_PSTAT
6962 #include <sys/pstat.h>
6963 #endif
6964 #if SPT_TYPE == SPT_PSSTRINGS
6965 #include <machine/vmparam.h>
6966 #include <sys/exec.h>
6967 #ifndef PS_STRINGS		/* hmmmm....  apparently not available after all */
6968 #undef SPT_TYPE
6969 #define SPT_TYPE	SPT_REUSEARGV
6970 #else
6971 #ifndef NKPDE			/* FreeBSD 2.0 */
6972 #define NKPDE 63
6973 typedef unsigned int *pt_entry_t;
6974 #endif
6975 #endif
6976 #endif
6977 
6978 #if SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV
6979 #define SETPROC_STATIC	static
6980 #else
6981 #define SETPROC_STATIC
6982 #endif
6983 
6984 #if SPT_TYPE == SPT_SYSMIPS
6985 #include <sys/sysmips.h>
6986 #include <sys/sysnews.h>
6987 #endif
6988 
6989 #if SPT_TYPE == SPT_SCO
6990 #ifdef UNIXWARE
6991 #include <sys/exec.h>
6992 #include <sys/ksym.h>
6993 #include <sys/proc.h>
6994 #include <sys/user.h>
6995 #else /* UNIXWARE */
6996 #include <sys/immu.h>
6997 #include <sys/dir.h>
6998 #include <sys/user.h>
6999 #include <sys/fs/s5param.h>
7000 #endif /* UNIXWARE */
7001 #if PSARGSZ > MAXLINE
7002 #define SPT_BUFSIZE	PSARGSZ
7003 #endif
7004 #ifndef _PATH_KMEM
7005 #define _PATH_KMEM	"/dev/kmem"
7006 #endif /* _PATH_KMEM */
7007 #endif /* SPT_SCO */
7008 
7009 #ifndef SPT_PADCHAR
7010 #define SPT_PADCHAR	' '
7011 #endif
7012 
7013 #ifndef SPT_BUFSIZE
7014 #define SPT_BUFSIZE	MAXLINE
7015 #endif
7016 
7017 #endif /* SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN */
7018 
7019 #if SPT_TYPE == SPT_REUSEARGV || SPT_TYPE == SPT_CHANGEARGV
7020 char **Argv = NULL;		/* pointer to argument vector */
7021 #endif
7022 
7023 #if SPT_TYPE == SPT_REUSEARGV
7024 char *LastArgv = NULL;		/* end of argv */
7025 #endif
7026 
7027 /*
7028    **  Pointers for setproctitle.
7029    **   This allows "ps" listings to give more useful information.
7030  */
7031 void initsetproctitle(argc, argv, envp)
7032      int argc;
7033      char **argv;
7034      char **envp;
7035 {
7036 #if SPT_TYPE == SPT_REUSEARGV
7037     register int i, envpsize = 0;
7038     char **newenviron;
7039     extern char **environ;
7040 
7041     /*
7042        **  Save start and extent of argv for setproctitle.
7043      */
7044 
7045     LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
7046     if (envp != NULL) {
7047 	/*
7048 	   **  Move the environment so setproctitle can use the space at
7049 	   **  the top of memory.
7050 	 */
7051 	for (i = 0; envp[i] != NULL; i++)
7052 	    envpsize += strlen(envp[i]) + 1;
7053 	newenviron = (char **) malloc(sizeof(char *) * (i + 1));
7054 	if (newenviron) {
7055 	    int err = 0;
7056 	    for (i = 0; envp[i] != NULL; i++) {
7057 		if ((newenviron[i] = strdup(envp[i])) == NULL) {
7058 		    err = 1;
7059 		    break;
7060 		}
7061 	    }
7062 	    if (err) {
7063 		for (i = 0; newenviron[i] != NULL; i++)
7064 		    free(newenviron[i]);
7065 		free(newenviron);
7066 		i = 0;
7067 	    }
7068 	    else {
7069 		newenviron[i] = NULL;
7070 		environ = newenviron;
7071 	    }
7072 	}
7073 	else {
7074 	    i = 0;
7075 	}
7076 
7077 	/*
7078 	   **  Find the last environment variable within wu-ftpd's
7079 	   **  process memory area.
7080 	 */
7081 	while (i > 0 && (envp[i - 1] < argv[0] ||
7082 		    envp[i - 1] > (argv[argc - 1] + strlen(argv[argc - 1]) +
7083 				   1 + envpsize)))
7084 	    i--;
7085 
7086 	if (i > 0)
7087 	    LastArgv = envp[i - 1] + strlen(envp[i - 1]);
7088     }
7089 #endif /* SPT_TYPE == SPT_REUSEARGV */
7090 
7091 #if SPT_TYPE == SPT_REUSEARGV || SPT_TYPE == SPT_CHANGEARGV
7092     Argv = argv;
7093 #endif
7094 }
7095 
7096 
7097 #if SPT_TYPE != SPT_BUILTIN
7098 
7099 /*VARARGS1 */
7100 void setproctitle(const char *fmt,...)
7101 {
7102 #if SPT_TYPE != SPT_NONE
7103     register char *p;
7104     register int i;
7105     SETPROC_STATIC char buf[SPT_BUFSIZE];
7106     VA_LOCAL_DECL
7107 #if SPT_TYPE == SPT_PSTAT
7108 	union pstun pst;
7109 #endif
7110 #if SPT_TYPE == SPT_SCO
7111     static off_t seek_off;
7112     static int kmemfd = -1;
7113     static int kmempid = -1;
7114 #ifdef UNIXWARE
7115     off_t offset;
7116     void *ptr;
7117     struct mioc_rksym rks;
7118 #endif /* UNIXWARE */
7119 #endif /* SPT_SCO */
7120 
7121     p = buf;
7122 
7123     /* print ftpd: heading for grep */
7124     (void) strcpy(p, "ftpd: ");
7125     p += strlen(p);
7126 
7127     /* print the argument string */
7128     VA_START(fmt);
7129     (void) vsnprintf(p, SPACELEFT(buf, p), fmt, ap);
7130     VA_END;
7131 
7132     i = strlen(buf);
7133 
7134 #if SPT_TYPE == SPT_PSTAT
7135     pst.pst_command = buf;
7136     pstat(PSTAT_SETCMD, pst, i, 0, 0);
7137 #endif
7138 #if SPT_TYPE == SPT_PSSTRINGS
7139     PS_STRINGS->ps_nargvstr = 1;
7140     PS_STRINGS->ps_argvstr = buf;
7141 #endif
7142 #if SPT_TYPE == SPT_SYSMIPS
7143     sysmips(SONY_SYSNEWS, NEWS_SETPSARGS, buf);
7144 #endif
7145 #if SPT_TYPE == SPT_SCO
7146     if (kmemfd < 0 || kmempid != getpid()) {
7147 	if (kmemfd >= 0)
7148 	    close(kmemfd);
7149 	if ((kmemfd = open(_PATH_KMEM, O_RDWR, 0)) < 0)
7150 	    return;
7151 	(void) fcntl(kmemfd, F_SETFD, 1);
7152 	kmempid = getpid();
7153 #ifdef UNIXWARE
7154 	seek_off = 0;
7155 	rks.mirk_symname = "upointer";
7156 	rks.mirk_buf = &ptr;
7157 	rks.mirk_buflen = sizeof(ptr);
7158 	if (ioctl(kmemfd, MIOC_READKSYM, &rks) < 0)
7159 	    return;
7160 	offset = (off_t) ptr + (off_t) & ((struct user *) 0)->u_procp;
7161 	if (lseek(kmemfd, offset, SEEK_SET) != offset)
7162 	    return;
7163 	if (read(kmemfd, &ptr, sizeof(ptr)) != sizeof(ptr))
7164 	    return;
7165 	offset = (off_t) ptr + (off_t) & ((struct proc *) 0)->p_execinfo;
7166 	if (lseek(kmemfd, offset, SEEK_SET) != offset)
7167 	    return;
7168 	if (read(kmemfd, &ptr, sizeof(ptr)) != sizeof(ptr))
7169 	    return;
7170 	seek_off = (off_t) ptr + (off_t) ((struct execinfo *) 0)->ei_psargs;
7171 #else /* UNIXWARE */
7172 	seek_off = UVUBLK + (off_t) & ((struct user *) 0)->u_psargs;
7173 #endif /* UNIXWARE */
7174     }
7175 #ifdef UNIXWARE
7176     if (seek_off == 0)
7177 	return;
7178 #endif /* UNIXWARE */
7179     buf[PSARGSZ - 1] = '\0';
7180     if (lseek(kmemfd, (off_t) seek_off, SEEK_SET) == seek_off)
7181 	(void) write(kmemfd, buf, PSARGSZ);
7182 #endif /* SPT_SCO */
7183 #if SPT_TYPE == SPT_REUSEARGV
7184     if (i > LastArgv - Argv[0] - 2) {
7185 	i = LastArgv - Argv[0] - 2;
7186 	buf[i] = '\0';
7187     }
7188     (void) strcpy(Argv[0], buf);
7189     p = &Argv[0][i];
7190     while (p < LastArgv)
7191 	*p++ = SPT_PADCHAR;
7192     Argv[1] = NULL;
7193 #endif
7194 #if SPT_TYPE == SPT_CHANGEARGV
7195     Argv[0] = buf;
7196     Argv[1] = 0;
7197 #endif
7198 #endif /* SPT_TYPE != SPT_NONE */
7199 }
7200 
7201 #endif /* SPT_TYPE != SPT_BUILTIN */
7202 
7203 #ifdef KERBEROS
7204 /* thanks to gshapiro@wpi.wpi.edu for the following kerberosities */
7205 
7206 void init_krb()
7207 {
7208     char hostname[100];
7209 
7210 #ifdef HAVE_SYSINFO
7211     if (sysinfo(SI_HOSTNAME, hostname, sizeof(hostname)) < 0) {
7212 	perror("sysinfo");
7213 #else
7214     if (gethostname(hostname, sizeof(hostname)) < 0) {
7215 	perror("gethostname");
7216 #endif
7217 	exit(1);
7218     }
7219     if (strchr(hostname, '.'))
7220 	*(strchr(hostname, '.')) = 0;
7221 
7222     sprintf(krb_ticket_name, "/var/dss/kerberos/tkt/tkt.%d", getpid());
7223     krb_set_tkt_string(krb_ticket_name);
7224 
7225     config_auth();
7226 
7227     if (krb_svc_init("hesiod", hostname, (char *) NULL, 0, (char *) NULL,
7228 		     (char *) NULL) != KSUCCESS) {
7229 	fprintf(stderr, "Couldn't initialize Kerberos\n");
7230 	exit(1);
7231     }
7232 }
7233 
7234 void end_krb()
7235 {
7236     unlink(krb_ticket_name);
7237 }
7238 
7239 #endif /* KERBEROS */
7240 
7241 #ifdef ULTRIX_AUTH
7242 static int ultrix_check_pass(char *passwd, char *xpasswd)
7243 {
7244     struct svcinfo *svp;
7245     int auth_status;
7246 
7247     if ((svp = getsvc()) == (struct svcinfo *) NULL) {
7248 	syslog(LOG_WARNING, "getsvc() failed in ultrix_check_pass");
7249 	return -1;
7250     }
7251     if (pw == (struct passwd *) NULL) {
7252 	return -1;
7253     }
7254     if (((svp->svcauth.seclevel == SEC_UPGRADE) &&
7255 	 (!strcmp(pw->pw_passwd, "*")))
7256 	|| (svp->svcauth.seclevel == SEC_ENHANCED)) {
7257 	if ((auth_status = authenticate_user(pw, passwd, "/dev/ttypXX")) >= 0) {
7258 	    /* Indicate successful validation */
7259 	    return auth_status;
7260 	}
7261 	if (auth_status < 0 && errno == EPERM) {
7262 	    /* Log some information about the failed login attempt. */
7263 	    switch (abs(auth_status)) {
7264 	    case A_EBADPASS:
7265 		break;
7266 	    case A_ESOFTEXP:
7267 		syslog(LOG_NOTICE, "password will expire soon for user %s",
7268 		       pw->pw_name);
7269 		break;
7270 	    case A_EHARDEXP:
7271 		syslog(LOG_NOTICE, "password has expired for user %s",
7272 		       pw->pw_name);
7273 		break;
7274 	    case A_ENOLOGIN:
7275 		syslog(LOG_NOTICE, "user %s attempted login to disabled acct",
7276 		       pw->pw_name);
7277 		break;
7278 	    }
7279 	}
7280     }
7281     else {
7282 	if ((*pw->pw_passwd != '\0') && (!strcmp(xpasswd, pw->pw_passwd))) {
7283 	    /* passwd in /etc/passwd isn't empty && encrypted passwd matches */
7284 	    return 0;
7285 	}
7286     }
7287     return -1;
7288 }
7289 #endif /* ULTRIX_AUTH */
7290 
7291 #ifdef USE_PAM
7292 /* This is rather an abuse of PAM, but the FTP protocol doesn't allow much
7293  * flexibility here.  :-(
7294  */
7295 
7296 /* Static variables used to communicate between the conversation function
7297  * and the server_login function
7298  */
7299 static char *PAM_password;
7300 
7301 /* PAM conversation function
7302  * Here we assume (for now, at least) that echo on means login name, and
7303  * echo off means password.
7304  */
7305 #ifdef SOLARIS_2
7306 /* Workaround bug 4430970/4413889 which causes a compiler warning, necessary
7307  * as usr/src/Makefile.master now includes "-errwarn=%all".
7308  */
7309 static int PAM_conv(int num_msg, struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
7310 #else
7311 static int PAM_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
7312 #endif
7313 {
7314     int replies = 0;
7315     struct pam_response *reply = NULL;
7316 
7317 #define COPY_STRING(s) (s) ? strdup(s) : NULL
7318 
7319     reply = malloc(sizeof(struct pam_response) * num_msg);
7320     if (!reply)
7321 	return PAM_CONV_ERR;
7322 
7323     for (replies = 0; replies < num_msg; replies++) {
7324 	switch (msg[replies]->msg_style) {
7325 	case PAM_PROMPT_ECHO_ON:
7326 	    return PAM_CONV_ERR;
7327 	    break;
7328 	case PAM_PROMPT_ECHO_OFF:
7329 	    reply[replies].resp_retcode = PAM_SUCCESS;
7330 	    reply[replies].resp = COPY_STRING(PAM_password);
7331 	    /* PAM frees resp */
7332 	    break;
7333 	case PAM_TEXT_INFO:
7334 	    /* ignore it... */
7335 	    reply[replies].resp_retcode = PAM_SUCCESS;
7336 	    reply[replies].resp = NULL;
7337 	    break;
7338 	case PAM_ERROR_MSG:
7339 	    /* ignore it... */
7340 	    reply[replies].resp_retcode = PAM_SUCCESS;
7341 	    reply[replies].resp = NULL;
7342 	    break;
7343 	default:
7344 	    /* Must be an error of some sort... */
7345 	    return PAM_CONV_ERR;
7346 	}
7347     }
7348     *resp = reply;
7349     return PAM_SUCCESS;
7350 }
7351 static struct pam_conv PAM_conversation =
7352 {
7353     &PAM_conv,
7354     NULL
7355 };
7356 
7357 static int pam_check_pass(char *user, char *passwd)
7358 {
7359     char tty[20];
7360     int pam_session = 0;
7361 
7362     /* Now use PAM to do authentication and session logging. Bail out if
7363      * there are any errors. Since this is a limited protocol, and an even
7364      * more limited function within a server speaking this protocol, we
7365      * can't be as verbose as would otherwise make sense.
7366      */
7367     PAM_password = passwd;
7368     pamh = (pam_handle_t *)0;
7369     if (pam_start("ftp", user, &PAM_conversation, &pamh) != PAM_SUCCESS)
7370 	return 0;
7371 
7372 #if ((defined(BSD) && (BSD >= 199103)) || defined(sun))
7373     (void) sprintf(tty, "/dev/ftp%ld", (long) getpid());
7374 #else
7375     (void) sprintf(tty, "/dev/ftpd%d", getpid());
7376 #endif
7377 
7378     if (pam_set_item(pamh, PAM_TTY, tty) != PAM_SUCCESS)
7379 	goto pam_fail;
7380     if (pam_set_item(pamh, PAM_RHOST, remotehost) != PAM_SUCCESS)
7381 	goto pam_fail;
7382     if (pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS) {
7383 #ifdef SOLARIS_BSM_AUDIT
7384 	audit_ftpd_bad_pw(user);
7385 #endif
7386 	goto pam_fail;
7387     }
7388     if (pam_acct_mgmt(pamh, 0) != PAM_SUCCESS) {
7389 #ifdef SOLARIS_BSM_AUDIT
7390 	audit_ftpd_bad_pw(user);
7391 #endif
7392 	goto pam_fail;
7393     }
7394     if (pam_open_session(pamh, 0) != PAM_SUCCESS)
7395 	goto pam_fail;
7396     pam_session = 1;
7397 #ifdef PAM_ESTABLISH_CRED
7398     if (pam_setcred(pamh, PAM_ESTABLISH_CRED) != PAM_SUCCESS)
7399 	goto pam_fail;
7400 #else
7401     if (pam_setcred(pamh, PAM_CRED_ESTABLISH) != PAM_SUCCESS)
7402 	goto pam_fail;
7403 #endif
7404     /* If this point is reached, the user has been authenticated. */
7405     return 1;
7406 
7407 pam_fail:
7408     if (pam_session)
7409 	(void) pam_close_session(pamh, 0);
7410     (void) pam_end(pamh, 0);
7411     pamh = (pam_handle_t *)0;
7412     return 0;
7413 }
7414 #endif
7415 
7416 #ifdef DAEMON
7417 
7418 #ifdef INET6
7419 static struct in6_addr acl_DaemonAddress6(void)
7420 {
7421     struct in6_addr rv = in6addr_any;
7422     struct aclmember *entry = NULL;
7423 
7424     if (getaclentry("daemonaddress", &entry) && ARG0) {
7425 	if (inet_pton6(ARG0, &rv) != 1)
7426 	    rv = in6addr_any;
7427     }
7428     return rv;
7429 }
7430 #endif /* INET6 */
7431 static unsigned long int acl_DaemonAddress(void)
7432 {
7433     unsigned long int rv = INADDR_ANY;
7434     struct aclmember *entry = NULL;
7435 
7436     if (getaclentry("daemonaddress", &entry) && ARG0) {
7437 	rv = inet_addr(ARG0);
7438 	if (rv == -1)
7439 	    rv = INADDR_ANY;
7440     }
7441     return rv;
7442 }
7443 
7444 /* I am running as a standalone daemon (not under inetd) */
7445 static void do_daemon(void)
7446 {
7447     struct SOCKSTORAGE server;
7448     struct servent *serv;
7449     int pgrp;
7450     int lsock;
7451     int one = 1;
7452     FILE *pidfile;
7453     int i;
7454 #if defined(UNIXWARE) || defined(AIX)
7455     size_t addrlen;
7456 #else
7457     int addrlen;
7458 #endif
7459 
7460     /* Some of this is "borrowed" from inn - lots of it isn't */
7461 
7462     if (be_daemon == 2) {
7463 	/* Fork - so I'm not the owner of the process group any more */
7464 	i = fork();
7465 	if (i < 0) {
7466 	    syslog(LOG_ERR, "cant fork %m");
7467 	    exit(1);
7468 	}
7469 	/* No need for the parent any more */
7470 	if (i > 0)
7471 	    exit(0);
7472 
7473 #ifdef NO_SETSID
7474 	pgrp = setpgrp(0, getpid());
7475 #else
7476 	pgrp = setsid();
7477 #endif
7478 	if (pgrp < 0) {
7479 	    syslog(LOG_ERR, "cannot daemonise: %m");
7480 	    exit(1);
7481 	}
7482     }
7483 
7484     if (!Bypass_PID_Files)
7485 	if ((pidfile = fopen(_PATH_FTPD_PID, "w"))) {
7486 	    fprintf(pidfile, "%ld\n", (long) getpid());
7487 	    fclose(pidfile);
7488 	}
7489 	else {
7490 	    syslog(LOG_ERR, "Cannot write pidfile: %m");
7491 	}
7492 
7493     /* Close off all file descriptors and reopen syslog */
7494     if (be_daemon == 2) {
7495 	closelog();
7496 	closefds(0);
7497 	(void) open(_PATH_DEVNULL, O_RDWR);
7498 	(void) dup2(0, 1);
7499 	/* junk stderr */
7500 	(void) freopen(_PATH_DEVNULL, "w", stderr);
7501 
7502 #ifdef FACILITY
7503 	openlog("ftpd", LOG_PID | LOG_NDELAY, FACILITY);
7504 #else
7505 	openlog("ftpd", LOG_PID);
7506 #endif
7507     }
7508 
7509     if (RootDirectory != NULL) {
7510 	if ((chroot(RootDirectory) < 0)
7511 	    || (chdir("/") < 0)) {
7512 	    syslog(LOG_ERR, "Cannot chroot to initial directory, aborting.");
7513 	    exit(1);
7514 	}
7515 	free(RootDirectory);
7516 	RootDirectory = NULL;
7517     }
7518 
7519     if (!use_accessfile)
7520 	syslog(LOG_WARNING, "FTP server started without ftpaccess file");
7521 
7522     syslog(LOG_INFO, "FTP server (%s) ready.", version);
7523 
7524     /* Create a socket to listen on */
7525 #ifdef INET6
7526     if (listen_v4 == 0)
7527 	lsock = socket(AF_INET6, SOCK_STREAM, 0);
7528     else
7529 #endif
7530     lsock = socket(AF_INET, SOCK_STREAM, 0);
7531     if (lsock < 0) {
7532 	syslog(LOG_ERR, "Cannot create socket to listen on: %m");
7533 	exit(1);
7534     }
7535     if (setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) < 0) {
7536 	syslog(LOG_ERR, "Cannot set SO_REUSEADDR option: %m");
7537 	exit(1);
7538     }
7539     if (keepalive)
7540 	(void) setsockopt(lsock, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
7541 
7542 #ifdef INET6
7543     if (listen_v4 == 0) {
7544 	struct sockaddr_in6 *server_sin6 = (struct sockaddr_in6 *)&server;
7545 
7546 	memset(&server, 0, sizeof(struct sockaddr_in6));
7547 	server_sin6->sin6_family = AF_INET6;
7548 	server_sin6->sin6_addr = acl_DaemonAddress6();
7549     }
7550     else {
7551 	struct sockaddr_in *server_sin = (struct sockaddr_in *)&server;
7552 
7553 	server_sin->sin_family = AF_INET;
7554 	server_sin->sin_addr.s_addr = acl_DaemonAddress();
7555     }
7556 #else
7557     server.sin_family = AF_INET;
7558     server.sin_addr.s_addr = acl_DaemonAddress();
7559 #endif
7560     if (daemon_port == 0) {
7561 	if (!(serv = getservbyname("ftp", "tcp"))) {
7562 	    syslog(LOG_ERR, "Cannot find service ftp: %m");
7563 	    exit(1);
7564 	}
7565 	SET_SOCK_PORT(server, serv->s_port);
7566 	daemon_port = ntohs(serv->s_port);
7567     }
7568     else
7569 	SET_SOCK_PORT(server, htons(daemon_port));
7570 
7571     if (bind(lsock, (struct sockaddr *) &server, SOCK_LEN(server)) < 0) {
7572 	syslog(LOG_ERR, "Cannot bind socket: %m");
7573 	exit(1);
7574     }
7575 
7576     listen(lsock, MAX_BACKLOG);
7577 
7578     sprintf(proctitle, "accepting connections on port %i", daemon_port);
7579     setproctitle("%s", proctitle);
7580 
7581     while (1) {
7582 	int pid;
7583 	int msgsock;
7584 
7585 	addrlen = sizeof(his_addr);
7586 	msgsock = accept(lsock, (struct sockaddr *) &his_addr, &addrlen);
7587 	if (msgsock < 0) {
7588 	    int severity = LOG_ERR;
7589 
7590 	    if (errno == EINTR || errno == ECONNABORTED)
7591 		severity = LOG_INFO;
7592 	    syslog(severity, "Accept failed: %m");
7593 	    sleep(1);
7594 	    continue;
7595 	}
7596 
7597 	/* Fork off a handler */
7598 	pid = fork();
7599 	if (pid < 0) {
7600 	    syslog(LOG_ERR, "failed to fork: %m");
7601 	    close(msgsock);
7602 	    sleep(1);
7603 	    continue;
7604 	}
7605 	if (pid == 0) {
7606 	    /* I am that forked off child */
7607 	    /* Only parent needs lsock */
7608 	    close(lsock);
7609 	    closelog();
7610 	    /* Make sure that stdin/stdout are the new socket */
7611 	    dup2(msgsock, 0);
7612 	    dup2(msgsock, 1);
7613 	    if (msgsock != 0 && msgsock != 1)
7614 		close(msgsock);
7615 #ifdef FACILITY
7616 	    openlog("ftpd", LOG_PID | LOG_NDELAY, FACILITY);
7617 #else
7618 	    openlog("ftpd", LOG_PID);
7619 #endif
7620 	    setup_paths();
7621 	    access_init();
7622 	    return;
7623 	}
7624 
7625 	/* I am the parent */
7626 	close(msgsock);
7627 
7628 	/* Quick check to see if any of the forked off children have
7629 	 * terminated. */
7630 	while ((pid = waitpid((pid_t) -1, (int *) 0, WNOHANG)) > 0) {
7631 	    /* A child has finished */
7632 	}
7633 
7634 	access_init();
7635     }
7636 }
7637 
7638 #endif /* DAEMON */
7639 
7640 #ifdef RATIO
7641 int is_downloadfree(char *fname)
7642 {
7643     char        rpath[MAXPATHLEN];
7644     char	class[BUFSIZ];
7645     char        *cp;
7646     int		which;
7647     struct aclmember *entry = NULL;
7648 
7649     if( wu_realpath(fname,rpath,chroot_path) == NULL )
7650         return 0;
7651 
7652     (void) acl_getclass(class);
7653 
7654     if (debug)
7655 	syslog(LOG_DEBUG, "class: %s, fname: %s, rpath: %s", class, fname, rpath);
7656 
7657     while( getaclentry("dl-free-dir",&entry) ) {
7658         if( ARG0 == NULL )
7659             continue;
7660         if( strncmp(rpath,ARG0,strlen(ARG0)) == 0 ) {
7661 	    if( ARG1 == NULL )
7662 		return 1;
7663 	    else for(which = 1; (which < MAXARGS) && ARG[which]; which++) {
7664 		if( strcmp(class,ARG[which]) == 0 )
7665 		    return 1;
7666 	    }
7667         }
7668     }
7669     while( getaclentry("dl-free",&entry) ) {
7670         if( ARG0 == NULL )
7671             continue;
7672         if( *(ARG0) != '/' ) {  /* compare basename */
7673             if( (cp = strrchr(rpath,'/')) == NULL ) {
7674                 cp = rpath;
7675             }
7676             else {
7677                 ++cp;
7678             }
7679             if( strcmp(cp,ARG0) == 0 ) {
7680 		if( ARG1 == NULL )
7681 		    return 1;
7682 		else for(which = 1; (which < MAXARGS) && ARG[which]; which++) {
7683 		    if( strcmp(class,ARG[which]) == 0 )
7684 		    return 1;
7685 		}
7686             }
7687         }
7688         else {  /* compare real path */
7689             if( strcmp(rpath,ARG0) == 0 ) {
7690 		if( ARG1 == NULL )
7691 		    return 1;
7692 		else for(which = 1; (which < MAXARGS) && ARG[which] ; which++) {
7693 		    if( strcmp(class,ARG[which]) == 0 )
7694 		    return 1;
7695 		}
7696             }
7697         }
7698     }
7699     return 0;
7700 }
7701 #endif /* RATIO */
7702 
7703 int pasv_allowed(char *remoteaddr)
7704 {
7705     char class[MAXPATHLEN];
7706     int which;
7707     struct aclmember *entry = NULL;
7708     (void) acl_getclass(class);
7709     while (getaclentry("pasv-allow", &entry)) {
7710 	if ((ARG0 != NULL) && (strcasecmp(class, ARG0) == 0))
7711 	    for (which = 1; (which < MAXARGS) && (ARG[which] != NULL); which++) {
7712 		if (hostmatch(ARG[which], remoteaddr, NULL))
7713 		    return 1;
7714 	    }
7715     }
7716     return 0;
7717 }
7718 
7719 int port_allowed(char *remoteaddr)
7720 {
7721     char class[MAXPATHLEN];
7722     int which;
7723     struct aclmember *entry = NULL;
7724     (void) acl_getclass(class);
7725     while (getaclentry("port-allow", &entry)) {
7726 	if ((ARG0 != NULL) && (strcasecmp(class, ARG0) == 0))
7727 	    for (which = 1; (which < MAXARGS) && (ARG[which] != NULL); which++) {
7728 		if (hostmatch(ARG[which], remoteaddr, NULL))
7729 		    return 1;
7730 	    }
7731     }
7732     return 0;
7733 }
7734 
7735 #ifdef MAIL_ADMIN
7736 char *email(char *full_address)
7737 {
7738     /* Get the plain address part from an e-mail address
7739        (i.e. remove realname) */
7740 
7741     static char *email_buf = NULL;
7742     char *addr, *ptr;
7743 
7744     if (email_buf != NULL)
7745 	free(email_buf);
7746 
7747     email_buf = (char *) malloc(strlen(full_address) + 1);
7748     addr = email_buf;
7749     memset(addr, 0, strlen(full_address) + 1);
7750     strcpy(addr, full_address);
7751 
7752     /* Realname <user@host> type address */
7753     if ((ptr = (char *) strchr(addr, '<')) != NULL) {
7754 	addr = ++ptr;
7755 	if ((ptr = (char *) strchr(addr, '>')) != NULL)
7756 	    *ptr = '\0';
7757     }
7758 
7759     /* user@host (Realname) type address */
7760     if (((char *) strchr(addr, ' ')) != NULL)
7761 	addr[strchr(addr, ' ') - addr] = '\0';
7762 
7763     return addr;
7764 }
7765 
7766 FILE *SockOpen(char *host, int clientPort)
7767 {
7768     int sock;
7769     unsigned long inaddr;
7770     struct sockaddr_in ad;
7771     FILE *fp;
7772 #ifdef INET6
7773     struct sockaddr_in6 ad6;
7774     struct addrinfo hints, *result, *res;
7775     int af = AF_INET;
7776 #else
7777     struct hostent *hp;
7778 #endif
7779 
7780     memset(&ad, 0, sizeof(ad));
7781     ad.sin_family = AF_INET;
7782 
7783 #ifdef INET6
7784     memset(&ad6, 0, sizeof(ad6));
7785     ad6.sin6_family = AF_INET6;
7786 
7787     memset(&hints, 0, sizeof(hints));
7788     hints.ai_flags = AI_CANONNAME;
7789     hints.ai_family = PF_UNSPEC;
7790 
7791     if (getaddrinfo(host, NULL, &hints, &result) != 0)
7792 	return (FILE *) NULL;
7793 
7794     for (res = result; res; res = res->ai_next) {
7795 	af = res->ai_family;
7796 	if (af == AF_INET)
7797 	    memcpy(&ad.sin_addr, &((struct sockaddr_in *)res->ai_addr)->sin_addr, sizeof(struct in_addr));
7798 	else if (af == AF_INET6)
7799 	    memcpy(&ad6.sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
7800 	else
7801 	    continue;
7802 
7803 	if (af == AF_INET6) {
7804 	    ad6.sin6_port = htons(clientPort);
7805 	    sock = socket(AF_INET6, SOCK_STREAM, 0);
7806 	    if (sock < 0)
7807 		continue;
7808 	    if (connect(sock, (struct sockaddr *) &ad6, sizeof(ad6)) != -1)
7809 		break;
7810 	    close(sock);
7811 	}
7812 	else {
7813 	    ad.sin_port = htons(clientPort);
7814 	    sock = socket(AF_INET, SOCK_STREAM, 0);
7815 	    if (sock < 0)
7816 		continue;
7817 	    if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) != -1)
7818 		break;
7819 	    close(sock);
7820 	}
7821     }
7822     freeaddrinfo(result);
7823     if (!res)
7824 	return (FILE *) NULL;
7825 #else
7826     inaddr = inet_addr(host);
7827     if (inaddr != (unsigned long) -1)
7828 	memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
7829     else {
7830 	hp = gethostbyname(host);
7831 	if (hp == NULL)
7832 	    return (FILE *) NULL;
7833 	memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
7834     }
7835     ad.sin_port = htons(clientPort);
7836     sock = socket(AF_INET, SOCK_STREAM, 0);
7837     if (sock < 0)
7838 	return (FILE *) NULL;
7839     if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0) {
7840 	close(sock);
7841 	return (FILE *) NULL;
7842     }
7843 #endif /* INET6 */
7844 
7845     fp = fdopen(sock, "r+");
7846     setvbuf(fp, NULL, _IOLBF, 2048);
7847     return (fp);
7848 }
7849 
7850 int SockPrintf(FILE *sockfp, char *format,...)
7851 {
7852     va_list ap;
7853     char buf[16384];
7854 
7855     va_start(ap, format);
7856     vsnprintf(buf, sizeof(buf), format, ap);
7857     buf[sizeof(buf) - 1] = '\0';
7858     va_end(ap);
7859     return SockWrite(buf, 1, strlen(buf), sockfp);
7860 }
7861 
7862 int SockWrite(char *buf, int size, int len, FILE *sockfp)
7863 {
7864     return (fwrite(buf, size, len, sockfp));
7865 }
7866 
7867 char *SockGets(FILE *sockfp, char *buf, int len)
7868 {
7869     return (fgets(buf, len, sockfp));
7870 }
7871 
7872 int SockPuts(FILE *sockfp, char *buf)
7873 {
7874     int rc;
7875 
7876     if ((rc = SockWrite(buf, 1, strlen(buf), sockfp)))
7877 	return rc;
7878     return SockWrite("\r\n", 1, 2, sockfp);
7879 }
7880 
7881 int Reply(FILE *sockfp)
7882 {
7883     char *reply, *rec, *separator;
7884     int ret = 0;
7885 
7886     if ((reply = (char *) malloc(BUFSIZ)) == NULL)
7887 	return ret;
7888     memset(reply, 0, 1024);
7889     do {
7890 	rec = SockGets(sockfp, reply, BUFSIZ);
7891 	if (rec != NULL) {
7892 	    ret = strtol(reply, &separator, 10);
7893 	}
7894 	else
7895 	    ret = 250;
7896     } while ((rec != NULL) && (separator[0] != ' '));
7897     free(reply);
7898     fflush(sockfp);	/* Solaris bug: need to clear buf before fwrite() */
7899     return ret;
7900 }
7901 
7902 int Send(FILE *sockfp, char *format,...)
7903 {
7904     va_list ap;
7905     char buf[16384];
7906 
7907     va_start(ap, format);
7908     vsnprintf(buf, sizeof(buf), format, ap);
7909     buf[sizeof(buf) - 1] = '\0';
7910     va_end(ap);
7911     SockWrite(buf, 1, strlen(buf), sockfp);
7912     return Reply(sockfp);
7913 }
7914 #endif /* MAIL_ADMIN */
7915 
7916 
7917 /*
7918  * fixpath
7919  *
7920  * In principal, this is similar to realpath() or the mapping chdir function.
7921  * It removes unnecessary path components.  We do this to put a stop to
7922  * attempts to cause a memory starvation DoS.
7923  *
7924  */
7925 
7926 void fixpath(char *path)
7927 {
7928     int abs = 0;
7929     char *in;
7930     char *out;
7931 
7932     if (*path == '/') {
7933 	abs = 1;
7934 	path++;
7935     }
7936     else if (*path == '~') {
7937 	do
7938 	    path++;
7939 	while ((*path != '\0') && (*path != '/'));
7940 	if (*path == '/')
7941 	    path++;
7942     }
7943     in = path;
7944     out = path;
7945     while (*in != '\0') {
7946 	if (*in == '/')
7947 	    in++;
7948 	else if ((in[0] == '.') && ((in[1] == '/') || (in[1] == '\0'))) {
7949 	    in++;
7950 	    if (*in == '/')
7951 		in++;
7952 	}
7953 	else if ((in[0] == '.') && (in[1] == '.') && ((in[2] == '/') || (in[2] == '\0'))) {
7954 	    if (out == path) {
7955 		if (abs) {
7956 		    in++;
7957 		    in++;
7958 		    if (*in == '/')
7959 			in++;
7960 		}
7961 		else {
7962 		    *out++ = *in++;
7963 		    *out++ = *in++;
7964 		    if (*in == '/')
7965 			*out++ = *in++;
7966 		    path = out;
7967 		}
7968 	    }
7969 	    else {
7970 		out--;
7971 		while ((out != path) && (*--out != '/'));
7972 		in++;
7973 		in++;
7974 		if (*in == '/')
7975 		    in++;
7976 	    }
7977 	}
7978 	else {
7979 	    do
7980 		*out++ = *in++;
7981 	    while ((*in != '\0') && (*in != '/'));
7982 	    if (*in == '/')
7983 		*out++ = *in++;
7984 	}
7985     }
7986     *out = '\0';
7987 }
7988 
7989 #if defined(SOLARIS_2)
7990 
7991 /* Callback function to cleanup_nscd()'s fdwalk().
7992  * If "fd" has the same inode, device as nscd door
7993  * it returns 1 otherwise it returns 0.
7994  */
7995 int close_nsdoor(void *cb_data, int fd)
7996 {
7997     struct stat fd_buf;
7998     struct stat *nsdoor_buf = (struct stat *) cb_data;
7999 
8000     if (fstat(fd, &fd_buf) != 0) {
8001 	return (0);
8002     }
8003 
8004     if ((nsdoor_buf->st_dev == fd_buf.st_dev) &&
8005 	(nsdoor_buf->st_ino == fd_buf.st_ino)) {
8006 	close(fd);
8007 	return (1);
8008     }
8009 
8010     return (0);
8011 }
8012 
8013 /* Walk through the list of open file descriptors
8014  * of the ftp dameon and find the nscd door fd and
8015  * close it.
8016  */
8017 void cleanup_nscd()
8018 {
8019     struct stat nsdoor_buf;
8020 
8021     if (stat(NAME_SERVICE_DOOR, &nsdoor_buf) == 0) {
8022 	fdwalk(close_nsdoor, &nsdoor_buf);
8023     }
8024 }
8025 
8026 #endif
8027