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