NetBSD/libexec/ftpd/ftpd.c

3985 lines
95 KiB
C
Raw Normal View History

/* $NetBSD: ftpd.c,v 1.203 2016/07/19 21:25:38 shm Exp $ */
/*
* Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
1993-03-21 12:45:37 +03:00
/*
1994-06-29 05:49:37 +04:00
* Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
1993-03-21 12:45:37 +03:00
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
1993-03-21 12:45:37 +03:00
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Copyright (C) 1997 and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
1993-03-21 12:45:37 +03:00
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\
The Regents of the University of California. All rights reserved.");
1993-03-21 12:45:37 +03:00
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
#else
__RCSID("$NetBSD: ftpd.c,v 1.203 2016/07/19 21:25:38 shm Exp $");
#endif
1993-03-21 12:45:37 +03:00
#endif /* not lint */
/*
* FTP server.
*/
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/resource.h>
1993-03-21 12:45:37 +03:00
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#define FTP_NAMES
#include <arpa/ftp.h>
#include <arpa/inet.h>
#include <arpa/telnet.h>
1994-06-29 05:49:37 +04:00
#include <ctype.h>
1993-03-21 12:45:37 +03:00
#include <dirent.h>
1994-06-29 05:49:37 +04:00
#include <err.h>
#include <errno.h>
1993-03-21 12:45:37 +03:00
#include <fcntl.h>
#include <fnmatch.h>
1994-06-29 05:49:37 +04:00
#include <glob.h>
#include <grp.h>
1994-06-29 05:49:37 +04:00
#include <limits.h>
#include <netdb.h>
1993-03-21 12:45:37 +03:00
#include <pwd.h>
#include <poll.h>
1994-06-29 05:49:37 +04:00
#include <signal.h>
#include <stdarg.h>
1993-03-21 12:45:37 +03:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
1994-06-29 05:49:37 +04:00
#include <syslog.h>
#include <time.h>
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
#include <tzfile.h>
1994-06-29 05:49:37 +04:00
#include <unistd.h>
#include <util.h>
#ifdef SUPPORT_UTMP
#include <utmp.h>
#endif
#ifdef SUPPORT_UTMPX
#include <utmpx.h>
#endif
#ifdef SKEY
#include <skey.h>
#endif
#ifdef KERBEROS5
#include <com_err.h>
1999-08-25 20:23:52 +04:00
#include <krb5/krb5.h>
#endif
1994-06-29 05:49:37 +04:00
#ifdef LOGIN_CAP
#include <login_cap.h>
#endif
#ifdef USE_PAM
#include <security/pam_appl.h>
#endif
2015-01-25 18:52:44 +03:00
#include "pfilter.h"
#define GLOBAL
1994-06-29 05:49:37 +04:00
#include "extern.h"
#include "pathnames.h"
#include "version.h"
1994-06-29 05:49:37 +04:00
static sig_atomic_t transflag;
static sig_atomic_t urgflag;
1993-03-21 12:45:37 +03:00
int data;
int Dflag;
1998-06-26 21:41:38 +04:00
int sflag;
1993-03-21 12:45:37 +03:00
int stru; /* avoid C keyword */
int mode;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
int dataport; /* use specific data port */
int dopidfile; /* maintain pid file */
int doutmp; /* update utmp file */
int dowtmp; /* update wtmp file */
int doxferlog; /* syslog/write wu-ftpd style xferlog entries */
int xferlogfd; /* fd to write wu-ftpd xferlog entries to */
int getnameopts; /* flags for use with getname() */
int dropprivs; /* if privileges should or have been dropped */
int mapped; /* IPv4 connection on AF_INET6 socket */
1993-03-21 12:45:37 +03:00
off_t file_size;
off_t byte_count;
static char ttyline[20];
#ifdef USE_PAM
static int auth_pam(void);
pam_handle_t *pamh = NULL;
#endif
#ifdef SUPPORT_UTMP
static struct utmp utmp; /* for utmp */
#endif
#ifdef SUPPORT_UTMPX
static struct utmpx utmpx; /* for utmpx */
#endif
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
static const char *anondir = NULL;
static const char *confdir = _DEFAULT_CONFDIR;
static char *curname; /* current USER name */
static size_t curname_len; /* length of curname (include NUL) */
#if defined(KERBEROS) || defined(KERBEROS5)
int has_ccache = 0;
int notickets = 1;
char *krbtkfile_env = NULL;
char *tty = ttyline;
int login_krb5_forwardable_tgt = 0;
#endif
int epsvall = 0;
1993-03-21 12:45:37 +03:00
/*
* 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;
enum send_status {
SS_SUCCESS,
SS_ABORTED, /* transfer aborted */
SS_NO_TRANSFER, /* no transfer made yet */
SS_FILE_ERROR, /* file read error */
SS_DATA_ERROR /* data send error */
};
2000-05-20 06:20:18 +04:00
static int bind_pasv_addr(void);
static int checkuser(const char *, const char *, int, int, char **);
static int checkaccess(const char *);
static int checkpassword(const struct passwd *, const char *);
static void do_pass(int, int, const char *);
2000-05-20 06:20:18 +04:00
static void end_login(void);
static FILE *getdatasock(const char *);
static char *gunique(const char *);
static void login_utmp(const char *, const char *, const char *,
struct sockinet *);
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
static void logremotehost(struct sockinet *);
2011-08-30 00:41:06 +04:00
__dead static void lostconn(int);
__dead static void toolong(int);
__dead static void sigquit(int);
static void sigurg(int);
static int handleoobcmd(void);
2000-05-20 06:20:18 +04:00
static int receive_data(FILE *, FILE *);
static int send_data(FILE *, FILE *, const struct stat *, int);
2000-05-20 06:20:18 +04:00
static struct passwd *sgetpwnam(const char *);
static int write_data(int, char *, size_t, off_t *, struct timeval *,
int);
static enum send_status
send_data_with_read(int, int, const struct stat *, int);
static enum send_status
send_data_with_mmap(int, int, const struct stat *, int);
static void logrusage(const struct rusage *, const struct rusage *);
static void logout_utmp(void);
2000-05-20 06:20:18 +04:00
int main(int, char *[]);
#if defined(KERBEROS)
2000-05-20 06:20:18 +04:00
int klogin(struct passwd *, char *, char *, char *);
void kdestroy(void);
#endif
#if defined(KERBEROS5)
int k5login(struct passwd *, char *, char *, char *);
void k5destroy(void);
#endif
1994-06-29 05:49:37 +04:00
int
2000-05-20 06:20:18 +04:00
main(int argc, char *argv[])
1993-03-21 12:45:37 +03:00
{
int ch, on = 1, tos, keepalive;
socklen_t addrlen;
#ifdef KERBEROS5
krb5_error_code kerror;
#endif
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
char *p;
const char *xferlogname = NULL;
long l;
struct sigaction sa;
sa_family_t af = AF_UNSPEC;
1993-03-21 12:45:37 +03:00
connections = 1;
ftpd_debug = 0;
logging = 0;
pdata = -1;
Dflag = 0;
1998-06-26 21:41:38 +04:00
sflag = 0;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
dataport = 0;
dopidfile = 1; /* default: DO use a pid file to count users */
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
doutmp = 0; /* default: Do NOT log to utmp */
dowtmp = 1; /* default: DO log to wtmp */
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
doxferlog = 0; /* default: Do NOT syslog xferlog */
xferlogfd = -1; /* default: Do NOT write xferlog file */
getnameopts = 0; /* default: xlate addrs to name */
dropprivs = 0;
mapped = 0;
usedefault = 1;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
emailaddr = NULL;
hostname[0] = '\0';
homedir[0] = '\0';
gidcount = 0;
is_oob = 0;
version = FTPD_VERSION;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
/*
* LOG_NDELAY sets up the logging connection immediately,
* necessary for anonymous ftp's that chroot and can't do it later.
*/
openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
while ((ch = getopt(argc, argv,
"46a:c:C:Dde:h:HlL:nP:qQrst:T:uUvV:wWX")) != -1) {
1994-06-29 05:49:37 +04:00
switch (ch) {
case '4':
af = AF_INET;
break;
case '6':
af = AF_INET6;
break;
case 'a':
anondir = optarg;
break;
case 'c':
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
confdir = optarg;
break;
case 'C':
if ((p = strchr(optarg, '@')) != NULL) {
*p++ = '\0';
strlcpy(remotehost, p, MAXHOSTNAMELEN + 1);
if (inet_pton(AF_INET, p,
&his_addr.su_addr) == 1) {
his_addr.su_family = AF_INET;
his_addr.su_len =
sizeof(his_addr.si_su.su_sin);
#ifdef INET6
} else if (inet_pton(AF_INET6, p,
&his_addr.su_6addr) == 1) {
his_addr.su_family = AF_INET6;
his_addr.su_len =
sizeof(his_addr.si_su.su_sin6);
#endif
} else
his_addr.su_family = AF_UNSPEC;
}
pw = sgetpwnam(optarg);
exit(checkaccess(optarg) ? 0 : 1);
/* NOTREACHED */
case 'D':
Dflag = 1;
break;
1993-03-21 12:45:37 +03:00
case 'd':
case 'v': /* deprecated */
ftpd_debug = 1;
1993-03-21 12:45:37 +03:00
break;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
case 'e':
emailaddr = optarg;
break;
case 'h':
strlcpy(hostname, optarg, sizeof(hostname));
break;
case 'H':
if (gethostname(hostname, sizeof(hostname)) == -1)
hostname[0] = '\0';
hostname[sizeof(hostname) - 1] = '\0';
break;
1993-03-21 12:45:37 +03:00
case 'l':
1994-06-29 05:49:37 +04:00
logging++; /* > 1 == extra logging */
1993-03-21 12:45:37 +03:00
break;
case 'L':
xferlogname = optarg;
break;
case 'n':
getnameopts = NI_NUMERICHOST;
break;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
case 'P':
errno = 0;
p = NULL;
l = strtol(optarg, &p, 10);
if (errno || *optarg == '\0' || *p != '\0' ||
l < IPPORT_RESERVED ||
l > IPPORT_ANONMAX) {
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
syslog(LOG_WARNING, "Invalid dataport %s",
optarg);
dataport = 0;
}
dataport = (int)l;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
break;
case 'q':
dopidfile = 1;
break;
case 'Q':
dopidfile = 0;
break;
case 'r':
dropprivs = 1;
break;
1998-06-26 21:41:38 +04:00
case 's':
sflag = 1;
break;
1993-03-21 12:45:37 +03:00
case 't':
case 'T':
2001-01-10 03:20:49 +03:00
syslog(LOG_WARNING,
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
"-%c has been deprecated in favour of ftpd.conf",
ch);
1994-06-29 05:49:37 +04:00
break;
1993-03-21 12:45:37 +03:00
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
case 'u':
doutmp = 1;
break;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
case 'U':
doutmp = 0;
break;
case 'V':
if (EMPTYSTR(optarg) || strcmp(optarg, "-") == 0)
version = NULL;
else
version = ftpd_strdup(optarg);
break;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
case 'w':
dowtmp = 1;
break;
case 'W':
dowtmp = 0;
break;
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
case 'X':
doxferlog |= 1;
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
break;
1993-03-21 12:45:37 +03:00
default:
if (optopt == 'a' || optopt == 'C')
exit(1);
2001-01-10 03:20:49 +03:00
syslog(LOG_WARNING, "unknown flag -%c ignored", optopt);
1993-03-21 12:45:37 +03:00
break;
}
}
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
if (EMPTYSTR(confdir))
confdir = _DEFAULT_CONFDIR;
2015-01-25 18:52:44 +03:00
pfilter_open();
if (dowtmp) {
#ifdef SUPPORT_UTMPX
ftpd_initwtmpx();
#endif
#ifdef SUPPORT_UTMP
ftpd_initwtmp();
#endif
}
errno = 0;
l = sysconf(_SC_LOGIN_NAME_MAX);
if (l == -1 && errno != 0) {
syslog(LOG_ERR, "sysconf _SC_LOGIN_NAME_MAX: %m");
exit(1);
} else if (l <= 0) {
syslog(LOG_WARNING, "using conservative LOGIN_NAME_MAX value");
curname_len = _POSIX_LOGIN_NAME_MAX;
} else
curname_len = (size_t)l;
curname = malloc(curname_len);
if (curname == NULL) {
syslog(LOG_ERR, "malloc: %m");
exit(1);
}
curname[0] = '\0';
if (Dflag) {
int error, fd, i, n, *socks;
struct pollfd *fds;
struct addrinfo hints, *res, *res0;
if (daemon(1, 0) == -1) {
syslog(LOG_ERR, "failed to daemonize: %m");
exit(1);
}
(void)memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_IGN;
sa.sa_flags = SA_NOCLDWAIT;
sigemptyset(&sa.sa_mask);
(void)sigaction(SIGCHLD, &sa, NULL);
(void)memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(NULL, "ftp", &hints, &res0);
if (error) {
syslog(LOG_ERR, "getaddrinfo: %s", gai_strerror(error));
exit(1);
}
for (n = 0, res = res0; res != NULL; res = res->ai_next)
n++;
if (n == 0) {
syslog(LOG_ERR, "no addresses available");
exit(1);
}
socks = malloc(n * sizeof(int));
fds = malloc(n * sizeof(struct pollfd));
if (socks == NULL || fds == NULL) {
syslog(LOG_ERR, "malloc: %m");
exit(1);
}
for (n = 0, res = res0; res != NULL; res = res->ai_next) {
socks[n] = socket(res->ai_family, res->ai_socktype,
res->ai_protocol);
if (socks[n] == -1)
continue;
(void)setsockopt(socks[n], SOL_SOCKET, SO_REUSEADDR,
&on, sizeof(on));
if (bind(socks[n], res->ai_addr, res->ai_addrlen)
== -1) {
(void)close(socks[n]);
continue;
}
if (listen(socks[n], 12) == -1) {
(void)close(socks[n]);
continue;
}
fds[n].fd = socks[n];
fds[n].events = POLLIN;
n++;
}
if (n == 0) {
syslog(LOG_ERR, "%m");
exit(1);
}
freeaddrinfo(res0);
if (pidfile(NULL) == -1)
syslog(LOG_ERR, "failed to write a pid file: %m");
for (;;) {
if (poll(fds, n, INFTIM) == -1) {
if (errno == EINTR)
continue;
syslog(LOG_ERR, "poll: %m");
exit(1);
}
for (i = 0; i < n; i++) {
if (fds[i].revents & POLLIN) {
fd = accept(fds[i].fd, NULL, NULL);
if (fd == -1) {
syslog(LOG_ERR, "accept: %m");
continue;
}
switch (fork()) {
case -1:
syslog(LOG_ERR, "fork: %m");
break;
case 0:
goto child;
/* NOTREACHED */
}
(void)close(fd);
}
}
}
child:
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
for (i = 0; i < n; i++)
(void)close(socks[i]);
}
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
memset((char *)&his_addr, 0, sizeof(his_addr));
addrlen = sizeof(his_addr.si_su);
if (getpeername(0, (struct sockaddr *)&his_addr.si_su, &addrlen) < 0) {
syslog((errno == ENOTCONN) ? LOG_NOTICE : LOG_ERR,
"getpeername (%s): %m",argv[0]);
exit(1);
}
his_addr.su_len = addrlen;
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
memset((char *)&ctrl_addr, 0, sizeof(ctrl_addr));
addrlen = sizeof(ctrl_addr.si_su);
if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
exit(1);
}
ctrl_addr.su_len = addrlen;
#ifdef INET6
if (his_addr.su_family == AF_INET6
&& IN6_IS_ADDR_V4MAPPED(&his_addr.su_6addr)) {
#if 1
/*
* IPv4 control connection arrived to AF_INET6 socket.
* I hate to do this, but this is the easiest solution.
*
* The assumption is untrue on SIIT environment.
*/
struct sockinet tmp_addr;
const int off = sizeof(struct in6_addr) - sizeof(struct in_addr);
tmp_addr = his_addr;
memset(&his_addr, 0, sizeof(his_addr));
his_addr.su_family = AF_INET;
his_addr.su_len = sizeof(his_addr.si_su.su_sin);
memcpy(&his_addr.su_addr, &tmp_addr.su_6addr.s6_addr[off],
sizeof(his_addr.su_addr));
his_addr.su_port = tmp_addr.su_port;
tmp_addr = ctrl_addr;
memset(&ctrl_addr, 0, sizeof(ctrl_addr));
ctrl_addr.su_family = AF_INET;
ctrl_addr.su_len = sizeof(ctrl_addr.si_su.su_sin);
memcpy(&ctrl_addr.su_addr, &tmp_addr.su_6addr.s6_addr[off],
sizeof(ctrl_addr.su_addr));
ctrl_addr.su_port = tmp_addr.su_port;
#else
while (fgets(line, sizeof(line), fd) != NULL) {
if ((cp = strchr(line, '\n')) != NULL)
*cp = '\0';
reply(-530, "%s", line);
}
(void) fflush(stdout);
(void) fclose(fd);
reply(530,
"Connection from IPv4 mapped address is not supported.");
exit(0);
#endif
mapped = 1;
} else
#endif /* INET6 */
mapped = 0;
#ifdef IP_TOS
if (!mapped && his_addr.su_family == AF_INET) {
tos = IPTOS_LOWDELAY;
if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos,
sizeof(int)) < 0)
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
}
#endif
/* if the hostname hasn't been given, attempt to determine it */
if (hostname[0] == '\0') {
if (getnameinfo((struct sockaddr *)&ctrl_addr.si_su,
ctrl_addr.su_len, hostname, sizeof(hostname), NULL, 0,
getnameopts) != 0)
(void)gethostname(hostname, sizeof(hostname));
hostname[sizeof(hostname) - 1] = '\0';
}
/* set this here so klogin can use it... */
(void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
1993-03-21 12:45:37 +03:00
(void) freopen(_PATH_DEVNULL, "w", stderr);
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
(void) sigaction(SIGCHLD, &sa, NULL);
sa.sa_handler = sigquit;
sa.sa_flags = SA_RESTART;
sigfillset(&sa.sa_mask); /* block all sigs in these handlers */
(void) sigaction(SIGHUP, &sa, NULL);
(void) sigaction(SIGINT, &sa, NULL);
(void) sigaction(SIGQUIT, &sa, NULL);
(void) sigaction(SIGTERM, &sa, NULL);
sa.sa_handler = lostconn;
(void) sigaction(SIGPIPE, &sa, NULL);
sa.sa_handler = toolong;
(void) sigaction(SIGALRM, &sa, NULL);
sa.sa_handler = sigurg;
(void) sigaction(SIGURG, &sa, NULL);
1993-03-21 12:45:37 +03:00
/* Try to handle urgent data inline */
#ifdef SO_OOBINLINE
if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
2001-01-10 03:20:49 +03:00
syslog(LOG_WARNING, "setsockopt: %m");
1993-03-21 12:45:37 +03:00
#endif
/* Set keepalives on the socket to detect dropped connections. */
#ifdef SO_KEEPALIVE
keepalive = 1;
if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive,
sizeof(int)) < 0)
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
#endif
1993-03-21 12:45:37 +03:00
#ifdef F_SETOWN
if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
2001-01-10 03:20:49 +03:00
syslog(LOG_WARNING, "fcntl F_SETOWN: %m");
1993-03-21 12:45:37 +03:00
#endif
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
logremotehost(&his_addr);
1993-03-21 12:45:37 +03:00
/*
* Set up default state
*/
data = -1;
type = TYPE_A;
form = FORM_N;
stru = STRU_F;
mode = MODE_S;
tmpline[0] = '\0';
hasyyerrored = 0;
1994-06-29 05:49:37 +04:00
#ifdef KERBEROS5
kerror = krb5_init_context(&kcontext);
if (kerror) {
2001-01-10 03:20:49 +03:00
syslog(LOG_ERR, "%s when initializing Kerberos context",
error_message(kerror));
exit(0);
}
#endif /* KERBEROS5 */
init_curclass();
curclass.timeout = 300; /* 5 minutes, as per login(1) */
curclass.type = CLASS_REAL;
1994-06-29 05:49:37 +04:00
/* If logins are disabled, print out the message. */
if (display_file(_PATH_NOLOGIN, 530)) {
1994-06-29 05:49:37 +04:00
reply(530, "System not available.");
exit(0);
}
(void)display_file(conffilename(_NAME_FTPWELCOME), 220);
1994-06-29 05:49:37 +04:00
/* reply(220,) must follow */
if (EMPTYSTR(version))
reply(220, "%s FTP server ready.", hostname);
else
reply(220, "%s FTP server (%s) ready.", hostname, version);
if (xferlogname != NULL) {
xferlogfd = open(xferlogname, O_WRONLY | O_APPEND | O_CREAT,
0660);
if (xferlogfd == -1)
syslog(LOG_WARNING, "open xferlog `%s': %m",
xferlogname);
else
doxferlog |= 2;
}
ftp_loop();
1993-03-21 12:45:37 +03:00
/* NOTREACHED */
}
1994-06-29 05:49:37 +04:00
static void
lostconn(int signo __unused)
1993-03-21 12:45:37 +03:00
{
1994-06-29 05:49:37 +04:00
if (ftpd_debug)
1993-03-21 12:45:37 +03:00
syslog(LOG_DEBUG, "lost connection");
dologout(1);
1993-03-21 12:45:37 +03:00
}
static void
toolong(int signo __unused)
{
/* XXXSIGRACE */
reply(421,
"Timeout (" LLF " seconds): closing control connection.",
(LLT)curclass.timeout);
if (logging)
syslog(LOG_INFO, "User %s timed out after " LLF " seconds",
(pw ? pw->pw_name : "unknown"), (LLT)curclass.timeout);
dologout(1);
}
static void
sigquit(int signo)
{
if (ftpd_debug)
syslog(LOG_DEBUG, "got signal %d", signo);
dologout(1);
}
static void
sigurg(int signo __unused)
{
urgflag = 1;
}
1993-03-21 12:45:37 +03:00
/*
* 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).
*/
1994-06-29 05:49:37 +04:00
static struct passwd *
2000-05-20 06:20:18 +04:00
sgetpwnam(const char *name)
1993-03-21 12:45:37 +03:00
{
static struct passwd save;
1994-06-29 05:49:37 +04:00
struct passwd *p;
1993-03-21 12:45:37 +03:00
if ((p = getpwnam(name)) == NULL)
return (p);
if (save.pw_name) {
1998-07-27 05:45:09 +04:00
free((char *)save.pw_name);
memset(save.pw_passwd, 0, strlen(save.pw_passwd));
1998-07-27 05:45:09 +04:00
free((char *)save.pw_passwd);
free((char *)save.pw_gecos);
free((char *)save.pw_dir);
free((char *)save.pw_shell);
1993-03-21 12:45:37 +03:00
}
save = *p;
save.pw_name = ftpd_strdup(p->pw_name);
save.pw_passwd = ftpd_strdup(p->pw_passwd);
save.pw_gecos = ftpd_strdup(p->pw_gecos);
save.pw_dir = ftpd_strdup(p->pw_dir);
save.pw_shell = ftpd_strdup(p->pw_shell);
1993-03-21 12:45:37 +03:00
return (&save);
}
static int login_attempts; /* number of failed login attempts */
static int askpasswd; /* had USER command, ask for PASSwd */
static int permitted; /* USER permitted */
1993-03-21 12:45:37 +03:00
/*
* 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
* _NAME_FTPUSERS, and ftp account exists, set guest and pw, then just return.
1993-03-21 12:45:37 +03:00
* 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
* _NAME_FTPUSERS to allow people such as root and uucp to be avoided.
1993-03-21 12:45:37 +03:00
*/
1994-06-29 05:49:37 +04:00
void
2000-05-20 06:20:18 +04:00
user(const char *name)
1993-03-21 12:45:37 +03:00
{
char *class;
#ifdef LOGIN_CAP
login_cap_t *lc = NULL;
#endif
#ifdef USE_PAM
int e;
#endif
class = NULL;
1993-03-21 12:45:37 +03:00
if (logged_in) {
switch (curclass.type) {
case CLASS_GUEST:
1993-03-21 12:45:37 +03:00
reply(530, "Can't change user from guest login.");
return;
case CLASS_CHROOT:
reply(530, "Can't change user from chroot user.");
return;
case CLASS_REAL:
if (dropprivs) {
reply(530, "Can't change user.");
return;
}
end_login();
break;
default:
abort();
1993-03-21 12:45:37 +03:00
}
}
#if defined(KERBEROS)
kdestroy();
#endif
#if defined(KERBEROS5)
k5destroy();
#endif
curclass.type = CLASS_REAL;
askpasswd = 0;
permitted = 0;
1993-03-21 12:45:37 +03:00
if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
/* need `pw' setup for checkaccess() and checkuser () */
if ((pw = sgetpwnam("ftp")) == NULL)
reply(530, "User %s unknown.", name);
else if (! checkaccess("ftp") || ! checkaccess("anonymous"))
1993-03-21 12:45:37 +03:00
reply(530, "User %s access denied.", name);
else {
curclass.type = CLASS_GUEST;
1993-03-21 12:45:37 +03:00
askpasswd = 1;
1994-06-29 05:49:37 +04:00
reply(331,
"Guest login ok, type your name as password.");
}
if (!askpasswd) {
if (logging)
syslog(LOG_NOTICE,
"ANONYMOUS FTP LOGIN REFUSED FROM %s",
remoteloghost);
end_login();
goto cleanup_user;
}
name = "ftp";
} else
pw = sgetpwnam(name);
strlcpy(curname, name, curname_len);
/* check user in /etc/ftpusers, and setup class */
permitted = checkuser(_NAME_FTPUSERS, curname, 1, 0, &class);
1994-05-24 10:52:17 +04:00
/* check user in /etc/ftpchroot */
2006-09-26 10:47:20 +04:00
#ifdef LOGIN_CAP
lc = login_getpwclass(pw);
2006-09-26 10:47:20 +04:00
#endif
if (checkuser(_NAME_FTPCHROOT, curname, 0, 0, NULL)
#ifdef LOGIN_CAP /* Allow login.conf configuration as well */
|| login_getcapbool(lc, "ftp-chroot", 0)
#endif
) {
if (curclass.type == CLASS_GUEST) {
syslog(LOG_NOTICE,
"Can't change guest user to chroot class; remove entry in %s",
_NAME_FTPCHROOT);
exit(1);
}
curclass.type = CLASS_CHROOT;
}
/* determine default class */
if (class == NULL) {
switch (curclass.type) {
case CLASS_GUEST:
class = ftpd_strdup("guest");
break;
case CLASS_CHROOT:
class = ftpd_strdup("chroot");
break;
case CLASS_REAL:
class = ftpd_strdup("real");
break;
default:
syslog(LOG_ERR, "unknown curclass.type %d; aborting",
curclass.type);
abort();
}
}
/* parse ftpd.conf, setting up various parameters */
parse_conf(class);
/* if not guest user, check for valid shell */
if (pw == NULL)
permitted = 0;
else {
const char *cp, *shell;
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 && curclass.type != CLASS_GUEST)
permitted = 0;
}
/* deny quickly (after USER not PASS) if requested */
if (CURCLASS_FLAGS_ISSET(denyquick) && !permitted) {
reply(530, "User %s may not use FTP.", curname);
if (logging)
syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
remoteloghost, curname);
end_login();
goto cleanup_user;
}
/* if haven't asked yet (i.e, not anon), ask now */
if (!askpasswd) {
askpasswd = 1;
#ifdef USE_PAM
e = auth_pam(); /* this does reply(331, ...) */
do_pass(1, e, "");
goto cleanup_user;
#else /* !USE_PAM */
#ifdef SKEY
if (skey_haskey(curname) == 0) {
const char *myskey;
myskey = skey_keyinfo(curname);
reply(331, "Password [ %s ] required for %s.",
myskey ? myskey : "error getting challenge",
curname);
} else
1994-05-24 10:52:17 +04:00
#endif
reply(331, "Password required for %s.", curname);
#endif /* !USE_PAM */
}
1994-05-24 10:52:17 +04:00
cleanup_user:
#ifdef LOGIN_CAP
login_close(lc);
#endif
1993-03-21 12:45:37 +03:00
/*
* Delay before reading passwd after first failed
* attempt to slow down passwd-guessing programs.
*/
if (login_attempts)
sleep((unsigned) login_attempts);
if (class)
free(class);
1993-03-21 12:45:37 +03:00
}
/*
* Determine whether something is to happen (allow access, chroot)
* for a user. Each line is a shell-style glob followed by
* `yes' or `no'.
*
* For backward compatibility, `allow' and `deny' are synonymns
* for `yes' and `no', respectively.
*
* Each glob is matched against the username in turn, and the first
* match found is used. If no match is found, the result is the
* argument `def'. If a match is found but without and explicit
* `yes'/`no', the result is the opposite of def.
*
* If the file doesn't exist at all, the result is the argument
* `nofile'
*
* Any line starting with `#' is considered a comment and ignored.
*
* Returns 0 if the user is denied, or 1 if they are allowed.
*
* NOTE: needs struct passwd *pw setup before use.
*/
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
static int
2000-05-20 06:20:18 +04:00
checkuser(const char *fname, const char *name, int def, int nofile,
char **retclass)
{
FILE *fd;
int retval;
char *word, *perm, *class, *buf, *p;
size_t len, line;
retval = def;
if (retclass != NULL)
*retclass = NULL;
if ((fd = fopen(conffilename(fname), "r")) == NULL)
return nofile;
line = 0;
for (;
(buf = fparseln(fd, &len, &line, NULL, FPARSELN_UNESCCOMM |
FPARSELN_UNESCCONT | FPARSELN_UNESCESC)) != NULL;
free(buf), buf = NULL) {
word = perm = class = NULL;
p = buf;
if (len < 1)
continue;
if (p[len - 1] == '\n')
p[--len] = '\0';
if (EMPTYSTR(p))
continue;
NEXTWORD(p, word);
NEXTWORD(p, perm);
NEXTWORD(p, class);
if (EMPTYSTR(word))
continue;
if (!EMPTYSTR(class)) {
if (strcasecmp(class, "all") == 0 ||
strcasecmp(class, "none") == 0) {
syslog(LOG_WARNING,
"%s line %d: illegal user-defined class `%s' - skipping entry",
fname, (int)line, class);
continue;
}
}
/* have a host specifier */
if ((p = strchr(word, '@')) != NULL) {
unsigned char net[16], mask[16], *addr;
int addrlen, bits, bytes, a;
*p++ = '\0';
/* check against network or CIDR */
memset(net, 0x00, sizeof(net));
if ((bits = inet_net_pton(his_addr.su_family, p, net,
sizeof(net))) != -1) {
#ifdef INET6
if (his_addr.su_family == AF_INET) {
#endif
addrlen = 4;
addr = (unsigned char *)&his_addr.su_addr;
#ifdef INET6
} else {
addrlen = 16;
addr = (unsigned char *)&his_addr.su_6addr;
}
#endif
bytes = bits / 8;
bits = bits % 8;
if (bytes > 0)
memset(mask, 0xFF, bytes);
if (bytes < addrlen)
mask[bytes] = 0xFF << (8 - bits);
if (bytes + 1 < addrlen)
memset(mask + bytes + 1, 0x00,
addrlen - bytes - 1);
for (a = 0; a < addrlen; a++)
if ((addr[a] & mask[a]) != net[a])
break;
if (a < addrlen)
continue;
/* check against hostname glob */
} else if (fnmatch(p, remotehost, FNM_CASEFOLD) != 0)
continue;
}
/* have a group specifier */
if ((p = strchr(word, ':')) != NULL) {
gid_t *groups, *ng;
int gsize, i, found;
if (pw == NULL)
continue; /* no match for unknown user */
*p++ = '\0';
groups = NULL;
gsize = 16;
do {
ng = realloc(groups, gsize * sizeof(gid_t));
if (ng == NULL)
fatal(
"Local resource failure: realloc");
groups = ng;
} while (getgrouplist(pw->pw_name, pw->pw_gid,
groups, &gsize) == -1);
found = 0;
for (i = 0; i < gsize; i++) {
struct group *g;
if ((g = getgrgid(groups[i])) == NULL)
continue;
if (fnmatch(p, g->gr_name, 0) == 0) {
found = 1;
break;
}
}
free(groups);
if (!found)
continue;
}
/* check against username glob */
if (fnmatch(word, name, 0) != 0)
continue;
if (perm != NULL &&
((strcasecmp(perm, "allow") == 0) ||
(strcasecmp(perm, "yes") == 0)))
retval = 1;
else if (perm != NULL &&
((strcasecmp(perm, "deny") == 0) ||
(strcasecmp(perm, "no") == 0)))
retval = 0;
else
retval = !def;
if (!EMPTYSTR(class) && retclass != NULL)
*retclass = ftpd_strdup(class);
free(buf);
break;
}
(void) fclose(fd);
return (retval);
}
/*
* Check if user is allowed by /etc/ftpusers
* returns 1 for yes, 0 for no
*
* NOTE: needs struct passwd *pw setup (for checkuser())
*/
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
static int
2000-05-20 06:20:18 +04:00
checkaccess(const char *name)
{
return (checkuser(_NAME_FTPUSERS, name, 1, 0, NULL));
}
2002-08-20 17:51:09 +04:00
static void
login_utmp(const char *line, const char *name, const char *host,
struct sockinet *haddr)
2002-08-20 17:51:09 +04:00
{
#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
struct timeval tv;
(void)gettimeofday(&tv, NULL);
#endif
#ifdef SUPPORT_UTMPX
if (doutmp) {
(void)memset(&utmpx, 0, sizeof(utmpx));
utmpx.ut_tv = tv;
utmpx.ut_pid = getpid();
utmpx.ut_id[0] = 'f';
utmpx.ut_id[1] = 't';
utmpx.ut_id[2] = 'p';
utmpx.ut_id[3] = '*';
utmpx.ut_type = USER_PROCESS;
(void)strncpy(utmpx.ut_name, name, sizeof(utmpx.ut_name));
(void)strncpy(utmpx.ut_line, line, sizeof(utmpx.ut_line));
(void)strncpy(utmpx.ut_host, host, sizeof(utmpx.ut_host));
(void)memcpy(&utmpx.ut_ss, &haddr->si_su, haddr->su_len);
ftpd_loginx(&utmpx);
2002-08-20 17:51:09 +04:00
}
if (dowtmp)
ftpd_logwtmpx(line, name, host, haddr, 0, USER_PROCESS);
2002-08-20 17:51:09 +04:00
#endif
#ifdef SUPPORT_UTMP
if (doutmp) {
(void)memset(&utmp, 0, sizeof(utmp));
(void)time(&utmp.ut_time);
(void)strncpy(utmp.ut_name, name, sizeof(utmp.ut_name));
(void)strncpy(utmp.ut_line, line, sizeof(utmp.ut_line));
(void)strncpy(utmp.ut_host, host, sizeof(utmp.ut_host));
ftpd_login(&utmp);
2002-08-20 17:51:09 +04:00
}
if (dowtmp)
ftpd_logwtmp(line, name, host);
2002-08-20 17:51:09 +04:00
#endif
}
static void
logout_utmp(void)
{
#ifdef SUPPORT_UTMPX
int okwtmpx = dowtmp;
2002-08-20 17:51:09 +04:00
#endif
#ifdef SUPPORT_UTMP
int okwtmp = dowtmp;
2002-08-20 17:51:09 +04:00
#endif
if (logged_in) {
2002-08-20 17:51:09 +04:00
#ifdef SUPPORT_UTMPX
if (doutmp)
okwtmpx &= ftpd_logoutx(ttyline, 0, DEAD_PROCESS);
if (okwtmpx)
ftpd_logwtmpx(ttyline, "", "", NULL, 0, DEAD_PROCESS);
2002-08-20 17:51:09 +04:00
#endif
#ifdef SUPPORT_UTMP
if (doutmp)
okwtmp &= ftpd_logout(ttyline);
if (okwtmp)
ftpd_logwtmp(ttyline, "", "");
2002-08-20 17:51:09 +04:00
#endif
}
}
1993-03-21 12:45:37 +03:00
/*
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
* Terminate login as previous user (if any), resetting state;
1993-03-21 12:45:37 +03:00
* used when USER command is given or login fails.
*/
1994-06-29 05:49:37 +04:00
static void
2000-05-20 06:20:18 +04:00
end_login(void)
1993-03-21 12:45:37 +03:00
{
#ifdef USE_PAM
int e;
#endif
2002-08-20 17:51:09 +04:00
logout_utmp();
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
show_chdir_messages(-1); /* flush chdir cache */
if (pw != NULL && pw->pw_passwd != NULL)
memset(pw->pw_passwd, 0, strlen(pw->pw_passwd));
1993-03-21 12:45:37 +03:00
pw = NULL;
logged_in = 0;
askpasswd = 0;
permitted = 0;
quietmessages = 0;
gidcount = 0;
curclass.type = CLASS_REAL;
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
(void) seteuid((uid_t)0);
#ifdef LOGIN_CAP
setusercontext(NULL, getpwuid(0), 0,
LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
#endif
#ifdef USE_PAM
if (pamh) {
if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS)
syslog(LOG_ERR, "pam_setcred: %s",
pam_strerror(pamh, e));
if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS)
syslog(LOG_ERR, "pam_close_session: %s",
pam_strerror(pamh, e));
if ((e = pam_end(pamh, e)) != PAM_SUCCESS)
syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
pamh = NULL;
}
#endif
1993-03-21 12:45:37 +03:00
}
1994-06-29 05:49:37 +04:00
void
2000-05-20 06:20:18 +04:00
pass(const char *passwd)
{
do_pass(0, 0, passwd);
}
/*
* Perform the passwd confirmation and login.
*
* If pass_checked is zero, confirm passwd is correct, & ignore pass_rval.
* This is the traditional PASS implementation.
*
* If pass_checked is non-zero, use pass_rval and ignore passwd.
* This is used by auth_pam() which has already parsed PASS.
* This only applies to curclass.type != CLASS_GUEST.
*/
static void
do_pass(int pass_checked, int pass_rval, const char *passwd)
1993-03-21 12:45:37 +03:00
{
int rval;
char root[MAXPATHLEN];
#ifdef LOGIN_CAP
login_cap_t *lc = NULL;
#endif
#ifdef USE_PAM
int e;
#endif
rval = 1;
1993-03-21 12:45:37 +03:00
if (logged_in || askpasswd == 0) {
reply(503, "Login with USER first.");
return;
}
askpasswd = 0;
if (curclass.type != CLASS_GUEST) {
/* "ftp" is the only account allowed with no password */
1994-06-29 05:49:37 +04:00
if (pw == NULL) {
rval = 1; /* failure below */
goto skip;
}
if (pass_checked) { /* password validated in user() */
rval = pass_rval;
goto skip;
}
#ifdef USE_PAM
syslog(LOG_ERR, "do_pass: USE_PAM shouldn't get here");
rval = 1;
goto skip;
#endif
#if defined(KERBEROS)
if (klogin(pw, "", hostname, (char *)passwd) == 0) {
rval = 0;
goto skip;
}
#endif
#if defined(KERBEROS5)
if (k5login(pw, "", hostname, (char *)passwd) == 0) {
rval = 0;
goto skip;
}
#endif
#ifdef SKEY
if (skey_haskey(pw->pw_name) == 0) {
char *p;
int r;
p = ftpd_strdup(passwd);
r = skey_passcheck(pw->pw_name, p);
free(p);
if (r != -1) {
rval = 0;
goto skip;
}
1994-06-29 05:49:37 +04:00
}
1994-05-24 10:52:17 +04:00
#endif
if (!sflag)
rval = checkpassword(pw, passwd);
else
rval = 1;
skip:
/*
* If rval > 0, the user failed the authentication check
* above. If rval == 0, either Kerberos or local
* authentication succeeded.
*/
if (rval) {
2000-07-08 22:24:28 +04:00
reply(530, "%s", rval == 2 ? "Password expired." :
"Login incorrect.");
2015-01-25 18:52:44 +03:00
pfilter_notify(1, rval == 2 ? "exppass" : "badpass");
if (logging) {
1994-06-29 05:49:37 +04:00
syslog(LOG_NOTICE,
"FTP LOGIN FAILED FROM %s", remoteloghost);
syslog(LOG_AUTHPRIV | LOG_NOTICE,
1994-06-29 05:49:37 +04:00
"FTP LOGIN FAILED FROM %s, %s",
remoteloghost, curname);
}
1993-03-21 12:45:37 +03:00
pw = NULL;
if (login_attempts++ >= 5) {
syslog(LOG_NOTICE,
"repeated login failures from %s",
remoteloghost);
1993-03-21 12:45:37 +03:00
exit(0);
}
return;
}
}
/* password ok; check if anything else prevents login */
if (! permitted) {
reply(530, "User %s may not use FTP.", pw->pw_name);
if (logging)
syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
remoteloghost, pw->pw_name);
goto bad;
}
1993-03-21 12:45:37 +03:00
login_attempts = 0; /* this time successful */
1994-06-29 05:49:37 +04:00
if (setegid((gid_t)pw->pw_gid) < 0) {
reply(550, "Can't set gid.");
goto bad;
1994-06-29 05:49:37 +04:00
}
#ifdef LOGIN_CAP
if ((lc = login_getpwclass(pw)) != NULL) {
#ifdef notyet
char remote_ip[NI_MAXHOST];
if (getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
remote_ip, sizeof(remote_ip) - 1, NULL, 0,
NI_NUMERICHOST))
*remote_ip = 0;
remote_ip[sizeof(remote_ip) - 1] = 0;
if (!auth_hostok(lc, remotehost, remote_ip)) {
2015-01-25 18:52:44 +03:00
pfilter_notify(1, "bannedhost");
syslog(LOG_INFO|LOG_AUTH,
"FTP LOGIN FAILED (HOST) as %s: permission denied.",
pw->pw_name);
reply(530, "Permission denied.");
pw = NULL;
return;
}
if (!auth_timeok(lc, time(NULL))) {
reply(530, "Login not available right now.");
pw = NULL;
return;
}
#endif
}
setsid();
setusercontext(lc, pw, 0,
LOGIN_SETLOGIN|LOGIN_SETGROUP|LOGIN_SETPRIORITY|
LOGIN_SETRESOURCES|LOGIN_SETUMASK);
#else
1993-03-21 12:45:37 +03:00
(void) initgroups(pw->pw_name, pw->pw_gid);
/* cache groups for cmds.c::matchgroup() */
#endif
#ifdef USE_PAM
if (pamh) {
if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
syslog(LOG_ERR, "pam_open_session: %s",
pam_strerror(pamh, e));
} else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED))
!= PAM_SUCCESS) {
syslog(LOG_ERR, "pam_setcred: %s",
pam_strerror(pamh, e));
}
}
#endif
gidcount = getgroups(0, NULL);
if (gidlist)
free(gidlist);
gidlist = malloc(gidcount * sizeof *gidlist);
gidcount = getgroups(gidcount, gidlist);
1993-03-21 12:45:37 +03:00
2002-08-20 17:51:09 +04:00
/* open utmp/wtmp before chroot */
login_utmp(ttyline, pw->pw_name, remotehost, &his_addr);
1993-03-21 12:45:37 +03:00
logged_in = 1;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
connections = 1;
if (dopidfile)
count_users();
if (curclass.limit != -1 && connections > curclass.limit) {
if (! EMPTYSTR(curclass.limitfile))
(void)display_file(conffilename(curclass.limitfile),
530);
reply(530,
"User %s access denied, connection limit of " LLF
" reached.",
pw->pw_name, (LLT)curclass.limit);
syslog(LOG_NOTICE,
"Maximum connection limit of " LLF
" for class %s reached, login refused for %s",
(LLT)curclass.limit, curclass.classname, pw->pw_name);
goto bad;
}
homedir[0] = '/';
switch (curclass.type) {
case CLASS_GUEST:
/*
* We MUST do a chdir() after the chroot. Otherwise
* the old current directory will be accessible as "."
* outside the new root!
*/
format_path(root,
curclass.chroot ? curclass.chroot :
anondir ? anondir :
pw->pw_dir);
format_path(homedir,
curclass.homedir ? curclass.homedir :
"/");
if (EMPTYSTR(homedir))
homedir[0] = '/';
if (EMPTYSTR(root) || chroot(root) < 0) {
syslog(LOG_NOTICE,
"GUEST user %s: can't chroot to %s: %m",
pw->pw_name, root);
goto bad_guest;
}
if (chdir(homedir) < 0) {
syslog(LOG_NOTICE,
"GUEST user %s: can't chdir to %s: %m",
pw->pw_name, homedir);
bad_guest:
1993-03-21 12:45:37 +03:00
reply(550, "Can't set guest privileges.");
goto bad;
}
break;
case CLASS_CHROOT:
format_path(root,
curclass.chroot ? curclass.chroot :
pw->pw_dir);
format_path(homedir,
curclass.homedir ? curclass.homedir :
"/");
if (EMPTYSTR(homedir))
homedir[0] = '/';
if (EMPTYSTR(root) || chroot(root) < 0) {
syslog(LOG_NOTICE,
"CHROOT user %s: can't chroot to %s: %m",
pw->pw_name, root);
goto bad_chroot;
}
if (chdir(homedir) < 0) {
syslog(LOG_NOTICE,
"CHROOT user %s: can't chdir to %s: %m",
pw->pw_name, homedir);
bad_chroot:
reply(550, "Can't change root.");
goto bad;
}
break;
case CLASS_REAL:
2006-02-25 05:28:55 +03:00
/* only chroot REAL if explicitly requested */
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
if (! EMPTYSTR(curclass.chroot)) {
format_path(root, curclass.chroot);
if (EMPTYSTR(root) || chroot(root) < 0) {
syslog(LOG_NOTICE,
"REAL user %s: can't chroot to %s: %m",
pw->pw_name, root);
goto bad_chroot;
}
}
format_path(homedir,
curclass.homedir ? curclass.homedir :
pw->pw_dir);
if (EMPTYSTR(homedir) || chdir(homedir) < 0) {
if (chdir("/") < 0) {
syslog(LOG_NOTICE,
"REAL user %s: can't chdir to %s: %m",
pw->pw_name,
!EMPTYSTR(homedir) ? homedir : "/");
reply(530,
"User %s: can't change directory to %s.",
pw->pw_name,
!EMPTYSTR(homedir) ? homedir : "/");
goto bad;
} else {
reply(-230,
"No directory! Logging in with home=/");
homedir[0] = '/';
}
}
break;
}
#ifndef LOGIN_CAP
setsid();
setlogin(pw->pw_name);
#endif
if (dropprivs ||
(curclass.type != CLASS_REAL &&
ntohs(ctrl_addr.su_port) > IPPORT_RESERVED + 1)) {
dropprivs++;
if (setgid((gid_t)pw->pw_gid) < 0) {
reply(550, "Can't set gid.");
goto bad;
}
if (setuid((uid_t)pw->pw_uid) < 0) {
reply(550, "Can't set uid.");
goto bad;
}
} else {
if (seteuid((uid_t)pw->pw_uid) < 0) {
reply(550, "Can't set uid.");
goto bad;
}
1993-03-21 12:45:37 +03:00
}
setenv("HOME", homedir, 1);
if (curclass.type == CLASS_GUEST && passwd[0] == '-')
quietmessages = 1;
/*
* Display a login message, if it exists.
* N.B. reply(230,) must follow the message.
*/
if (! EMPTYSTR(curclass.motd))
(void)display_file(conffilename(curclass.motd), 230);
show_chdir_messages(230);
if (curclass.type == CLASS_GUEST) {
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
char *p;
1993-03-21 12:45:37 +03:00
reply(230, "Guest login ok, access restrictions apply.");
#if defined(HAVE_SETPROCTITLE)
1994-06-29 05:49:37 +04:00
snprintf(proctitle, sizeof(proctitle),
"%s: anonymous/%s", remotehost, passwd);
setproctitle("%s", proctitle);
#endif /* defined(HAVE_SETPROCTITLE) */
1993-03-21 12:45:37 +03:00
if (logging)
syslog(LOG_INFO,
"ANONYMOUS FTP LOGIN FROM %s, %s (class: %s, type: %s)",
remoteloghost, passwd,
curclass.classname, CURCLASSTYPE);
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
/* store guest password reply into pw_passwd */
REASSIGN(pw->pw_passwd, ftpd_strdup(passwd));
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
for (p = pw->pw_passwd; *p; p++)
if (!isgraph((unsigned char)*p))
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
*p = '_';
1993-03-21 12:45:37 +03:00
} else {
reply(230, "User %s logged in.", pw->pw_name);
#if defined(HAVE_SETPROCTITLE)
1994-06-29 05:49:37 +04:00
snprintf(proctitle, sizeof(proctitle),
"%s: %s", remotehost, pw->pw_name);
setproctitle("%s", proctitle);
#endif /* defined(HAVE_SETPROCTITLE) */
1993-03-21 12:45:37 +03:00
if (logging)
syslog(LOG_INFO,
"FTP LOGIN FROM %s as %s (class: %s, type: %s)",
remoteloghost, pw->pw_name,
curclass.classname, CURCLASSTYPE);
1993-03-21 12:45:37 +03:00
}
(void) umask(curclass.umask);
#ifdef LOGIN_CAP
login_close(lc);
#endif
return;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
bad:
#ifdef LOGIN_CAP
login_close(lc);
#endif
/* Forget all about it... */
1993-03-21 12:45:37 +03:00
end_login();
}
1994-06-29 05:49:37 +04:00
void
retrieve(const char *argv[], const char *name)
1993-03-21 12:45:37 +03:00
{
FILE *fin, *dout;
1993-03-21 12:45:37 +03:00
struct stat st;
2000-05-20 06:20:18 +04:00
int (*closefunc)(FILE *) = NULL;
int dolog, sendrv, closerv, stderrfd, isconversion, isdata, isls;
struct timeval start, finish, td, *tdp;
struct rusage rusage_before, rusage_after;
const char *dispname;
const char *error;
1993-03-21 12:45:37 +03:00
sendrv = closerv = stderrfd = -1;
isconversion = isdata = isls = dolog = 0;
tdp = NULL;
dispname = name;
fin = dout = NULL;
error = NULL;
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
if (argv == NULL) { /* if not running a command ... */
dolog = 1;
isdata = 1;
fin = fopen(name, "r");
closefunc = fclose;
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
if (fin == NULL) /* doesn't exist?; try a conversion */
argv = do_conversion(name);
if (argv != NULL) {
isconversion++;
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
syslog(LOG_DEBUG, "get command: '%s' on '%s'",
argv[0], name);
}
}
if (argv != NULL) {
char temp[MAXPATHLEN];
1993-03-21 12:45:37 +03:00
if (strcmp(argv[0], INTERNAL_LS) == 0) {
isls = 1;
stderrfd = -1;
} else {
(void)snprintf(temp, sizeof(temp), "%s", TMPFILE);
stderrfd = mkstemp(temp);
if (stderrfd != -1)
(void)unlink(temp);
}
dispname = argv[0];
fin = ftpd_popen(argv, "r", stderrfd);
closefunc = ftpd_pclose;
1993-03-21 12:45:37 +03:00
st.st_size = -1;
st.st_blksize = BUFSIZ;
}
if (fin == NULL) {
1994-06-29 05:49:37 +04:00
if (errno != 0) {
perror_reply(550, dispname);
if (dolog)
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
logxfer("get", -1, name, NULL, NULL,
strerror(errno));
1994-06-29 05:49:37 +04:00
}
goto cleanupretrieve;
1993-03-21 12:45:37 +03:00
}
1994-06-29 05:49:37 +04:00
byte_count = -1;
if (argv == NULL
&& (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
error = "Not a plain file";
reply(550, "%s: %s.", dispname, error);
1993-03-21 12:45:37 +03:00
goto done;
}
if (restart_point) {
if (type == TYPE_A) {
off_t i;
1994-06-29 05:49:37 +04:00
int c;
1993-03-21 12:45:37 +03:00
for (i = 0; i < restart_point; i++) {
1993-03-21 12:45:37 +03:00
if ((c=getc(fin)) == EOF) {
error = strerror(errno);
perror_reply(550, dispname);
1993-03-21 12:45:37 +03:00
goto done;
}
if (c == '\n')
i++;
1994-06-29 05:49:37 +04:00
}
} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
error = strerror(errno);
perror_reply(550, dispname);
1993-03-21 12:45:37 +03:00
goto done;
}
}
dout = dataconn(dispname, st.st_size, "w");
1993-03-21 12:45:37 +03:00
if (dout == NULL)
goto done;
(void)getrusage(RUSAGE_SELF, &rusage_before);
(void)gettimeofday(&start, NULL);
sendrv = send_data(fin, dout, &st, isdata);
(void)gettimeofday(&finish, NULL);
(void)getrusage(RUSAGE_SELF, &rusage_after);
closedataconn(dout); /* close now to affect timing stats */
timersub(&finish, &start, &td);
tdp = &td;
done:
if (dolog) {
logxfer("get", byte_count, name, NULL, tdp, error);
if (tdp != NULL)
logrusage(&rusage_before, &rusage_after);
}
closerv = (*closefunc)(fin);
if (sendrv == 0) {
FILE *errf;
struct stat sb;
if (!isls && argv != NULL && closerv != 0) {
reply(-226,
"Command returned an exit status of %d",
closerv);
if (isconversion)
2001-01-10 03:20:49 +03:00
syslog(LOG_WARNING,
"retrieve command: '%s' returned %d",
argv[0], closerv);
}
if (!isls && argv != NULL && stderrfd != -1 &&
(fstat(stderrfd, &sb) == 0) && sb.st_size > 0 &&
((errf = fdopen(stderrfd, "r")) != NULL)) {
char *cp, line[LINE_MAX];
reply(-226, "Command error messages:");
rewind(errf);
while (fgets(line, sizeof(line), errf) != NULL) {
if ((cp = strchr(line, '\n')) != NULL)
*cp = '\0';
reply(0, " %s", line);
}
(void) fflush(stdout);
(void) fclose(errf);
/* a reply(226,) must follow */
}
reply(226, "Transfer complete.");
}
cleanupretrieve:
if (stderrfd != -1)
(void)close(stderrfd);
if (isconversion)
free(argv);
1993-03-21 12:45:37 +03:00
}
1994-06-29 05:49:37 +04:00
void
store(const char *name, const char *fmode, int unique)
1993-03-21 12:45:37 +03:00
{
FILE *fout, *din;
struct stat st;
2000-05-20 06:20:18 +04:00
int (*closefunc)(FILE *);
struct timeval start, finish, td, *tdp;
const char *desc, *error;
1993-03-21 12:45:37 +03:00
din = NULL;
desc = (*fmode == 'w') ? "put" : "append";
error = NULL;
1993-03-21 12:45:37 +03:00
if (unique && stat(name, &st) == 0 &&
1994-06-29 05:49:37 +04:00
(name = gunique(name)) == NULL) {
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
logxfer(desc, -1, name, NULL, NULL,
"cannot create unique file");
goto cleanupstore;
1994-06-29 05:49:37 +04:00
}
1993-03-21 12:45:37 +03:00
if (restart_point)
fmode = "r+";
fout = fopen(name, fmode);
1993-03-21 12:45:37 +03:00
closefunc = fclose;
tdp = NULL;
1993-03-21 12:45:37 +03:00
if (fout == NULL) {
perror_reply(553, name);
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
logxfer(desc, -1, name, NULL, NULL, strerror(errno));
goto cleanupstore;
1993-03-21 12:45:37 +03:00
}
1994-06-29 05:49:37 +04:00
byte_count = -1;
1993-03-21 12:45:37 +03:00
if (restart_point) {
if (type == TYPE_A) {
off_t i;
1994-06-29 05:49:37 +04:00
int c;
1993-03-21 12:45:37 +03:00
for (i = 0; i < restart_point; i++) {
1993-03-21 12:45:37 +03:00
if ((c=getc(fout)) == EOF) {
error = strerror(errno);
1993-03-21 12:45:37 +03:00
perror_reply(550, name);
goto done;
}
if (c == '\n')
i++;
1994-06-29 05:49:37 +04:00
}
1993-03-21 12:45:37 +03:00
/*
* We must do this seek to "current" position
* because we are changing from reading to
* writing.
*/
if (fseek(fout, 0L, SEEK_CUR) < 0) {
error = strerror(errno);
1993-03-21 12:45:37 +03:00
perror_reply(550, name);
goto done;
}
} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
error = strerror(errno);
1993-03-21 12:45:37 +03:00
perror_reply(550, name);
goto done;
}
}
din = dataconn(name, (off_t)-1, "r");
if (din == NULL)
goto done;
(void)gettimeofday(&start, NULL);
1993-03-21 12:45:37 +03:00
if (receive_data(din, fout) == 0) {
if (unique)
reply(226, "Transfer complete (unique file name:%s).",
name);
else
reply(226, "Transfer complete.");
}
(void)gettimeofday(&finish, NULL);
closedataconn(din); /* close now to affect timing stats */
timersub(&finish, &start, &td);
tdp = &td;
done:
logxfer(desc, byte_count, name, NULL, tdp, error);
1993-03-21 12:45:37 +03:00
(*closefunc)(fout);
cleanupstore:
;
1993-03-21 12:45:37 +03:00
}
1994-06-29 05:49:37 +04:00
static FILE *
getdatasock(const char *fmode)
1993-03-21 12:45:37 +03:00
{
int on, s, t, tries;
in_port_t port;
1993-03-21 12:45:37 +03:00
on = 1;
1993-03-21 12:45:37 +03:00
if (data >= 0)
return (fdopen(data, fmode));
if (! dropprivs)
(void) seteuid((uid_t)0);
s = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
1993-03-21 12:45:37 +03:00
if (s < 0)
goto bad;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1994-06-29 05:49:37 +04:00
(char *) &on, sizeof(on)) < 0)
1993-03-21 12:45:37 +03:00
goto bad;
if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
(char *) &on, sizeof(on)) < 0)
goto bad;
/* anchor socket to avoid multi-homing problems */
data_source = ctrl_addr;
/*
* By default source port for PORT connctions is
* ctrlport-1 (see RFC959 section 5.2).
* However, if privs have been dropped and that
* would be < IPPORT_RESERVED, use a random port
* instead.
*/
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
if (dataport)
port = dataport;
else
port = ntohs(ctrl_addr.su_port) - 1;
if (dropprivs && port < IPPORT_RESERVED)
port = 0; /* use random port */
data_source.su_port = htons(port);
1993-03-21 12:45:37 +03:00
for (tries = 1; ; tries++) {
if (bind(s, (struct sockaddr *)&data_source.si_su,
data_source.su_len) >= 0)
1993-03-21 12:45:37 +03:00
break;
if (errno != EADDRINUSE || tries > 10)
goto bad;
sleep(tries);
}
if (! dropprivs)
(void) seteuid((uid_t)pw->pw_uid);
1993-03-21 12:45:37 +03:00
#ifdef IP_TOS
if (!mapped && ctrl_addr.su_family == AF_INET) {
on = IPTOS_THROUGHPUT;
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on,
sizeof(int)) < 0)
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
}
1993-03-21 12:45:37 +03:00
#endif
return (fdopen(s, fmode));
bad:
/* Return the real value of errno (close may change it) */
1994-06-29 05:49:37 +04:00
t = errno;
if (! dropprivs)
(void) seteuid((uid_t)pw->pw_uid);
if (s >= 0)
(void) close(s);
1994-06-29 05:49:37 +04:00
errno = t;
1993-03-21 12:45:37 +03:00
return (NULL);
}
FILE *
dataconn(const char *name, off_t size, const char *fmode)
1993-03-21 12:45:37 +03:00
{
char sizebuf[32];
FILE *file;
int retry, tos, keepalive, conerrno;
1993-03-21 12:45:37 +03:00
file_size = size;
byte_count = 0;
if (size != (off_t) -1)
(void)snprintf(sizebuf, sizeof(sizebuf), " (" LLF " byte%s)",
(LLT)size, PLURAL(size));
1993-03-21 12:45:37 +03:00
else
1997-07-21 09:13:10 +04:00
sizebuf[0] = '\0';
1993-03-21 12:45:37 +03:00
if (pdata >= 0) {
struct sockinet from;
int s;
socklen_t fromlen = sizeof(from.su_len);
1993-03-21 12:45:37 +03:00
(void) alarm(curclass.timeout);
s = accept(pdata, (struct sockaddr *)&from.si_su, &fromlen);
(void) alarm(0);
1993-03-21 12:45:37 +03:00
if (s < 0) {
reply(425, "Can't open data connection.");
(void) close(pdata);
pdata = -1;
1994-06-29 05:49:37 +04:00
return (NULL);
1993-03-21 12:45:37 +03:00
}
(void) close(pdata);
pdata = s;
switch (from.su_family) {
case AF_INET:
1993-03-21 12:45:37 +03:00
#ifdef IP_TOS
if (!mapped) {
tos = IPTOS_THROUGHPUT;
(void) setsockopt(s, IPPROTO_IP, IP_TOS,
(char *)&tos, sizeof(int));
}
break;
#endif
}
/* Set keepalives on the socket to detect dropped conns. */
#ifdef SO_KEEPALIVE
keepalive = 1;
(void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
(char *)&keepalive, sizeof(int));
1993-03-21 12:45:37 +03:00
#endif
1994-06-29 05:49:37 +04:00
reply(150, "Opening %s mode data connection for '%s'%s.",
1993-03-21 12:45:37 +03:00
type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
return (fdopen(pdata, fmode));
1993-03-21 12:45:37 +03:00
}
if (data >= 0) {
1994-06-29 05:49:37 +04:00
reply(125, "Using existing data connection for '%s'%s.",
1993-03-21 12:45:37 +03:00
name, sizebuf);
usedefault = 1;
return (fdopen(data, fmode));
1993-03-21 12:45:37 +03:00
}
if (usedefault)
data_dest = his_addr;
usedefault = 1;
retry = conerrno = 0;
do {
file = getdatasock(fmode);
if (file == NULL) {
char hbuf[NI_MAXHOST];
char pbuf[NI_MAXSERV];
if (getnameinfo((struct sockaddr *)&data_source.si_su,
data_source.su_len, hbuf, sizeof(hbuf), pbuf,
sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV))
strlcpy(hbuf, "?", sizeof(hbuf));
reply(425, "Can't create data socket (%s,%s): %s.",
hbuf, pbuf, strerror(errno));
return (NULL);
}
data = fileno(file);
conerrno = 0;
if (connect(data, (struct sockaddr *)&data_dest.si_su,
data_dest.su_len) == 0)
break;
conerrno = errno;
(void) fclose(file);
file = NULL;
data = -1;
if (conerrno == EADDRINUSE) {
1993-03-21 12:45:37 +03:00
sleep((unsigned) swaitint);
retry += swaitint;
} else {
break;
1993-03-21 12:45:37 +03:00
}
} while (retry <= swaitmax);
if (conerrno != 0) {
1993-03-21 12:45:37 +03:00
perror_reply(425, "Can't build data connection");
return (NULL);
}
1994-06-29 05:49:37 +04:00
reply(150, "Opening %s mode data connection for '%s'%s.",
1993-03-21 12:45:37 +03:00
type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
return (file);
}
void
closedataconn(FILE *fd)
{
if (fd == NULL)
return;
(void)fclose(fd);
data = -1;
if (pdata >= 0)
(void)close(pdata);
pdata = -1;
}
int
write_data(int fd, char *buf, size_t size, off_t *bufrem,
struct timeval *then, int isdata)
{
struct timeval now, td;
ssize_t c;
while (size > 0) {
c = size;
if (curclass.writesize) {
if (curclass.writesize < c)
c = curclass.writesize;
}
if (curclass.rateget) {
if (*bufrem < c)
c = *bufrem;
}
(void) alarm(curclass.timeout);
c = write(fd, buf, c);
if (c <= 0)
return (1);
buf += c;
size -= c;
byte_count += c;
if (isdata) {
total_data_out += c;
total_data += c;
}
total_bytes_out += c;
total_bytes += c;
if (curclass.rateget) {
*bufrem -= c;
if (*bufrem == 0) {
(void)gettimeofday(&now, NULL);
timersub(&now, then, &td);
if (td.tv_sec == 0) {
usleep(1000000 - td.tv_usec);
(void)gettimeofday(then, NULL);
} else
*then = now;
*bufrem = curclass.rateget;
}
}
}
return (0);
}
static enum send_status
send_data_with_read(int filefd, int netfd, const struct stat *st, int isdata)
{
struct timeval then;
off_t bufrem;
ssize_t readsize;
char *buf;
int c, error;
if (curclass.readsize > 0)
readsize = curclass.readsize;
else
readsize = st->st_blksize;
if ((buf = malloc(readsize)) == NULL) {
perror_reply(451, "Local resource failure: malloc");
return (SS_NO_TRANSFER);
}
if (curclass.rateget) {
bufrem = curclass.rateget;
(void)gettimeofday(&then, NULL);
} else
bufrem = readsize;
for (;;) {
(void) alarm(curclass.timeout);
c = read(filefd, buf, readsize);
if (c == 0)
error = SS_SUCCESS;
else if (c < 0)
error = SS_FILE_ERROR;
else if (write_data(netfd, buf, c, &bufrem, &then, isdata))
error = SS_DATA_ERROR;
else if (urgflag && handleoobcmd())
error = SS_ABORTED;
else
continue;
free(buf);
return (error);
}
}
static enum send_status
send_data_with_mmap(int filefd, int netfd, const struct stat *st, int isdata)
{
struct timeval then;
off_t bufrem, filesize, off, origoff;
ssize_t mapsize, winsize;
int error, sendbufsize, sendlowat;
void *win;
bufrem = 0;
if (curclass.sendbufsize) {
sendbufsize = curclass.sendbufsize;
if (setsockopt(netfd, SOL_SOCKET, SO_SNDBUF,
&sendbufsize, sizeof(int)) == -1)
syslog(LOG_WARNING, "setsockopt(SO_SNDBUF, %d): %m",
sendbufsize);
}
if (curclass.sendlowat) {
sendlowat = curclass.sendlowat;
if (setsockopt(netfd, SOL_SOCKET, SO_SNDLOWAT,
&sendlowat, sizeof(int)) == -1)
syslog(LOG_WARNING, "setsockopt(SO_SNDLOWAT, %d): %m",
sendlowat);
}
winsize = curclass.mmapsize;
filesize = st->st_size;
if (ftpd_debug)
syslog(LOG_INFO, "mmapsize = " LLF ", writesize = " LLF,
(LLT)winsize, (LLT)curclass.writesize);
if (winsize <= 0)
goto try_read;
off = lseek(filefd, (off_t)0, SEEK_CUR);
if (off == -1)
goto try_read;
origoff = off;
if (curclass.rateget) {
bufrem = curclass.rateget;
(void)gettimeofday(&then, NULL);
} else
bufrem = winsize;
while (1) {
mapsize = MIN(filesize - off, winsize);
if (mapsize == 0)
break;
win = mmap(NULL, mapsize, PROT_READ,
MAP_FILE|MAP_SHARED, filefd, off);
if (win == MAP_FAILED) {
if (off == origoff)
goto try_read;
return (SS_FILE_ERROR);
}
(void) madvise(win, mapsize, MADV_SEQUENTIAL);
error = write_data(netfd, win, mapsize, &bufrem, &then,
isdata);
(void) madvise(win, mapsize, MADV_DONTNEED);
munmap(win, mapsize);
if (urgflag && handleoobcmd())
return (SS_ABORTED);
if (error)
return (SS_DATA_ERROR);
off += mapsize;
}
return (SS_SUCCESS);
try_read:
return (send_data_with_read(filefd, netfd, st, isdata));
}
1993-03-21 12:45:37 +03:00
/*
* Transfer the contents of "instr" to "outstr" peer using the appropriate
* encapsulation of the data subject to Mode, Structure, and Type.
1993-03-21 12:45:37 +03:00
*
* NB: Form isn't handled.
*/
static int
send_data(FILE *instr, FILE *outstr, const struct stat *st, int isdata)
1993-03-21 12:45:37 +03:00
{
int c, filefd, netfd, rval;
1993-03-21 12:45:37 +03:00
urgflag = 0;
transflag = 1;
rval = -1;
1993-03-21 12:45:37 +03:00
switch (type) {
case TYPE_A:
/* XXXLUKEM: rate limit ascii send (get) */
(void) alarm(curclass.timeout);
1993-03-21 12:45:37 +03:00
while ((c = getc(instr)) != EOF) {
if (urgflag && handleoobcmd())
goto cleanup_send_data;
1993-03-21 12:45:37 +03:00
byte_count++;
if (c == '\n') {
if (ferror(outstr))
goto data_err;
(void) putc('\r', outstr);
if (isdata) {
total_data_out++;
total_data++;
}
total_bytes_out++;
total_bytes++;
1993-03-21 12:45:37 +03:00
}
(void) putc(c, outstr);
if (isdata) {
total_data_out++;
total_data++;
}
total_bytes_out++;
total_bytes++;
if ((byte_count % 4096) == 0)
(void) alarm(curclass.timeout);
1993-03-21 12:45:37 +03:00
}
(void) alarm(0);
1993-03-21 12:45:37 +03:00
fflush(outstr);
if (ferror(instr))
goto file_err;
if (ferror(outstr))
goto data_err;
rval = 0;
goto cleanup_send_data;
1993-03-21 12:45:37 +03:00
case TYPE_I:
case TYPE_L:
filefd = fileno(instr);
netfd = fileno(outstr);
switch (send_data_with_mmap(filefd, netfd, st, isdata)) {
case SS_SUCCESS:
break;
case SS_ABORTED:
case SS_NO_TRANSFER:
goto cleanup_send_data;
case SS_FILE_ERROR:
goto file_err;
case SS_DATA_ERROR:
goto data_err;
}
rval = 0;
goto cleanup_send_data;
1993-03-21 12:45:37 +03:00
default:
reply(550, "Unimplemented TYPE %d in send_data", type);
goto cleanup_send_data;
1993-03-21 12:45:37 +03:00
}
data_err:
(void) alarm(0);
1993-03-21 12:45:37 +03:00
perror_reply(426, "Data connection");
goto cleanup_send_data;
1993-03-21 12:45:37 +03:00
file_err:
(void) alarm(0);
1993-03-21 12:45:37 +03:00
perror_reply(551, "Error on input file");
goto cleanup_send_data;
cleanup_send_data:
(void) alarm(0);
transflag = 0;
urgflag = 0;
if (isdata) {
total_files_out++;
total_files++;
}
total_xfers_out++;
total_xfers++;
return (rval);
1993-03-21 12:45:37 +03:00
}
/*
1994-06-29 05:49:37 +04:00
* Transfer data from peer to "outstr" using the appropriate encapulation of
* the data subject to Mode, Structure, and Type.
1993-03-21 12:45:37 +03:00
*
* N.B.: Form isn't handled.
*/
1994-06-29 05:49:37 +04:00
static int
2000-05-20 06:20:18 +04:00
receive_data(FILE *instr, FILE *outstr)
1993-03-21 12:45:37 +03:00
{
int c, netfd, filefd, rval;
int volatile bare_lfs;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
off_t byteswritten;
char *buf;
ssize_t readsize;
struct sigaction sa, sa_saved;
struct stat st;
1993-03-21 12:45:37 +03:00
memset(&sa, 0, sizeof(sa));
sigfillset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = lostconn;
(void) sigaction(SIGALRM, &sa, &sa_saved);
bare_lfs = 0;
urgflag = 0;
transflag = 1;
rval = -1;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
byteswritten = 0;
buf = NULL;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
#define FILESIZECHECK(x) \
do { \
if (curclass.maxfilesize != -1 && \
(x) > curclass.maxfilesize) { \
errno = EFBIG; \
goto file_err; \
} \
} while (0)
1993-03-21 12:45:37 +03:00
switch (type) {
case TYPE_I:
case TYPE_L:
netfd = fileno(instr);
filefd = fileno(outstr);
(void) alarm(curclass.timeout);
if (curclass.readsize)
readsize = curclass.readsize;
else if (fstat(filefd, &st) != -1)
readsize = (ssize_t)st.st_blksize;
else
readsize = BUFSIZ;
if ((buf = malloc(readsize)) == NULL) {
perror_reply(451, "Local resource failure: malloc");
goto cleanup_recv_data;
}
if (curclass.rateput) {
while (1) {
int d;
struct timeval then, now, td;
off_t bufrem;
(void)gettimeofday(&then, NULL);
errno = c = d = 0;
for (bufrem = curclass.rateput; bufrem > 0; ) {
if ((c = read(netfd, buf,
MIN(readsize, bufrem))) <= 0)
goto recvdone;
if (urgflag && handleoobcmd())
goto cleanup_recv_data;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
FILESIZECHECK(byte_count + c);
if ((d = write(filefd, buf, c)) != c)
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
goto file_err;
(void) alarm(curclass.timeout);
bufrem -= c;
byte_count += c;
total_data_in += c;
total_data += c;
total_bytes_in += c;
total_bytes += c;
}
(void)gettimeofday(&now, NULL);
timersub(&now, &then, &td);
if (td.tv_sec == 0)
usleep(1000000 - td.tv_usec);
}
} else {
while ((c = read(netfd, buf, readsize)) > 0) {
if (urgflag && handleoobcmd())
goto cleanup_recv_data;
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
FILESIZECHECK(byte_count + c);
if (write(filefd, buf, c) != c)
goto file_err;
(void) alarm(curclass.timeout);
byte_count += c;
total_data_in += c;
total_data += c;
total_bytes_in += c;
total_bytes += c;
}
1993-03-21 12:45:37 +03:00
}
recvdone:
if (c < 0)
1993-03-21 12:45:37 +03:00
goto data_err;
rval = 0;
goto cleanup_recv_data;
1993-03-21 12:45:37 +03:00
case TYPE_E:
reply(553, "TYPE E not implemented.");
goto cleanup_recv_data;
1993-03-21 12:45:37 +03:00
case TYPE_A:
(void) alarm(curclass.timeout);
/* XXXLUKEM: rate limit ascii receive (put) */
1993-03-21 12:45:37 +03:00
while ((c = getc(instr)) != EOF) {
if (urgflag && handleoobcmd())
goto cleanup_recv_data;
1993-03-21 12:45:37 +03:00
byte_count++;
total_data_in++;
total_data++;
total_bytes_in++;
total_bytes++;
if ((byte_count % 4096) == 0)
(void) alarm(curclass.timeout);
1993-03-21 12:45:37 +03:00
if (c == '\n')
bare_lfs++;
while (c == '\r') {
if (ferror(outstr))
goto data_err;
if ((c = getc(instr)) != '\n') {
byte_count++;
total_data_in++;
total_data++;
total_bytes_in++;
total_bytes++;
if ((byte_count % 4096) == 0)
(void) alarm(curclass.timeout);
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
byteswritten++;
FILESIZECHECK(byteswritten);
1993-03-21 12:45:37 +03:00
(void) putc ('\r', outstr);
if (c == '\0' || c == EOF)
goto contin2;
}
}
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
byteswritten++;
FILESIZECHECK(byteswritten);
1993-03-21 12:45:37 +03:00
(void) putc(c, outstr);
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
contin2: ;
1993-03-21 12:45:37 +03:00
}
(void) alarm(0);
1993-03-21 12:45:37 +03:00
fflush(outstr);
if (ferror(instr))
goto data_err;
if (ferror(outstr))
goto file_err;
if (bare_lfs) {
reply(-226,
"WARNING! %d bare linefeeds received in ASCII mode",
1994-06-29 05:49:37 +04:00
bare_lfs);
reply(0, "File may not have transferred correctly.");
1993-03-21 12:45:37 +03:00
}
rval = 0;
goto cleanup_recv_data;
1993-03-21 12:45:37 +03:00
default:
reply(550, "Unimplemented TYPE %d in receive_data", type);
goto cleanup_recv_data;
1993-03-21 12:45:37 +03:00
}
#undef FILESIZECHECK
1993-03-21 12:45:37 +03:00
data_err:
(void) alarm(0);
1993-03-21 12:45:37 +03:00
perror_reply(426, "Data Connection");
goto cleanup_recv_data;
1993-03-21 12:45:37 +03:00
file_err:
(void) alarm(0);
1993-03-21 12:45:37 +03:00
perror_reply(452, "Error writing file");
goto cleanup_recv_data;
cleanup_recv_data:
(void) alarm(0);
(void) sigaction(SIGALRM, &sa_saved, NULL);
if (buf)
free(buf);
transflag = 0;
urgflag = 0;
total_files_in++;
total_files++;
total_xfers_in++;
total_xfers++;
return (rval);
1993-03-21 12:45:37 +03:00
}
1994-06-29 05:49:37 +04:00
void
2000-05-20 06:20:18 +04:00
statcmd(void)
1993-03-21 12:45:37 +03:00
{
struct sockinet *su = NULL;
static char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
unsigned char *a, *p;
int ispassive, af;
off_t otbi, otbo, otb;
1993-03-21 12:45:37 +03:00
2011-09-16 20:13:16 +04:00
a = p = NULL;
reply(-211, "%s FTP server status:", hostname);
reply(0, "Version: %s", EMPTYSTR(version) ? "<suppressed>" : version);
hbuf[0] = '\0';
if (!getnameinfo((struct sockaddr *)&his_addr.si_su, his_addr.su_len,
hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST)
&& strcmp(remotehost, hbuf) != 0)
reply(0, "Connected to %s (%s)", remotehost, hbuf);
else
reply(0, "Connected to %s", remotehost);
1993-03-21 12:45:37 +03:00
if (logged_in) {
if (curclass.type == CLASS_GUEST)
reply(0, "Logged in anonymously");
1993-03-21 12:45:37 +03:00
else
reply(0, "Logged in as %s%s", pw->pw_name,
curclass.type == CLASS_CHROOT ? " (chroot)" : "");
1993-03-21 12:45:37 +03:00
} else if (askpasswd)
reply(0, "Waiting for password");
1993-03-21 12:45:37 +03:00
else
reply(0, "Waiting for user name");
cprintf(stdout, " TYPE: %s", typenames[type]);
if (type == TYPE_A || type == TYPE_E)
cprintf(stdout, ", FORM: %s", formnames[form]);
if (type == TYPE_L) {
1993-03-21 12:45:37 +03:00
#if NBBY == 8
cprintf(stdout, " %d", NBBY);
1993-03-21 12:45:37 +03:00
#else
/* XXX: `bytesize' needs to be defined in this case */
cprintf(stdout, " %d", bytesize);
1993-03-21 12:45:37 +03:00
#endif
}
cprintf(stdout, "; STRUcture: %s; transfer MODE: %s\r\n",
1993-03-21 12:45:37 +03:00
strunames[stru], modenames[mode]);
ispassive = 0;
if (data != -1) {
reply(0, "Data connection open");
su = NULL;
} else if (pdata != -1) {
reply(0, "in Passive mode");
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
if (curclass.advertise.su_len != 0)
su = &curclass.advertise;
else
su = &pasv_addr;
ispassive = 1;
1993-03-21 12:45:37 +03:00
goto printaddr;
} else if (usedefault == 0) {
su = (struct sockinet *)&data_dest;
if (epsvall) {
reply(0, "EPSV only mode (EPSV ALL)");
goto epsvonly;
}
printaddr:
/* PASV/PORT */
if (su->su_family == AF_INET) {
a = (unsigned char *) &su->su_addr;
p = (unsigned char *) &su->su_port;
1993-03-21 12:45:37 +03:00
#define UC(b) (((int) b) & 0xff)
reply(0, "%s (%d,%d,%d,%d,%d,%d)",
ispassive ? "PASV" : "PORT" ,
UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
UC(p[0]), UC(p[1]));
}
/* LPSV/LPRT */
{
int alen, i;
alen = 0;
switch (su->su_family) {
case AF_INET:
a = (unsigned char *) &su->su_addr;
p = (unsigned char *) &su->su_port;
alen = sizeof(su->su_addr);
af = 4;
break;
#ifdef INET6
case AF_INET6:
a = (unsigned char *) &su->su_6addr;
p = (unsigned char *) &su->su_port;
alen = sizeof(su->su_6addr);
af = 6;
break;
#endif
default:
af = 0;
break;
}
if (af) {
cprintf(stdout, " %s (%d,%d",
ispassive ? "LPSV" : "LPRT", af, alen);
for (i = 0; i < alen; i++)
cprintf(stdout, ",%d", UC(a[i]));
cprintf(stdout, ",%d,%d,%d)\r\n",
2, UC(p[0]), UC(p[1]));
1993-03-21 12:45:37 +03:00
#undef UC
}
}
/* EPRT/EPSV */
epsvonly:
af = af2epsvproto(su->su_family);
hbuf[0] = '\0';
if (af > 0) {
struct sockinet tmp;
tmp = *su;
#ifdef INET6
if (tmp.su_family == AF_INET6)
tmp.su_scope_id = 0;
#endif
if (getnameinfo((struct sockaddr *)&tmp.si_su,
tmp.su_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
NI_NUMERICHOST | NI_NUMERICSERV) == 0)
reply(0, "%s (|%d|%s|%s|)",
ispassive ? "EPSV" : "EPRT",
af, hbuf, sbuf);
}
1993-03-21 12:45:37 +03:00
} else
reply(0, "No data connection");
if (logged_in) {
reply(0,
"Data sent: " LLF " byte%s in " LLF " file%s",
(LLT)total_data_out, PLURAL(total_data_out),
(LLT)total_files_out, PLURAL(total_files_out));
reply(0,
"Data received: " LLF " byte%s in " LLF " file%s",
(LLT)total_data_in, PLURAL(total_data_in),
(LLT)total_files_in, PLURAL(total_files_in));
reply(0,
"Total data: " LLF " byte%s in " LLF " file%s",
(LLT)total_data, PLURAL(total_data),
(LLT)total_files, PLURAL(total_files));
}
otbi = total_bytes_in;
otbo = total_bytes_out;
otb = total_bytes;
reply(0, "Traffic sent: " LLF " byte%s in " LLF " transfer%s",
(LLT)otbo, PLURAL(otbo),
(LLT)total_xfers_out, PLURAL(total_xfers_out));
reply(0, "Traffic received: " LLF " byte%s in " LLF " transfer%s",
(LLT)otbi, PLURAL(otbi),
(LLT)total_xfers_in, PLURAL(total_xfers_in));
reply(0, "Total traffic: " LLF " byte%s in " LLF " transfer%s",
(LLT)otb, PLURAL(otb),
(LLT)total_xfers, PLURAL(total_xfers));
if (logged_in && !CURCLASS_FLAGS_ISSET(private)) {
struct ftpconv *cp;
2000-07-08 22:24:28 +04:00
reply(0, "%s", "");
reply(0, "Class: %s, type: %s",
curclass.classname, CURCLASSTYPE);
reply(0, "Check PORT/LPRT commands: %sabled",
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
CURCLASS_FLAGS_ISSET(checkportcmd) ? "en" : "dis");
if (! EMPTYSTR(curclass.display))
reply(0, "Display file: %s", curclass.display);
if (! EMPTYSTR(curclass.notify))
reply(0, "Notify fileglob: %s", curclass.notify);
reply(0, "Idle timeout: " LLF ", maximum timeout: " LLF,
(LLT)curclass.timeout, (LLT)curclass.maxtimeout);
reply(0, "Current connections: %d", connections);
if (curclass.limit == -1)
reply(0, "Maximum connections: unlimited");
else
reply(0, "Maximum connections: " LLF,
(LLT)curclass.limit);
if (curclass.limitfile)
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
reply(0, "Connection limit exceeded message file: %s",
conffilename(curclass.limitfile));
if (! EMPTYSTR(curclass.chroot))
reply(0, "Chroot format: %s", curclass.chroot);
2001-12-12 11:13:33 +03:00
reply(0, "Deny bad ftpusers(5) quickly: %sabled",
CURCLASS_FLAGS_ISSET(denyquick) ? "en" : "dis");
if (! EMPTYSTR(curclass.homedir))
reply(0, "Homedir format: %s", curclass.homedir);
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
if (curclass.maxfilesize == -1)
reply(0, "Maximum file size: unlimited");
else
reply(0, "Maximum file size: " LLF,
(LLT)curclass.maxfilesize);
if (! EMPTYSTR(curclass.motd))
reply(0, "MotD file: %s", conffilename(curclass.motd));
reply(0,
"Modify commands (CHMOD, DELE, MKD, RMD, RNFR, UMASK): %sabled",
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
CURCLASS_FLAGS_ISSET(modify) ? "en" : "dis");
reply(0, "Upload commands (APPE, STOR, STOU): %sabled",
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
CURCLASS_FLAGS_ISSET(upload) ? "en" : "dis");
reply(0, "Sanitize file names: %sabled",
CURCLASS_FLAGS_ISSET(sanenames) ? "en" : "dis");
reply(0, "PASV/LPSV/EPSV connections: %sabled",
CURCLASS_FLAGS_ISSET(passive) ? "en" : "dis");
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
if (curclass.advertise.su_len != 0) {
char buf[50]; /* big enough for IPv6 address */
const char *bp;
bp = inet_ntop(curclass.advertise.su_family,
(void *)&curclass.advertise.su_addr,
buf, sizeof(buf));
if (bp != NULL)
reply(0, "PASV advertise address: %s", bp);
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
}
if (curclass.portmin && curclass.portmax)
reply(0, "PASV port range: " LLF " - " LLF,
(LLT)curclass.portmin, (LLT)curclass.portmax);
if (curclass.rateget)
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
reply(0, "Rate get limit: " LLF " bytes/sec",
(LLT)curclass.rateget);
else
reply(0, "Rate get limit: disabled");
if (curclass.rateput)
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
reply(0, "Rate put limit: " LLF " bytes/sec",
(LLT)curclass.rateput);
else
reply(0, "Rate put limit: disabled");
if (curclass.mmapsize)
reply(0, "Mmap size: " LLF, (LLT)curclass.mmapsize);
else
reply(0, "Mmap size: disabled");
if (curclass.readsize)
reply(0, "Read size: " LLF, (LLT)curclass.readsize);
else
reply(0, "Read size: default");
if (curclass.writesize)
reply(0, "Write size: " LLF, (LLT)curclass.writesize);
else
reply(0, "Write size: default");
if (curclass.recvbufsize)
reply(0, "Receive buffer size: " LLF,
(LLT)curclass.recvbufsize);
else
reply(0, "Receive buffer size: default");
if (curclass.sendbufsize)
reply(0, "Send buffer size: " LLF,
(LLT)curclass.sendbufsize);
else
reply(0, "Send buffer size: default");
if (curclass.sendlowat)
reply(0, "Send low water mark: " LLF,
(LLT)curclass.sendlowat);
else
reply(0, "Send low water mark: default");
reply(0, "Umask: %.04o", curclass.umask);
for (cp = curclass.conversions; cp != NULL; cp=cp->next) {
if (cp->suffix == NULL || cp->types == NULL ||
cp->command == NULL)
continue;
reply(0, "Conversion: %s [%s] disable: %s, command: %s",
cp->suffix, cp->types, cp->disable, cp->command);
}
}
1993-03-21 12:45:37 +03:00
reply(211, "End of status");
}
1994-06-29 05:49:37 +04:00
void
2000-05-20 06:20:18 +04:00
fatal(const char *s)
1993-03-21 12:45:37 +03:00
{
1994-06-29 05:49:37 +04:00
1993-03-21 12:45:37 +03:00
reply(451, "Error in server: %s\n", s);
reply(221, "Closing connection due to server error.");
dologout(0);
/* NOTREACHED */
}
/*
* reply() --
* depending on the value of n, display fmt with a trailing CRLF and
* prefix of:
* n < -1 prefix the message with abs(n) + "-" (initial line)
* n == 0 prefix the message with 4 spaces (middle lines)
* n > 0 prefix the message with n + " " (final line)
*/
1994-06-29 05:49:37 +04:00
void
reply(int n, const char *fmt, ...)
1993-03-21 12:45:37 +03:00
{
char msg[MAXPATHLEN * 2 + 100];
size_t b;
va_list ap;
2000-05-20 06:20:18 +04:00
if (n == 0)
b = snprintf(msg, sizeof(msg), " ");
else if (n < 0)
b = snprintf(msg, sizeof(msg), "%d-", -n);
else
b = snprintf(msg, sizeof(msg), "%d ", n);
va_start(ap, fmt);
vsnprintf(msg + b, sizeof(msg) - b, fmt, ap);
va_end(ap);
cprintf(stdout, "%s\r\n", msg);
1993-03-21 12:45:37 +03:00
(void)fflush(stdout);
if (ftpd_debug)
syslog(LOG_DEBUG, "<--- %s", msg);
1993-03-21 12:45:37 +03:00
}
1994-06-29 05:49:37 +04:00
static void
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
logremotehost(struct sockinet *who)
1993-03-21 12:45:37 +03:00
{
#if defined(HAVE_SOCKADDR_SNPRINTF)
char abuf[BUFSIZ];
#endif
struct sockaddr *sa = (struct sockaddr *)&who->si_su;
if (getnameinfo(sa, who->su_len, remotehost, sizeof(remotehost), NULL,
0, getnameopts))
strlcpy(remotehost, "?", sizeof(remotehost));
#if defined(HAVE_SOCKADDR_SNPRINTF)
sockaddr_snprintf(abuf, sizeof(abuf), "%a", sa);
snprintf(remoteloghost, sizeof(remoteloghost), "%s(%s)", remotehost,
abuf);
#else
strlcpy(remoteloghost, remotehost, sizeof(remoteloghost));
#endif
#if defined(HAVE_SETPROCTITLE)
1994-06-29 05:49:37 +04:00
snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
setproctitle("%s", proctitle);
#endif /* defined(HAVE_SETPROCTITLE) */
1994-06-29 05:49:37 +04:00
if (logging)
syslog(LOG_INFO, "connection from %s to %s",
remoteloghost, hostname);
1993-03-21 12:45:37 +03:00
}
/*
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
* Record logout in wtmp file and exit with supplied status.
* NOTE: because this is called from signal handlers it cannot
* use stdio (or call other functions that use stdio).
1993-03-21 12:45:37 +03:00
*/
1994-06-29 05:49:37 +04:00
void
2000-05-20 06:20:18 +04:00
dologout(int status)
1993-03-21 12:45:37 +03:00
{
/*
* Prevent reception of SIGURG from resulting in a resumption
* back to the main program loop.
*/
transflag = 0;
logout_utmp();
1993-03-21 12:45:37 +03:00
if (logged_in) {
#ifdef KERBEROS
if (!notickets && krbtkfile_env)
unlink(krbtkfile_env);
#endif
1993-03-21 12:45:37 +03:00
}
/* beware of flushing buffers after a SIGPIPE */
if (xferlogfd != -1)
close(xferlogfd);
1993-03-21 12:45:37 +03:00
_exit(status);
}
2001-04-12 06:28:59 +04:00
void
abor(void)
{
2001-04-12 06:28:59 +04:00
if (!transflag)
return;
tmpline[0] = '\0';
is_oob = 0;
reply(426, "Transfer aborted. Data connection closed.");
reply(226, "Abort successful");
transflag = 0; /* flag that the transfer has aborted */
}
2001-04-12 06:28:59 +04:00
void
statxfer(void)
{
2001-04-12 06:28:59 +04:00
if (!transflag)
return;
tmpline[0] = '\0';
is_oob = 0;
if (file_size != (off_t) -1)
reply(213,
"Status: " LLF " of " LLF " byte%s transferred",
(LLT)byte_count, (LLT)file_size,
PLURAL(byte_count));
else
reply(213, "Status: " LLF " byte%s transferred",
(LLT)byte_count, PLURAL(byte_count));
}
/*
* Call when urgflag != 0 to handle Out Of Band commands.
* Returns non zero if the OOB command aborted the transfer
* by setting transflag to 0. (c.f., "ABOR").
*/
static int
2012-06-19 10:06:34 +04:00
handleoobcmd(void)
1993-03-21 12:45:37 +03:00
{
char *cp;
int ret;
1993-03-21 12:45:37 +03:00
if (!urgflag)
return (0);
urgflag = 0;
1993-03-21 12:45:37 +03:00
/* only process if transfer occurring */
if (!transflag)
return (0);
1993-03-21 12:45:37 +03:00
cp = tmpline;
ret = get_line(cp, sizeof(tmpline)-1, stdin);
if (ret == -1) {
1993-03-21 12:45:37 +03:00
reply(221, "You could at least say goodbye.");
dologout(0);
} else if (ret == -2) {
/* Ignore truncated command */
/* XXX: abort xfer with "500 command too long", & return 1 ? */
return 0;
1993-03-21 12:45:37 +03:00
}
/*
* Manually parse OOB commands, because we can't
* recursively call the yacc parser...
*/
if (strcasecmp(cp, "ABOR\r\n") == 0) {
abor();
} else if (strcasecmp(cp, "STAT\r\n") == 0) {
statxfer();
} else {
/* XXX: error with "500 unknown command" ? */
}
return (transflag == 0);
1993-03-21 12:45:37 +03:00
}
static int
2000-05-20 06:20:18 +04:00
bind_pasv_addr(void)
{
static int passiveport;
int port, len;
len = pasv_addr.su_len;
if (curclass.portmin == 0 && curclass.portmax == 0) {
pasv_addr.su_port = 0;
return (bind(pdata, (struct sockaddr *)&pasv_addr.si_su, len));
}
if (passiveport == 0) {
srand(getpid());
passiveport = rand() % (curclass.portmax - curclass.portmin)
+ curclass.portmin;
}
port = passiveport;
while (1) {
port++;
if (port > curclass.portmax)
port = curclass.portmin;
else if (port == passiveport) {
errno = EAGAIN;
return (-1);
}
pasv_addr.su_port = htons(port);
if (bind(pdata, (struct sockaddr *)&pasv_addr.si_su, len) == 0)
break;
if (errno != EADDRINUSE)
return (-1);
}
passiveport = port;
return (0);
}
1993-03-21 12:45:37 +03:00
/*
* Note: a response of 425 is not mentioned as a possible response to
1994-06-29 05:49:37 +04:00
* the PASV command in RFC959. However, it has been blessed as
* a legitimate response by Jon Postel in a telephone conversation
1993-03-21 12:45:37 +03:00
* with Rick Adams on 25 Jan 89.
*/
1994-06-29 05:49:37 +04:00
void
2000-05-20 06:20:18 +04:00
passive(void)
1993-03-21 12:45:37 +03:00
{
socklen_t len;
int recvbufsize;
1994-06-29 05:49:37 +04:00
char *p, *a;
1993-03-21 12:45:37 +03:00
if (pdata >= 0)
close(pdata);
1993-03-21 12:45:37 +03:00
pdata = socket(AF_INET, SOCK_STREAM, 0);
if (pdata < 0 || !logged_in) {
1993-03-21 12:45:37 +03:00
perror_reply(425, "Can't open passive connection");
return;
}
pasv_addr = ctrl_addr;
if (bind_pasv_addr() < 0)
1993-03-21 12:45:37 +03:00
goto pasv_error;
len = pasv_addr.su_len;
if (getsockname(pdata, (struct sockaddr *) &pasv_addr.si_su, &len) < 0)
1993-03-21 12:45:37 +03:00
goto pasv_error;
pasv_addr.su_len = len;
if (curclass.recvbufsize) {
recvbufsize = curclass.recvbufsize;
if (setsockopt(pdata, SOL_SOCKET, SO_RCVBUF, &recvbufsize,
sizeof(int)) == -1)
syslog(LOG_WARNING, "setsockopt(SO_RCVBUF, %d): %m",
recvbufsize);
}
1993-03-21 12:45:37 +03:00
if (listen(pdata, 1) < 0)
goto pasv_error;
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
if (curclass.advertise.su_len != 0)
a = (char *) &curclass.advertise.su_addr;
else
a = (char *) &pasv_addr.su_addr;
p = (char *) &pasv_addr.su_port;
1993-03-21 12:45:37 +03:00
#define UC(b) (((int) b) & 0xff)
reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
return;
pasv_error:
(void) close(pdata);
pdata = -1;
perror_reply(425, "Can't open passive connection");
return;
}
/*
* convert protocol identifier to/from AF
*/
int
lpsvproto2af(int proto)
{
switch (proto) {
case 4:
return AF_INET;
#ifdef INET6
case 6:
return AF_INET6;
#endif
default:
return -1;
}
}
int
af2lpsvproto(int af)
{
switch (af) {
case AF_INET:
return 4;
#ifdef INET6
case AF_INET6:
return 6;
#endif
default:
return -1;
}
}
int
epsvproto2af(int proto)
{
switch (proto) {
case 1:
return AF_INET;
#ifdef INET6
case 2:
return AF_INET6;
#endif
default:
return -1;
}
}
int
af2epsvproto(int af)
{
switch (af) {
case AF_INET:
return 1;
#ifdef INET6
case AF_INET6:
return 2;
#endif
default:
return -1;
}
}
/*
* 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
* 229 Entering Extended Passive Mode (|||port|)
*/
void
long_passive(const char *cmd, int pf)
{
socklen_t len;
char *p, *a;
if (!logged_in) {
syslog(LOG_NOTICE, "long passive but not logged in");
reply(503, "Login with USER first.");
return;
}
if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
/*
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
* XXX: only EPRT/EPSV ready clients will understand this
*/
if (strcmp(cmd, "EPSV") != 0)
reply(501, "Network protocol mismatch"); /*XXX*/
else
epsv_protounsupp("Network protocol mismatch");
return;
}
if (pdata >= 0)
close(pdata);
pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
if (pdata < 0) {
perror_reply(425, "Can't open passive connection");
return;
}
pasv_addr = ctrl_addr;
if (bind_pasv_addr() < 0)
goto pasv_error;
len = pasv_addr.su_len;
if (getsockname(pdata, (struct sockaddr *) &pasv_addr.si_su, &len) < 0)
goto pasv_error;
pasv_addr.su_len = len;
if (listen(pdata, 1) < 0)
goto pasv_error;
p = (char *) &pasv_addr.su_port;
#define UC(b) (((int) b) & 0xff)
if (strcmp(cmd, "LPSV") == 0) {
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
struct sockinet *advert;
if (curclass.advertise.su_len != 0)
advert = &curclass.advertise;
else
advert = &pasv_addr;
switch (advert->su_family) {
case AF_INET:
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
a = (char *) &advert->su_addr;
reply(228,
"Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d)",
4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
2, UC(p[0]), UC(p[1]));
return;
#ifdef INET6
case AF_INET6:
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
a = (char *) &advert->su_6addr;
reply(228,
"Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
6, 16,
UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
2, UC(p[0]), UC(p[1]));
return;
#endif
}
#undef UC
} else if (strcmp(cmd, "EPSV") == 0) {
switch (pasv_addr.su_family) {
case AF_INET:
#ifdef INET6
case AF_INET6:
#endif
reply(229, "Entering Extended Passive Mode (|||%d|)",
ntohs(pasv_addr.su_port));
return;
}
} else {
/* more proper error code? */
}
pasv_error:
1993-03-21 12:45:37 +03:00
(void) close(pdata);
pdata = -1;
perror_reply(425, "Can't open passive connection");
return;
}
int
extended_port(const char *arg)
{
char *tmp = NULL;
char *result[3];
char *p, *q;
char delim;
struct addrinfo hints;
struct addrinfo *res = NULL;
int i;
unsigned long proto;
tmp = ftpd_strdup(arg);
p = tmp;
delim = p[0];
p++;
memset(result, 0, sizeof(result));
for (i = 0; i < 3; i++) {
q = strchr(p, delim);
if (!q || *q != delim)
goto parsefail;
*q++ = '\0';
result[i] = p;
p = q;
}
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
/* some more sanity checks */
errno = 0;
p = NULL;
(void)strtoul(result[2], &p, 10);
if (errno || !*result[2] || *p)
goto parsefail;
errno = 0;
p = NULL;
proto = strtoul(result[0], &p, 10);
if (errno || !*result[0] || *p)
goto protounsupp;
memset(&hints, 0, sizeof(hints));
hints.ai_family = epsvproto2af((int)proto);
if (hints.ai_family < 0)
goto protounsupp;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICHOST;
if (getaddrinfo(result[1], result[2], &hints, &res))
goto parsefail;
if (res->ai_next)
goto parsefail;
if (sizeof(data_dest) < res->ai_addrlen)
goto parsefail;
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
memcpy(&data_dest.si_su, res->ai_addr, res->ai_addrlen);
data_dest.su_len = res->ai_addrlen;
#ifdef INET6
if (his_addr.su_family == AF_INET6 &&
data_dest.su_family == AF_INET6) {
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
/* XXX: more sanity checks! */
data_dest.su_scope_id = his_addr.su_scope_id;
}
#endif
if (tmp != NULL)
free(tmp);
if (res)
freeaddrinfo(res);
return 0;
parsefail:
reply(500, "Invalid argument, rejected.");
usedefault = 1;
2000-11-13 14:52:41 +03:00
if (tmp != NULL)
free(tmp);
if (res)
freeaddrinfo(res);
return -1;
protounsupp:
epsv_protounsupp("Protocol not supported");
usedefault = 1;
2000-11-13 14:52:41 +03:00
if (tmp != NULL)
free(tmp);
return -1;
}
/*
* 522 Protocol not supported (proto,...)
* as we assume address family for control and data connections are the same,
* we do not return the list of address families we support - instead, we
* return the address family of the control connection.
*/
void
epsv_protounsupp(const char *message)
{
int proto;
proto = af2epsvproto(ctrl_addr.su_family);
if (proto < 0)
- new ftpd.conf directives: maxfilesize set the maximum size of uploaded files sanenames if set, only permit uploaded filenames that contain characters from the set "-+,._A-Za-z0-9" and that don't start with `.' - new/changed command line options: -e emailaddr define email address for %E (see below) -P dataport use dataport as the dataport (instead of ctrlport-1) -q use pid files to count users [default] -Q don't use pid files to count users -u write entries to utmp -U don't write entries to utmp [default] -w write entries to wtmp [default] -W don't write entries to wtmp NOTE: -U used to mean `write utmp entries'. Its meaning has changed so that it's orthogonal with -q/-Q and -w/-W. This isn't considered a major problem, because using -U isn't going to enable something you don't want, but will disable something you did want (which is safer). - new display file escape sequences: %E email address %s literal `s' if the previous %M or %N wasn't ``1''. %S literal `S' if the previous %M or %N wasn't ``1''. - expand the description of building ~ftp/incoming to cover the appropriate ftpd.conf(5) directives (which are defaults, but it pays to explicitly explain them) - replace strsuftoi() with strsuftoll(), which returns a long long if supported, otherwise a long - rework the way that check_modify and check_upload are done in the yacc parser; they're merged into a common check_write() function which is called explicitly - merge all ftpclass `flag variables' into a single bitfield-based flag element - move various common bits of parse_conf() into a couple of macros - clean up some comments
2000-11-16 16:15:13 +03:00
reply(501, "%s", message); /* XXX */
else
reply(522, "%s, use (%d)", message, proto);
}
1993-03-21 12:45:37 +03:00
/*
* Generate unique name for file with basename "local".
* The file named "local" is already known to exist.
* Generates failure reply on error.
1997-07-21 09:13:10 +04:00
*
* XXX: this function should under go changes similar to
* the mktemp(3)/mkstemp(3) changes.
1993-03-21 12:45:37 +03:00
*/
1994-06-29 05:49:37 +04:00
static char *
2000-05-20 06:20:18 +04:00
gunique(const char *local)
1993-03-21 12:45:37 +03:00
{
static char new[MAXPATHLEN];
1993-03-21 12:45:37 +03:00
struct stat st;
1994-06-29 05:49:37 +04:00
char *cp;
int count;
1993-03-21 12:45:37 +03:00
1994-06-29 05:49:37 +04:00
cp = strrchr(local, '/');
1993-03-21 12:45:37 +03:00
if (cp)
*cp = '\0';
if (stat(cp ? local : ".", &st) < 0) {
perror_reply(553, cp ? local : ".");
return (NULL);
1993-03-21 12:45:37 +03:00
}
if (cp)
*cp = '/';
for (count = 1; count < 100; count++) {
(void)snprintf(new, sizeof(new) - 1, "%s.%d", local, count);
1993-03-21 12:45:37 +03:00
if (stat(new, &st) < 0)
1994-06-29 05:49:37 +04:00
return (new);
1993-03-21 12:45:37 +03:00
}
reply(452, "Unique file name cannot be created.");
1994-06-29 05:49:37 +04:00
return (NULL);
1993-03-21 12:45:37 +03:00
}
/*
* Format and send reply containing system error number.
*/
1994-06-29 05:49:37 +04:00
void
2000-05-20 06:20:18 +04:00
perror_reply(int code, const char *string)
1993-03-21 12:45:37 +03:00
{
int save_errno;
1994-06-29 05:49:37 +04:00
save_errno = errno;
1993-03-21 12:45:37 +03:00
reply(code, "%s: %s.", string, strerror(errno));
errno = save_errno;
1993-03-21 12:45:37 +03:00
}
static char *onefile[] = {
NULL,
1993-03-21 12:45:37 +03:00
0
};
1994-06-29 05:49:37 +04:00
void
2000-05-20 06:20:18 +04:00
send_file_list(const char *whichf)
1993-03-21 12:45:37 +03:00
{
struct stat st;
DIR *dirp;
1993-03-21 12:45:37 +03:00
struct dirent *dir;
FILE *volatile dout;
char **volatile dirlist;
char *dirname, *p;
char *notglob;
int volatile simple;
int volatile freeglob;
1994-06-29 05:49:37 +04:00
glob_t gl;
dirp = NULL;
dout = NULL;
notglob = NULL;
simple = 0;
freeglob = 0;
urgflag = 0;
1994-06-29 05:49:37 +04:00
p = NULL;
1994-06-29 05:49:37 +04:00
if (strpbrk(whichf, "~{[*?") != NULL) {
int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE|GLOB_LIMIT;
1994-06-29 05:49:37 +04:00
memset(&gl, 0, sizeof(gl));
freeglob = 1;
if (glob(whichf, flags, 0, &gl)) {
reply(450, "Not found");
goto cleanup_send_file_list;
1994-06-29 05:49:37 +04:00
} else if (gl.gl_pathc == 0) {
1993-03-21 12:45:37 +03:00
errno = ENOENT;
perror_reply(450, whichf);
goto cleanup_send_file_list;
1993-03-21 12:45:37 +03:00
}
1994-06-29 05:49:37 +04:00
dirlist = gl.gl_pathv;
1993-03-21 12:45:37 +03:00
} else {
notglob = ftpd_strdup(whichf);
onefile[0] = notglob;
1993-03-21 12:45:37 +03:00
dirlist = onefile;
simple = 1;
}
/* XXX: } for vi sm */
1993-03-21 12:45:37 +03:00
while ((dirname = *dirlist++) != NULL) {
int trailingslash = 0;
1993-03-21 12:45:37 +03:00
if (stat(dirname, &st) < 0) {
/*
* If user typed "ls -l", etc, and the client
* used NLST, do what the user meant.
*/
/* XXX: nuke this support? */
1993-03-21 12:45:37 +03:00
if (dirname[0] == '-' && *dirlist == NULL &&
transflag == 0) {
const char *argv[] = { INTERNAL_LS, "", NULL };
argv[1] = dirname;
retrieve(argv, dirname);
goto cleanup_send_file_list;
1993-03-21 12:45:37 +03:00
}
perror_reply(450, whichf);
goto cleanup_send_file_list;
1993-03-21 12:45:37 +03:00
}
1994-06-29 05:49:37 +04:00
if (S_ISREG(st.st_mode)) {
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
/*
* XXXRFC:
* should we follow RFC959 and not work
* for non directories?
*/
1993-03-21 12:45:37 +03:00
if (dout == NULL) {
dout = dataconn("file list", (off_t)-1, "w");
if (dout == NULL)
goto cleanup_send_file_list;
transflag = 1;
1993-03-21 12:45:37 +03:00
}
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
cprintf(dout, "%s%s\n", dirname,
type == TYPE_A ? "\r" : "");
1993-03-21 12:45:37 +03:00
continue;
1994-06-29 05:49:37 +04:00
} else if (!S_ISDIR(st.st_mode))
1993-03-21 12:45:37 +03:00
continue;
if (dirname[strlen(dirname) - 1] == '/')
trailingslash++;
1993-03-21 12:45:37 +03:00
if ((dirp = opendir(dirname)) == NULL)
continue;
while ((dir = readdir(dirp)) != NULL) {
char nbuf[MAXPATHLEN];
1993-03-21 12:45:37 +03:00
2015-08-10 10:32:49 +03:00
if (urgflag && handleoobcmd()) {
(void) closedir(dirp);
goto cleanup_send_file_list;
2015-08-10 10:32:49 +03:00
}
if (ISDOTDIR(dir->d_name) || ISDOTDOTDIR(dir->d_name))
1993-03-21 12:45:37 +03:00
continue;
(void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname,
trailingslash ? "" : "/", dir->d_name);
1993-03-21 12:45:37 +03:00
/*
* We have to do a stat to ensure it's
1993-03-21 12:45:37 +03:00
* not a directory or special file.
*/
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
/*
* XXXRFC:
* should we follow RFC959 and filter out
* non files ? lukem - NO!, or not until
* our ftp client uses MLS{T,D} for completion.
*/
1993-03-21 12:45:37 +03:00
if (simple || (stat(nbuf, &st) == 0 &&
1994-06-29 05:49:37 +04:00
S_ISREG(st.st_mode))) {
1993-03-21 12:45:37 +03:00
if (dout == NULL) {
dout = dataconn("file list", (off_t)-1,
"w");
2015-08-10 10:32:49 +03:00
if (dout == NULL) {
(void) closedir(dirp);
goto cleanup_send_file_list;
2015-08-10 10:32:49 +03:00
}
transflag = 1;
1993-03-21 12:45:37 +03:00
}
p = nbuf;
1993-03-21 12:45:37 +03:00
if (nbuf[0] == '.' && nbuf[1] == '/')
p = &nbuf[2];
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
cprintf(dout, "%s%s\n", p,
type == TYPE_A ? "\r" : "");
1993-03-21 12:45:37 +03:00
}
}
(void) closedir(dirp);
}
if (dout == NULL)
reply(450, "No files found.");
1993-03-21 12:45:37 +03:00
else if (ferror(dout) != 0)
perror_reply(451, "Data connection");
1993-03-21 12:45:37 +03:00
else
reply(226, "Transfer complete.");
cleanup_send_file_list:
closedataconn(dout);
transflag = 0;
urgflag = 0;
total_xfers++;
total_xfers_out++;
if (notglob)
free(notglob);
if (freeglob)
1994-06-29 05:49:37 +04:00
globfree(&gl);
1993-03-21 12:45:37 +03:00
}
char *
2000-05-20 06:20:18 +04:00
conffilename(const char *s)
{
static char filename[MAXPATHLEN];
if (*s == '/')
strlcpy(filename, s, sizeof(filename));
else
(void)snprintf(filename, sizeof(filename), "%s/%s", confdir ,s);
return (filename);
}
/*
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
* logxfer --
* if logging > 1, then based on the arguments, syslog a message:
* if bytes != -1 "<command> <file1> = <bytes> bytes"
* else if file2 != NULL "<command> <file1> <file2>"
* else "<command> <file1>"
* if elapsed != NULL, append "in xxx.yyy seconds"
* if error != NULL, append ": " + error
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
*
* if doxferlog != 0, bytes != -1, and command is "get", "put",
* or "append", syslog and/or write a wu-ftpd style xferlog entry
*/
void
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
logxfer(const char *command, off_t bytes, const char *file1, const char *file2,
const struct timeval *elapsed, const char *error)
{
char buf[MAXPATHLEN * 2 + 100];
char realfile1[MAXPATHLEN], realfile2[MAXPATHLEN];
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
const char *r1, *r2;
char direction;
size_t len;
time_t now;
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
if (logging <=1 && !doxferlog)
return;
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
r1 = r2 = NULL;
if ((r1 = realpath(file1, realfile1)) == NULL)
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
r1 = file1;
if (file2 != NULL)
if ((r2 = realpath(file2, realfile2)) == NULL)
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
r2 = file2;
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
/*
* syslog command
*/
if (logging > 1) {
len = snprintf(buf, sizeof(buf), "%s %s", command, r1);
if (bytes != (off_t)-1)
len += snprintf(buf + len, sizeof(buf) - len,
" = " LLF " byte%s", (LLT) bytes, PLURAL(bytes));
else if (r2 != NULL)
len += snprintf(buf + len, sizeof(buf) - len,
" %s", r2);
if (elapsed != NULL)
len += snprintf(buf + len, sizeof(buf) - len,
" in " LLF ".%.03ld seconds",
(LLT)elapsed->tv_sec,
2008-12-29 03:33:34 +03:00
(long)(elapsed->tv_usec / 1000));
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
if (error != NULL)
len += snprintf(buf + len, sizeof(buf) - len,
": %s", error);
syslog(LOG_INFO, "%s", buf);
}
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
/*
* syslog wu-ftpd style log entry, prefixed with "xferlog: "
*/
if (!doxferlog || bytes == -1)
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
return;
if (strcmp(command, "get") == 0)
direction = 'o';
else if (strcmp(command, "put") == 0 || strcmp(command, "append") == 0)
direction = 'i';
else
return;
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
time(&now);
len = snprintf(buf, sizeof(buf),
"%.24s " LLF " %s " LLF " %s %c %s %c %c %s FTP 0 * %c\n",
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
/*
* XXX: wu-ftpd puts ' (send)' or ' (recv)' in the syslog message, and removes
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
* the full date. This may be problematic for accurate log parsing,
* given that syslog messages don't contain the full date.
*/
ctime(&now),
(LLT)
2008-12-29 03:33:34 +03:00
(elapsed == NULL ? 0 : elapsed->tv_sec + (elapsed->tv_usec > 0)),
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
remotehost,
(LLT) bytes,
Features: * Add ftpd.conf(5) directive `advertise'; change the address that is advertised to the client for PASV transfers. this may be useful in certain firewall/NAT environments. Feature requested in [bin/9606] by Scott Presnell. * Add -X option; syslog wu-ftpd style xferlog messages, prefixed with `xferlog: '. An example line from syslog (wrapped): Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000 2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c These messages can be converted to a wu-ftpd style xferlog file suitable for parsing with third-party tools with something like: grep 'xferlog: ' /var/log/xferlog | \ sed -e 's/^.*xferlog: //' >wuxferlog The format is the same as the wu-ftpd xferlog entries (with the leading syslog stuff), but different from the wu-ftpd syslogged xferlog entries because the latter is not as easy to convert into the standard xferlog file format. The choice to only syslog the xferlog messages rather than append to a /var/log/xferlog file was made because the latter doesn't work to well in the situation where the logfile is rotated and compressed and a long-running ftpd still has a file-descriptor to the now nonexistant xferlog file, and the log message will then get lost. Feature requested in [bin/11651] by Hubert Feyrer. Fixes: * In ftpd(8), clarify the -a and -c options. * More clarifications in ftpd.conf(5). * Ensure that all ftpd.conf commands set a parameter back to sane defaults if an argument of `none' or bad settings are given. * Support the `chroot' directive for `REAL' users too (for consistency). * For `GUEST' users, store the supplied password in pw->pw_passwd for use later in the xferlog. * If show_chdir_messages() is given a code of -1, flush the cache of visited directories. Invoke show_chdir_messages(-1) in end_login(). * Only syslog session stats if logging is requested. * Rename logcmd() -> logxfer(), and dolog() -> logremotehost(). * Use cprintf() instead of fprintf() where appropriate. * Minor KNF, and make a couple of functions static that were declared static.
2000-12-18 05:32:50 +03:00
r1,
type == TYPE_A ? 'a' : 'b',
"_", /* XXX: take conversions into account? */
direction,
curclass.type == CLASS_GUEST ? 'a' :
curclass.type == CLASS_CHROOT ? 'g' :
curclass.type == CLASS_REAL ? 'r' : '?',
curclass.type == CLASS_GUEST ? pw->pw_passwd : pw->pw_name,
error != NULL ? 'i' : 'c'
);
if ((doxferlog & 2) && xferlogfd != -1)
write(xferlogfd, buf, len);
if ((doxferlog & 1)) {
buf[len-1] = '\n'; /* strip \n from syslog message */
syslog(LOG_INFO, "xferlog: %s", buf);
}
}
/*
* Log the resource usage.
*
* XXX: more resource usage to logging?
*/
void
logrusage(const struct rusage *rusage_before,
const struct rusage *rusage_after)
{
struct timeval usrtime, systime;
if (logging <= 1)
return;
timersub(&rusage_after->ru_utime, &rusage_before->ru_utime, &usrtime);
timersub(&rusage_after->ru_stime, &rusage_before->ru_stime, &systime);
syslog(LOG_INFO, LLF ".%.03ldu " LLF ".%.03lds %ld+%ldio %ldpf+%ldw",
(LLT)usrtime.tv_sec, (long)(usrtime.tv_usec / 1000),
(LLT)systime.tv_sec, (long)(systime.tv_usec / 1000),
rusage_after->ru_inblock - rusage_before->ru_inblock,
rusage_after->ru_oublock - rusage_before->ru_oublock,
rusage_after->ru_majflt - rusage_before->ru_majflt,
rusage_after->ru_nswap - rusage_before->ru_nswap);
}
/*
* Determine if `password' is valid for user given in `pw'.
* Returns 2 if password expired, 1 if otherwise failed, 0 if ok
*/
int
checkpassword(const struct passwd *pwent, const char *password)
{
const char *orig;
char *new;
time_t change, expire, now;
change = expire = 0;
if (pwent == NULL)
return 1;
time(&now);
orig = pwent->pw_passwd; /* save existing password */
expire = pwent->pw_expire;
change = pwent->pw_change;
if (change == _PASSWORD_CHGNOW)
change = now;
if (orig[0] == '\0') /* don't allow empty passwords */
return 1;
new = crypt(password, orig); /* encrypt given password */
if (strcmp(new, orig) != 0) /* compare */
return 1;
if ((expire && now >= expire) || (change && now >= change))
return 2; /* check if expired */
return 0; /* OK! */
}
char *
ftpd_strdup(const char *s)
{
char *new = strdup(s);
if (new == NULL)
fatal("Local resource failure: malloc");
/* NOTREACHED */
return (new);
}
/*
* As per fprintf(), but increment total_bytes and total_bytes_out,
* by the appropriate amount.
*/
void
cprintf(FILE *fd, const char *fmt, ...)
{
off_t b;
va_list ap;
va_start(ap, fmt);
b = vfprintf(fd, fmt, ap);
va_end(ap);
total_bytes += b;
total_bytes_out += b;
}
#ifdef USE_PAM
/*
* the following code is stolen from imap-uw PAM authentication module and
* login.c
*/
typedef struct {
const char *uname; /* user name */
int triedonce; /* if non-zero, tried before */
} ftpd_cred_t;
static int
auth_conv(int num_msg, const struct pam_message **msg,
struct pam_response **resp, void *appdata)
{
int i, ret;
size_t n;
ftpd_cred_t *cred = (ftpd_cred_t *) appdata;
struct pam_response *myreply;
char pbuf[FTP_BUFLEN];
if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG)
return (PAM_CONV_ERR);
myreply = calloc(num_msg, sizeof *myreply);
if (myreply == NULL)
return PAM_BUF_ERR;
for (i = 0; i < num_msg; i++) {
myreply[i].resp_retcode = 0;
myreply[i].resp = NULL;
switch (msg[i]->msg_style) {
case PAM_PROMPT_ECHO_ON: /* user */
myreply[i].resp = ftpd_strdup(cred->uname);
/* PAM frees resp. */
break;
case PAM_PROMPT_ECHO_OFF: /* authtok (password) */
/*
* Only send a single 331 reply and
* then expect a PASS.
*/
if (cred->triedonce) {
syslog(LOG_ERR,
"auth_conv: already performed PAM_PROMPT_ECHO_OFF");
goto fail;
}
cred->triedonce++;
if (msg[i]->msg[0] == '\0') {
(void)strlcpy(pbuf, "password", sizeof(pbuf));
} else {
/* Uncapitalize msg */
(void)strlcpy(pbuf, msg[i]->msg, sizeof(pbuf));
if (isupper((unsigned char)pbuf[0]))
pbuf[0] = tolower(
(unsigned char)pbuf[0]);
/* Remove trailing ':' and whitespace */
n = strlen(pbuf);
while (n-- > 0) {
if (isspace((unsigned char)pbuf[n]) ||
pbuf[n] == ':')
pbuf[n] = '\0';
else
break;
}
}
/* Send reply, wait for a response. */
reply(331, "User %s accepted, provide %s.",
cred->uname, pbuf);
(void) alarm(curclass.timeout);
ret = get_line(pbuf, sizeof(pbuf)-1, stdin);
(void) alarm(0);
if (ret == -1) {
reply(221, "You could at least say goodbye.");
dologout(0);
} else if (ret == -2) {
/* XXX: should we do this reply(-530, ..) ? */
reply(-530, "Command too long.");
goto fail;
}
/* Ensure it is PASS */
if (strncasecmp(pbuf, "PASS ", 5) != 0) {
syslog(LOG_ERR,
"auth_conv: unexpected reply '%.4s'", pbuf);
/* XXX: should we do this reply(-530, ..) ? */
reply(-530, "Unexpected reply '%.4s'.", pbuf);
goto fail;
}
/* Strip CRLF from "PASS" reply */
n = strlen(pbuf);
while (--n >= 5 &&
(pbuf[n] == '\r' || pbuf[n] == '\n'))
pbuf[n] = '\0';
/* Copy password into reply */
myreply[i].resp = ftpd_strdup(pbuf+5);
/* PAM frees resp. */
break;
case PAM_TEXT_INFO:
case PAM_ERROR_MSG:
break;
default: /* unknown message style */
goto fail;
}
}
*resp = myreply;
return PAM_SUCCESS;
fail:
free(myreply);
*resp = NULL;
return PAM_CONV_ERR;
}
/*
* Attempt to authenticate the user using PAM. Returns 0 if the user is
* authenticated, or 1 if not authenticated. If some sort of PAM system
* error occurs (e.g., the "/etc/pam.conf" file is missing) then this
* function returns -1. This can be used as an indication that we should
* fall back to a different authentication mechanism.
* pw maybe be updated to a new user if PAM_USER changes from curname.
*/
static int
auth_pam(void)
{
const char *tmpl_user;
const void *item;
int rval;
int e;
ftpd_cred_t auth_cred = { curname, 0 };
struct pam_conv conv = { &auth_conv, &auth_cred };
e = pam_start("ftpd", curname, &conv, &pamh);
if (e != PAM_SUCCESS) {
/*
* In OpenPAM, it's OK to pass NULL to pam_strerror()
* if context creation has failed in the first place.
*/
syslog(LOG_ERR, "pam_start: %s", pam_strerror(NULL, e));
return -1;
}
e = pam_set_item(pamh, PAM_RHOST, remotehost);
if (e != PAM_SUCCESS) {
syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
pam_strerror(pamh, e));
if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
}
pamh = NULL;
return -1;
}
e = pam_set_item(pamh, PAM_SOCKADDR, &his_addr);
if (e != PAM_SUCCESS) {
syslog(LOG_ERR, "pam_set_item(PAM_SOCKADDR): %s",
pam_strerror(pamh, e));
if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
}
pamh = NULL;
return -1;
}
e = pam_authenticate(pamh, 0);
if (ftpd_debug)
syslog(LOG_DEBUG, "pam_authenticate: user '%s' returned %d",
curname, e);
switch (e) {
case PAM_SUCCESS:
/*
* With PAM we support the concept of a "template"
* user. The user enters a login name which is
* authenticated by PAM, usually via a remote service
* such as RADIUS or TACACS+. If authentication
* succeeds, a different but related "template" name
* is used for setting the credentials, shell, and
* home directory. The name the user enters need only
* exist on the remote authentication server, but the
* template name must be present in the local password
* database.
*
* This is supported by two various mechanisms in the
* individual modules. However, from the application's
* point of view, the template user is always passed
* back as a changed value of the PAM_USER item.
*/
if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
PAM_SUCCESS) {
tmpl_user = (const char *) item;
if (pw == NULL
|| strcmp(pw->pw_name, tmpl_user) != 0) {
pw = sgetpwnam(tmpl_user);
if (ftpd_debug)
syslog(LOG_DEBUG,
"auth_pam: PAM changed "
"user from '%s' to '%s'",
curname, pw->pw_name);
(void)strlcpy(curname, pw->pw_name,
curname_len);
}
} else
syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
pam_strerror(pamh, e));
rval = 0;
break;
case PAM_AUTH_ERR:
case PAM_USER_UNKNOWN:
case PAM_MAXTRIES:
rval = 1;
break;
default:
syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e));
rval = -1;
break;
}
if (rval == 0) {
e = pam_acct_mgmt(pamh, 0);
if (e != PAM_SUCCESS) {
syslog(LOG_ERR, "pam_acct_mgmt: %s",
pam_strerror(pamh, e));
rval = 1;
}
}
if (rval != 0) {
if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
}
pamh = NULL;
}
return rval;
}
#endif /* USE_PAM */