ftpd.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/****************************************************************************
Copyright (c) 1999,2000,2001 WU-FTPD Development Group.
All rights reserved.
Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994
The Regents of the University of California.
Portions Copyright (c) 1993, 1994 Washington University in Saint Louis.
Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc.
Portions Copyright (c) 1989 Massachusetts Institute of Technology.
Portions Copyright (c) 1998 Sendmail, Inc.
Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P. Allman.
Portions Copyright (c) 1997 by Stan Barber.
Portions Copyright (c) 1997 by Kent Landfield.
Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997
Free Software Foundation, Inc.
Use and distribution of this software and its source code are governed
by the terms and conditions of the WU-FTPD Software License ("LICENSE").
If you did not receive a copy of the license, it may be obtained online
$Id: ftpd.c,v 1.111 2000/07/01 18:17:39 wuftpd Exp $
****************************************************************************/
/* FTP server. */
#include "config.h"
#ifdef AIX
#include <netinet/if_ether.h>
#endif
#ifdef AUX
#include <compat.h>
#endif
#include <netinet/in_systm.h>
#define FTP_NAMES
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <setjmp.h>
#include <errno.h>
#include <string.h>
#ifdef INTERNAL_LS
#ifdef HAVE_GLOB_H
#include <glob.h>
#else
#include <wuftpd_glob.h>
#endif
#endif
#ifdef HAVE_GRP_H
#include <grp.h>
#endif
#include "proto.h"
#ifdef HAVE_UFS_QUOTA_H
#endif
#ifdef HAVE_SYS_FS_UFS_QUOTA_H
#endif
#ifdef HAVE_SYS_SYSLOG_H
#endif
#include <syslog.h>
#endif
#ifdef TIME_WITH_SYS_TIME
#include <time.h>
#else
#ifdef HAVE_SYS_TIME_H
#else
#include <time.h>
#endif
#endif
#ifdef HAVE_SYS_SENDFILE_H
#include <sys/sendfile.h>
#endif
#include "conversions.h"
#include "extensions.h"
#ifdef SHADOW_PASSWORD
#include <shadow.h>
#endif
#include "pathnames.h"
#ifdef M_UNIX
#include <resolv.h>
#endif
#if defined(HAVE_FCNTL_H)
#include <fcntl.h>
#endif
#ifdef HAVE_SYSINFO
#include <sys/systeminfo.h>
#endif
#ifdef KERBEROS
#include <auth.h>
#include <krb.h>
#endif
#ifdef ULTRIX_AUTH
#include <auth.h>
#endif
#ifndef HAVE_LSTAT
#endif
#ifdef AFS_AUTH
#endif
#ifdef DCE_AUTH
#include <dce/sec_login.h>
#include <dce/dce_error.h>
#endif
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#else
#endif
#if defined(USE_LONGJMP)
#define wu_longjmp(x, y) longjmp((x), (y))
#ifndef JMP_BUF
#endif
#else
#define wu_longjmp(x, y) siglongjmp((x), (y))
#ifndef JMP_BUF
#define JMP_BUF sigjmp_buf
#endif
#endif
#ifndef MAXHOSTNAMELEN
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#endif
#ifdef MAIL_ADMIN
#define MAILSERVERS 10
#define INCMAILS 10
int mailservers = 0;
char *mailserver[MAILSERVERS];
int incmails = 0;
char *mailfrom;
char *email(char *full_address);
#endif /* MAIL_ADMIN */
#endif
/* File containing login names NOT to be used on this machine. Commonly used
* to disallow uucp. */
extern int errno;
#ifndef NO_CRYPT_PROTO
extern char *crypt(const char *, const char *);
#endif
extern char version[];
extern char *home; /* pointer to home directory for glob */
extern char cbuf[];
extern off_t restart_point;
extern int yyerrorcalled;
struct SOCKSTORAGE ctrl_addr;
struct SOCKSTORAGE data_source;
struct SOCKSTORAGE data_dest;
struct SOCKSTORAGE his_addr;
struct SOCKSTORAGE pasv_addr;
struct SOCKSTORAGE vect_addr;
int route_vectored = 0;
int passive_port_min = 1024;
int passive_port_max = 65535;
int restricted_user = 0;
unsigned short data_port = 0;
#ifdef INET6
int ctrl_v4mapped = 0;
int epsv_all = 0;
int listen_v4 = 0; /* when set, listen on IPv4 socket in standalone mode */
#endif
#ifdef VIRTUAL
char virtual_root[MAXPATHLEN];
char virtual_banner[MAXPATHLEN];
char virtual_email[MAXPATHLEN];
char virtual_hostname[MAXHOSTNAMELEN];
char virtual_address[MAXHOSTNAMELEN];
extern int virtual_mode;
extern int virtual_ftpaccess;
#endif
#ifdef QUOTA
#endif
#if defined(USE_GSS)
#include "gssutil.h"
extern gss_info_t gss_info;
int allow_ccc = 0;
int ccc_ok = 0;
extern char *cur_auth_type;
#endif /* USE_GSS */
int data;
int logged_in = 0;
char chroot_path[MAXPATHLEN];
int debug = 0;
int disable_rfc931 = 0;
extern unsigned int timeout_idle;
extern unsigned int timeout_maxidle;
extern unsigned int timeout_data;
extern unsigned int timeout_accept;
extern unsigned int timeout_connect;
/* previously defaulted to 1, and -l or -L set them to 1, so that there was
no way to turn them *off*! Changed so that the manpage reflects common
sense. -L is way noisy; -l we'll change to be "just right". _H */
int logging = 0;
int log_commands = 0;
int log_security = 0;
int syslogmsg = 0;
static int wtmp_logging = 1;
#ifdef SECUREOSF
#define SecureWare /* Does this mean it works for all SecureWare? */
#endif
#ifdef HPUX_10_TRUSTED
#include <hpsecurity.h>
#endif
#if defined(SecureWare) || defined(HPUX_10_TRUSTED)
#include <prot.h>
#endif
int anonymous = 1;
int guest;
int type;
int form;
int stru; /* avoid C keyword */
int mode;
int transflag;
int ftwflag;
int TCPwindowsize = 0; /* 0 = use system default */
#ifdef TRANSFER_COUNT
off_t data_count_in = 0;
off_t data_count_out = 0;
off_t byte_count_in = 0;
off_t byte_count_out = 0;
int file_count_total = 0; /* total number of data files */
int file_count_in = 0;
int file_count_out = 0;
int xfer_count_total = 0; /* total number of transfers */
int xfer_count_in = 0;
int xfer_count_out = 0;
#ifdef TRANSFER_LIMIT
int file_limit_raw_in = 0;
int file_limit_raw_out = 0;
int file_limit_raw_total = 0;
int file_limit_data_in = 0;
int file_limit_data_out = 0;
int file_limit_data_total = 0;
off_t data_limit_raw_in = 0;
off_t data_limit_raw_out = 0;
off_t data_limit_data_in = 0;
off_t data_limit_data_out = 0;
#ifdef RATIO /* 1998/08/04 K.Wakui */
off_t total_free_dl = 0;
int upload_download_rate = 0;
int freefile;
int is_downloadfree( char * );
#endif /* RATIO */
#endif
#endif
static char *RootDirectory = NULL;
#define CMASK 022
#endif
#ifdef ALTERNATE_CD
char defhome[] = "/";
#endif
char tmpline[7];
char hostname[MAXHOSTNAMELEN];
char remotehost[MAXHOSTNAMELEN];
char remoteaddr[MAXHOSTNAMELEN];
char *remoteident = "[nowhere yet]";
#define MAXUSERNAMELEN 256
char the_user[MAXUSERNAMELEN];
/* Access control and logging passwords */
/* OFF by default. _H */
int use_accessfile = 0;
char guestpw[MAXHOSTNAMELEN];
char privatepw[MAXHOSTNAMELEN];
int nameserved = 0;
extern char authuser[];
extern int authenticated;
extern int keepalive;
/* File transfer logging (xferlog) */
int xferlog = 0;
int log_outbound_xfers = 0;
int log_incoming_xfers = 0;
char logfile[MAXPATHLEN];
/* Allow use of lreply(); this is here since some older FTP clients don't
* support continuation messages. In violation of the RFCs... */
int dolreplies = 1;
/* Spontaneous reply text. To be sent along with next reply to user */
int autospout_free = 0;
/* allowed on-the-fly file manipulations (compress, tar) */
int mangleopts = 0;
/* number of login failures before attempts are logged and FTP *EXITS* */
int lgi_failure_threshold = 5;
/* Timeout intervals for retrying connections to hosts that don't accept PORT
* cmds. This is a kludge, but given the problems with TCP... */
void setproctitle(const char *fmt,...);
void initsetproctitle(int, char **, char **);
#ifndef HAVE_VSNPRINTF
#endif
#ifndef HAVE_SNPRINTF
#endif
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SKEY
#include <skey.h>
int pwok = 0;
#endif
#ifdef OPIE
#include <opie.h>
int pwok = 0;
int af_pwok = 0;
#endif
#ifdef KERBEROS
void init_krb();
void end_krb();
char krb_ticket_name[100];
#endif /* KERBEROS */
#ifdef ULTRIX_AUTH
#endif
#ifdef USE_PAM
#if defined(ULTRIX_AUTH) || defined(SECUREOSF) || defined(KERBEROS) || defined(SKEY) || defined (OPIE) || defined (BSD_AUTH)
#endif
#include <security/pam_appl.h>
#endif
#ifndef INTERNAL_LS
/* ls program commands and options for lreplies on and off */
#endif
#define FTPD_OPTS ":4aAdiIlLoP:qQr:t:T:u:vVwWxX"
#if defined(DAEMON)
# define DAEMON_OPTS "p:sS"
#else /* !(defined(DAEMON)) */
# define DAEMON_OPTS
#endif /* !(defined(DAEMON)) */
#if defined(USE_GSS)
# define GSS_OPTS "CK"
#else /* !(defined(USE_GSS)) */
# define GSS_OPTS
#endif /* !(defined(USE_GSS)) */
/* Some systems use one format, some another. This takes care of the garbage */
#ifndef L_FORMAT /* Autoconf detects this... */
#define L_FORMAT "qd"
#else
#ifdef _AIX42
#define L_FORMAT "lld"
#else
#ifdef SOLARIS_2
#define L_FORMAT "ld"
#else
#define L_FORMAT "d"
#endif
#endif
#endif
#endif
#ifdef DAEMON
int be_daemon = 0; /* Run standalone? */
int daemon_port = 0;
static void do_daemon(void);
#endif
int Bypass_PID_Files = 0;
#ifdef OTHER_PASSWD
#include "getpwnam.h"
char _path_passwd[MAXPATHLEN];
#ifdef SHADOW_PASSWORD
char _path_shadow[MAXPATHLEN];
#endif
#endif
#if defined(USE_PAM) && defined(OTHER_PASSWD)
int use_pam = 1;
#else
int use_pam = 0;
#endif
void print_copyright(void);
void dolog(struct SOCKSTORAGE *);
#ifdef THROUGHPUT
extern void throughput_calc(char *, int *, double *);
extern void throughput_adjust(char *);
#endif
time_t limit_time = 0;
int pasv_allowed(char *remoteaddr);
int port_allowed(char *remoteaddr);
#endif
{
}
{
if (draconian_FILE != NULL) {
}
}
{
static int first_time = TRUE;
char c;
int set;
if (first_time) {
/* flush-wait yes|no [typelist] */
if (!ARG0)
continue;
else
continue;
if (!ARG1)
else if (type_match(ARG1)) {
break;
}
}
first_time = FALSE;
}
if (flushwait) {
if (draconian_FILE != NULL)
if (draconian_FILE != NULL)
}
/*
* GAL - the read() here should be checked to ensure it returned 0 (indicating
* EOF) or -1 (an error occurred). Anything else (real data) is a protocol
* error.
*/
}
static int IPClassOfService(const char *type)
{
char *endp;
/* ipcos control|data <value> [<typelist>] */
if (!ARG2) {
errno = 0;
}
else if (type_match(ARG2)) {
errno = 0;
break;
}
}
}
}
}
return ipcos;
}
{
#else
int addrlen;
#endif
int on = 1;
int cos;
int c;
#ifndef INTERNAL_LS
int which;
#endif
extern int optopt;
extern char *optarg;
char *hp;
#ifdef VIRTUAL
#else
int virtual_len;
#endif
struct SOCKSTORAGE virtual_addr;
#endif
#ifdef AUX
#endif
closelog();
#ifdef FACILITY
#else
#endif
#ifdef SecureWare
setreuid(0, 0);
#endif
res_init(); /* bug in old (1.1.1) resolver */
#endif
switch (c) {
case '4':
#ifdef INET6
listen_v4 = 1;
#endif
break;
case 'a':
use_accessfile = 1;
break;
case 'A':
use_accessfile = 0;
break;
case 'v':
debug = 1;
break;
case 'd':
debug = 1;
break;
#if defined(USE_GSS)
case 'C':
break;
case 'K':
break;
#endif /* USE_GSS */
case 'l':
logging = 1;
break;
case 'L':
log_commands = 3;
break;
case 'i':
log_incoming_xfers = 3;
break;
case 'I':
disable_rfc931 = 1;
break;
case 'o':
log_outbound_xfers = 3;
break;
case 'q':
Bypass_PID_Files = 0;
break;
case 'Q':
Bypass_PID_Files = 1;
break;
case 'r':
if (RootDirectory != NULL)
}
break;
case 'P':
break;
#ifdef DAEMON
case 'p':
break;
case 's':
be_daemon = 1;
break;
case 'S':
be_daemon = 2;
break;
#endif /* DAEMON */
case 't':
if (timeout_maxidle < timeout_idle)
break;
case 'T':
if (timeout_idle > timeout_maxidle)
break;
case 'u':
{
unsigned int val = 0;
else
break;
}
case 'V':
exit(0);
/* NOTREACHED */
case 'w':
wtmp_logging = 1;
break;
case 'W':
wtmp_logging = 0;
break;
case 'x':
syslogmsg = 2;
break;
case 'X':
syslogmsg = 1;
break;
case ':':
break;
default:
break;
}
}
/* Checking for random signals ... */
#ifdef NEED_SIGFIX
#endif
#ifndef SIG_DEBUG
#ifdef SIGHUP
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGINT
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGQUIT
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGILL
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGTRAP
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGIOT
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGEMT
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGFPE
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGKILL
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGBUS
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGSEGV
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGSYS
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGALRM
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGSTOP
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGTSTP
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGTTIN
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGTTOU
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGIO
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGXCPU
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGXFSZ
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGWINCH
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGVTALRM
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGPROF
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGUSR1
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGUSR2
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGPIPE
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGCHLD
#ifdef NEED_SIGFIX
#endif
#endif
#ifdef SIGURG
#ifdef NEED_SIGFIX
#endif
#endif
#endif /* SIG_DEBUG */
#ifdef VIRTUAL
virtual_root[0] = '\0';
virtual_banner[0] = '\0';
#endif
setup_paths();
#ifdef OTHER_PASSWD
#ifdef SHADOW_PASSWORD
#endif
#endif
access_init();
#ifdef DAEMON
if (be_daemon != 0)
do_daemon();
else {
#endif
#ifndef DEBUG
exit(1);
#endif
}
#ifdef DAEMON
}
#endif
#ifndef DEBUG
exit(1);
#endif
}
/* Sanity check */
#ifdef INET6
#endif
) {
#ifndef DEBUG
exit(1);
#endif
}
#ifdef SOLARIS_BSM_AUDIT
/* Set audit characteristics */
if (audit_settid(0)) {
exit(1);
}
#endif
#ifdef INET6
/* IP_TOS is an IPv4 socket option */
#endif
}
#ifdef TCP_NODELAY
/*
* Disable Nagle on the control channel so that we don't have to wait
* for peer's ACK before issuing our next reply.
*/
#endif
if (keepalive)
/* Try to handle urgent data inline */
#ifdef SO_OOBINLINE
#endif
#ifdef F_SETOWN
{
int pid;
}
#endif
#ifdef INET6
ctrl_v4mapped = 1;
#endif
if (data_port == 0) {
else
}
if (RootDirectory != NULL) {
if ((chroot(RootDirectory) < 0)
|| (chdir("/") < 0)) {
exit(1);
}
}
/* set resolver options */
/* Set up default state */
data = -1;
tmpline[0] = '\0';
yyerrorcalled = 0;
}
else {
#ifdef HAVE_SYSINFO
#else
#endif
/* set the FQDN here */
if (hp) {
}
}
conv_init();
#ifdef MAIL_ADMIN
incmails = 0;
#endif /* MAIL_ADMIN */
#ifdef VIRTUAL
/*
** If virtual_mode is set at this point then an alternate ftpaccess
** is in use. Otherwise we need to check the Master ftpaccess file
** to see if the site is only using the "virtual" directives to
** specify virtual site directives.
**
** In this manner an admin can put a virtual site in the ftpservers
** file if they need expanded configuration support or can use the
*/
if (virtual_mode) {
/* Get the root of the virtual server directory */
if (ARG0)
}
/* Get the logfile to use */
if (ARG0)
}
}
else {
virtual_hostname[0] = '\0';
virtual_address[0] = '\0';
virtual_len = sizeof(virtual_addr);
continue;
if (debug)
virtual_mode = 1;
/* reset hostname to this virtual name */
virtual_email[0] = '\0';
}
}
}
}
}
#ifdef OTHER_PASSWD
#ifdef USE_PAM
use_pam = 0;
#endif
}
#ifdef SHADOW_PASSWORD
#ifdef USE_PAM
use_pam = 0;
#endif
}
#endif
#endif
#ifdef MAIL_ADMIN
}
}
#endif
}
}
if (!virtual_mode) {
continue;
#ifdef MAIL_ADMIN
}
}
#endif
}
}
}
}
#ifdef VIRTUAL_DEBUG
if (virtual_mode) {
if (virtual_ftpaccess)
else
if (!virtual_ftpaccess)
}
#endif
#endif
hostname);
exit(0);
}
#ifdef OPIE
#endif
/* check permitted access based on name and address lookup of remote host */
if (!check_rhost_reverse()) {
exit(0);
}
if (!check_rhost_matches()) {
exit(0);
}
show_banner(220);
#ifndef INTERNAL_LS
}
}
else {
#else
#endif
#else
#endif
}
}
}
else {
#else
#endif
#else
#endif
}
}
}
else
#endif /* ! INTERNAL_LS */
#ifdef MAIL_ADMIN
mailservers = 0;
if (mailservers == 0)
if (incmails == 0) {
}
else
}
#endif /* MAIL_ADMIN */
{
int version_option = 0;
int which;
version_option = 0;
version_option = 3;
version_option = 2;
version_option = 1;
}
switch (version_option) {
default:
break;
case 1:
break;
case 2:
break;
case 3:
output_text[0] = '\0';
if (which > 1)
}
break;
}
}
for (;;)
(void) yyparse();
/* NOTREACHED */
}
{
#ifdef HAVE_SIGLIST
#else
#endif
chdir("/");
exit(1);
/* dologout(-1); *//* NOTREACHED */
}
{
#ifdef VERBOSE_ERROR_LOGING
#else
if (debug)
#endif
dologout(-1);
}
static char ttyline[20];
#ifdef MAPPING_CHDIR
/* Keep track of the path the user has chdir'd into and respond with
* that to pwd commands. This is to avoid having the absolue disk
* path returned, which I want to avoid.
*/
#if !defined(HAVE_GETCWD)
char *mapping_getwd(char *path)
{
return path;
}
#endif /* !defined(HAVE_GETCWD) */
{
return path;
}
/* Make these globals rather than local to mapping_chdir to avoid stack overflow */
char pathspace[MAXPATHLEN];
char old_mapped_path[MAXPATHLEN];
{
/* . */
/* ignore it */
return;
}
/* .. */
char *last;
/* lop the last directory off the path */
/* If start of pathname leave the / */
if (last == mapped_path)
last++;
*last = '\0';
}
return;
}
/* append the dir part with a leading / unless at root */
}
int mapping_chdir(char *orig_path)
{
int ret;
/* / at start of path, set the start of the mapped_path to / */
if (path[0] == '/') {
mapped_path[0] = '/';
path++;
}
char *dir;
*sl = '\0';
if (*dir)
if (*path == '\0')
break;
}
if (*path)
}
return ret;
}
/* From now on use the mapping version */
#define chdir(d) mapping_chdir(d)
#define getwd(d) mapping_getwd(d)
#define getcwd(d,u) mapping_getcwd((d),(u))
#endif /* MAPPING_CHDIR */
/* Helper function for sgetpwnam(). */
char *sgetsave(char *s)
{
char *new;
dologout(1);
/* NOTREACHED */
}
return (new);
}
/* Save the result of a getpwnam. Used for USER command, since the data
* returned must not be clobbered by any other command (e.g., globbing). */
{
register struct passwd *p;
#ifdef M_UNIX
#endif
char *sgetsave(char *s);
#ifdef KERBEROS
register struct authorization *q;
#endif /* KERBEROS */
#if defined(SecureWare) || defined(HPUX_10_TRUSTED)
#endif
#ifdef KERBEROS
init_krb();
q = getauthuid(p->pw_uid);
end_krb();
#endif /* KERBEROS */
#ifdef M_UNIX
#if defined(SecureWare) || defined(HPUX_10_TRUSTED)
goto DONE;
#endif /* SecureWare || HPUX_10_TRUSTED */
#ifdef OTHER_PASSWD
#else
#endif
goto DONE;
#else /* M_UNIX */
#if defined(SecureWare) || defined(HPUX_10_TRUSTED)
#endif /* SecureWare || HPUX_10_TRUSTED */
#ifdef OTHER_PASSWD
#else
#endif
return (p);
#endif /* M_UNIX */
save = *p;
#ifdef KERBEROS
else
#else
#endif
#ifdef SHADOW_PASSWORD
#ifdef OTHER_PASSWD
#else
setspent();
#endif
int expired = 0;
/*XXX Does this work on all Shadow Password Implementations? */
/* it is supposed to work on Solaris 2.x */
long today;
expired++;
expired++;
}
/* Don't overwrite the password if the shadow read fails, getpwnam() is NIS
aware but getspnam() is not. */
/* Shadow passwords are optional on Linux. --marekm */
else {
}
#endif
/* marekm's fix for linux proc file system shadow passwd exposure problem */
#ifndef OTHER_PASSWD
endspent();
#endif
}
#endif
#ifdef M_UNIX
DONE:
endpwent();
#endif
#if defined(SecureWare) || defined(HPUX_10_TRUSTED)
endprpwent();
#endif
#ifdef M_UNIX
return (ret);
#else
return (&save);
#endif
}
#if defined(SKEY) && !defined(__NetBSD__)
/*
* From Wietse Venema, Eindhoven University of Technology.
*/
/* skey_challenge - additional password prompt stuff */
{
static char buf[128];
char sbuf[40];
else
return (buf);
}
#endif
int login_attempts; /* number of failed login attempts */
int askpasswd; /* had user command, ask for passwd */
#ifndef HELP_CRACKERS
char DelayedMessageFile[MAXPATHLEN];
#endif
#if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
static int defaultserver_allow(const char *username)
{
int which;
return (1);
return (0);
}
static int defaultserver_deny(const char *username)
{
int which;
return (1);
return (0);
}
static int defaultserver_private(void)
{
return (1);
return (0);
}
#endif
/* USER command. Sets global passwd pointer pw if named account exists and is
* acceptable; sets askpasswd if a PASS command is expected. If logged in
* previously, need to reset state. If name is "ftp" or "anonymous", the
* name is not in the ftpusers file, and ftp account exists, set anonymous and
* pw, then just return. If account doesn't exist, ask for passwd anyway.
* Otherwise, check user requesting login privileges. Disallow anyone who
* does not have a standard shell as returned by getusershell(). Disallow
* anyone mentioned in the ftpusers file to allow people such as root and
* uucp to be avoided. */
/*
char *getusershell();
*/
{
char *cp;
char *shell;
#ifdef BSD_AUTH
char *auth;
#endif
#if defined(USE_GSS)
int gss_need_passwd = 1;
#endif
/* H* fix: if we're logged in at all, we can't log in again. */
if (logged_in) {
#ifdef VERBOSE_ERROR_LOGING
#endif
return;
}
#ifndef HELP_CRACKERS
askpasswd = 1;
DelayedMessageFile[0] = '\0';
#endif
#ifdef BSD_AUTH
*auth++ = 0;
#endif
#ifdef HOST_ACCESS /* 19-Mar-93 BM */
#ifndef HELP_CRACKERS
#else
"FTP LOGIN REFUSED (name in %s) FROM %s, %s",
return;
#endif
}
#endif
anonymous = 0;
guest = 0;
int machineok = 1;
char guestservername[MAXHOSTNAMELEN];
guestservername[0] = '\0';
#ifdef NO_ANONYMOUS_ACCESS
remoteident, name);
return;
#else
#if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
if (!virtual_mode && defaultserver_private()) {
#ifndef HELP_CRACKERS
remoteident, name);
#else
"FTP LOGIN REFUSED (anonymous ftp denied on default server) FROM %s, %s",
remoteident, name);
return;
#endif
}
#endif
#ifndef HELP_CRACKERS
#else
"FTP LOGIN REFUSED (ftp in %s) FROM %s, %s",
return;
#endif
/*
** Algorithm used:
** - if no "guestserver" directive is present,
** anonymous access is allowed, for backward compatibility.
** - if a "guestserver" directive is present,
** anonymous access is restricted to the machines listed,
** usually the machine whose CNAME on the current domain
** is "ftp"...
**
** the format of the "guestserver" line is
** guestserver [<machine1> [<machineN>]]
** that is, "guestserver" will forbid anonymous access on all machines
** while "guestserver ftp inf" will allow anonymous access on
** the two machines whose CNAMES are "ftp.enst.fr" and "inf.enst.fr".
**
** if anonymous access is denied on the current machine,
** the user will be asked to use the first machine listed (if any)
** on the "guestserver" line instead:
** 530- Guest login not allowed on this machine,
** connect to ftp.enst.fr instead.
**
** -- <Nicolas.Pioch@enst.fr>
*/
}
char *tmphost;
/*
** if a "guestserver" line is present,
** default is not to allow guest logins
*/
machineok = 0;
if (hostname[0]
/*
** hostname is the only first part of the FQDN
** this may or may not correspond to the h_name value
** (machines with more than one IP#, CNAMEs...)
** -> need to fix that, calling gethostbyname on hostname
**
** WARNING!
** for SunOS 4.x, you need to have a working resolver in the libc
** for CNAMES to work properly.
** If you don't, add "-lresolv" to the libraries before compiling!
*/
char dns_localhost[MAXHOSTNAMELEN];
int machinecount;
for (machinecount = 0;
machinecount++) {
/*
** remember the name of the first machine for redirection
*/
if (!machinecount) {
sizeof(guestservername));
}
machineok++;
break;
}
}
}
}
}
if (!machineok) {
if (guestservername[0])
reply(530,
"Guest login not allowed on this machine, connect to %s instead.",
else
reply(530,
"Guest login not allowed on this machine.");
"FTP LOGIN REFUSED (localhost not in guestservers) FROM %s, %s",
remoteident, name);
/* End of the big patch -- Nap */
dologout(0);
}
#ifndef HELP_CRACKERS
remoteident, name);
#else
"FTP LOGIN REFUSED (access denied) FROM %s, %s",
remoteident, name);
dologout(0);
#endif
}
else {
askpasswd = 1;
/* H* fix: obey use_accessfile a little better. This way, things set on the
command line [like xferlog stuff] don't get stupidly overridden.
if (use_accessfile)
}
}
else {
#ifndef HELP_CRACKERS
remoteident, name);
#else
remoteident, name);
#endif
#ifdef SOLARIS_BSM_AUDIT
#endif
}
return;
#endif
}
#ifdef ANON_ONLY
/* H* fix: define the above to completely DISABLE logins by real users,
despite ftpusers, shells, or any of that rot. You can always hang your
"real" server off some other port, and access-control it. */
else { /* "ftp" or "anon" -- MARK your conditionals, okay?! */
#ifndef HELP_CRACKERS
remoteident, name);
#else
"FTP LOGIN REFUSED (not anonymous) FROM %s, %s",
remoteident, name);
#endif
return;
}
/* fall here if username okay in any case */
#endif /* ANON_ONLY */
#if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
#ifndef HELP_CRACKERS
remoteident, name);
#else
"FTP LOGIN REFUSED (ftp denied on default server) FROM %s, %s",
remoteident, name);
return;
#endif
}
#endif
#if defined(USE_GSS)
if (gss_info.must_gss_auth &&
(!IS_GSSAUTH(cur_auth_type) ||
return;
}
#endif /* USE_GSS */
#ifndef HELP_CRACKERS
remoteident, name);
#else
"FTP LOGIN REFUSED (username in denied-uid) FROM %s, %s",
remoteident, name);
#endif
return;
}
#if defined(USE_GSS)
if (IS_GSSAUTH(cur_auth_type) &&
if (gss_info.must_gss_auth &&
!GSSUSERAUTH_OK(gss_info)) {
if (logging)
remoteident, name);
return;
}
/*
* If GSSAPI user auth failed, or it succeeded but creds were
* not forwarded as required, prompt for password.
*/
(GSSUSERAUTH_OK(gss_info) &&
if (gss_need_passwd) {
"GSSAPI user %s is authorized as %s password required",
askpasswd = 1;
return;
}
}
#endif /* defined(USE_GSS) */
#if !defined(USE_PAM) || (defined(USE_PAM) && defined(OTHER_PASSWD)) || defined(SOLARIS_2) /* PAM should be doing these checks, not ftpd */
if(!use_pam) {
#endif
break;
endusershell();
#ifndef HELP_CRACKERS
else
syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in %s) FROM %s, %s", _path_ftpusers, remoteident, name);
#else
else
syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in %s) FROM %s, %s", _path_ftpusers, remoteident, name);
#endif /* HELP_CRACKERS */
return;
}
} /* if(!use_pam) */
#endif
#endif /* !USE_PAM || (USE_PAM && OTHER_PASSWD) || SOLARIS_2 */
/* if user is a member of any of the guestgroups, cause a chroot() */
/* after they log in successfully */
if (use_accessfile) { /* see above. _H */
guest = 0;
}
}
#ifndef HELP_CRACKERS
remoteident, name);
#else
remoteident, name);
#endif
return;
}
else if (use_accessfile) /* see above. _H */
#ifdef BSD_AUTH
char *s;
for (;;) {
break;
}
}
else {
#endif /* BSD_AUTH */
#ifdef SKEY
#ifndef __NetBSD__
#ifdef SKEY_NAME
/* this is the old way, but freebsd uses it */
#else
/* this is the new way */
#endif /* SKEY_NAME */
#else
if (skey_haskey(name) == 0) {
char *myskey;
}
else
#endif /* __NetBSD__ */
#else
#ifdef OPIE
{
if (askpasswd == -1) {
pwok = 0;
}
else
}
#else /* !SKEY */
#if defined(USE_GSS)
/*
* We got this far, we are allowing the GSSAPI authentication
* to succeed without further passwd prompting. Jump
* to "pass" processing.
*/
askpasswd = 0;
logged_in = 1;
pass("");
return;
}
#endif /* defined(USE_GSS) */
#endif /* OPIE */
#endif /* SKEY */
#ifdef BSD_AUTH
}
#endif /* BSD_AUTH */
askpasswd = 1;
/* Delay before reading passwd after first failed attempt to slow down
* passwd-guessing programs. */
if (login_attempts) {
enable_signaling(); /* we can allow signals once again: kinch */
sleep((unsigned) login_attempts);
}
return;
}
/* Check if a user is in the ftpusers file */
{
register char *p;
#ifdef SOLARIS_ETC_FTPUSERS
static int etc_ftpusers = 0;
if (etc_ftpusers) {
etc_ftpusers = 0;
}
#endif
*p = '\0';
if (line[0] == '#')
continue;
#ifdef SOLARIS_BSM_AUDIT
#endif
#ifdef SOLARIS_ETC_FTPUSERS
if (etc_ftpusers)
#endif
return (1);
}
}
}
#ifdef SOLARIS_ETC_FTPUSERS
etc_ftpusers = 1;
goto retry;
}
#endif
return (0);
}
{
int which;
char *ptr;
/*
* keyword <uid-range> [<uid-range> ...]
*
* uid-range may be a username or begin with '%' and be treated as numeric:
* %<uid> A single numeric UID
* %<uid>+ All UIDs greater or equal to UID
* %<uid>- All UIDs greater or equal to UID
* %-<uid> All UIDs less or equal to UID
* %<uid>-<uid> All UIDs between the two (inclusive)
* * All UIDs
*/
return (1);
return (1);
}
else {
*ptr++ = '\0';
*--ptr = '+';
return (1);
}
*--ptr = '+';
}
}
else {
*ptr++ = '\0';
&& ((*ptr == '\0')
*--ptr = '-';
return (1);
}
*--ptr = '-';
}
}
else {
#ifdef OTHER_PASSWD
#else
#endif
return (1);
}
}
}
return (0);
}
{
int which;
char *ptr;
char **member;
/*
* keyword <gid-range> [<gid-range> ...]
*
* gid-range may be a groupname or begin with '%' and be treated as numeric:
* %<gid> A single GID
* %<gid>+ All GIDs greater or equal to GID
* %<gid>- All GIDs greater or equal to GID
* %-<gid> All GIDs less or equal to GID
* %<gid>-<gid> All GIDs between the two (inclusive)
* * All GIDs
*/
return (1);
return (1);
}
else {
*ptr++ = '\0';
*--ptr = '+';
return (1);
}
*--ptr = '+';
}
}
else {
*ptr++ = '\0';
&& ((*ptr == '\0')
*--ptr = '-';
return (1);
}
*--ptr = '-';
}
}
else {
return (1);
if (username) {
return (1);
}
}
}
}
}
return (0);
}
{
}
{
}
{
}
{
}
/* Terminate login as previous user, if any, resetting state; used when USER
* command is given or login fails. */
void end_login(void)
{
delay_signaling(); /* we can't allow any signals while euid==0: kinch */
if (logged_in) {
if (wtmp_logging)
#ifdef USE_PAM
(void) pam_close_session(pamh, 0);
pamh = (pam_handle_t *)0;
}
#endif
}
#ifdef AFS_AUTH
#endif
logged_in = 0;
anonymous = 0;
guest = 0;
}
int validate_eaddr(char *eaddr)
{
switch (eaddr[i]) {
case '.':
if (!host)
return 0;
if (state == 2)
state = 3;
host = 0;
break;
case '@':
return 0;
state = 2;
host = 0;
break;
case '!':
case '%':
return 0;
state = 1;
host = 0;
break;
case '-':
break;
default:
host++;
}
}
return 1;
else
return 0;
}
#if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
static int AllowVirtualUser(const char *username)
{
int which;
return (1);
return (0);
}
static int DenyVirtualUser(const char *username)
{
int which;
return (1);
return (0);
}
static int DenyVirtualAnonymous(void)
{
return (1);
return (0);
}
#endif
{
#endif
int passwarn = 0;
int rval = 1;
int success_code = 230;
int cos;
#ifdef SECUREOSF
int crypt_alg = 0;
#endif
#ifdef BSD_AUTH
extern int ext_auth;
extern char *check_auth();
#endif
#ifdef ULTRIX_AUTH
int numfails;
#endif /* ULTRIX_AUTH */
#ifdef HAS_PW_EXPIRE
int set_expired = FALSE;
#endif
#ifdef AFS_AUTH
char *reason;
#endif /* AFS_AUTH */
#ifdef DCE_AUTH
#endif /* DCE_AUTH */
#if defined(USE_GSS)
/*
* LOGIC:
* If [ the user presented GSSAPI creds and was authorized ]
* jump down past the password validation code.
*/
/*
* We could reply(202, "PASS command superfluous.") here, but
* allow this for compat with some clients.
*/
success_code = 232;
goto pwd_validation_done;
}
#endif /* defined(USE_GSS) */
#ifdef VERBOSE_ERROR_LOGING
#endif
return;
}
askpasswd = 0;
/* Disable lreply() if the first character of the password is '-' since
* some hosts don't understand continuation messages and hang... */
if (*passwd == '-')
dolreplies = 0;
else
dolreplies = 1;
if (!anonymous) { /* "ftp" is only account allowed no password */
#ifndef HELP_CRACKERS
if (DenyLoginAfterPassword) {
#ifdef SOLARIS_BSM_AUDIT
#endif
acl_remove();
if (++login_attempts >= lgi_failure_threshold) {
exit(0);
}
return;
}
#endif
if (*passwd == '-')
passwd++;
#ifdef USE_PAM
#ifdef OTHER_PASSWD
if (use_pam
#if defined(USE_GSS)
&& !GSSUSERAUTH_OK(gss_info)
#endif
) {
#endif
/* PAM authentication
* If PAM authenticates a user we know nothing about on the local
* system, use the generic guest account credentials. We should make
* this somehow a configurable item somewhere; later more on that.
*
* For now assume the guest (not anonymous) identity, so the site
* admins can still differentiate between the truw anonymous user and
* a little bit more special ones. Otherwise he wouldn't go the extra
* mile to have a different user database, right?
* --gaftonc */
rval = 0;
/* assume guest account identity */
anonymous = 0;
guest = 1;
/* even go as far as... */
}
}
}
#ifdef OTHER_PASSWD
} else {
#endif
#endif /* USE_PAM */
#ifdef BSD_AUTH
if (ext_auth) {
#ifdef LOG_FAILED /* 27-Apr-93 EHK/BM */
/*
* To avoid logging passwords mistakenly entered as
* usernames, only log the names of users which exist.
*/
#endif /* LOG_FAILED */
acl_remove();
if (++login_attempts >= lgi_failure_threshold) {
exit(0);
}
return;
}
}
else {
#endif /* BSD_AUTH */
*guestpw = '\0';
salt = "xx";
else
#ifndef OPIE
#ifdef SECUREOSF
else
crypt_alg = 0;
}
else
crypt_alg = 0;
#ifndef __NetBSD__
pwok = 0;
#else
else
#endif
#else /* !SKEY */
#endif /* SKEY */
#else /* OPIE */
rval = 0;
#endif /* OPIE */
#ifdef ULTRIX_AUTH
#else
#ifdef AFS_AUTH
if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION | KA_USERAUTH_DOSETPAG, pw->pw_name, "", 0, passwd, 0, 0, 0, &reason) == 0)
rval = 0;
else
else
#endif /* AFS_AUTH */
/* The strcmp does not catch null passwords! */
#ifdef HAS_PW_EXPIRE
set_expired = TRUE;
}
}
#endif
#ifdef HAS_PW_EXPIRE
!set_expired &&
#endif
#endif
rval = 0;
}
#ifdef DCE_AUTH
#ifndef ALWAYS_TRY_DCE
else
#endif /* ALWAYS_TRY_DCE */
{
if (status == error_status_ok) {
printf("230-sec_login_setup_identity OK\n");
/* validate password with login context */
printf("230-sec_login_valid_and_cert_ident OK\n");
printf("230-sec_login_set_context finished\n");
if (status != error_status_ok) {
int pstatus;
printf("230-%s\n", s);
}
else {
/*sec_login_get_pwent(lhdl, &pw, &status); */
rval = 0;
}
}
}
}
#endif /* DCE_AUTH */
}
#ifdef USE_PAM
}
#endif
#endif /* !USE_PAM || (USE_PAM && OTHER_PASSWD) */
if (rval) {
#ifdef LOG_FAILED /* 27-Apr-93 EHK/BM */
/* H* add-on: yell about attempts to use the trojan. This may alarm you
if you're "stringsing" the binary and you see "NULL" pop out in just
about the same place as it would have in 2.2c! */
else {
/*
* To avoid logging passwords mistakenly entered as
* usernames, only log the names of users which exist.
*/
}
#endif
#ifdef SOLARIS_BSM_AUDIT
#endif
acl_remove();
if (++login_attempts >= lgi_failure_threshold) {
exit(0);
}
return;
}
#ifdef BSD_AUTH
}
#endif
/* ANONYMOUS USER PROCESSING STARTS HERE */
}
else {
int valid;
int enforce = 0;
else
valid = 1;
enforce = 1;
/* Block off "default" responses like mozilla@ and IE30User@
* (at the administrator's discretion). --AC
*/
if (ARG0
|| ((*passwd == '-')
valid = 0;
break;
}
}
#ifdef VERBOSE_ERROR_LOGING
#endif
#ifdef SOLARIS_BSM_AUDIT
#endif
acl_remove();
if (++login_attempts >= lgi_failure_threshold) {
exit(0);
}
return;
}
else if (!valid)
passwarn = 1;
}
if (!*passwd) {
}
else {
*pwout++ = '_';
else
}
#ifndef HELP_CRACKERS
if (DenyLoginAfterPassword) {
#ifdef SOLARIS_BSM_AUDIT
#endif
acl_remove();
if (++login_attempts >= lgi_failure_threshold) {
exit(0);
}
return;
}
#endif
}
#if defined(USE_GSS)
#endif /* USE_GSS */
/* if logging is enabled, open logfile before chroot or set group ID */
if (xferlog < 0) {
xferlog = 0;
}
}
#ifdef DEBUG
/* I had a lot of trouble getting xferlog working, because of two factors:
acl_setfunctions making stupid assumptions, and sprintf LOSING. _H */
/*
* Actually, sprintf was not losing, but the rules changed... next release
* this will be fixed the correct way, but right now, it works well enough
* -- sob
*/
#endif
enable_signaling(); /* we can allow signals once again: kinch */
/* if autogroup command applies to user's class change pw->pw_gid */
(void) acl_autogroup(pw);
guest = 0;
}
/* END AUTHENTICATION */
/* SET GROUP ID STARTS HERE */
#ifndef AIX
#else
#endif
#ifdef DEBUG
#endif
/* WTMP PROCESSING STARTS HERE */
if (wtmp_logging) {
/* open wtmp before chroot */
#else
#endif
#ifdef DEBUG
#endif
}
logged_in = 1;
expand_id();
#ifdef QUOTA
#endif
restricted_user = 0;
if (!anonymous)
restricted_user = 1;
char *sp;
/* We MUST do a chdir() after the chroot. Otherwise the old current
* directory will be accessible as "." outside the new root! */
#ifdef ALTERNATE_CD
#endif
#ifdef VIRTUAL
if (virtual_mode && !guest) {
#ifdef CLOSED_VIRTUAL_SERVER
if (DenyVirtualAnonymous()) {
#ifdef VERBOSE_ERROR_LOGING
#endif
if (++login_attempts >= lgi_failure_threshold) {
dologout(0);
}
goto bad;
}
#endif
/* Anonymous user in virtual_mode */
}
else
#endif
/*
* New chroot logic.
*
* If VIRTUAL is supported, the chroot for anonymous users on the
* virtual host has already been determined. Otherwise the logic
* below applies:
*
* If this is an anonymous user, the chroot directory is determined
* by the "anonymous-root" clause and the home directory is taken
*
* If this a guest user, the chroot directory is determined by the
* "guest-root" clause and the home directory is taken from the
*
* The effect of this logic is that the entire chroot environment
* is under the control of the ftpaccess file and the supporting
* files in the ftp environment. The system-wide passwd file is
* used only to authenticate the user.
*/
{
if (anonymous) {
(void) acl_getclass(class);
if (!ARG1) {
if (!root_path)
}
else {
int which;
if (!root_path)
}
else {
}
}
}
}
}
else { /* (guest) */
if (!ARG1) {
if (!root_path)
}
else {
int which;
char *ptr;
if (!root_path)
}
else {
}
else {
*ptr++ = '\0';
*--ptr = '+';
}
}
else {
*ptr++ = '\0';
&& ((*ptr == '\0')
*--ptr = '-';
}
}
else {
#ifdef OTHER_PASSWD
#else
#endif
}
}
}
}
}
}
if (root_path) {
#if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
if (virtual_mode && strcmp(root_path, virtual_root) && !(AllowVirtualUser(pw->pw_name) && !DenyVirtualUser(pw->pw_name))) {
#ifdef VERBOSE_ERROR_LOGING
#endif
if (++login_attempts >= lgi_failure_threshold) {
dologout(0);
}
goto bad;
}
#endif
#ifdef VERBOSE_ERROR_LOGING
#endif
goto bad;
}
#ifdef OTHER_PASSWD
#else
#endif
goto slimy_hack; /* onea these days I'll make this structured code, honest ... */
}
}
/* determine root and home directory */
#if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
if (virtual_mode && strcmp(chroot_path, virtual_root) && !(AllowVirtualUser(pw->pw_name) && !DenyVirtualUser(pw->pw_name))) {
#ifdef VERBOSE_ERROR_LOGING
#endif
if (++login_attempts >= lgi_failure_threshold) {
dologout(0);
}
goto bad;
}
#endif
#ifdef VERBOSE_ERROR_LOGING
#endif
goto bad;
}
}
else {
*sp++ = '\0';
#if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
if (virtual_mode && strcmp(chroot_path, virtual_root) && !(AllowVirtualUser(pw->pw_name) && !DenyVirtualUser(pw->pw_name))) {
#ifdef VERBOSE_ERROR_LOGING
#endif
if (++login_attempts >= lgi_failure_threshold) {
dologout(0);
}
goto bad;
}
#endif
#ifdef VERBOSE_ERROR_LOGING
#endif
goto bad;
}
#ifdef ALTERNATE_CD
#endif
}
/* shut up you stupid compiler! */ {
int i = 0;
i++;
}
}
#if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
#ifdef VERBOSE_ERROR_LOGING
#endif
if (++login_attempts >= lgi_failure_threshold) {
dologout(0);
}
goto bad;
}
#endif
#ifdef AIX
{
/* AIX 3 lossage. Don't ask. It's undocumented. */
/* setgroups(NULL, NULL); */
#ifdef VERBOSE_ERROR_LOGING
#endif
goto bad;
}
}
#ifdef UID_DEBUG
#endif
#else /* AIX */
#ifdef HAVE_SETREUID
#else
#endif
#ifdef VERBOSE_ERROR_LOGING
#endif
goto bad;
}
#endif /* AIX */
#ifdef PARANOID
#ifdef VERBOSE_ERROR_LOGING
#endif
goto bad;
#else /* PARANOID */
#ifdef VERBOSE_ERROR_LOGING
#endif
goto bad;
}
else {
#ifdef ALTERNATE_CD
#endif
}
#endif /* PARANOID */
}
}
if (passwarn) {
"Next time please use your e-mail address as your password");
}
login_attempts = 0; /* this time successful */
/* following two lines were inside the next scope... */
#ifdef ULTRIX_AUTH
"There have been %d unsuccessful login attempts on your account",
numfails);
}
#endif /* ULTRIX_AUTH */
(void) is_shutdown(0, 0); /* display any shutdown messages now */
if (anonymous) {
(int) (sizeof(proctitle) - sizeof(remotehost) -
sizeof(": anonymous/")), passwd);
if (logging)
}
else {
" Access restrictions apply." : "");
if (logging)
/* H* mod: if non-anonymous user, copy it to "authuser" so everyone can
see it, since whoever he was @foreign-host is now largely irrelevant.
NMM mod: no, it isn't! Think about accounting for the transfers from or
to a shared account. */
/* strcpy (authuser, pw->pw_name); */
} /* anonymous */
#ifdef ALTERNATE_CD
if (!home)
#endif
time(&login_time);
{
}
#ifdef INET6
/* IP_TOS is an IPv4 socket option */
#endif
}
#ifdef SOLARIS_BSM_AUDIT
#endif
return;
bad:
/* Forget all about it... */
if (xferlog)
xferlog = 0;
acl_remove();
#ifdef SOLARIS_BSM_AUDIT
#endif
end_login();
return;
}
{
}
{
}
{
}
{
}
char *opt_string(int options)
{
static char buf[100];
*ptr++ = 'C';
*ptr++ = 'T';
if ((options & O_UNCOMPRESS) != 0)
*ptr++ = 'U';
if (options == 0)
*ptr++ = '_';
*ptr++ = '\0';
return (buf);
}
#ifdef INTERNAL_LS
{
char *a;
a[len] = 0;
else
return a;
}
{
{"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
char *permissions;
struct stat s;
struct tm *t;
char *ls_entry;
char *link;
#ifndef LS_NUMERIC_UIDS
#endif
return NULL;
permissions[0] = 'l';
if (classify)
classify = '@';
}
permissions[0] = 'd';
if (classify)
classify = '/';
}
permissions[0] = 'b';
permissions[0] = 'c';
permissions[0] = 'p';
if (classify == 1)
classify = '=';
}
#ifdef S_ISSOCK
permissions[0] = 's';
#endif
if (classify == 1)
classify = '*';
#ifndef HIDE_SETUID
#endif
}
#ifndef HIDE_SETUID
#endif
if (classify == 1)
classify = '*';
#ifndef HIDE_SETUID
#endif
}
#ifndef HIDE_SETUID
#endif
if (classify == 1)
classify = '*';
#ifndef HIDE_SETUID
#endif
}
#ifndef HIDE_SETUID
#endif
#ifndef LS_NUMERIC_UIDS
#ifdef OTHER_PASSWD
#else
#endif
#endif
if (s.st_uid == 0)
else {
#ifdef SOLARIS_2
#else
#endif
}
}
if (s.st_gid == 0)
else {
#ifdef SOLARIS_2
#else
#endif
}
}
#ifdef HAVE_LSTAT
}
}
#endif
#ifdef SOLARIS_2
#define N_FORMAT "lu"
#else
#if defined(__FreeBSD__) || defined(__bsdi__)
#define N_FORMAT "u"
#else
#define N_FORMAT "u"
#endif
#endif
if (nameonly) {
}
else {
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);
else {
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);
}
}
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);
else {
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);
}
}
if (classify > 1)
return ls_entry;
}
{
int total;
char *realdir; /* fixed up value to pass to glob() */
char **subdirs; /* Subdirs to be scanned for ls -R */
int numSubdirs = 0;
glob_t g;
char isDir; /* 0: d is a file; 1: d is some files; 2: d is dir */
struct stat s;
char *dirlist;
char *c;
char *lsentry;
int i;
#ifndef GLOB_PERIOD
char *dperiod;
#endif
isDir = 0;
realdir[0] = '*';
isDir = 1;
isDir = 2;
else {
isDir = 2;
}
}
}
if (isDir == 0) {
if (ls_l) {
if (draconian_FILE != NULL) {
#if defined(USE_GSS)
#else
#endif /* defined(USE_GSS) */
}
}
}
else {
if (draconian_FILE != NULL) {
#if defined(USE_GSS)
#else
#endif /* defined(USE_GSS) */
}
}
}
else {
if (ls_R) {
numSubdirs = 0;
}
dl_size = 65536;
dl_used = 0;
total = 0;
memset(&g, 0, sizeof(g));
if (ls_a) {
#ifdef GLOB_PERIOD
g.gl_pathc = 0;
#else
g.gl_pathc = 0;
#endif
}
g.gl_pathc = 0;
for (i = 0; i < g.gl_pathc; i++) {
c = g.gl_pathv[i];
if (lstat(c, &s) != -1) {
if (ls_l) {
/* This can actually happen even though the lstat() worked -
if someone deletes the file between the lstat() and ls_file()
calls. Unlikely, but better safe than sorry... */
}
}
else {
int flag;
}
}
if ((numSubdirs % 200) == 0)
}
}
dl_size += 65536;
}
}
globfree(&g);
if (draconian_FILE != NULL) {
#if defined(USE_GSS)
#else
#endif /* defined(USE_GSS) */
}
}
if (draconian_FILE != NULL) {
#if defined(USE_GSS)
#else
#endif /* defined(USE_GSS) */
}
if (ls_R) {
for (i = 0; i < numSubdirs; i++) {
if (draconian_FILE != NULL) {
#if defined(USE_GSS)
#else
#endif /* defined(USE_GSS) */
}
}
}
}
}
{
char free_file = 0;
if (nlst == 0)
free_file = 1;
}
file[0] = '.';
ls_l = 1;
ls_a = 1;
ls_R = 1;
ls_F = 1;
free_file = 1;
}
else {
ls_l = 1;
ls_a = 1;
ls_R = 1;
ls_F = 1;
}
}
file++;
free_file = 1;
}
transflag++;
if (file[0] == '\0') {
if (free_file != 0)
free_file = 1;
}
data = -1;
pdata = -1;
if (draconian_FILE != NULL) {
#if defined(USE_GSS)
if (sec_fflush(out) < 0) {
alarm(0);
transflag = 0;
goto ls_done;
}
#else
#endif /* defined(USE_GSS) */
}
if (draconian_FILE != NULL) {
}
if (draconian_FILE != NULL) {
}
alarm(0);
transflag = 0;
if (free_file != 0)
}
#endif /* INTERNAL_LS */
{
int options = 0;
char *logname;
char namebuf[MAXPATHLEN];
char fnbuf[MAXPATHLEN];
static int TransferComplete; /* static as retrieve can call itself */
char realname[MAXPATHLEN];
int stat_ret = -1;
TransferComplete = 0;
/* there isn't a command and the file exists */
if (log_security)
if (anonymous)
else
return;
}
#ifdef TRANSFER_COUNT
#ifdef TRANSFER_LIMIT
if (retrieve_is_data)
if (log_security)
if (anonymous)
else
return;
}
if (log_security)
if (anonymous)
else
return;
}
#ifdef RATIO
if (retrieve_is_data && (upload_download_rate > 0) )
}
else {
goto done;
}
}
#endif /* RATIO */
#endif
#endif
char *ptr;
continue;
continue;
continue;
continue;
continue;
continue;
continue;
}
continue;
continue;
continue;
}
continue;
continue;
}
else {
continue;
}
return;
}
sizeof(namebuf))
continue;
if (log_security)
if (anonymous)
else
return;
}
}
}
but I can tar /etc or /, I still win. Be careful out there... _H*
but you could put .notar in / and /etc and stop that ! */
if (log_security)
if (anonymous)
else
return;
}
return;
}
return;
}
return;
*ptr = '\0';
reply(550,
"Local error: conversion program not found. Cannot %s file.",
return;
}
goto logresults; /* transfer of converted file completed */
}
}
}
else { /* run command */
#ifdef HAVE_ST_BLKSIZE
#endif
}
if (errno != 0)
if (log_security)
if (anonymous)
else
return;
}
goto done;
}
if (restart_point) {
register int c;
off_t i;
i = 0;
while (i++ < restart_point) {
goto done;
}
if (c == '\n')
i++;
}
}
goto done;
}
}
goto done;
if (sendbufsz > 0) {
}
else {
#ifdef BUFFER_SIZE
#else
#endif
}
#ifdef THROUGHPUT
#else
#endif
#ifdef SIGPIPE
#endif
#ifdef SIGPIPE
#endif
if (ThisRetrieveIsData)
if (!xfertime)
xfertime++;
/* Gather transfer statistics */
xferdone = 1;
xferdone = 0;
/* Ensure msg always ends with '\n' */
}
else {
}
if (syslogmsg != 1)
if (syslogmsg != 0) {
/*
* To preserve the behavior when the xferlog format was fixed, skip
* over the time string if the message starts with the local time.
*/
msgp += 25;
}
}
data = -1;
pdata = -1;
done:
if (closefunc)
}
{
int TransferIncomplete = 1;
int fdout;
char realname[MAXPATHLEN];
#ifdef OVERWRITE
int overwrite = 1;
int exists = 0;
#endif /* OVERWRITE */
int open_flags = 0;
#ifdef UPLOAD
int valid = 0;
#endif /* UPLOAD */
#ifdef TRANSFER_COUNT
#ifdef TRANSFER_LIMIT
if (log_security)
if (anonymous)
else
return;
}
if (log_security)
if (anonymous)
else
return;
}
#endif
#endif
return;
/*
* check the filename, is it legal?
*/
if (log_security)
if (anonymous)
else
return;
}
#ifdef OVERWRITE
/* if overwrite permission denied and file exists... then deny the user
* permission to write the file. */
if (type_match(ARG1))
overwrite = 0;
open_flags |= O_EXCL;
}
}
#ifdef PARANOID
overwrite = 0;
#endif
exists = 1;
if (log_security)
if (anonymous)
else
return;
}
#endif /* OVERWRITE */
#ifdef UPLOAD
if (log_security)
if (anonymous)
else
return;
}
/* do not truncate the file if we are restarting */
if (restart_point)
open_flags &= ~O_TRUNC;
/* if the user has an explicit new file mode, than open the file using
* that mode. We must take care to not let the umask affect the file
* mode.
*
* else open the file and let the default umask determine the file mode. */
if (f_mode >= 0) {
}
else
if (fdout < 0) {
if (log_security)
if (anonymous)
else
return;
}
/* if we have a uid and gid, then use them. */
#ifdef OVERWRITE
if (!exists)
#endif
if (valid > 0) {
if (uid != 0)
chown_priv_on(0);
if (ret < 0) {
return;
}
}
else
}
#endif /* UPLOAD */
mode = "r+";
#ifdef UPLOAD
#else
#endif /* UPLOAD */
if (log_security)
if (anonymous)
else
return;
}
register int c;
off_t i;
i = 0;
while (i++ < restart_point) {
goto done;
}
if (c == '\n')
i++;
}
/* We must do this seek to "current" position because we are
* changing from reading to writing. */
#if _FILE_OFFSET_BITS == 64
#else
#endif
goto done;
}
}
goto done;
}
}
goto done;
/* shouldn't fail, but just in case */
}
if (TransferIncomplete == 0) {
if (unique)
else
}
#ifdef MAIL_ADMIN
char pathname[MAXPATHLEN];
goto mailfail;
}
goto mailfail;
}
goto mailfail;
}
goto mailfail;
}
temp2++;
}
if (temp2 == 0) {
goto mailfail;
}
goto mailfail;
}
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);
}
#endif /* MAIL_ADMIN */
if (!xfertime)
xfertime++;
/* Gather transfer statistics */
xferdone = 1;
xferdone = 0;
/* Ensure msg always ends with '\n' */
}
else {
}
if (syslogmsg != 1)
if (syslogmsg != 0) {
/*
* To preserve the behavior when the xferlog format was fixed, skip
* over the time string if the message starts with the local time.
*/
msgp += 25;
}
}
data = -1;
pdata = -1;
done:
}
{
if (data >= 0)
port_priv_on(0);
if (s < 0)
goto bad;
goto bad;
if (keepalive)
if (TCPwindowsize)
(char *) &TCPwindowsize, sizeof(TCPwindowsize));
/* anchor socket to avoid multi-homing problems */
#ifdef INET6
sizeof(struct in_addr));
}
else {
}
#else
#endif
#endif
break;
goto bad;
}
{
goto bad;
}
}
#endif
#ifdef INET6
/* IP_TOS is an IPv4 socket option */
#endif
}
#ifdef TCP_NOPUSH
/*
* Turn off push flag to keep sender TCP from sending short packets
* at the boundaries of each write(). Should probably do a SO_SNDBUF
* to set the send buffer size as well, but that may not be desirable
* in heavy-load situations.
*/
on = 1;
#endif
bad:
if (s != -1)
(void) close(s);
return (NULL);
}
{
char sizebuf[32];
int retry = 0;
int on = 1;
int cos;
#ifdef THROUGHPUT
int bps;
double bpsmult;
#endif
byte_count = 0;
else
if (pdata >= 0) {
struct SOCKSTORAGE from;
char dataaddr[MAXHOSTNAMELEN];
#else
#endif
int s;
#ifdef FD_ZERO
int rv;
#endif
if (keepalive)
if (TCPwindowsize)
(char *) &TCPwindowsize, sizeof(TCPwindowsize));
#ifdef FD_ZERO
do {
#ifdef HPUX_SELECT
#else
#endif
else
s = -1;
#else /* FD_ZERO */
alarm(0);
#endif
if (s == -1) {
pdata = -1;
return (NULL);
}
pdata = s;
#ifdef INET6
/* IP_TOS is an IPv4 socket option */
#endif
if (!pasv_allowed(dataaddr))
/*
* This will log when data connection comes from an address different
* than the control connection.
*/
#ifdef FIGHT_PASV_PORT_RACE
pdata = -1;
return (NULL);
#else
#endif
}
#ifdef THROUGHPUT
if (bps != -1) {
}
else
#endif
}
if (data >= 0) {
usedefault = 1;
}
if (usedefault)
return (NULL);
}
usedefault = 1;
do {
return (NULL);
}
alarm(0);
if (cval == -1) {
/*
* When connect fails, the state of the socket is unspecified so
* it should be closed and a new socket created for each connection
* attempt. This also prevents denial of service problems when
* running on operating systems that only allow one non-connected
* socket bound to the same local address.
*/
data = -1;
}
else {
return (NULL);
}
}
} while (cval == -1);
if (keepalive)
if (TCPwindowsize)
(char *) &TCPwindowsize, sizeof(TCPwindowsize));
#ifdef THROUGHPUT
if (bps != -1) {
}
else
#endif
return (file);
}
/* Tranfer the contents of "instr" to "outstr" peer using the appropriate
* encapsulation of the data subject to Mode, Structure, and Type.
*
* NB: Form isn't handled. */
int
#ifdef THROUGHPUT
#else
#endif
{
register int c, cnt = 0;
static char *buf;
#ifdef THROUGHPUT
int bps;
double bpsmult;
#endif
#ifdef SENDFILE
int use_sf = 0;
struct sendfilevec sfv;
#endif
alarm(0);
transflag = 0;
#ifdef SIGPIPE
#endif
if (buf)
retrieve_is_data = 1;
return (0);
}
transflag++;
#ifdef THROUGHPUT
#endif
switch (type) {
case TYPE_A:
#ifdef SIGPIPE
/*
* Ignore SIGPIPE while sending data, necessary so lostconn() isn't
* called if we write to the data connection after the client has
* closed it.
*/
#endif
#ifdef THROUGHPUT
if (bps != -1)
#endif
if (++byte_count % 4096 == 0)
if (c == '\n') {
goto data_err;
if (++byte_count % 4096 == 0)
#if defined(USE_GSS)
goto data_err;
#else
#endif
#ifdef TRANSFER_COUNT
if (retrieve_is_data) {
}
#endif
}
#if defined(USE_GSS)
goto data_err;
#else
#endif
#ifdef TRANSFER_COUNT
if (retrieve_is_data) {
}
#endif
#ifdef THROUGHPUT
sleep(1);
}
#endif
}
#ifdef THROUGHPUT
if (bps != -1)
#endif
if (draconian_FILE != NULL) {
#if defined(USE_GSS)
if (sec_fflush(outstr) < 0)
goto data_err;
#else
#endif /* defined(USE_GSS) */
}
if (draconian_FILE != NULL) {
}
transflag = 0;
goto file_err;
goto data_err;
alarm(0);
#ifdef SIGPIPE
#endif
#ifdef TRANSFER_COUNT
if (retrieve_is_data) {
}
#endif
retrieve_is_data = 1;
return (1);
case TYPE_I:
case TYPE_L:
#ifdef THROUGHPUT
if (bps != -1)
#endif
#ifdef SENDFILE
/* check the input file is a regular file */
#if defined(USE_GSS)
#endif /* defined(USE_GSS) */
{
use_sf = 1;
/*
* Use a private sfv_flag SFV_NOWAIT to tell sendfilev(),
* when zero-copy is enabled, not to wait for all data to be
* ACKed before returning. This is important for throughput
* performance when sendfilev() is called to send small piece
* at a time.
*/
}
}
if (use_sf == 0)
#endif
transflag = 0;
retrieve_is_data = 1;
return (0);
}
#ifdef SIGPIPE
/*
* Ignore SIGPIPE while sending data, necessary so lostconn() isn't
* called if we write to the data connection after the client has
* closed it.
*/
#endif
#ifdef THROUGHPUT
if (bps != -1)
#endif
while ((draconian_FILE != NULL) && (
#ifdef SENDFILE
|| (!use_sf &&
#endif
#if defined(USE_GSS)
#else
#endif /* defined(USE_GSS) */
#ifdef SENDFILE
)
#endif
)) {
#ifdef SENDFILE
#endif
byte_count += cnt;
#ifdef TRANSFER_COUNT
if (retrieve_is_data) {
#ifdef RATIO
if( freefile ) {
total_free_dl += cnt;
}
#endif /* RATIO */
data_count_total += cnt;
data_count_out += cnt;
}
byte_count_total += cnt;
byte_count_out += cnt;
#endif
#ifdef THROUGHPUT
if (bps != -1) {
sleep(1);
}
#endif /* THROUGHPUT */
}
#ifdef THROUGHPUT
if (bps != -1)
#endif
#if defined(USE_GSS)
if (sec_fflush(outstr) < 0)
goto data_err;
#endif
transflag = 0;
if (buf)
if (draconian_FILE != NULL) {
}
if (cnt != 0) {
#ifdef SENDFILE
goto data_err;
#endif
if (cnt < 0)
goto file_err;
goto data_err;
}
if (draconian_FILE == NULL)
goto data_err;
alarm(0);
#ifdef SIGPIPE
#endif
#ifdef TRANSFER_COUNT
if (retrieve_is_data) {
}
#endif
retrieve_is_data = 1;
return (1);
default:
transflag = 0;
retrieve_is_data = 1;
return (0);
}
alarm(0);
transflag = 0;
#ifdef SIGPIPE
#endif
retrieve_is_data = 1;
return (0);
alarm(0);
transflag = 0;
#ifdef SIGPIPE
#endif
retrieve_is_data = 1;
return (0);
}
/* Transfer data from peer to "outstr" using the appropriate encapulation of
* the data subject to Mode, Structure, and Type.
*
* N.B.: Form isn't handled. */
{
register int c;
static char *buf;
#ifdef BUFFER_SIZE
#else
#endif
alarm(0);
transflag = 0;
if (buf)
return (-1);
}
transflag++;
switch (type) {
case TYPE_I:
case TYPE_L:
#if defined(USE_GSS)
if (GSSUSERAUTH_OK(gss_info))
else
#endif
if (recvbufsz > 0)
transflag = 0;
return (-1);
}
while ((draconian_FILE != NULL) &&
#if defined(USE_GSS)
#else
#endif
break;
}
byte_count += wcnt;
#ifdef TRANSFER_COUNT
data_count_total += wcnt;
data_count_in += wcnt;
byte_count_total += wcnt;
byte_count_in += wcnt;
#endif
if (n == -1)
break;
}
transflag = 0;
goto data_err;
if (n == -1)
goto file_err;
alarm(0);
#ifdef TRANSFER_COUNT
#endif
return (0);
case TYPE_E:
transflag = 0;
return (-1);
case TYPE_A:
while ((draconian_FILE != NULL) &&
#if defined(USE_GSS)
#else
#endif
) {
if (++byte_count % 4096 == 0)
if (c == '\n')
bare_lfs++;
while (c == '\r') {
goto file_err;
if (draconian_FILE != NULL) {
#if defined(USE_GSS)
#else
#endif
#ifdef TRANSFER_COUNT
#endif
if (c == EOF) /* null byte fix, noid@cyborg.larc.nasa.gov */
goto contin2;
if (++byte_count % 4096 == 0)
}
}
#ifdef TRANSFER_COUNT
#endif
contin2:;
}
goto data_err;
goto file_err;
transflag = 0;
alarm(0);
if (bare_lfs) {
lreply(0, " File may not have transferred correctly.");
}
#ifdef TRANSFER_COUNT
#endif
return (0);
default:
transflag = 0;
return (-1);
}
alarm(0);
transflag = 0;
return (-1);
alarm(0);
transflag = 0;
return (-1);
}
void statfilecmd(char *filename)
{
#ifndef INTERNAL_LS
int c;
#endif /* ! INTERNAL_LS */
if (filename[0] == '\0')
filename = ".";
#ifndef INTERNAL_LS
if (anonymous && dolreplies)
else
#endif /* ! INTERNAL_LS */
#ifndef INTERNAL_LS
/*
while ((c = getc(fin)) != EOF) {
if (c == '\n') {
if (ferror(stdout)) {
perror_reply(421, "control connection");
(void) ftpd_pclose(fin);
dologout(1);
/ * NOTREACHED * /
}
if (ferror(fin)) {
perror_reply(551, filename);
(void) ftpd_pclose(fin);
return;
}
(void) putc('\r', stdout);
}
(void) putc(c, stdout);
}
*/
*ptr = '\0';
}
(void) ftpd_pclose(fin);
#else /* INTERNAL_LS */
#endif /* INTERNAL_LS */
}
void statcmd(void)
{
struct SOCKSTORAGE *sin;
u_char *a, *p;
unsigned short port;
#ifdef INET6
int isv4 = 0;
#endif
if (nameserved)
else
if (logged_in) {
if (anonymous)
lreply(0, " Logged in anonymously");
else
}
else if (askpasswd)
lreply(0, " Waiting for password");
else
lreply(0, " Waiting for user name");
#ifdef NBBY
lreply(0, " TYPE: %s %d; STRUcture: %s; transfer MODE: %s",
#else
lreply(0, " TYPE: %s %d; STRUcture: %s; transfer MODE: %s",
#endif /* NBBY */
else
lreply(0, " TYPE: %s%s%s; STRUcture: %s; transfer MODE: %s",
if (data != -1)
lreply(0, " Data connection open");
if (usedefault == 0) {
}
else {
if (route_vectored)
else
}
#define UC(b) (((int) b) & 0xff)
#ifdef INET6
isv4 = 1;
{
isv4 = 1;
a += 12; /* move to the IPv4 part of an IPv4-mapped IPv6 address */
}
if (epsv_all)
lreply(0, " EPSV only mode (EPSV ALL)");
#endif
lreply(0, " %s (%d,%d,%d,%d,%d,%d)",
#ifdef INET6
if (!epsv_all)
if (isv4)
lreply(0, " %s (4,4,%d,%d,%d,%d,2,%d,%d)",
else
lreply(0, " %s (6,16,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
"%d,%d,%d,%d,2,%d,%d)",
#endif
}
else
lreply(0, " No data connection");
#ifdef TRANSFER_COUNT
lreply(0, " %" L_FORMAT " traffic bytes transmitted in %d transfers", byte_count_out, xfer_count_out);
lreply(0, " %" L_FORMAT " traffic bytes total in %d transfers", byte_count_total, xfer_count_total);
#endif
}
void fatal(char *s)
{
dologout(0);
/* NOTREACHED */
}
{
if (n) /* if numeric is 0, don't output one; use n==0 in place of printf's */
/* This is somewhat of a kludge for autospout. I personally think that
* autospout should be done differently, but that's not my department. -Kev
*/
if (flags & USE_REPLY_NOTFMT)
else
#if defined(USE_GSS)
if (IS_GSSAUTH(cur_auth_type) &&
}
#endif
if (debug) /* debugging output :) */
/* Yes, you want the debugging output before the client output; wrapping
* stuff goes here, you see, and you want to log the cleartext and send
* the wrapped text to the client.
*/
#ifdef TRANSFER_COUNT
#endif
/*
* We dont need to worry about "sec_fflush" here since "sec_reply"
* already wrapped the reply if necessary.
*/
}
{
while (*ptr) {
*p = '\0';
/* send a line...(note that this overrides dolreplies!) */
if (p)
else
break; /* oh, we're done; drop out of the loop */
}
if (autospout_free) { /* free autospout if necessary */
autospout_free = 0;
}
autospout = 0; /* clear the autospout */
}
/* send the reply */
}
{
if (!dolreplies) /* prohibited from doing long replies? */
return;
/* send the reply */
}
void ack(char *s)
{
}
void nack(char *s)
{
}
void yyerror(char *s)
{
char *cp;
if (s == NULL || yyerrorcalled != 0)
return;
*cp = '\0';
yyerrorcalled = 1;
return;
}
{
char realname[MAXPATHLEN];
/*
* delete permission?
*/
if (log_security)
if (anonymous)
else
return;
}
return;
}
int d_mode;
int valid;
/*
* check the directory, can we rmdir here?
*/
if (log_security)
if (anonymous)
else
return;
}
if (log_security)
if (anonymous)
else
return;
}
goto done;
}
if (log_security)
if (anonymous)
else
return;
}
done:
{
char path[MAXPATHLEN];
if (log_security)
if (anonymous) {
}
else {
remoteident, path);
}
else if (anonymous) {
remoteident, path);
}
else {
remoteident, path);
}
}
ack("DELE");
}
{
char cdpath[MAXPATHLEN];
/* alias checking */
else {
ack("CWD");
}
return;
}
}
/* check for "cdpath" directories. */
ack("CWD");
return;
}
}
}
else {
ack("CWD");
}
}
{
int d_mode;
int valid;
char realname[MAXPATHLEN];
/*
* check the directory, can we mkdir here?
*/
if (log_security)
if (anonymous)
else
return;
}
/*
* check the filename, is it legal?
*/
if (log_security)
if (anonymous)
else
return;
}
if (valid <= 0) {
d_mode = 0777;
}
if (log_security)
if (anonymous)
else
}
else {
if (log_security)
if (anonymous)
else
}
return;
}
if (valid > 0) {
if (uid != 0)
chown_priv_on(0);
if (ret < 0) {
return;
}
}
else
}
if (log_security)
if (anonymous) {
}
else {
remoteident, path);
}
/* According to RFC 959:
* The 257 reply to the MKD command must always contain the
* absolute pathname of the created directory.
* This is implemented here using similar code to the PWD command.
* XXX - still need to do `quote-doubling'.
*/
}
{
int d_mode;
int valid;
char realname[MAXPATHLEN];
/*
* delete permission?
*/
return;
/*
* check the directory, can we rmdir here?
*/
if (log_security)
if (anonymous)
else
return;
}
else {
if (log_security)
if (anonymous)
else
}
}
else {
char path[MAXPATHLEN];
if (log_security)
if (anonymous) {
}
else {
remoteident, path);
}
ack("RMD");
}
}
void pwd(void)
{
int pathlen;
#ifndef MAPPING_CHDIR
#ifdef HAVE_GETCWD
extern char *getcwd();
#else
extern char *getwd(char *);
#endif
#endif /* MAPPING_CHDIR */
#ifdef HAVE_GETCWD
#else
#endif
/* Dink! If you couldn't get the path and the buffer is now likely to
be undefined, why are you trying to PRINT it?! _H*
reply(550, "%s.", path); */
{
}
/* relative to home directory if restricted_user */
if (restricted_user) {
pathlen--;
if (!*rpath)
}
}
char *renamefrom(char *name)
{
return ((char *) 0);
}
return (name);
}
{
char realfrom[MAXPATHLEN];
char realto[MAXPATHLEN];
#ifdef PARANOID
#endif
/*
* check the filename, is it legal?
*/
if (log_security)
if (anonymous)
else
return;
}
/*
* if rename permission denied and file exists... then deny the user
* permission to rename the file.
*/
if (type_match(ARG1))
if (anonymous) {
if (*ARG0 == 'y')
allowed = 1;
}
else if (*ARG0 == 'n')
allowed = 0;
}
if (!allowed) {
if (log_security)
if (anonymous)
else
return;
}
#ifdef PARANOID
/* Almost forgot about this. Don't allow renaming TO existing files --
otherwise someone can rename "trivial" to "warez", and "warez" is gone!
XXX: This part really should do the same "overwrite" check as store(). */
if (log_security)
if (anonymous)
else
return;
}
#endif
if (log_security)
if (anonymous)
else
}
else {
char frompath[MAXPATHLEN];
char topath[MAXPATHLEN];
if (log_security)
if (anonymous) {
}
else {
}
ack("RNTO");
}
}
{
char *blah;
int rval;
nameserved = 0;
if (rhlookup) {
nameserved = 1;
}
else {
#ifdef DNS_TRYAGAIN
int num_dns_tries = 0;
/*
* far away connections might take some time to get their IP address
* resolved. That's why we try again -- maybe our DNS cache has the
* PTR-RR now. This code is sloppy. Far better is to check what the
* resolver returned so that in case of error, there's no need to
* try again.
*/
#endif /* DNS_TRYAGAIN */
#ifdef DNS_TRYAGAIN
sleep(3);
goto dns_again; /* try DNS lookup once more */
}
#endif /* DNS_TRYAGAIN */
if (rval)
nameserved = 1;
}
}
/* Create a composite source identification string, to improve the logging
* when RFC 931 is being used. */
{
#ifndef DEBUG
exit(1);
#endif
}
else if (authenticated)
else
}
#ifdef DAEMON
#else
#if 0 /* this is redundant unless the caller doesn't do *anything*, and
tcpd will pick it up and deal with it better anyways. _H */
if (logging)
#endif
#endif
}
/* Record logout in wtmp file and exit with supplied status. */
{
/*
* Prevent reception of SIGURG from resulting in a resumption
* back to the main program loop.
*/
transflag = 0;
/*
* Cancel any pending alarm request, reception of SIGALRM would cause
* dologout() to be called again from the SIGALRM handler toolong().
*/
(void) alarm(0);
if (logged_in) {
delay_signaling(); /* we can't allow any signals while euid==0: kinch */
#if defined(SOLARIS_BSM_AUDIT) && !defined(SOLARIS_NO_AUDIT_FTPD_LOGOUT)
#endif
if (wtmp_logging)
#ifdef USE_PAM
(void) pam_close_session(pamh, 0);
pamh = (pam_handle_t *)0;
}
#endif
}
if (logging)
if (xferlog)
acl_remove();
if (data >= 0)
if (pdata >= 0)
#ifdef AFS_AUTH
#endif
/* beware of flushing buffers after a SIGPIPE */
}
{
char *cp;
#ifdef SIGPIPE
void (*pipe_handler)();
#endif
/* only process if transfer occurring */
if (!transflag) {
#ifdef SIGURG
#endif
return;
}
#ifdef SIGPIPE
#endif
dologout(0);
}
tmpline[0] = '\0';
#ifdef SIGPIPE
#endif
#ifdef SIGURG
#endif
if (ftwflag > 0) {
ftwflag++;
return;
}
}
tmpline[0] = '\0';
else
}
#ifdef SIGPIPE
#endif
#ifdef SIGURG
#endif
}
/* Note: a response of 425 is not mentioned as a possible response to the
* PASV command in RFC959. However, it has been blessed as a legitimate
* response by Jon Postel in a telephone conversation with Rick Adams on 25
* Jan 89. */
{
/* First prime number after 2^n where 4 <= n <= 16 */
static int prime = 0;
static int range;
#else
int len;
#endif
int bind_error, serrno;
int on = 1;
unsigned short port;
register char *p, *a;
struct SOCKSTORAGE *reply_addr;
#ifdef INET6
int isv4 = 0;
#endif
/* H* fix: if we already *have* a passive socket, close it first. Prevents
a whole variety of entertaining clogging attacks. */
if (pdata >= 0) {
pdata = -1;
}
if (!logged_in) {
return;
}
#ifdef INET6
switch (proto) {
case 0:
&& !ctrl_v4mapped) {
return;
}
else
break;
case 1:
else if (ctrl_v4mapped) {
sizeof(struct in_addr));
}
else {
return;
}
break;
case 2:
else {
return;
}
break;
default:
return;
}
#else
#endif
if (passive_port_min == 0 && passive_port_max == 0) {
/* let the kernel allocate the port */
SET_SOCK_PORT(pasv_addr, 0);
}
else if (prime == 0) {
/* find the first prime greater than the range in the primes list */
;
/* shouldn't happen, but check just in case */
if (primes[i] == 0) {
/* let the kernel allocate the port */
SET_SOCK_PORT(pasv_addr, 0);
}
else
}
port_priv_on(0); /* necessary as port can be < 1024 */
if (pdata < 0) {
return;
}
if (keepalive)
if (TCPwindowsize) {
}
bind_error = -1;
errno = EADDRINUSE;
/* try each port in the specified range a maximum of 3 times */
if (i > 0)
sleep(i);
else {
/*
* Using the modulus operator with a prime number allows us to
* try each port in the range once.
*/
;
}
}
}
if (bind_error != 0) {
goto pasv_error;
}
/* if the kernel allocated the port, find out which one */
goto pasv_error;
goto pasv_error;
usedefault = 1;
if (route_vectored)
reply_addr = &vect_addr;
else
reply_addr = &pasv_addr;
a = (char *) SOCK_ADDR(*reply_addr);
p = (char *) &port;
#define UC(b) (((int) b) & 0xff)
if (debug) {
if (s) {
free(s);
}
}
#ifdef INET6
isv4 = 1;
isv4 = 1;
a += 12; /* move to the IPv4 part of an IPv4-mapped IPv6 address */
}
switch (passive_mode) {
case TYPE_PASV:
return;
case TYPE_EPSV:
return;
case TYPE_LPSV:
if (isv4) {
"(%d,%d,%d,%d,%d,%d,%d,%d,%d)",
}
else {
"(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
"%d,%d,%d,%d,%d)", 6, 16,
}
return;
}
#else
return;
#endif /* INET6 */
pdata = -1;
if (debug) {
if (s) {
free(s);
}
}
return;
}
/*
* Generate unique name for file with basename "local". The file named
* "local" is already known to exist. Generates failure reply on error.
*/
{
static char new[MAXPATHLEN];
int count = 0;
if (cp)
*cp = '\0';
return ((char *) 0);
}
if (cp)
*cp = '/';
*cp++ = '.';
if (count == 10) {
cp -= 2;
*cp++ = '.';
}
return (new);
}
return ((char *) 0);
}
/* Format and send reply containing system error number. */
{
/*
* If restricted user and string starts with home dir path, strip it off
* and return only the relative path.
*/
string = "/";
}
}
}
static char *onefile[] =
{"", 0};
extern char **ftpglob(register char *v);
extern char *globerr;
void send_file_list(char *whichfiles)
{
/* static so not clobbered by longjmp(), volatile would also work */
static char **sdirlist;
int simple = 0;
int statret;
** already included so we don't need the following line. 'sides, it
** breaks the GNU EGCS C compiler
** extern char *strpbrk(const char *, const char *);
*/
#ifdef TRANSFER_COUNT
#ifdef TRANSFER_LIMIT
if (log_security)
if (anonymous)
else
return;
}
#endif
#endif
if (whichfiles[0] == '\0') {
goto globfree;
}
}
else {
if (statret >= 0) {
goto globfree;
}
}
}
}
}
goto globfree;
}
goto globfree;
}
}
else {
onefile[0] = whichfiles;
simple = 1;
}
transflag = 0;
data = -1;
pdata = -1;
goto globfree;
}
if (statret < 0)
if (statret < 0) {
/* If user typed "ls -l", etc, and the client used NLST, do what
* the user meant. */
retrieve_is_data = 0;
#ifndef INTERNAL_LS
#else
#endif
retrieve_is_data = 1;
goto globfree;
}
transflag = 0;
data = -1;
pdata = -1;
}
goto globfree;
}
#ifndef NLST_SHOWS_DIRS
#endif
{
goto globfree;
transflag++;
}
if (draconian_FILE != NULL) {
#if defined(USE_GSS)
#else
#endif /* USE_GSS */
}
#ifdef TRANSFER_COUNT
}
#endif
}
}
if (draconian_FILE != NULL) {
#if defined(USE_GSS)
if (sec_fflush(dout) < 0) {
alarm(0);
goto sfl_cleanup; /* send file list cleanup */
}
#else
#endif /* USE_GSS */
}
if (draconian_FILE != NULL) {
}
}
alarm(0);
}
else {
#ifdef TRANSFER_COUNT
#endif
alarm(0);
}
transflag = 0;
data = -1;
pdata = -1;
}
if (sdirlist) {
}
}
/*
** SETPROCTITLE -- set process title for ps
**
** Parameters:
** fmt -- a printf style format string.
** a, b, c -- possible parameters to fmt.
**
** Returns:
** none.
**
** Side Effects:
** Clobbers argv of our main procedure so ps(1) will
** display the title.
*/
#define SPT_NONE 0 /* don't use it at all */
#ifndef SPT_TYPE
#define SPT_TYPE SPT_REUSEARGV
#endif
#endif
#if SPT_TYPE == SPT_PSSTRINGS
#ifndef PS_STRINGS /* hmmmm.... apparently not available after all */
#define SPT_TYPE SPT_REUSEARGV
#else
#ifndef NKPDE /* FreeBSD 2.0 */
#define NKPDE 63
typedef unsigned int *pt_entry_t;
#endif
#endif
#endif
#define SETPROC_STATIC static
#else
#define SETPROC_STATIC
#endif
#if SPT_TYPE == SPT_SYSMIPS
#endif
#ifdef UNIXWARE
#else /* UNIXWARE */
#endif /* UNIXWARE */
#define SPT_BUFSIZE PSARGSZ
#endif
#ifndef _PATH_KMEM
#define _PATH_KMEM "/dev/kmem"
#endif /* _PATH_KMEM */
#endif /* SPT_SCO */
#ifndef SPT_PADCHAR
#define SPT_PADCHAR ' '
#endif
#ifndef SPT_BUFSIZE
#define SPT_BUFSIZE MAXLINE
#endif
#endif /* SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN */
#endif
#if SPT_TYPE == SPT_REUSEARGV
#endif
/*
** Pointers for setproctitle.
** This allows "ps" listings to give more useful information.
*/
int argc;
char **argv;
char **envp;
{
#if SPT_TYPE == SPT_REUSEARGV
register int i, envpsize = 0;
char **newenviron;
extern char **environ;
/*
** Save start and extent of argv for setproctitle.
*/
/*
** Move the environment so setproctitle can use the space at
** the top of memory.
*/
if (newenviron) {
int err = 0;
err = 1;
break;
}
}
if (err) {
for (i = 0; newenviron[i] != NULL; i++)
free(newenviron[i]);
i = 0;
}
else {
newenviron[i] = NULL;
}
}
else {
i = 0;
}
/*
** Find the last environment variable within wu-ftpd's
** process memory area.
*/
1 + envpsize)))
i--;
if (i > 0)
}
#endif /* SPT_TYPE == SPT_REUSEARGV */
#endif
}
#if SPT_TYPE != SPT_BUILTIN
/*VARARGS1 */
void setproctitle(const char *fmt,...)
{
register char *p;
register int i;
#endif
static int kmemfd = -1;
static int kmempid = -1;
#ifdef UNIXWARE
void *ptr;
struct mioc_rksym rks;
#endif /* UNIXWARE */
#endif /* SPT_SCO */
p = buf;
/* print ftpd: heading for grep */
(void) strcpy(p, "ftpd: ");
p += strlen(p);
/* print the argument string */
#endif
#if SPT_TYPE == SPT_PSSTRINGS
#endif
#if SPT_TYPE == SPT_SYSMIPS
#endif
if (kmemfd >= 0)
return;
#ifdef UNIXWARE
seek_off = 0;
return;
return;
return;
return;
return;
#else /* UNIXWARE */
#endif /* UNIXWARE */
}
#ifdef UNIXWARE
if (seek_off == 0)
return;
#endif /* UNIXWARE */
#endif /* SPT_SCO */
#if SPT_TYPE == SPT_REUSEARGV
buf[i] = '\0';
}
p = &Argv[0][i];
while (p < LastArgv)
*p++ = SPT_PADCHAR;
#endif
#if SPT_TYPE == SPT_CHANGEARGV
Argv[1] = 0;
#endif
#endif /* SPT_TYPE != SPT_NONE */
}
#endif /* SPT_TYPE != SPT_BUILTIN */
#ifdef KERBEROS
/* thanks to gshapiro@wpi.wpi.edu for the following kerberosities */
void init_krb()
{
char hostname[100];
#ifdef HAVE_SYSINFO
perror("sysinfo");
#else
perror("gethostname");
#endif
exit(1);
}
config_auth();
exit(1);
}
}
void end_krb()
{
}
#endif /* KERBEROS */
#ifdef ULTRIX_AUTH
{
int auth_status;
return -1;
}
return -1;
}
/* Indicate successful validation */
return auth_status;
}
/* Log some information about the failed login attempt. */
switch (abs(auth_status)) {
case A_EBADPASS:
break;
case A_ESOFTEXP:
break;
case A_EHARDEXP:
break;
case A_ENOLOGIN:
break;
}
}
}
else {
return 0;
}
}
return -1;
}
#endif /* ULTRIX_AUTH */
#ifdef USE_PAM
/* This is rather an abuse of PAM, but the FTP protocol doesn't allow much
* flexibility here. :-(
*/
/* Static variables used to communicate between the conversation function
* and the server_login function
*/
static char *PAM_password;
/* PAM conversation function
* Here we assume (for now, at least) that echo on means login name, and
* echo off means password.
*/
#ifdef SOLARIS_2
/* Workaround bug 4430970/4413889 which causes a compiler warning, necessary
* as usr/src/Makefile.master now includes "-errwarn=%all".
*/
static int PAM_conv(int num_msg, struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
#else
static int PAM_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
#endif
{
int replies = 0;
if (!reply)
return PAM_CONV_ERR;
case PAM_PROMPT_ECHO_ON:
return PAM_CONV_ERR;
break;
case PAM_PROMPT_ECHO_OFF:
/* PAM frees resp */
break;
case PAM_TEXT_INFO:
/* ignore it... */
break;
case PAM_ERROR_MSG:
/* ignore it... */
break;
default:
/* Must be an error of some sort... */
return PAM_CONV_ERR;
}
}
return PAM_SUCCESS;
}
static struct pam_conv PAM_conversation =
{
&PAM_conv,
};
{
char tty[20];
int pam_session = 0;
/* Now use PAM to do authentication and session logging. Bail out if
* there are any errors. Since this is a limited protocol, and an even
* more limited function within a server speaking this protocol, we
* can't be as verbose as would otherwise make sense.
*/
pamh = (pam_handle_t *)0;
return 0;
#else
#endif
goto pam_fail;
goto pam_fail;
#ifdef SOLARIS_BSM_AUDIT
#endif
goto pam_fail;
}
#ifdef SOLARIS_BSM_AUDIT
#endif
goto pam_fail;
}
goto pam_fail;
pam_session = 1;
#ifdef PAM_ESTABLISH_CRED
goto pam_fail;
#else
goto pam_fail;
#endif
/* If this point is reached, the user has been authenticated. */
return 1;
if (pam_session)
(void) pam_close_session(pamh, 0);
pamh = (pam_handle_t *)0;
return 0;
}
#endif
#ifdef DAEMON
#ifdef INET6
static struct in6_addr acl_DaemonAddress6(void)
{
rv = in6addr_any;
}
return rv;
}
#endif /* INET6 */
static unsigned long int acl_DaemonAddress(void)
{
unsigned long int rv = INADDR_ANY;
if (rv == -1)
rv = INADDR_ANY;
}
return rv;
}
/* I am running as a standalone daemon (not under inetd) */
static void do_daemon(void)
{
struct SOCKSTORAGE server;
int pgrp;
int lsock;
int one = 1;
int i;
#else
int addrlen;
#endif
/* Some of this is "borrowed" from inn - lots of it isn't */
if (be_daemon == 2) {
/* Fork - so I'm not the owner of the process group any more */
i = fork();
if (i < 0) {
exit(1);
}
/* No need for the parent any more */
if (i > 0)
exit(0);
#ifdef NO_SETSID
#else
#endif
if (pgrp < 0) {
exit(1);
}
}
if (!Bypass_PID_Files)
}
else {
}
/* Close off all file descriptors and reopen syslog */
if (be_daemon == 2) {
closelog();
closefds(0);
(void) dup2(0, 1);
/* junk stderr */
#ifdef FACILITY
#else
#endif
}
if (RootDirectory != NULL) {
if ((chroot(RootDirectory) < 0)
|| (chdir("/") < 0)) {
exit(1);
}
}
if (!use_accessfile)
/* Create a socket to listen on */
#ifdef INET6
if (listen_v4 == 0)
else
#endif
if (lsock < 0) {
exit(1);
}
exit(1);
}
if (keepalive)
#ifdef INET6
if (listen_v4 == 0) {
}
else {
}
#else
#endif
if (daemon_port == 0) {
exit(1);
}
}
else
exit(1);
}
while (1) {
int pid;
int msgsock;
if (msgsock < 0) {
sleep(1);
continue;
}
/* Fork off a handler */
if (pid < 0) {
sleep(1);
continue;
}
if (pid == 0) {
/* I am that forked off child */
/* Only parent needs lsock */
closelog();
#ifdef FACILITY
#else
#endif
setup_paths();
access_init();
return;
}
/* I am the parent */
/* Quick check to see if any of the forked off children have
* terminated. */
/* A child has finished */
}
access_init();
}
}
#endif /* DAEMON */
#ifdef RATIO
int is_downloadfree(char *fname)
{
char rpath[MAXPATHLEN];
char *cp;
int which;
return 0;
(void) acl_getclass(class);
if (debug)
continue;
return 1;
return 1;
}
}
}
continue;
}
else {
++cp;
}
return 1;
return 1;
}
}
}
else { /* compare real path */
return 1;
return 1;
}
}
}
}
return 0;
}
#endif /* RATIO */
int pasv_allowed(char *remoteaddr)
{
char class[MAXPATHLEN];
int which;
(void) acl_getclass(class);
return 1;
}
}
return 0;
}
int port_allowed(char *remoteaddr)
{
char class[MAXPATHLEN];
int which;
(void) acl_getclass(class);
return 1;
}
}
return 0;
}
#ifdef MAIL_ADMIN
char *email(char *full_address)
{
/* Get the plain address part from an e-mail address
(i.e. remove realname) */
/* Realname <user@host> type address */
*ptr = '\0';
}
/* user@host (Realname) type address */
return addr;
}
{
int sock;
unsigned long inaddr;
struct sockaddr_in ad;
#ifdef INET6
struct sockaddr_in6 ad6;
#else
#endif
#ifdef INET6
else
continue;
if (sock < 0)
continue;
break;
}
else {
if (sock < 0)
continue;
break;
}
}
if (!res)
#else
if (inaddr != (unsigned long) -1)
else {
}
if (sock < 0)
}
#endif /* INET6 */
return (fp);
}
{
char buf[16384];
}
{
}
{
}
{
int rc;
return rc;
}
{
int ret = 0;
return ret;
do {
}
else
ret = 250;
return ret;
}
{
char buf[16384];
}
#endif /* MAIL_ADMIN */
/*
* fixpath
*
* In principal, this is similar to realpath() or the mapping chdir function.
* It removes unnecessary path components. We do this to put a stop to
* attempts to cause a memory starvation DoS.
*
*/
{
int abs = 0;
char *in;
char *out;
if (*path == '/') {
abs = 1;
path++;
}
else if (*path == '~') {
do
path++;
if (*path == '/')
path++;
}
while (*in != '\0') {
if (*in == '/')
in++;
in++;
if (*in == '/')
in++;
}
if (abs) {
in++;
in++;
if (*in == '/')
in++;
}
else {
if (*in == '/')
}
}
else {
out--;
in++;
in++;
if (*in == '/')
in++;
}
}
else {
do
if (*in == '/')
}
}
*out = '\0';
}