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