ftpd.c
上传用户:zibowangxu
上传日期:2007-01-04
资源大小:331k
文件大小:183k
- /****************************************************************************
-
- Copyright (c) 1999 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
- at http://www.wu-ftpd.org/license.html.
-
- $Id: ftpd.c,v 1.106 1999/10/14 14:41:47 wuftpd Exp $
-
- ****************************************************************************/
- /* FTP server. */
- #include "config.h"
- #include <sys/types.h>
- #include <sys/param.h>
- #include <sys/stat.h>
- #include <sys/ioctl.h>
- #include <sys/socket.h>
- #include <sys/file.h>
- #include <sys/wait.h>
- #ifdef AIX
- #include <sys/id.h>
- #include <sys/priv.h>
- #include <netinet/if_ether.h>
- #include <net/if_dl.h>
- #endif
- #ifdef AUX
- #include <compat.h>
- #endif
- #include <netinet/in.h>
- #include <netinet/in_systm.h>
- #include <netinet/ip.h>
- #define FTP_NAMES
- #include "../support/ftp.h"
- #include <arpa/inet.h>
- #include <arpa/telnet.h>
- #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 <sys/stat.h>
- #define VA_LOCAL_DECL va_list ap;
- #define VA_START(f) va_start(ap, f)
- #define VA_END va_end(ap)
- #include "proto.h"
- #ifdef HAVE_UFS_QUOTA_H
- #include <ufs/quota.h>
- #endif
- #ifdef HAVE_SYS_FS_UFS_QUOTA_H
- #include <sys/fs/ufs_quota.h>
- #endif
- #ifdef HAVE_SYS_SYSLOG_H
- #include <sys/syslog.h>
- #endif
- #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H))
- #include <syslog.h>
- #endif
- #ifdef TIME_WITH_SYS_TIME
- #include <time.h>
- #include <sys/time.h>
- #else
- #ifdef HAVE_SYS_TIME_H
- #include <sys/time.h>
- #else
- #include <time.h>
- #endif
- #endif
- #include "conversions.h"
- #include "extensions.h"
- #ifdef SHADOW_PASSWORD
- #include <shadow.h>
- #endif
- #include "pathnames.h"
- #ifdef M_UNIX
- #include <arpa/nameser.h>
- #include <resolv.h>
- #endif
- #if defined(HAVE_FCNTL_H)
- #include <fcntl.h>
- #endif
- #ifdef HAVE_SYSINFO
- #include <sys/systeminfo.h>
- #endif
- #ifdef KERBEROS
- #include <sys/types.h>
- #include <auth.h>
- #include <krb.h>
- #endif
- #ifdef ULTRIX_AUTH
- #include <auth.h>
- #include <sys/svcinfo.h>
- #endif
- #ifndef HAVE_LSTAT
- #define lstat stat
- #endif
- #ifdef AFS_AUTH
- #include <afs/stds.h>
- #include <afs/kautils.h>
- #endif
- #ifdef DCE_AUTH
- #include <dce/rpc.h>
- #include <dce/sec_login.h>
- #include <dce/dce_error.h>
- #endif
- #ifdef HAVE_DIRENT_H
- #include <dirent.h>
- #else
- #include <sys/dir.h>
- #endif
- #ifdef HAVE_GETRLIMIT
- #include <sys/resource.h>
- #endif
- #if defined(USE_LONGJMP)
- #define wu_longjmp(x, y) longjmp((x), (y))
- #define wu_setjmp(x) setjmp(x)
- #ifndef JMP_BUF
- #define JMP_BUF jmp_buf
- #endif
- #else
- #define wu_longjmp(x, y) siglongjmp((x), (y))
- #define wu_setjmp(x) sigsetjmp((x), 1)
- #ifndef JMP_BUF
- #define JMP_BUF sigjmp_buf
- #endif
- #endif
- #ifndef MAXHOSTNAMELEN
- #define MAXHOSTNAMELEN 64 /* may be too big */
- #endif
- #ifndef TRUE
- #define TRUE 1
- #endif
- #ifndef FALSE
- #define FALSE !TRUE
- #endif
- #ifdef MAIL_ADMIN
- #define MAILSERVERS 10
- #define INCMAILS 10
- int mailservers = 0;
- char *mailserver[MAILSERVERS];
- int incmails = 0;
- char *incmail[INCMAILS];
- char *mailfrom;
- char *email(char *full_address);
- FILE *SockOpen(char *host, int clientPort);
- char *SockGets(FILE *sockfp, char *buf, int len);
- int SockWrite(char *buf, int size, int nels, FILE *sockfp);
- int SockPrintf(FILE *sockfp, char *format,...);
- int SockPuts(FILE *sockfp, char *buf);
- int Reply(FILE *sockfp);
- int Send(FILE *sockfp, char *format,...);
- #endif /* MAIL_ADMIN */
- #if defined(_SCO_DS) && !defined(SIGURG)
- #define SIGURG SIGUSR1
- #endif
- /* File containing login names NOT to be used on this machine. Commonly used
- * to disallow uucp. */
- extern int errno;
- extern int pidfd;
- extern char *ctime(const time_t *);
- #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 sockaddr_in ctrl_addr;
- struct sockaddr_in data_source;
- struct sockaddr_in data_dest;
- struct sockaddr_in his_addr;
- struct sockaddr_in pasv_addr;
- struct sockaddr_in vect_addr;
- int route_vectored = 0;
- int passive_port_min = -1;
- int passive_port_max = -1;
- int restricted_user = 0;
- #ifdef VIRTUAL
- char virtual_root[MAXPATHLEN];
- char virtual_banner[MAXPATHLEN];
- char virtual_email[MAXPATHLEN];
- char virtual_hostname[MAXHOSTNAMELEN];
- char virtual_address[MAXHOSTNAMELEN];
- char hostaddress[32];
- extern int virtual_mode;
- extern int virtual_ftpaccess;
- #endif
- #ifdef QUOTA
- extern struct dqblk quota;
- #endif
- int data;
- jmp_buf errcatch;
- JMP_BUF urgcatch;
- int logged_in = 0;
- struct passwd *pw;
- 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 usedefault = 1; /* for data transfers */
- int pdata = -1; /* for passive mode */
- int transflag;
- int ftwflag;
- off_t file_size;
- off_t byte_count;
- int TCPwindowsize = 0; /* 0 = use system default */
- #ifdef TRANSFER_COUNT
- int data_count_total = 0; /* total number of data bytes */
- int data_count_in = 0;
- int data_count_out = 0;
- int byte_count_total = 0; /* total number of general traffic */
- int byte_count_in = 0;
- int 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;
- int data_limit_raw_in = 0;
- int data_limit_raw_out = 0;
- int data_limit_raw_total = 0;
- int data_limit_data_in = 0;
- int data_limit_data_out = 0;
- int data_limit_data_total = 0;
- #endif
- #endif
- int retrieve_is_data = 1; /* !0=data, 0=general traffic -- for 'ls' */
- char LastFileTransferred[MAXPATHLEN] = "";
- static char *RootDirectory = NULL;
- #if !defined(CMASK) || CMASK == 0
- #undef CMASK
- #define CMASK 022
- #endif
- mode_t defumask = CMASK; /* default umask value */
- #ifdef ALTERNATE_CD
- char defhome[] = "/";
- #endif
- char tmpline[7];
- char hostname[MAXHOSTNAMELEN];
- char remotehost[MAXHOSTNAMELEN];
- char remoteaddr[MAXHOSTNAMELEN];
- char *remoteident = "[nowhere yet]";
- /* log failures 27-apr-93 ehk/bm */
- #ifdef LOG_FAILED
- #define MAXUSERNAMELEN 256
- char the_user[MAXUSERNAMELEN];
- #endif
- /* 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 */
- 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 */
- char *autospout = NULL;
- 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... */
- #define SWAITMAX 90 /* wait at most 90 seconds */
- #define SWAITINT 5 /* interval between retries */
- int swaitmax = SWAITMAX;
- int swaitint = SWAITINT;
- SIGNAL_TYPE lostconn(int sig);
- SIGNAL_TYPE randomsig(int sig);
- SIGNAL_TYPE myoob(int sig);
- FILE *getdatasock(char *mode);
- FILE *dataconn(char *name, off_t size, char *mode);
- void setproctitle(const char *fmt,...);
- void initsetproctitle(int, char **, char **);
- void reply(int, char *fmt,...);
- void lreply(int, char *fmt,...);
- #ifndef HAVE_VSNPRINTF
- extern int vsnprintf(char *, size_t, const char *, va_list);
- #endif
- #ifndef HAVE_SNPRINTF
- extern int snprintf(char *, size_t, const char *,...);
- #endif
- #ifdef HAVE_LIBRESOLV
- int initialize_dns(struct sockaddr_in *remote_socket);
- int check_reverse_dns(void);
- int check_matching_dns(void);
- #endif
- #ifdef NEED_SIGFIX
- extern sigset_t block_sigmask; /* defined in sigfix.c */
- #endif
- char proctitle[BUFSIZ]; /* initial part of title */
- #if defined(SKEY) && defined(OPIE)
- #error YOU SHOULD NOT HAVE BOTH SKEY AND OPIE DEFINED!!!!!
- #endif
- #ifdef SKEY
- #include <skey.h>
- int pwok = 0;
- #endif
- #ifdef OPIE
- #include <opie.h>
- int pwok = 0;
- int af_pwok = 0;
- struct opie opiestate;
- #endif
- #ifdef KERBEROS
- void init_krb();
- void end_krb();
- char krb_ticket_name[100];
- #endif /* KERBEROS */
- #ifdef ULTRIX_AUTH
- int ultrix_check_pass(char *passwd, char *xpasswd);
- #endif
- #ifdef USE_PAM
- #if defined(ULTRIX_AUTH) || defined(SHADOW_PASSWORD) || defined(SECUREOSF) || defined(KERBEROS) || defined(SKEY) || defined (OPIE) || defined (BSD_AUTH)
- #error No other auth methods are allowed with PAM.
- #endif
- static int pam_check_pass(char *user, char *passwd);
- #endif
- #ifndef INTERNAL_LS
- /* ls program commands and options for lreplies on and off */
- char ls_long[1024];
- char ls_short[1024];
- char ls_plain[1024];
- #endif
- #ifdef DAEMON
- int be_daemon = 0; /* Run standalone? */
- int daemon_port = 0;
- void do_daemon(int argc, char **argv, char **envp);
- #endif
- int Bypass_PID_Files = 0;
- void end_login(void);
- void print_copyright(void);
- char *mapping_getcwd(char *path, size_t size);
- #ifdef THROUGHPUT
- int send_data(char *name, FILE *, FILE *, off_t);
- #else
- int send_data(FILE *, FILE *, off_t);
- #endif
- void dolog(struct sockaddr_in *);
- void dologout(int);
- void perror_reply(int, char *);
- int denieduid(uid_t);
- int alloweduid(uid_t);
- int deniedgid(gid_t);
- int allowedgid(gid_t);
- int restricteduid(uid_t);
- int unrestricteduid(uid_t);
- int restrictedgid(gid_t);
- int unrestrictedgid(gid_t);
- #ifdef THROUGHPUT
- extern void throughput_calc(char *, int *, double *);
- extern void throughput_adjust(char *);
- #endif
- time_t login_time;
- time_t limit_time = 0;
- int regexmatch(char *name, char *rgexp);
- int pasv_allowed(char *remoteaddr);
- int port_allowed(char *remoteaddr);
- #if sparc && !__svr4__
- int fclose(FILE *);
- #endif
- static SIGNAL_TYPE alarm_signal(int sig)
- {
- }
- static FILE *draconian_FILE = NULL;
- static SIGNAL_TYPE draconian_alarm_signal(int sig)
- {
- if (draconian_FILE != NULL) {
- fclose(draconian_FILE);
- draconian_FILE = NULL;
- }
- }
- static void socket_flush_wait(FILE *file)
- {
- #ifndef SUPPORT_BROKEN_CLIENTS
- char c;
- int fd = fileno(file);
- if (draconian_FILE != NULL)
- shutdown(fd, 1);
- if (draconian_FILE != NULL)
- read(fd, &c, 1);
- /*
- * 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.
- */
- #endif
- }
- int main(int argc, char **argv, char **envp)
- {
- #if defined(UNIXWARE) || defined(AIX)
- size_t addrlen;
- #else
- int addrlen;
- #endif
- int on = 1;
- #ifdef IPTOS_LOWDELAY
- int tos;
- #endif
- int c;
- #ifndef INTERNAL_LS
- int which;
- #endif
- extern int optopt;
- extern char *optarg;
- struct hostent *shp;
- struct aclmember *entry;
- #ifdef VIRTUAL
- #if defined(UNIXWARE) || defined(AIX)
- size_t virtual_len;
- #else
- int virtual_len;
- #endif
- struct sockaddr_in *virtual_ptr;
- struct sockaddr_in virtual_addr;
- #endif
- #ifndef DAEMON
- struct servent *serv;
- #endif
- #ifdef AUX
- setcompat(COMPAT_POSIX | COMPAT_BSDSETUGID);
- #endif
- closelog();
- #ifdef FACILITY
- openlog("ftpd", LOG_PID | LOG_NDELAY, FACILITY);
- #else
- openlog("ftpd", LOG_PID);
- #endif
- #ifdef SecureWare
- setluid(1); /* make sure there is a valid luid */
- set_auth_parameters(argc, argv);
- setreuid(0, 0);
- #endif
- #if defined(M_UNIX) && !defined(_M_UNIX)
- res_init(); /* bug in old (1.1.1) resolver */
- _res.retrans = 20; /* because of fake syslog in 3.2.2 */
- setlogmask(LOG_UPTO(LOG_INFO));
- #endif
- #ifndef DAEMON
- addrlen = sizeof(his_addr);
- if (getpeername(0, (struct sockaddr *) &his_addr, &addrlen) < 0) {
- syslog(LOG_ERR, "getpeername (%s): %m", argv[0]);
- #ifndef DEBUG
- exit(1);
- #endif
- }
- addrlen = sizeof(ctrl_addr);
- if (getsockname(0, (struct sockaddr *) &ctrl_addr, &addrlen) < 0) {
- syslog(LOG_ERR, "getsockname (%s): %m", argv[0]);
- #ifndef DEBUG
- exit(1);
- #endif
- }
- #ifdef IPTOS_LOWDELAY
- tos = IPTOS_LOWDELAY;
- if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(int)) < 0)
- syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
- #endif
- serv = getservbyname("ftp-data", "tcp");
- if (serv != NULL)
- data_source.sin_port = serv->s_port;
- else
- data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
- #endif /* DAEMON */
- #ifndef DAEMON
- while ((c = getopt(argc, argv, ":aAvdlLiIoP:qQr:t:T:u:wVWX")) != -1) {
- #else /* DAEMON */
- while ((c = getopt(argc, argv, ":aAvdlLiIop:P:qQr:sSt:T:u:VwWX")) != -1) {
- #endif /* DAEMON */
- switch (c) {
- case 'a':
- use_accessfile = 1;
- break;
- case 'A':
- use_accessfile = 0;
- break;
- case 'v':
- debug = 1;
- break;
- case 'd':
- debug = 1;
- break;
- case 'l':
- logging = 1;
- break;
- case 'L':
- log_commands = 1;
- break;
- case 'i':
- log_incoming_xfers = 1;
- break;
- case 'I':
- disable_rfc931 = 1;
- break;
- case 'o':
- log_outbound_xfers = 1;
- break;
- case 'q':
- Bypass_PID_Files = 0;
- break;
- case 'Q':
- Bypass_PID_Files = 1;
- break;
- case 'r':
- if ((optarg != NULL) && (optarg[0] != ' ')) {
- RootDirectory = malloc(strlen(optarg) + 1);
- if (RootDirectory != NULL)
- strcpy(RootDirectory, optarg);
- }
- break;
- case 'P':
- data_source.sin_port = htons(atoi(optarg));
- break;
- #ifdef DAEMON
- case 'p':
- daemon_port = atoi(optarg);
- break;
- case 's':
- be_daemon = 1;
- break;
- case 'S':
- be_daemon = 2;
- break;
- #endif /* DAEMON */
- case 't':
- timeout_idle = atoi(optarg);
- if (timeout_maxidle < timeout_idle)
- timeout_maxidle = timeout_idle;
- break;
- case 'T':
- timeout_maxidle = atoi(optarg);
- if (timeout_idle > timeout_maxidle)
- timeout_idle = timeout_maxidle;
- break;
- case 'u':
- {
- unsigned int val = 0;
- while (*optarg && *optarg >= '0' && *optarg <= '9')
- val = val * 8 + *optarg++ - '0';
- if (*optarg || val > 0777)
- syslog(LOG_ERR, "bad value for -u");
- else
- defumask = val;
- break;
- }
- case 'V':
- print_copyright();
- 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 ':':
- syslog(LOG_ERR, "option -%c requires an argument", optopt);
- break;
- default:
- syslog(LOG_ERR, "unknown option -%c ignored", optopt);
- break;
- }
- }
- initsetproctitle(argc, argv, envp);
- (void) freopen(_PATH_DEVNULL, "w", stderr);
- /* Checking for random signals ... */
- #ifdef NEED_SIGFIX
- sigemptyset(&block_sigmask);
- #endif
- #ifndef SIG_DEBUG
- #ifdef SIGHUP
- (void) signal(SIGHUP, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGHUP);
- #endif
- #endif
- #ifdef SIGINT
- (void) signal(SIGINT, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGINT);
- #endif
- #endif
- #ifdef SIGQUIT
- (void) signal(SIGQUIT, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGQUIT);
- #endif
- #endif
- #ifdef SIGILL
- (void) signal(SIGILL, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGILL);
- #endif
- #endif
- #ifdef SIGTRAP
- (void) signal(SIGTRAP, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGTRAP);
- #endif
- #endif
- #ifdef SIGIOT
- (void) signal(SIGIOT, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGIOT);
- #endif
- #endif
- #ifdef SIGEMT
- (void) signal(SIGEMT, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGEMT);
- #endif
- #endif
- #ifdef SIGFPE
- (void) signal(SIGFPE, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGFPE);
- #endif
- #endif
- #ifdef SIGKILL
- (void) signal(SIGKILL, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGKILL);
- #endif
- #endif
- #ifdef SIGBUS
- (void) signal(SIGBUS, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGBUS);
- #endif
- #endif
- #ifdef SIGSEGV
- (void) signal(SIGSEGV, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGSEGV);
- #endif
- #endif
- #ifdef SIGSYS
- (void) signal(SIGSYS, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGSYS);
- #endif
- #endif
- #ifdef SIGALRM
- (void) signal(SIGALRM, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGALRM);
- #endif
- #endif
- #ifdef SIGSTOP
- (void) signal(SIGSTOP, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGSTOP);
- #endif
- #endif
- #ifdef SIGTSTP
- (void) signal(SIGTSTP, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGTSTP);
- #endif
- #endif
- #ifdef SIGTTIN
- (void) signal(SIGTTIN, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGTTIN);
- #endif
- #endif
- #ifdef SIGTTOU
- (void) signal(SIGTTOU, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGTTOU);
- #endif
- #endif
- #ifdef SIGIO
- (void) signal(SIGIO, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGIO);
- #endif
- #endif
- #ifdef SIGXCPU
- (void) signal(SIGXCPU, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGXCPU);
- #endif
- #endif
- #ifdef SIGXFSZ
- (void) signal(SIGXFSZ, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGXFSZ);
- #endif
- #endif
- #ifdef SIGWINCH
- (void) signal(SIGWINCH, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGWINCH);
- #endif
- #endif
- #ifdef SIGVTALRM
- (void) signal(SIGVTALRM, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGVTALRM);
- #endif
- #endif
- #ifdef SIGPROF
- (void) signal(SIGPROF, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGPROF);
- #endif
- #endif
- #ifdef SIGUSR1
- (void) signal(SIGUSR1, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGUSR1);
- #endif
- #endif
- #ifdef SIGUSR2
- (void) signal(SIGUSR2, randomsig);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGUSR2);
- #endif
- #endif
- #ifdef SIGPIPE
- (void) signal(SIGPIPE, lostconn);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGPIPE);
- #endif
- #endif
- #ifdef SIGCHLD
- (void) signal(SIGCHLD, SIG_IGN);
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGCHLD);
- #endif
- #endif
- #ifdef SIGURG
- if (signal(SIGURG, myoob) == SIG_ERR)
- syslog(LOG_ERR, "signal: %m");
- #ifdef NEED_SIGFIX
- sigaddset(&block_sigmask, SIGURG);
- #endif
- #endif
- #endif /* SIG_DEBUG */
- #ifdef VIRTUAL
- virtual_root[0] = ' ';
- virtual_banner[0] = ' ';
- #endif
- setup_paths();
- access_init();
- #ifdef DAEMON
- if (be_daemon != 0)
- do_daemon(argc, argv, envp);
- addrlen = sizeof(his_addr);
- if (getpeername(0, (struct sockaddr *) &his_addr, &addrlen) < 0) {
- syslog(LOG_ERR, "getpeername (%s): %m", argv[0]);
- #ifndef DEBUG
- exit(1);
- #endif
- }
- addrlen = sizeof(ctrl_addr);
- if (getsockname(0, (struct sockaddr *) &ctrl_addr, &addrlen) < 0) {
- syslog(LOG_ERR, "getsockname (%s): %m", argv[0]);
- #ifndef DEBUG
- exit(1);
- #endif
- }
- #ifdef IPTOS_LOWDELAY
- tos = IPTOS_LOWDELAY;
- if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(int)) < 0)
- syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
- #endif
- if (keepalive)
- if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0)
- syslog(LOG_ERR, "setsockopt SO_KEEPALIVE %m");
- data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
- #endif /* DAEMON */
- /* Try to handle urgent data inline */
- #ifdef SO_OOBINLINE
- if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof(int)) < 0)
- syslog(LOG_ERR, "setsockopt (SO_OOBINLINE): %m");
- #endif
- #ifdef F_SETOWN
- if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
- syslog(LOG_ERR, "fcntl F_SETOWN: %m");
- #elif defined(SIOCSPGRP)
- {
- int pid;
- pid = getpid();
- if (ioctl(fileno(stdin), SIOCSPGRP, &pid) == -1)
- syslog(LOG_ERR, "ioctl SIOCSPGRP: %m");
- }
- #endif
- if (RootDirectory != NULL) {
- if ((chroot(RootDirectory) < 0)
- || (chdir("/") < 0)) {
- syslog(LOG_ERR, "Cannot chroot to initial directory, aborting.");
- exit(1);
- }
- }
- #ifdef HAVE_LIBRESOLV
- /* initialize the resolver, and set global DNS variables */
- initialize_dns(&his_addr);
- #endif
- dolog(&his_addr);
- /* Set up default state */
- data = -1;
- type = TYPE_A;
- form = FORM_N;
- stru = STRU_F;
- mode = MODE_S;
- tmpline[0] = ' ';
- yyerrorcalled = 0;
- entry = (struct aclmember *) NULL;
- if ((getaclentry("hostname", &entry)) && ARG0) {
- (void) strncpy(hostname, ARG0, sizeof(hostname));
- hostname[sizeof(hostname) - 1] = ' ';
- }
- else {
- #ifdef HAVE_SYSINFO
- sysinfo(SI_HOSTNAME, hostname, sizeof(hostname));
- #else
- (void) gethostname(hostname, sizeof(hostname));
- #endif
- /* set the FQDN here */
- shp = gethostbyname(hostname);
- if (shp != NULL) {
- (void) strncpy(hostname, shp->h_name, sizeof(hostname));
- hostname[sizeof(hostname) - 1] = ' ';
- }
- }
- route_vectored = routevector();
- conv_init();
- #ifdef MAIL_ADMIN
- incmails = 0;
- mailfrom = NULL;
- #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
- ** minimal root/banner/logfile if they do not need any more than that.
- */
- if (virtual_mode) {
- /* Get the root of the virtual server directory */
- entry = (struct aclmember *) NULL;
- if (getaclentry("root", &entry)) {
- if (ARG0)
- strcpy(virtual_root, ARG0);
- }
- /* Get the logfile to use */
- entry = (struct aclmember *) NULL;
- if (getaclentry("logfile", &entry)) {
- if (ARG0)
- strcpy(logfile, ARG0);
- }
- }
- else {
- virtual_hostname[0] = ' ';
- virtual_address[0] = ' ';
- virtual_len = sizeof(virtual_addr);
- if (getsockname(0, (struct sockaddr *) &virtual_addr, &virtual_len) == 0) {
- virtual_ptr = (struct sockaddr_in *) &virtual_addr;
- strcpy(virtual_address, inet_ntoa(virtual_ptr->sin_addr));
- shp = gethostbyaddr((char *) &virtual_ptr->sin_addr, sizeof(struct in_addr), AF_INET);
- if (shp != NULL) {
- (void) strncpy(virtual_hostname, shp->h_name, sizeof(virtual_hostname));
- virtual_hostname[sizeof(virtual_hostname) - 1] = ' ';
- }
- entry = (struct aclmember *) NULL;
- while (getaclentry("virtual", &entry)) {
- if (!ARG0 || !ARG1 || !ARG2)
- continue;
- if (hostmatch(ARG0, virtual_address, virtual_hostname)) {
- if (!strcasecmp(ARG1, "root")) {
- syslog(LOG_NOTICE, "VirtualFTP Connect to: %s [%s]",
- virtual_hostname, virtual_address);
- virtual_mode = 1;
- strncpy(virtual_root, ARG2, sizeof(virtual_root));
- virtual_root[sizeof(virtual_root) - 1] = ' ';
- /* reset hostname to this virtual name */
- (void) strcpy(hostname, virtual_hostname);
- virtual_email[0] = ' ';
- }
- if (!strcasecmp(ARG1, "banner")) {
- strncpy(virtual_banner, ARG2, sizeof(virtual_banner));
- virtual_banner[sizeof(virtual_banner) - 1] = ' ';
- }
- if (!strcasecmp(ARG1, "logfile")) {
- strncpy(logfile, ARG2, sizeof(logfile));
- logfile[sizeof(logfile) - 1] = ' ';
- }
- if (!strcasecmp(ARG1, "hostname")) {
- strncpy(hostname, ARG2, sizeof(hostname));
- hostname[sizeof(hostname) - 1] = ' ';
- }
- if (!strcasecmp(ARG1, "email")) {
- strncpy(virtual_email, ARG2, sizeof(virtual_email));
- virtual_email[sizeof(virtual_email) - 1] = ' ';
- }
- #ifdef MAIL_ADMIN
- if (mailfrom == NULL)
- if (!strcasecmp(ARG1, "mailfrom")) {
- mailfrom = strdup(ARG2);
- }
- if (!strcasecmp(ARG1, "incmail")) {
- if (incmails < INCMAILS)
- incmail[incmails++] = strdup(ARG2);
- }
- #endif
- }
- }
- if (!virtual_mode) {
- entry = (struct aclmember *) NULL;
- while (getaclentry("defaultserver", &entry)) {
- if (!ARG0 || !ARG1)
- continue;
- #ifdef MAIL_ADMIN
- if (mailfrom == NULL)
- if (!strcasecmp(ARG0, "mailfrom")) {
- mailfrom = strdup(ARG1);
- }
- if (!strcasecmp(ARG0, "incmail")) {
- if (incmails < INCMAILS)
- incmail[incmails++] = strdup(ARG1);
- }
- #endif
- }
- }
- }
- }
- #ifdef VIRTUAL_DEBUG
- lreply(220, "_path_ftpaccess == %s", _path_ftpaccess);
- lreply(220, "_path_ftpusers == %s", _path_ftpusers);
- lreply(220, "_path_ftphosts == %s", _path_ftphosts);
- lreply(220, "_path_private == %s", _path_private);
- lreply(220, "_path_cvt == %s", _path_cvt);
- if (virtual_mode) {
- if (virtual_ftpaccess)
- lreply(220, "VIRTUAL Mode: Using %s specific %s access file",
- hostname, _path_ftpaccess);
- else
- lreply(220, "VIRTUAL Mode: Using Master access file %s",
- _path_ftpaccess);
- lreply(220, "virtual_root == %s", virtual_root);
- if (!virtual_ftpaccess)
- lreply(220, "virtual_banner == %s", virtual_banner);
- }
- lreply(220, "logfile == %s", logfile);
- #endif
- #endif
- if (is_shutdown(1, 1) != 0) {
- syslog(LOG_INFO, "connection refused (server shut down) from %s",
- remoteident);
- reply(500, "%s FTP server shut down -- please try again later.",
- hostname);
- exit(0);
- }
- #ifdef OPIE
- af_pwok = opieaccessfile(remotehost);
- #endif
- #ifdef HAVE_LIBRESOLV
- /* check permitted access based on remote host DNS information */
- if (!check_reverse_dns()) {
- exit(0);
- }
- if (!check_matching_dns()) {
- exit(0);
- }
- #endif /* HAVE_LIBRESOLV */
- show_banner(220);
- #ifndef INTERNAL_LS
- entry = (struct aclmember *) NULL;
- if (getaclentry("lslong", &entry) && ARG0 && (int) strlen(ARG0) > 0) {
- strcpy(ls_long, ARG0);
- for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
- strcat(ls_long, " ");
- strcat(ls_long, ARG[which]);
- }
- }
- else {
- #if defined(SVR4) || defined(ISC)
- #if defined(AIX) || defined(SOLARIS2)
- strcpy(ls_long, "/bin/ls -lA");
- #else
- strcpy(ls_long, "/bin/ls -la");
- #endif
- #else
- strcpy(ls_long, "/bin/ls -lgA");
- #endif
- }
- strcat(ls_long, " %s");
- entry = (struct aclmember *) NULL;
- if (getaclentry("lsshort", &entry) && ARG0 && (int) strlen(ARG0) > 0) {
- strcpy(ls_short, ARG0);
- for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
- strcat(ls_short, " ");
- strcat(ls_short, ARG[which]);
- }
- }
- else {
- #if defined(SVR4) || defined(ISC)
- #if defined(AIX) || defined(SOLARIS2)
- strcpy(ls_short, "/bin/ls -lA");
- #else
- strcpy(ls_short, "/bin/ls -la");
- #endif
- #else
- strcpy(ls_short, "/bin/ls -lgA");
- #endif
- }
- strcat(ls_short, " %s");
- entry = (struct aclmember *) NULL;
- if (getaclentry("lsplain", &entry) && ARG0 && (int) strlen(ARG0) > 0) {
- strcpy(ls_plain, ARG0);
- for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
- strcat(ls_plain, " ");
- strcat(ls_plain, ARG[which]);
- }
- }
- else
- strcpy(ls_plain, "/bin/ls");
- strcat(ls_plain, " %s");
- #endif /* ! INTERNAL_LS */
- #ifdef MAIL_ADMIN
- mailservers = 0;
- entry = (struct aclmember *) NULL;
- while (getaclentry("mailserver", &entry) && ARG0 && mailservers < MAILSERVERS)
- mailserver[mailservers++] = strdup(ARG0);
- if (mailservers == 0)
- mailserver[mailservers++] = strdup("localhost");
- if (incmails == 0) {
- entry = (struct aclmember *) NULL;
- while (getaclentry("incmail", &entry) && ARG0 && incmails < INCMAILS)
- incmail[incmails++] = strdup(ARG0);
- }
- if (mailfrom == NULL) {
- entry = (struct aclmember *) NULL;
- if (getaclentry("mailfrom", &entry) && ARG0)
- mailfrom = strdup(ARG0);
- else
- mailfrom = strdup("wu-ftpd");
- }
- #endif /* MAIL_ADMIN */
- {
- #define OUTPUT_LEN 1024
- int version_option = 0;
- char output_text[OUTPUT_LEN + 1];
- int arg_count, output_len;
- entry = NULL;
- if (getaclentry("greeting", &entry) && ARG0) {
- if (!strcasecmp(ARG0, "full"))
- version_option = 0;
- else if (!strcasecmp(ARG0, "text") && ARG1)
- version_option = 3;
- else if (!strcasecmp(ARG0, "terse"))
- version_option = 2;
- else if (!strcasecmp(ARG0, "brief"))
- version_option = 1;
- }
- switch (version_option) {
- default:
- reply(220, "%s FTP server (%s) ready.", hostname, version);
- break;
- case 1:
- reply(220, "%s FTP server ready.", hostname);
- break;
- case 2:
- reply(220, "FTP server ready.");
- break;
- case 3:
- output_text[0] = ' ';
- output_len = 0;
- for (arg_count = 1; ARG[arg_count] != NULL; arg_count++) {
- int arg_len;
- arg_len = strlen(ARG[arg_count]);
- if ((output_len + arg_len) > OUTPUT_LEN) {
- /* avoid possible buffer overflow */
- break;
- }
- /* append the text to the greeting */
- strcat(output_text, ARG[arg_count]);
- output_len += arg_len;
- if (ARG[arg_count + 1] != NULL) {
- if ((output_len + 2) > OUTPUT_LEN) {
- /* avoid possible buffer overflow and adding a trailing space */
- break;
- }
- /* if the next entry exists, add a white space */
- strcat(output_text, " ");
- output_len += 1;
- }
- }
- reply(220, "%s", output_text);
- break;
- }
- }
- (void) setjmp(errcatch);
- for (;;)
- (void) yyparse();
- /* NOTREACHED */
- }
- SIGNAL_TYPE randomsig(int sig)
- {
- #ifdef HAVE_SIGLIST
- syslog(LOG_ERR, "exiting on signal %d: %s", sig, sys_siglist[sig]);
- #else
- syslog(LOG_ERR, "exiting on signal %d", sig);
- #endif
- chdir("/");
- signal(SIGIOT, SIG_DFL);
- signal(SIGILL, SIG_DFL);
- exit(1);
- /* dologout(-1); *//* NOTREACHED */
- }
- SIGNAL_TYPE lostconn(int sig)
- {
- #ifdef VERBOSE_ERROR_LOGING
- syslog(LOG_INFO, "lost connection to %s", remoteident);
- #else
- if (debug)
- syslog(LOG_DEBUG, "lost connection to %s", remoteident);
- #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.
- */
- char mapped_path[MAXPATHLEN] = "/";
- char *mapping_getwd(char *path)
- {
- strcpy(path, mapped_path);
- return path;
- }
- char *mapping_getcwd(char *path, size_t size)
- {
- strncpy(path, mapped_path, size);
- path[size - 1] = ' ';
- return path;
- }
- /* Make these globals rather than local to mapping_chdir to avoid stack overflow */
- char pathspace[MAXPATHLEN];
- char old_mapped_path[MAXPATHLEN];
- void do_elem(char *dir)
- {
- /* . */
- if (dir[0] == '.' && dir[1] == ' ') {
- /* ignore it */
- return;
- }
- /* .. */
- if (dir[0] == '.' && dir[1] == '.' && dir[2] == ' ') {
- char *last;
- /* lop the last directory off the path */
- if ((last = strrchr(mapped_path, '/'))) {
- /* If start of pathname leave the / */
- if (last == mapped_path)
- last++;
- *last = ' ';
- }
- return;
- }
- /* append the dir part with a leading / unless at root */
- if (!(mapped_path[0] == '/' && mapped_path[1] == ' '))
- if (strlen(mapped_path) < sizeof(mapped_path) - 1)
- strcat(mapped_path, "/");
- if (sizeof(mapped_path) - strlen(mapped_path) > 1)
- strncat(mapped_path, dir, sizeof(mapped_path) - strlen(mapped_path) - 1);
- }
- int mapping_chdir(char *orig_path)
- {
- int ret;
- char *sl, *path;
- strcpy(old_mapped_path, mapped_path);
- path = &pathspace[0];
- strcpy(path, orig_path);
- /* / at start of path, set the start of the mapped_path to / */
- if (path[0] == '/') {
- mapped_path[0] = '/';
- mapped_path[1] = ' ';
- path++;
- }
- while ((sl = strchr(path, '/'))) {
- char *dir;
- dir = path;
- *sl = ' ';
- path = sl + 1;
- if (*dir)
- do_elem(dir);
- if (*path == ' ')
- break;
- }
- if (*path)
- do_elem(path);
- if ((ret = chdir(mapped_path)) < 0) {
- strcpy(mapped_path, old_mapped_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;
- new = (char *) malloc(strlen(s) + 1);
- if (new == NULL) {
- perror_reply(421, "Local resource failure: malloc");
- dologout(1);
- /* NOTREACHED */
- }
- (void) strcpy(new, s);
- 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). */
- struct passwd *sgetpwnam(char *name)
- {
- static struct passwd save;
- register struct passwd *p;
- #ifdef M_UNIX
- struct passwd *ret = (struct passwd *) NULL;
- #endif
- char *sgetsave(char *s);
- #ifdef KERBEROS
- register struct authorization *q;
- #endif /* KERBEROS */
- #if defined(SecureWare) || defined(HPUX_10_TRUSTED)
- struct pr_passwd *pr;
- #endif
- #ifdef KERBEROS
- init_krb();
- q = getauthuid(p->pw_uid);
- end_krb();
- #endif /* KERBEROS */
- #ifdef M_UNIX
- #if defined(SecureWare) || defined(HPUX_10_TRUSTED)
- if ((pr = getprpwnam(name)) == NULL)
- goto DONE;
- #endif /* SecureWare || HPUX_10_TRUSTED */
- if ((p = getpwnam(name)) == NULL)
- goto DONE;
- #else /* M_UNIX */
- #if defined(SecureWare) || defined(HPUX_10_TRUSTED)
- if ((pr = getprpwnam(name)) == NULL)
- return ((struct passwd *) pr);
- #endif /* SecureWare || HPUX_10_TRUSTED */
- if ((p = getpwnam(name)) == NULL)
- return (p);
- #endif /* M_UNIX */
- if (save.pw_name)
- free(save.pw_name);
- if (save.pw_gecos)
- free(save.pw_gecos);
- if (save.pw_dir)
- free(save.pw_dir);
- if (save.pw_shell)
- free(save.pw_shell);
- if (save.pw_passwd)
- free(save.pw_passwd);
- save = *p;
- save.pw_name = sgetsave(p->pw_name);
- #ifdef KERBEROS
- save.pw_passwd = sgetsave(q->a_password);
- #elif defined(SecureWare) || defined(HPUX_10_TRUSTED)
- if (pr->uflg.fg_encrypt && pr->ufld.fd_encrypt && *pr->ufld.fd_encrypt)
- save.pw_passwd = sgetsave(pr->ufld.fd_encrypt);
- else
- save.pw_passwd = sgetsave("");
- #else
- save.pw_passwd = sgetsave(p->pw_passwd);
- #endif
- #ifdef SHADOW_PASSWORD
- if (p) {
- struct spwd *spw;
- setspent();
- if ((spw = getspnam(p->pw_name)) != NULL) {
- int expired = 0;
- /*XXX Does this work on all Shadow Password Implementations? */
- /* it is supposed to work on Solaris 2.x */
- time_t now;
- long today;
- now = time((time_t *) 0);
- today = now / (60 * 60 * 24);
- if ((spw->sp_expire > 0) && (spw->sp_expire < today))
- expired++;
- if ((spw->sp_max > 0) && (spw->sp_lstchg > 0) &&
- (spw->sp_lstchg + spw->sp_max < today))
- expired++;
- free(save.pw_passwd);
- save.pw_passwd = sgetsave(expired ? "" : spw->sp_pwdp);
- }
- /* 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 */
- #if !defined(LINUX) && !defined(UNIXWARE)
- else {
- free(save.pw_passwd);
- save.pw_passwd = sgetsave("");
- }
- #endif
- /* marekm's fix for linux proc file system shadow passwd exposure problem */
- endspent();
- }
- #endif
- save.pw_gecos = sgetsave(p->pw_gecos);
- save.pw_dir = sgetsave(p->pw_dir);
- save.pw_shell = sgetsave(p->pw_shell);
- #ifdef M_UNIX
- ret = &save;
- 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 */
- char *skey_challenge(char *name, struct passwd *pwd, int pwok)
- {
- static char buf[128];
- char sbuf[40];
- struct skey skey;
- /* Display s/key challenge where appropriate. */
- if (pwd == NULL || skeychallenge(&skey, pwd->pw_name, sbuf))
- sprintf(buf, "Password required for %s.", name);
- else
- sprintf(buf, "%s %s for %s.", sbuf,
- pwok ? "allowed" : "required", name);
- return (buf);
- }
- #endif
- int login_attempts; /* number of failed login attempts */
- int askpasswd; /* had user command, ask for passwd */
- #ifndef HELP_CRACKERS
- int DenyLoginAfterPassword;
- char DelayedMessageFile[MAXPATHLEN];
- extern void pr_mesg(int msgcode, char *msgfile);
- #endif
- #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
- static int defaultserver_allow(const char *username)
- {
- struct aclmember *entry = NULL;
- int which;
- while (getaclentry("defaultserver", &entry))
- if (ARG0 && !strcasecmp(ARG0, "allow"))
- for (which = 1; (which < MAXARGS) && ARG[which]; which++)
- if (!strcasecmp(username, ARG[which]) || !strcmp("*", ARG[which]))
- return (1);
- return (0);
- }
- static int defaultserver_deny(const char *username)
- {
- struct aclmember *entry = NULL;
- int which;
- while (getaclentry("defaultserver", &entry))
- if (ARG0 && !strcasecmp(ARG0, "deny"))
- for (which = 1; (which < MAXARGS) && ARG[which]; which++)
- if (!strcasecmp(username, ARG[which]) || !strcmp("*", ARG[which]))
- return (1);
- return (0);
- }
- static int defaultserver_private(void)
- {
- struct aclmember *entry = NULL;
- while (getaclentry("defaultserver", &entry))
- if (ARG0 && !strcasecmp(ARG0, "private"))
- 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 _PATH_FTPUSERS, 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 file _PATH_FTPUSERS to allow people such as root
- * and uucp to be avoided. */
- /*
- char *getusershell();
- */
- void user(char *name)
- {
- char *cp;
- char *shell;
- #ifdef BSD_AUTH
- char *auth;
- #endif
- /* H* fix: if we're logged in at all, we can't log in again. */
- if (logged_in) {
- #ifdef VERBOSE_ERROR_LOGING
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (already logged in as %s) FROM %s, %s",
- pw->pw_name, remoteident, name);
- #endif
- reply(530, "Already logged in.");
- return;
- }
- #ifndef HELP_CRACKERS
- askpasswd = 1;
- DenyLoginAfterPassword = 0;
- DelayedMessageFile[0] = ' ';
- #endif
- #ifdef BSD_AUTH
- if ((auth = strchr(name, ':')))
- *auth++ = 0;
- #endif
- #ifdef HOST_ACCESS /* 19-Mar-93 BM */
- if (!rhost_ok(name, remotehost, remoteaddr)) {
- #ifndef HELP_CRACKERS
- DenyLoginAfterPassword = 1;
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (name in %s) FROM %s, %s",
- _PATH_FTPHOSTS, remoteident, name);
- #else
- reply(530, "User %s access denied.", name);
- syslog(LOG_NOTICE,
- "FTP LOGIN REFUSED (name in %s) FROM %s, %s",
- _PATH_FTPHOSTS, remoteident, name);
- return;
- #endif
- }
- #endif
- #ifdef LOG_FAILED /* 06-Nov-92 EHK */
- strncpy(the_user, name, MAXUSERNAMELEN - 1);
- #endif
- anonymous = 0;
- acl_remove();
- if (!strcasecmp(name, "ftp") || !strcasecmp(name, "anonymous")) {
- struct aclmember *entry = NULL;
- int machineok = 1;
- char guestservername[MAXHOSTNAMELEN];
- guestservername[0] = ' ';
- #ifdef NO_ANONYMOUS_ACCESS
- reply(530, "Anonymous FTP access denied.");
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (anonymous ftp not supported) FROM %s, %s",
- remoteident, name);
- return;
- #else
- #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
- if (!virtual_mode && defaultserver_private()) {
- #ifndef HELP_CRACKERS
- DenyLoginAfterPassword = 1;
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (anonymous ftp denied on default server) FROM %s, %s",
- remoteident, name);
- #else
- reply(530, "User %s access denied.", name);
- syslog(LOG_NOTICE,
- "FTP LOGIN REFUSED (anonymous ftp denied on default server) FROM %s, %s",
- remoteident, name);
- return;
- #endif
- }
- #endif
- if (checkuser("ftp") || checkuser("anonymous")) {
- #ifndef HELP_CRACKERS
- DenyLoginAfterPassword = 1;
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp in %s) FROM %s, %s",
- _PATH_FTPUSERS, remoteident, name);
- #else
- reply(530, "User %s access denied.", name);
- syslog(LOG_NOTICE,
- "FTP LOGIN REFUSED (ftp in %s) FROM %s, %s",
- _PATH_FTPUSERS, remoteident, name);
- 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>
- */
- }
- else if (getaclentry("guestserver", &entry)
- && ARG0 && (int) strlen(ARG0) > 0) {
- struct hostent *tmphostent;
- /*
- ** if a "guestserver" line is present,
- ** default is not to allow guest logins
- */
- machineok = 0;
- if (hostname[0]
- && ((tmphostent = gethostbyname(hostname)))) {
- /*
- ** 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;
- strncpy(dns_localhost,
- tmphostent->h_name,
- sizeof(dns_localhost));
- dns_localhost[sizeof(dns_localhost) - 1] = ' ';
- for (machinecount = 0;
- entry->arg[machinecount] && (entry->arg[machinecount])[0];
- machinecount++) {
- if ((tmphostent = gethostbyname(entry->arg[machinecount]))) {
- /*
- ** remember the name of the first machine for redirection
- */
- if ((!machinecount) && tmphostent->h_name) {
- strncpy(guestservername, entry->arg[machinecount],
- sizeof(guestservername));
- guestservername[sizeof(guestservername) - 1] = ' ';
- }
- if (!strcasecmp(tmphostent->h_name, dns_localhost)) {
- machineok++;
- break;
- }
- }
- }
- }
- }
- if (!machineok) {
- if (guestservername[0])
- reply(530,
- "Guest login not allowed on this machine, connect to %s instead.",
- guestservername);
- else
- reply(530,
- "Guest login not allowed on this machine.");
- syslog(LOG_NOTICE,
- "FTP LOGIN REFUSED (localhost not in guestservers) FROM %s, %s",
- remoteident, name);
- /* End of the big patch -- Nap */
- }
- else if ((pw = sgetpwnam("ftp")) != NULL) {
- anonymous = 1; /* for the access_ok call */
- if (access_ok(530) < 1) {
- #ifndef HELP_CRACKERS
- DenyLoginAfterPassword = 1;
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s, %s",
- remoteident, name);
- reply(331, "Guest login ok, send your complete e-mail address as password.");
- #else
- reply(530, "User %s access denied.", name);
- syslog(LOG_NOTICE,
- "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.
- XXX: all these checks maybe should be in acl.c and access.c */
- if (use_accessfile)
- acl_setfunctions();
- reply(331, "Guest login ok, send your complete e-mail address as password.");
- }
- }
- else {
- #ifndef HELP_CRACKERS
- DenyLoginAfterPassword = 1;
- reply(331, "Guest login ok, send your complete e-mail address as password.");
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp not in /etc/passwd) FROM %s, %s",
- remoteident, name);
- #else
- reply(530, "User %s unknown.", name);
- syslog(LOG_NOTICE,
- "FTP LOGIN REFUSED (ftp not in /etc/passwd) FROM %s, %s",
- remoteident, name);
- #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
- DenyLoginAfterPassword = 1;
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (not anonymous) FROM %s, %s",
- remoteident, name);
- reply(331, "Password required for %s.", name);
- #else
- reply(530, "User %s unknown.", name);
- syslog(LOG_NOTICE,
- "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)
- if (!virtual_mode && defaultserver_deny(name) && !defaultserver_allow(name)) {
- #ifndef HELP_CRACKERS
- DenyLoginAfterPassword = 1;
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp denied on default server) FROM %s, %s",
- remoteident, name);
- #else
- reply(530, "User %s access denied.", name);
- syslog(LOG_NOTICE,
- "FTP LOGIN REFUSED (ftp denied on default server) FROM %s, %s",
- remoteident, name);
- return;
- #endif
- }
- #endif
- if ((pw = sgetpwnam(name)) != NULL) {
- if ((denieduid(pw->pw_uid) && !alloweduid(pw->pw_uid))
- || (deniedgid(pw->pw_gid) && !allowedgid(pw->pw_gid))) {
- #ifndef HELP_CRACKERS
- DenyLoginAfterPassword = 1;
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in denied-uid) FROM %s, %s",
- remoteident, name);
- reply(331, "Password required for %s.", name);
- #else
- reply(530, "User %s access denied.", name);
- syslog(LOG_NOTICE,
- "FTP LOGIN REFUSED (username in denied-uid) FROM %s, %s",
- remoteident, name);
- #endif
- return;
- }
- #ifndef USE_PAM /* PAM should be doing these checks, not ftpd */
- if ((shell = pw->pw_shell) == NULL || *shell == 0)
- shell = _PATH_BSHELL;
- while ((cp = getusershell()) != NULL)
- if (strcmp(cp, shell) == 0)
- break;
- endusershell();
- if (cp == NULL || checkuser(name)) {
- #ifndef HELP_CRACKERS
- DenyLoginAfterPassword = 1;
- if (cp == NULL)
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (shell not in /etc/shells) FROM %s, %s", remoteident, name);
- else
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in %s) FROM %s, %s", _PATH_FTPUSERS, remoteident, name);
- reply(331, "Password required for %s.", name);
- #else
- reply(530, "User %s access denied.", name);
- if (cp == NULL)
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (shell not in /etc/shells) FROM %s, %s", remoteident, name);
- else
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in %s) FROM %s, %s", _PATH_FTPUSERS, remoteident, name);
- #endif
- pw = (struct passwd *) NULL;
- return;
- }
- #endif /* USE_PAM */
- /* 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 = acl_guestgroup(pw);
- if (guest && acl_realgroup(pw))
- guest = 0;
- }
- }
- if (access_ok(530) < 1) {
- #ifndef HELP_CRACKERS
- DenyLoginAfterPassword = 1;
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s, %s",
- remoteident, name);
- reply(331, "Password required for %s.", name);
- #else
- reply(530, "User %s access denied.", name);
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s, %s",
- remoteident, name);
- #endif
- return;
- }
- else if (use_accessfile) /* see above. _H */
- acl_setfunctions();
- #ifdef BSD_AUTH
- if ((cp = start_auth(auth, name, pw)) != NULL) {
- char *s;
- for (;;) {
- s = strsep(&cp, "n");
- if (cp == NULL || *cp == ' ')
- break;
- lreply(331, s);
- }
- reply(331, s);
- }
- else {
- #endif
- #ifdef SKEY
- #ifndef __NetBSD__
- #ifdef SKEY_NAME
- /* this is the old way, but freebsd uses it */
- pwok = skeyaccess(name, NULL, remotehost, remoteaddr);
- #else
- /* this is the new way */
- pwok = skeyaccess(pw, NULL, remotehost, remoteaddr);
- #endif
- reply(331, "%s", skey_challenge(name, pw, pwok));
- #else
- if (skey_haskey(name) == 0) {
- char *myskey;
- myskey = skey_keyinfo(name);
- reply(331, "Password [%s] required for %s.",
- myskey ? myskey : "error getting challenge", name);
- }
- else
- reply(331, "Password required for %s.", name);
- #endif
- #else
- #ifdef OPIE
- {
- char prompt[OPIE_CHALLENGE_MAX + 1];
- opiechallenge(&opiestate, name, prompt);
- if (askpasswd == -1) {
- syslog(LOG_WARNING, "Invalid FTP user name %s attempted from %s", name, remotehost);
- pwok = 0;
- }
- else
- pwok = af_pwok && opiealways(pw->pw_dir);
- reply(331, "Response to %s %s for %s.",
- prompt, pwok ? "requested" : "required", name);
- }
- #else
- reply(331, "Password required for %s.", name);
- #endif
- #endif
- #ifdef BSD_AUTH
- }
- #endif
- 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 file _PATH_FTPUSERS */
- int checkuser(char *name)
- {
- register FILE *fd;
- register char *p;
- char line[BUFSIZ];
- if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) {
- while (fgets(line, sizeof(line), fd) != NULL)
- if ((p = strchr(line, 'n')) != NULL) {
- *p = ' ';
- if (line[0] == '#')
- continue;
- if (strcasecmp(line, name) == 0) {
- (void) fclose(fd);
- return (1);
- }
- }
- (void) fclose(fd);
- }
- return (0);
- }
- int denieduid(uid_t uid)
- {
- struct aclmember *entry = NULL;
- int which;
- char *ptr;
- struct passwd *pw;
- while (getaclentry("deny-uid", &entry)) {
- for (which = 0; (which < MAXARGS) && ARG[which]; which++) {
- if (!strcmp(ARG[which], "*"))
- return (1);
- if (ARG[which][0] == '%') {
- if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) {
- if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) {
- if (uid == strtoul(ARG[which] + 1, NULL, 0))
- return (1);
- }
- else {
- *ptr++ = ' ';
- if ((ARG[which][1] == ' ')
- || (uid >= strtoul(ARG[which] + 1, NULL, 0))) {
- *--ptr = '+';
- return (1);
- }
- *--ptr = '+';
- }
- }
- else {
- *ptr++ = ' ';
- if (((ARG[which][1] == ' ')
- || (uid >= strtoul(ARG[which] + 1, NULL, 0)))
- && ((*ptr == ' ')
- || (uid <= strtoul(ptr, NULL, 0)))) {
- *--ptr = '-';
- return (1);
- }
- *--ptr = '-';
- }
- }
- else {
- pw = getpwnam(ARG[which]);
- if (pw && (uid == pw->pw_uid))
- return (1);
- }
- }
- }
- return (0);
- }
- int alloweduid(uid_t uid)
- {
- struct aclmember *entry = NULL;
- int which;
- char *ptr;
- struct passwd *pw;
- while (getaclentry("allow-uid", &entry)) {
- for (which = 0; (which < MAXARGS) && ARG[which]; which++) {
- if (!strcmp(ARG[which], "*"))
- return (1);
- if (ARG[which][0] == '%') {
- if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) {
- if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) {
- if (uid == strtoul(ARG[which] + 1, NULL, 0))
- return (1);
- }
- else {
- *ptr++ = ' ';
- if ((ARG[which][1] == ' ')
- || (uid >= strtoul(ARG[which] + 1, NULL, 0))) {
- *--ptr = '+';
- return (1);
- }
- *--ptr = '+';
- }
- }
- else {
- *ptr++ = ' ';
- if (((ARG[which][1] == ' ')
- || (uid >= strtoul(ARG[which] + 1, NULL, 0)))
- && ((*ptr == ' ')
- || (uid <= strtoul(ptr, NULL, 0)))) {
- *--ptr = '-';
- return (1);
- }
- *--ptr = '-';
- }
- }
- else {
- pw = getpwnam(ARG[which]);
- if (pw && (uid == pw->pw_uid))
- return (1);
- }
- }
- }
- return (0);
- }
- int deniedgid(gid_t gid)
- {
- struct aclmember *entry = NULL;
- int which;
- char *ptr;
- struct group *grp;
- while (getaclentry("deny-gid", &entry)) {
- for (which = 0; (which < MAXARGS) && ARG[which]; which++) {
- if (!strcmp(ARG[which], "*"))
- return (1);
- if (ARG[which][0] == '%') {
- if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) {
- if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) {
- if (gid == strtoul(ARG[which] + 1, NULL, 0))
- return (1);
- }
- else {
- *ptr++ = ' ';
- if ((ARG[which][1] == ' ')
- || (gid >= strtoul(ARG[which] + 1, NULL, 0))) {
- *--ptr = '+';
- return (1);
- }
- *--ptr = '+';
- }
- }
- else {
- *ptr++ = ' ';
- if (((ARG[which][1] == ' ')
- || (gid >= strtoul(ARG[which] + 1, NULL, 0)))
- && ((*ptr == ' ')
- || (gid <= strtoul(ptr, NULL, 0)))) {
- *--ptr = '-';
- return (1);
- }
- *--ptr = '-';
- }
- }
- else {
- grp = getgrnam(ARG[which]);
- if (grp && (gid == grp->gr_gid))
- return (1);
- }
- }
- }
- return (0);
- }
- int allowedgid(gid_t gid)
- {
- struct aclmember *entry = NULL;
- int which;
- char *ptr;
- struct group *grp;
- while (getaclentry("allow-gid", &entry)) {
- for (which = 0; (which < MAXARGS) && ARG[which]; which++) {
- if (!strcmp(ARG[which], "*"))
- return (1);
- if (ARG[which][0] == '%') {
- if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) {
- if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) {
- if (gid == strtoul(ARG[which] + 1, NULL, 0))
- return (1);
- }
- else {
- *ptr++ = ' ';
- if ((ARG[which][1] == ' ')
- || (gid >= strtoul(ARG[which] + 1, NULL, 0))) {
- *--ptr = '+';
- return (1);
- }
- *--ptr = '+';
- }
- }
- else {
- *ptr++ = ' ';
- if (((ARG[which][1] == ' ')
- || (gid >= strtoul(ARG[which] + 1, NULL, 0)))
- && ((*ptr == ' ')
- || (gid <= strtoul(ptr, NULL, 0)))) {
- *--ptr = '-';
- return (1);
- }
- *--ptr = '-';
- }
- }
- else {
- grp = getgrnam(ARG[which]);
- if (grp && (gid == grp->gr_gid))
- 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 */
- (void) seteuid((uid_t) 0);
- if (logged_in)
- if (wtmp_logging)
- wu_logwtmp(ttyline, pw->pw_name, remotehost, 0);
- pw = NULL;
- #ifdef AFS_AUTH
- ktc_ForgetAllTokens();
- #endif
- logged_in = 0;
- anonymous = 0;
- guest = 0;
- }
- int validate_eaddr(char *eaddr)
- {
- int i, host, state;
- for (i = host = state = 0; eaddr[i] != ' '; i++) {
- switch (eaddr[i]) {
- case '.':
- if (!host)
- return 0;
- if (state == 2)
- state = 3;
- host = 0;
- break;
- case '@':
- if (!host || state > 1 || !strncasecmp("ftp", eaddr + i - host, host))
- return 0;
- state = 2;
- host = 0;
- break;
- case '!':
- case '%':
- if (!host || state > 1)
- return 0;
- state = 1;
- host = 0;
- break;
- case '-':
- break;
- default:
- host++;
- }
- }
- if (((state == 3) && host > 1) || ((state == 2) && !host) ||
- ((state == 1) && host > 1))
- return 1;
- else
- return 0;
- }
- #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
- static int AllowVirtualUser(const char *username)
- {
- struct aclmember *entry = NULL;
- int which;
- while (getaclentry("virtual", &entry))
- if (ARG0 && hostmatch(ARG0, virtual_address, virtual_hostname)
- && ARG1 && !strcasecmp(ARG1, "allow"))
- for (which = 2; (which < MAXARGS) && ARG[which]; which++)
- if (!strcasecmp(username, ARG[which]) || !strcmp("*", ARG[which]))
- return (1);
- return (0);
- }
- static int DenyVirtualUser(const char *username)
- {
- struct aclmember *entry = NULL;
- int which;
- while (getaclentry("virtual", &entry))
- if (ARG0 && hostmatch(ARG0, virtual_address, virtual_hostname)
- && ARG1 && !strcasecmp(ARG1, "deny"))
- for (which = 2; (which < MAXARGS) && ARG[which]; which++)
- if (!strcasecmp(username, ARG[which]) || !strcmp("*", ARG[which]))
- return (1);
- return (0);
- }
- static int DenyVirtualAnonymous(void)
- {
- struct aclmember *entry = NULL;
- while (getaclentry("virtual", &entry))
- if (ARG0 && hostmatch(ARG0, virtual_address, virtual_hostname)
- && ARG1 && !strcasecmp(ARG1, "private"))
- return (1);
- return (0);
- }
- #endif
- void pass(char *passwd)
- {
- #ifndef USE_PAM
- char *xpasswd, *salt;
- #endif
- int passwarn = 0;
- int rval = 1;
- #ifdef SECUREOSF
- struct pr_passwd *pr;
- 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
- sec_passwd_rec_t pwr;
- sec_login_handle_t lhdl;
- boolean32 rstpwd;
- sec_login_auth_src_t asrc;
- error_status_t status;
- #endif /* DCE_AUTH */
- if (logged_in || askpasswd == 0) {
- #ifdef VERBOSE_ERROR_LOGING
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED (PASS before USER) FROM %s",
- remoteident);
- #endif
- reply(503, "Login with USER first.");
- 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;
- /* ******** REGULAR/GUEST USER PASSWORD PROCESSING ********** */
- if (!anonymous) { /* "ftp" is only account allowed no password */
- #ifndef HELP_CRACKERS
- if (DenyLoginAfterPassword) {
- pr_mesg(530, DelayedMessageFile);
- reply(530, "Login incorrect.");
- acl_remove();
- pw = NULL;
- if (++login_attempts >= lgi_failure_threshold) {
- syslog(LOG_NOTICE, "repeated login failures from %s",
- remoteident);
- exit(0);
- }
- return;
- }
- #endif
- if (*passwd == '-')
- passwd++;
- #ifdef USE_PAM
- /* 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 */
- if (pam_check_pass(the_user, passwd)) {
- rval = 0;
- if (pw == NULL) {
- /* assume guest account identity */
- pw = sgetpwnam("ftp");
- anonymous = 0;
- guest = 1;
- /* even go as far as... */
- if (pw != NULL && pw->pw_name != NULL) {
- free(pw->pw_name);
- pw->pw_name = sgetsave(the_user);
- }
- }
- }
- #else /* !USE_PAM */
- #ifdef BSD_AUTH
- if (ext_auth) {
- if ((salt = check_auth(the_user, passwd))) {
- reply(530, salt);
- #ifdef LOG_FAILED /* 27-Apr-93 EHK/BM */
- syslog(LOG_INFO, "failed login from %s",
- remoteident);
- #endif
- acl_remove();
- pw = NULL;
- if (++login_attempts >= lgi_failure_threshold) {
- syslog(LOG_NOTICE, "repeated login failures from %s",
- remoteident);
- exit(0);
- }
- return;
- }
- }
- else {
- #endif
- *guestpw = ' ';
- if (pw == NULL)
- salt = "xx";
- else
- #ifndef OPIE
- salt = pw->pw_passwd;
- #ifdef SECUREOSF
- if ((pr = getprpwnam(pw->pw_name)) != NULL) {
- if (pr->uflg.fg_newcrypt)
- crypt_alg = pr->ufld.fd_newcrypt;
- else if (pr->sflg.fg_newcrypt)
- crypt_alg = pr->sfld.fd_newcrypt;
- else
- crypt_alg = 0;
- }
- else
- crypt_alg = 0;
- xpasswd = dispcrypt(passwd, salt, crypt_alg);
- #elif defined(SecureWare) || defined(HPUX_10_TRUSTED)
- xpasswd = bigcrypt(passwd, salt);
- #elif defined(KERBEROS)
- xpasswd = crypt16(passwd, salt);
- #elif defined(SKEY)
- #ifndef __NetBSD__
- xpasswd = skey_crypt(passwd, salt, pw, pwok);
- pwok = 0;
- #else
- if ((pw != NULL) && (pw->pw_name != NULL) && skey_haskey(pw->pw_name) == 0 &&
- skey_passcheck(pw->pw_name, passwd) != -1)
- xpasswd = pw->pw_passwd;
- else
- xpasswd = crypt(passwd, salt);
- #endif
- #else
- xpasswd = crypt(passwd, salt);
- #endif /* SKEY */
- #else /* OPIE */
- if (!opieverify(&opiestate, passwd))
- rval = 0;
- xpasswd = crypt(passwd, pw->pw_passwd);
- #endif /* OPIE */
- #ifdef ULTRIX_AUTH
- if ((numfails = ultrix_check_pass(passwd, xpasswd)) >= 0) {
- #else
- if (pw != NULL) {
- #ifdef AFS_AUTH
- if (strcmp(pw->pw_passwd, "X") == 0)
- if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION | KA_USERAUTH_DOSETPAG, pw->pw_name, "", 0, passwd, 0, 0, 0, &reason) == 0)
- rval = 0;
- else
- printf("230-AFS: %s", reason);
- else
- #endif /* AFS_AUTH */
- /* The strcmp does not catch null passwords! */
- #ifdef HAS_PW_EXPIRE
- if(pw->pw_expire != NULL) {
- if(pw->pw_expire && time(NULL) >= pw->pw_expire) {
- set_expired = TRUE;
- }
- }
- #endif
-
- if (*pw->pw_passwd != ' ' &&
- #ifdef HAS_PW_EXPIRE
- !set_expired &&
- #endif
- strcmp(xpasswd, pw->pw_passwd) == 0) {
- #endif
- rval = 0;
- }
- #ifdef DCE_AUTH
- #ifndef ALWAYS_TRY_DCE
- else
- #endif /* ALWAYS_TRY_DCE */
- {
- sec_login_setup_identity((unsigned_char_p_t) pw->pw_name, sec_login_no_flags, &lhdl, &status);
- if (status == error_status_ok) {
- printf("230-sec_login_setup_identity OKn");
- pwr.key.tagged_union.plain = (idl_char *) passwd;
- pwr.key.key_type = sec_passwd_plain;
- pwr.pepper = 0;
- pwr.version_number = sec_passwd_c_version_none;
- /* validate password with login context */
- sec_login_valid_and_cert_ident(lhdl, &pwr, &rstpwd, &asrc, &status);
- if (!rstpwd && (asrc == sec_login_auth_src_network) && (status == error_status_ok)) {
- printf("230-sec_login_valid_and_cert_ident OKn");
- sec_login_set_context(lhdl, &status);
- printf("230-sec_login_set_context finishedn");
- if (status != error_status_ok) {
- int pstatus;
- dce_error_string_t s;
- printf("230-Error status: %d:n", status);
- dce_error_inq_text(status, s, &pstatus);
- printf("230-%sn", s);
- fflush(stderr);
- sec_login_purge_context(lhdl, &status);
- }
- else {
- /*sec_login_get_pwent(lhdl, &pw, &status); */
- rval = 0;
- }
- }
- }
- }
- #endif /* DCE_AUTH */
- }
- #endif /* !USE_PAM */
- if (rval) {
- reply(530, "Login incorrect.");
- #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! */
- if (!strcasecmp(passwd, "NULL"))
- syslog(LOG_NOTICE, "REFUSED "NULL" from %s, %s",
- remoteident, the_user);
- else
- syslog(LOG_INFO, "failed login from %s",
- remoteident);
- #endif
- acl_remove();
- pw = NULL;
- if (++login_attempts >= lgi_failure_threshold) {
- syslog(LOG_NOTICE, "repeated login failures from %s",
- remoteident);
- exit(0);
- }
- return;
- }
- #ifdef BSD_AUTH
- }
- #endif
- /* ANONYMOUS USER PROCESSING STARTS HERE */
- }
- else {
- char *pwin, *pwout = guestpw;
- struct aclmember *entry = NULL;
- int valid;
- int enforce = 0;
- if (getaclentry("passwd-check", &entry) &&
- ARG0 && strcasecmp(ARG0, "none")) {
- if (!strcasecmp(ARG0, "rfc822"))
- valid = validate_eaddr(passwd);
- else if (!strcasecmp(ARG0, "trivial"))
- valid = (strchr(passwd, '@') == NULL) ? 0 : 1;
- else
- valid = 1;
- if (ARG1 && !strcasecmp(ARG1, "enforce"))
- enforce = 1;
- /* Block off "default" responses like mozilla@ and IE30User@
- * (at the administrator's discretion). --AC
- */
- entry = NULL;
- while (getaclentry("deny-email", &entry)) {
- if (ARG0
- && ((strcasecmp(passwd, ARG0) == 0)
- || regexmatch(passwd, ARG0)
- || ((*passwd == '-')
- && ((strcasecmp(passwd + 1, ARG0) == 0)
- || regexmatch(passwd + 1, ARG0))))) {
- valid = 0;
- break;
- }
- }
- if (!valid && enforce) {
- lreply(530, "The response '%s' is not valid", passwd);
- lreply(530, "Please use your e-mail address as your password");
- lreply(530, " for example: %s@%s or %s@",
- authenticated ? authuser : "joe", remotehost,
- authenticated ? authuser : "joe");
- lreply(530, "[%s will be added if password ends with @]",
- remotehost);
- reply(530, "Login incorrect.");
- #ifdef VERBOSE_ERROR_LOGING
- syslog(LOG_NOTICE, "FTP ACCESS REFUSED (anonymous password not rfc822) from %s",
- remoteident);
- #endif
- acl_remove();
- if (++login_attempts >= lgi_failure_threshold) {
- syslog(LOG_NOTICE, "repeated login failures from %s",
- remoteident);
- exit(0);
- }
- return;
- }
- else if (!valid)
- passwarn = 1;
- }
- if (!*passwd) {
- strcpy(guestpw, "[none_given]");
- }
- else {
- int cnt = sizeof(guestpw) - 2;
- for (pwin = passwd; *pwin && cnt--; pwin++)
- if (!isgraph(*pwin))
- *pwout++ = '_';
- else
- *pwout++ = *pwin;
- }
- #ifndef HELP_CRACKERS
- if (DenyLoginAfterPassword) {
- pr_mesg(530, DelayedMessageFile);
- reply(530, "Login incorrect.");
- acl_remove();
- pw = NULL;
- if (++login_attempts >= lgi_failure_threshold) {
- syslog(LOG_NOTICE, "repeated login failures from %s",
- remoteident);
- exit(0);
- }
- return;
- }
- #endif
- }
- /* if logging is enabled, open logfile before chroot or set group ID */
- if ((log_outbound_xfers || log_incoming_xfers) && (syslogmsg != 1)) {
- mode_t oldmask;
- oldmask = umask(0);
- xferlog = open(logfile, O_WRONLY | O_APPEND | O_CREAT, 0640);
- (void) umask(oldmask);
- if (xferlog < 0) {
- syslog(LOG_ERR, "cannot open logfile %s: %s", logfile,
- strerror(errno));
- 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
- */
- syslog(LOG_INFO, "-i %d,-o %d,xferlog %s: %d",
- log_incoming_xfers, log_outbound_xfers, logfile, xferlog);
- #endif
- enable_signaling(); /* we can allow signals once again: kinch */
- /* if autogroup command applies to user's class change pw->pw_gid */
- if (anonymous && use_accessfile) { /* see above. _H */
- (void) acl_autogroup(pw);
- guest = acl_guestgroup(pw); /* the new group may be a guest */
- if (guest && acl_realgroup(pw))
- guest = 0;
- anonymous = !guest;
- }
- /* END AUTHENTICATION */
- login_attempts = 0; /* this time successful */
- /* SET GROUP ID STARTS HERE */
- #ifndef AIX
- (void) setegid((gid_t) pw->pw_gid);
- #else
- (void) setgid((gid_t) pw->pw_gid);
- #endif
- (void) initgroups(pw->pw_name, pw->pw_gid);
- #ifdef DEBUG
- syslog(LOG_DEBUG, "initgroups has been called");
- #endif
- /* WTMP PROCESSING STARTS HERE */
- if (wtmp_logging) {
- /* open wtmp before chroot */
- #if ((defined(BSD) && (BSD >= 199103)) || defined(sun))
- (void) sprintf(ttyline, "ftp%ld", (long) getpid());
- #else
- (void) sprintf(ttyline, "ftpd%d", getpid());
- #endif
- #ifdef DEBUG
- syslog(LOG_DEBUG, "about to call wtmp");
- #endif
- wu_logwtmp(ttyline, pw->pw_name, remotehost, 1);
- }
- logged_in = 1;
- expand_id();
- #ifdef QUOTA
- memset("a, 0, sizeof(quota));
- get_quota(pw->pw_dir, pw->pw_uid);
- #endif
- restricted_user = 0;
- if (!anonymous)
- if ((restricteduid(pw->pw_uid) && !unrestricteduid(pw->pw_uid))
- || (restrictedgid(pw->pw_gid) && !unrestrictedgid(pw->pw_gid)))
- restricted_user = 1;
- if (anonymous || guest) {
- 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
- home = defhome;
- #endif
- #ifdef VIRTUAL
- if (virtual_mode && !guest) {
- #ifdef CLOSED_VIRTUAL_SERVER
- if (DenyVirtualAnonymous()) {
- #ifdef VERBOSE_ERROR_LOGING
- syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host anonymous access denied) for %s",
- remoteident);
- #endif
- reply(530, "Login incorrect.");
- if (++login_attempts >= lgi_failure_threshold) {
- syslog(LOG_NOTICE, "repeated login failures from %s", remoteident);
- exit(0);
- }
- goto bad;
- }
- #endif
- /* Anonymous user in virtual_mode */
- if (pw->pw_dir)
- free(pw->pw_dir);
- pw->pw_dir = sgetsave(virtual_root);
- }
- 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
- * from the etc/passwd file found after chroot'ing.
- *
- * If this a guest user, the chroot directory is determined by the
- * "guest-root" clause and the home directory is taken from the
- * etc/passwd file found after chroot'ing.
- *
- * 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.
- */
- {
- struct aclmember *entry = NULL;
- char *root_path = NULL;
- if (anonymous) {
- char class[1024];
- (void) acl_getclass(class);
- while (getaclentry("anonymous-root", &entry) && ARG0) {
- if (!ARG1) {
- if (!root_path)
- root_path = ARG0;
- }
- else {
- int which;
- for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
- if (!strcmp(ARG[which], "*")) {
- if (!root_path)
- root_path = ARG0;
- }
- else {
- if (!strcasecmp(ARG[which], class))
- root_path = ARG0;
- }
- }
- }
- }
- }
- else { /* (guest) */
- while (getaclentry("guest-root", &entry) && ARG0) {
- if (!ARG1) {
- if (!root_path)
- root_path = ARG0;
- }
- else {
- int which;
- char *ptr;
- for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
- if (!strcmp(ARG[which], "*")) {
- if (!root_path)
- root_path = ARG0;
- }
- else {
- if (ARG[which][0] == '%') {
- if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) {
- if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) {
- if (pw->pw_uid == strtoul(ARG[which] + 1, NULL, 0))
- root_path = ARG0;
- }
- else {
- *ptr++ = ' ';
- if ((ARG[which][1] == ' ')
- || (pw->pw_uid >= strtoul(ARG[which] + 1, NULL, 0)))
- root_path = ARG0;
- *--ptr = '+';
- }
- }
- else {
- *ptr++ = ' ';
- if (((ARG[which][1] == ' ')
- || (pw->pw_uid >= strtoul(ARG[which] + 1, NULL, 0)))
- && ((*ptr == ' ')
- || (pw->pw_uid <= strtoul(ptr, NULL, 0))))
- root_path = ARG0;
- *--ptr = '-';
- }
- }
- else {
- struct passwd *guest_pw = getpwnam(ARG[which]);
- if (guest_pw && (pw->pw_uid == guest_pw->pw_uid))
- root_path = ARG0;
- }
- }
- }
- }
- }
- }
- if (root_path) {
- struct passwd *chroot_pw = NULL;
- #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
- syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host access denied) for %s, %s",
- remoteident, pw->pw_name);
- #endif
- reply(530, "Login incorrect.");
- if (++login_attempts >= lgi_failure_threshold) {
- syslog(LOG_NOTICE, "repeated login failures from %s", remoteident);
- exit(0);
- }
- goto bad;
- }
- #endif
- (void) strncpy(chroot_path, root_path, sizeof(chroot_path));
- chroot_path[sizeof(chroot_path) - 1] = ' ';
- pw->pw_dir = sgetsave(chroot_path);
- if (chroot(root_path) < 0 || chdir("/") < 0) {
- #ifdef VERBOSE_ERROR_LOGING
- syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set guest privileges) for %s, %s",
- remoteident, pw->pw_name);
- #endif
- reply(530, "Can't set guest privileges.");
- goto bad;
- }
- if ((chroot_pw = getpwuid(pw->pw_uid)) != NULL)
- if (chdir(chroot_pw->pw_dir) >= 0)
- home = sgetsave(chroot_pw->pw_dir);
- goto slimy_hack; /* onea these days I'll make this structured code, honest ... */
- }
- }
- /* determine root and home directory */
- if ((sp = strstr(pw->pw_dir, "/./")) == NULL) {
- (void) strncpy(chroot_path, pw->pw_dir, sizeof(chroot_path));
- chroot_path[sizeof(chroot_path) - 1] = ' ';
- #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
- syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host access denied) for %s, %s",
- remoteident, pw->pw_name);
- #endif
- reply(530, "Login incorrect.");
- if (++login_attempts >= lgi_failure_threshold) {
- syslog(LOG_NOTICE, "repeated login failures from %s", remoteident);
- exit(0);
- }
- goto bad;
- }
- #endif
- if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
- #ifdef VERBOSE_ERROR_LOGING
- syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set guest privileges) for %s, %s",
- remoteident, pw->pw_name);
- #endif
- reply(530, "Can't set guest privileges.");
- goto bad;
- }
- }
- else {
- *sp++ = ' ';
- (void) strncpy(chroot_path, pw->pw_dir, sizeof(chroot_path));
- chroot_path[sizeof(chroot_path) - 1] = ' ';
- #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
- syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host access denied) for %s, %s",
- remoteident, pw->pw_name);
- #endif
- reply(530, "Login incorrect.");
- if (++login_attempts >= lgi_failure_threshold) {
- syslog(LOG_NOTICE, "repeated login failures from %s", remoteident);
- exit(0);
- }
- goto bad;
- }
- #endif
- if (chroot(pw->pw_dir) < 0 || chdir(++sp) < 0) {
- #ifdef VERBOSE_ERROR_LOGING
- syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set guest privileges) for %s, %s",
- remoteident, pw->pw_name);
- #endif
- reply(550, "Can't set guest privileges.");
- goto bad;
- }
- #ifdef ALTERNATE_CD
- home = sp;
- #endif
- }
- slimy_hack:
- /* shut up you stupid compiler! */ {
- int i = 0;
- i++;
- }
- }
- #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)
- else if (virtual_mode && !(AllowVirtualUser(pw->pw_name) && !DenyVirtualUser(pw->pw_name))) {
- #ifdef VERBOSE_ERROR_LOGING
- syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host access denied) for %s, %s",
- remoteident, pw->pw_name);
- #endif
- reply(530, "Login incorrect.");
- if (++login_attempts >= lgi_failure_threshold) {
- syslog(LOG_NOTICE, "repeated login failures from %s", remoteident);
- exit(0);
- }
- goto bad;
- }
- #endif
- #ifdef AIX
- {
- /* AIX 3 lossage. Don't ask. It's undocumented. */
- priv_t priv;
- priv.pv_priv[0] = 0;
- priv.pv_priv[1] = 0;
- /* setgroups(NULL, NULL); */
- if (setpriv(PRIV_SET | PRIV_INHERITED | PRIV_EFFECTIVE | PRIV_BEQUEATH,
- &priv, sizeof(priv_t)) < 0 ||
- setuidx(ID_REAL | ID_EFFECTIVE, (uid_t) pw->pw_uid) < 0 ||
- seteuid((uid_t) pw->pw_uid) < 0) {
- #ifdef VERBOSE_ERROR_LOGING
- syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set uid) for %s, %s",
- remoteident, pw->pw_name);
- #endif
- reply(530, "Can't set uid (AIX3).");
- goto bad;
- }
- }
- #ifdef UID_DEBUG
- lreply(230, "ruid=%d, euid=%d, suid=%d, luid=%d", getuidx(ID_REAL),
- getuidx(ID_EFFECTIVE), getuidx(ID_SAVED), getuidx(ID_LOGIN));
- lreply(230, "rgid=%d, egid=%d, sgid=%d, lgid=%d", getgidx(ID_REAL),
- getgidx(ID_EFFECTIVE), getgidx(ID_SAVED), getgidx(ID_LOGIN));
- #endif
- #else
- #ifdef HAVE_SETREUID
- if (setreuid(-1, (uid_t) pw->pw_uid) < 0) {
- #else
- if (seteuid((uid_t) pw->pw_uid) < 0) {
- #endif
- #ifdef VERBOSE_ERROR_LOGING
- syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set uid) for %s, %s",
- remoteident, pw->pw_name);
- #endif
- reply(530, "Can't set uid.");
- goto bad;
- }
- #endif
- if (!anonymous && !guest) {
- if (chdir(pw->pw_dir) < 0) {
- #ifdef PARANOID
- #ifdef VERBOSE_ERROR_LOGING
- syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot chdir) for %s, %s",
- remoteident, pw->pw_name);
- #endif
- reply(530, "User %s: can't change directory to %s.",
- pw->pw_name, pw->pw_dir);
- goto bad;
- #else
- if (chdir("/") < 0) {
- #ifdef VERBOSE_ERROR_LOGING
- syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot chdir) for %s, %s",
- remoteident, pw->pw_name);
- #endif
- reply(530, "User %s: can't change directory to %s.",
- pw->pw_name, pw->pw_dir);
- goto bad;
- }
- else {
- lreply(230, "No directory! Logging in with home=/");
- #ifdef ALTERNATE_CD
- home = defhome;
- #endif
- }
- #endif
- }
- }
- if (passwarn) {
- lreply(230, "The response '%s' is not valid", passwd);
- lreply(230,
- "Next time please use your e-mail address as your password");
- lreply(230, " for example: %s@%s",
- authenticated ? authuser : "joe", remotehost);
- }
- /* following two lines were inside the next scope... */
- show_message(230, LOG_IN);
- show_message(230, C_WD);
- show_readme(230, LOG_IN);
- show_readme(230, C_WD);
- #ifdef ULTRIX_AUTH
- if (!anonymous && numfails > 0) {
- lreply(230,
- "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) {
- reply(230, "Guest login ok, access restrictions apply.");
- sprintf(proctitle, "%s: anonymous/%.*s", remotehost,
- (int) (sizeof(proctitle) - sizeof(remotehost) -
- sizeof(": anonymous/")), passwd);
- setproctitle("%s", proctitle);
- if (logging)
- syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
- remoteident, passwd);
- }
- else {
- reply(230, "User %s logged in.%s", pw->pw_name, guest ?
- " Access restrictions apply." : "");
- sprintf(proctitle, "%s: %s", remotehost, pw->pw_name);
- setproctitle(proctitle);
- if (logging)
- syslog(LOG_INFO, "FTP LOGIN FROM %s, %s", remoteident, pw->pw_name);
- /* 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
- home = pw->pw_dir; /* home dir for globbing */
- (void) umask(defumask);
- time(&login_time);
- {
- struct aclmember *entry;
- entry = NULL;
- while (getaclentry("limit-time", &entry) && ARG0 && ARG1)
- if ((anonymous && strcasecmp(ARG0, "anonymous") == 0)
- || (guest && strcasecmp(ARG0, "guest") == 0)
- || ((guest | anonymous) && strcmp(ARG0, "*") == 0))
- limit_time = strtoul(ARG1, NULL, 0);
- }
- return;
- bad:
- /* Forget all about it... */
- if (xferlog)
- close(xferlog);
- xferlog = 0;
- end_login();
- return;
- }
- int restricteduid(uid_t uid)
- {
- struct aclmember *entry = NULL;
- int which;
- char *ptr;
- struct passwd *pw;
- while (getaclentry("restricted-uid", &entry)) {
- for (which = 0; (which < MAXARGS) && ARG[which]; which++) {
- if (!strcmp(ARG[which], "*"))
- return (1);
- if (ARG[which][0] == '%') {
- if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) {
- if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) {
- if (uid == strtoul(ARG[which] + 1, NULL, 0))
- return (1);
- }
- else {
- *ptr++ = ' ';
- if ((ARG[which][1] == ' ')
- || (uid >= strtoul(ARG[which] + 1, NULL, 0))) {
- *--ptr = '+';
- return (1);
- }
- *--ptr = '+';
- }
- }
- else {
- *ptr++ = ' ';
- if (((ARG[which][1] == ' ')
- || (uid >= strtoul(ARG[which] + 1, NULL, 0)))
- && ((*ptr == ' ')
- || (uid <= strtoul(ptr, NULL, 0)))) {
- *--ptr = '-';
- return (1);
- }
- *--ptr = '-';
- }
- }
- else {
- pw = getpwnam(ARG[which]);
- if (pw && (uid == pw->pw_uid))
- return (1);
- }
- }
- }
- return (0);
- }
- int unrestricteduid(uid_t uid)
- {
- struct aclmember *entry = NULL;
- int which;
- char *ptr;
- struct passwd *pw;
- while (getaclentry("unrestricted-uid", &entry)) {
- for (which = 0; (which < MAXARGS) && ARG[which]; which++) {
- if (!strcmp(ARG[which], "*"))
- return (1);
- if (ARG[which][0] == '%') {
- if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) {
- if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) {
- if (uid == strtoul(ARG[which] + 1, NULL, 0))
- return (1);
- }
- else {
- *ptr++ = ' ';
- if ((ARG[which][1] == ' ')
- || (uid >= strtoul(ARG[which] + 1, NULL, 0))) {
- *--ptr = '+';
- return (1);
- }
- *--ptr = '+';
- }
- }
- else {
- *ptr++ = ' ';
- if (((ARG[which][1] == ' ')
- || (uid >= strtoul(ARG[which] + 1, NULL, 0)))
- && ((*ptr == ' ')
- || (uid <= strtoul(ptr, NULL, 0)))) {
- *--ptr = '-';
- return (1);
- }
- *--ptr = '-';
- }
- }
- else {
- pw = getpwnam(ARG[which]);
- if (pw && (uid == pw->pw_uid))
- return (1);
- }
- }
- }
- return (0);
- }
- int restrictedgid(gid_t gid)
- {
- struct aclmember *entry = NULL;
- int which;
- char *ptr;
- struct group *grp;
- while (getaclentry("restricted-gid", &entry)) {
- for (which = 0; (which < MAXARGS) && ARG[which]; which++) {
- if (!strcmp(ARG[which], "*"))
- return (1);
- if (ARG[which][0] == '%') {
- if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) {
- if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) {
- if (gid == strtoul(ARG[which] + 1, NULL, 0))
- return (1);
- }
- else {
- *ptr++ = ' ';
- if ((ARG[which][1] == ' ')
- || (gid >= strtoul(ARG[which] + 1, NULL, 0))) {
- *--ptr = '+';
- return (1);
- }
- *--ptr = '+';
- }
- }
- else {
- *ptr++ = ' ';
- if (((ARG[which][1] == ' ')
- || (gid >= strtoul(ARG[which] + 1, NULL, 0)))
- && ((*ptr == ' ')
- || (gid <= strtoul(ptr, NULL, 0)))) {
- *--ptr = '-';
- return (1);
- }
- *--ptr = '-';
- }
- }
- else {
- grp = getgrnam(ARG[which]);
- if (grp && (gid == grp->gr_gid))
- return (1);
- }
- }
- }
- return (0);
- }
- int unrestrictedgid(gid_t gid)
- {
- struct aclmember *entry = NULL;
- int which;
- char *ptr;
- struct group *grp;
- while (getaclentry("unrestricted-gid", &entry)) {
- for (which = 0; (which < MAXARGS) && ARG[which]; which++) {
- if (!strcmp(ARG[which], "*"))
- return (1);
- if (ARG[which][0] == '%') {
- if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) {
- if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) {
- if (gid == strtoul(ARG[which] + 1, NULL, 0))
- return (1);
- }
- else {
- *ptr++ = ' ';
- if ((ARG[which][1] == ' ')
- || (gid >= strtoul(ARG[which] + 1, NULL, 0))) {
- *--ptr = '+';
- return (1);
- }
- *--ptr = '+';
- }
- }
- else {
- *ptr++ = ' ';
- if (((ARG[which][1] == ' ')
- || (gid >= strtoul(ARG[which] + 1, NULL, 0)))
- && ((*ptr == ' ')
- || (gid <= strtoul(ptr, NULL, 0)))) {
- *--ptr = '-';
- return (1);
- }
- *--ptr = '-';
- }
- }
- else {
- grp = getgrnam(ARG[which]);
- if (grp && (gid == grp->gr_gid))
- return (1);
- }
- }
- }
- return (0);
- }
- char *opt_string(int options)
- {
- static char buf[100];
- char *ptr = buf;
- if ((options & O_COMPRESS) != 0) /* debian fixes: NULL -> 0 */
- *ptr++ = 'C';
- if ((options & O_TAR) != 0)
- *ptr++ = 'T';
- if ((options & O_UNCOMPRESS) != 0)
- *ptr++ = 'U';
- if (options == 0)
- *ptr++ = '_';
- *ptr++ = ' ';
- return (buf);
- }
- #ifdef INTERNAL_LS
- char *rpad(char *s, unsigned int len)
- {
- char *a;
- a = (char *) malloc(len + 1);
- memset(a, ' ', len);
- a[len] = 0;
- if (strlen(s) <= len)
- memcpy(a, s, strlen(s));
- else
- strncpy(a, s, len);
- return a;
- }
- char *ls_file(const char *file, int nameonly, char remove_path, char classify)
- {
- static const char month[12][4] =
- {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
- char *permissions;
- struct stat s;
- struct tm *t;
- char *ls_entry;
- char *owner, *ownerg;
- char *rpowner, *rpownerg;
- char *link;
- #ifndef LS_NUMERIC_UIDS
- struct passwd *pw;
- struct group *gr;
- #endif
- link = NULL;
- owner = NULL;
- ownerg = NULL;
- if (lstat(file, &s) != 0) { /* File doesn't exist, or is not readable by user */
- return NULL;
- }
- ls_entry = (char *) malloc(312);
- memset(ls_entry, 0, 312);
- permissions = strdup("----------");
- if (S_ISLNK(s.st_mode)) {
- permissions[0] = 'l';
- if (classify)
- classify = '@';
- }
- else if (S_ISDIR(s.st_mode)) {
- permissions[0] = 'd';
- if (classify)
- classify = '/';
- }
- else if (S_ISBLK(s.st_mode))
- permissions[0] = 'b';
- else if (S_ISCHR(s.st_mode))
- permissions[0] = 'c';
- else if (S_ISFIFO(s.st_mode)) {
- permissions[0] = 'p';
- if (classify == 1)
- classify = '=';
- }
- #ifdef S_ISSOCK
- else if (S_ISSOCK(s.st_mode))
- permissions[0] = 's';
- #endif
- if ((s.st_mode & S_IRUSR) == S_IRUSR)
- permissions[1] = 'r';
- if ((s.st_mode & S_IWUSR) == S_IWUSR)
- permissions[2] = 'w';
- if ((s.st_mode & S_IXUSR) == S_IXUSR) {
- permissions[3] = 'x';
- if (classify == 1)
- classify = '*';
- #ifndef HIDE_SETUID
- if ((s.st_mode & S_ISUID) == S_ISUID)
- permissions[3] = 's';
- #endif
- }
- #ifndef HIDE_SETUID
- else if ((s.st_mode & S_ISUID) == S_ISUID)
- permissions[3] = 'S';
- #endif
- if ((s.st_mode & S_IRGRP) == S_IRGRP)
- permissions[4] = 'r';
- if ((s.st_mode & S_IWGRP) == S_IWGRP)
- permissions[5] = 'w';
- if ((s.st_mode & S_IXGRP) == S_IXGRP) {
- permissions[6] = 'x';
- if (classify == 1)
- classify = '*';
- #ifndef HIDE_SETUID
- if ((s.st_mode & S_ISGID) == S_ISGID)
- permissions[6] = 's';
- #endif
- }
- #ifndef HIDE_SETUID
- else if ((s.st_mode & S_ISGID) == S_ISGID)
- permissions[6] = 'S';
- #endif
- if ((s.st_mode & S_IROTH) == S_IROTH)
- permissions[7] = 'r';
- if ((s.st_mode & S_IWOTH) == S_IWOTH)
- permissions[8] = 'w';
- if ((s.st_mode & S_IXOTH) == S_IXOTH) {
- permissions[9] = 'x';
- if (classify == 1)
- classify = '*';
- #ifndef HIDE_SETUID
- if ((s.st_mode & S_ISVTX) == S_ISVTX)
- permissions[9] = 't';
- #endif
- }
- #ifndef HIDE_SETUID
- else if ((s.st_mode & S_ISVTX) == S_ISVTX)
- permissions[9] = 'T';
- #endif
- t = localtime(&s.st_mtime);
- #ifndef LS_NUMERIC_UIDS
- pw = getpwuid(s.st_uid);
- if (pw != NULL)
- owner = strdup(pw->pw_name);
- gr = getgrgid(s.st_gid);
- if (gr != NULL)
- ownerg = strdup(gr->gr_name);
- #endif
- if (owner == NULL) { /* Can't figure out username (or don't want to) */
- if (s.st_uid == 0)
- owner = strdup("root");
- else {
- owner = (char *) malloc(9);
- memset(owner, 0, 9);
- #ifdef SOLARIS_2
- sprintf(owner, "%lu", s.st_uid);
- #else
- sprintf(owner, "%u", s.st_uid);
- #endif
- }
- }
- if (ownerg == NULL) { /* Can't figure out groupname (or don't want to) */
- if (s.st_gid == 0)
- ownerg = strdup("root");
- else {
- ownerg = (char *) malloc(9);
- memset(ownerg, 0, 9);
- #ifdef SOLARIS_2
- sprintf(ownerg, "%lu", s.st_gid);
- #else
- sprintf(ownerg, "%u", s.st_gid);
- #endif
- }
- }
- #ifdef HAVE_LSTAT
- if ((s.st_mode & S_IFLNK) == S_IFLNK) {
- link = (char *) malloc(MAXPATHLEN);
- memset(link, 0, MAXPATHLEN);
- if (readlink(file, link, MAXPATHLEN) == -1) {
- free(link);
- link = NULL;
- }
- }
- #endif
- if (remove_path != 0 && strchr(file, '/'))
- file = strrchr(file, '/') + 1;
- rpowner = rpad(owner, 8);
- rpownerg = rpad(ownerg, 8);
- #ifdef SOLARIS_2
- #define N_FORMAT "lu"
- #define S_FORMAT "lu"
- #else
- #if defined(__FreeBSD__) || defined(__bsdi__)
- #define N_FORMAT "u"
- #define S_FORMAT "ld"
- #else
- #define N_FORMAT "u"
- #define S_FORMAT "u"
- #endif
- #endif
- if (nameonly) {
- sprintf(ls_entry, "%s", file);
- if (link != NULL)
- free(link);
- }
- else {
- if ((time(NULL) - s.st_mtime) > 6307200) { /* File is older than 6 months */
- if (link == NULL)
- sprintf(ls_entry, "%s %3" N_FORMAT " %s %s %8" S_FORMAT " %s %2u %5u %s", permissions, s.st_nlink, rpowner, rpownerg, (long) s.st_size, month[t->tm_mon], t->tm_mday, 1900 + t->tm_year, file);
- else {
- sprintf(ls_entry, "%s %3" N_FORMAT " %s %s %8" S_FORMAT " %s %2u %5u %s -> %s", permissions, s.st_nlink, rpowner, rpownerg, (long) s.st_size, month[t->tm_mon], t->tm_mday, 1900 + t->tm_year, file, link);
- free(link);
- }
- }
- else if (link == NULL)
- sprintf(ls_entry, "%s %3" N_FORMAT " %s %s %8" S_FORMAT " %s %2u %02u:%02u %s", permissions, s.st_nlink, rpowner, rpownerg, (long) s.st_size, month[t->tm_mon], t->tm_mday, t->tm_hour, t->tm_min, file);
- else {
- sprintf(ls_entry, "%s %3" N_FORMAT " %s %s %8" S_FORMAT " %s %2u %02u:%02u %s -> %s", permissions, s.st_nlink, rpowner, rpownerg, (long) s.st_size, month[t->tm_mon], t->tm_mday, t->tm_hour, t->tm_min, file, link);
- free(link);
- }
- }
- free(rpowner);
- free(rpownerg);
- free(owner);
- free(ownerg);
- if (classify > 1)
- sprintf(ls_entry + strlen(ls_entry), "%c", classify);
- strcat(ls_entry, "rn");
- free(permissions);
- return ls_entry;
- }
- void ls_dir(char *d, char ls_a, char ls_F, char ls_l, char ls_R, char omit_total, FILE *out)
- {
- 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;
- unsigned long dl_size, dl_used;
- char *c;
- char *lsentry;
- int i;
- #ifndef GLOB_PERIOD
- char *dperiod;
- #endif
- isDir = 0;
- realdir = (char *) malloc(strlen(d) + 3);
- memset(realdir, 0, strlen(d) + 3);
- strcpy(realdir, d);
- if (strcmp(realdir, ".") == 0)
- realdir[0] = '*';
- if (strcmp(realdir + strlen(realdir) - 2, "/.") == 0)
- realdir[strlen(realdir) - 1] = '*';
- if (realdir[strlen(realdir) - 1] == '/')
- strcat(realdir, "*");
- if (strchr(realdir, '*') || strchr(realdir, '?'))
- isDir = 1;