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