NetBSD/libexec/ftpd/ftpd.c

3263 lines
78 KiB
C
Raw Normal View History

/* $NetBSD: ftpd.c,v 1.156 2003/08/07 09:46:39 agc Exp $ */
/*
* Copyright (c) 1997-2003 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 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(
1994-06-29 05:49:37 +04:00
"@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n");
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.156 2003/08/07 09:46:39 agc 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 <setjmp.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
#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
1993-03-21 12:45:37 +03:00
int data;
jmp_buf urgcatch;
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 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 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;
#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_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 *);
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 *);
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 *);
2000-05-20 06:20:18 +04:00
static void lostconn(int);
static void myoob(int);
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 addrlen, ch, on = 1, tos, keepalive;
#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;
1993-03-21 12:45:37 +03:00
connections = 1;
1993-03-21 12:45:37 +03:00
debug = 0;
logging = 0;
pdata = -1;
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 */
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, "a:c:C:de:h:HlL:P:qQrst:T:uUvV:wWX"))
- 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
!= -1) {
1994-06-29 05:49:37 +04:00
switch (ch) {
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':
pw = sgetpwnam(optarg);
exit(checkaccess(optarg) ? 0 : 1);
/* NOTREACHED */
1993-03-21 12:45:37 +03:00
case 'd':
case 'v': /* deprecated */
1993-03-21 12:45:37 +03:00
debug = 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 '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;
- 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 = xstrdup(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;
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(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, 0)
!= 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);
(void) signal(SIGPIPE, lostconn);
(void) signal(SIGCHLD, SIG_IGN);
if (signal(SIGURG, myoob) == SIG_ERR)
2001-01-10 03:20:49 +03:00
syslog(LOG_WARNING, "signal: %m");
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(_PATH_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;
}
(void) setjmp(errcatch);
ftp_loop();
1993-03-21 12:45:37 +03:00
/* NOTREACHED */
}
1994-06-29 05:49:37 +04:00
static void
2000-05-20 06:20:18 +04:00
lostconn(int signo)
1993-03-21 12:45:37 +03:00
{
1994-06-29 05:49:37 +04:00
1993-03-21 12:45:37 +03:00
if (debug)
syslog(LOG_DEBUG, "lost connection");
dologout(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 = xstrdup(p->pw_name);
save.pw_passwd = xstrdup(p->pw_passwd);
save.pw_gecos = xstrdup(p->pw_gecos);
save.pw_dir = xstrdup(p->pw_dir);
save.pw_shell = xstrdup(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 */
static char curname[LOGIN_NAME_MAX]; /* current USER name */
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
* _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
* If account doesn't exist, ask for passwd anyway. Otherwise, check user
* requesting login privileges. Disallow anyone who does not have a standard
* shell as returned by getusershell(). Disallow anyone mentioned in the file
* _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
*/
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;
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",
remotehost);
end_login();
goto cleanup_user;
}
name = "ftp";
} else
pw = sgetpwnam(name);
strlcpy(curname, name, sizeof(curname));
/* check user in /etc/ftpusers, and setup class */
permitted = checkuser(_PATH_FTPUSERS, curname, 1, 0, &class);
1994-05-24 10:52:17 +04:00
/* check user in /etc/ftpchroot */
if (checkuser(_PATH_FTPCHROOT, curname, 0, 0, NULL)) {
if (curclass.type == CLASS_GUEST) {
syslog(LOG_NOTICE,
"Can't change guest user to chroot class; remove entry in %s",
_PATH_FTPCHROOT);
exit(1);
}
curclass.type = CLASS_CHROOT;
}
/* determine default class */
if (class == NULL) {
switch (curclass.type) {
case CLASS_GUEST:
class = xstrdup("guest");
break;
case CLASS_CHROOT:
class = xstrdup("chroot");
break;
case CLASS_REAL:
class = xstrdup("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",
remotehost, curname);
end_login();
goto cleanup_user;
}
/* if haven't asked yet (i.e, not anon), ask now */
if (!askpasswd) {
askpasswd = 1;
#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);
}
1994-05-24 10:52:17 +04:00
cleanup_user:
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 long net, mask, addr;
int bits;
*p++ = '\0';
/* check against network or CIDR */
if (isdigit(*p) &&
(bits = inet_net_pton(AF_INET, p,
&net, sizeof(net))) != -1) {
net = ntohl(net);
mask = 0xffffffffU << (32 - bits);
addr = ntohl(his_addr.su_addr.s_addr);
if ((addr & mask) != net)
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 = xstrdup(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(_PATH_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)
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));
ftpd_loginx(&utmpx);
2002-08-20 17:51:09 +04:00
}
if (dowtmp)
ftpd_logwtmpx(line, name, host, 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)
{
int okwtmp = dowtmp;
if (logged_in) {
if (doutmp) {
#ifdef SUPPORT_UTMPX
okwtmp = logoutx(ttyline, 0, DEAD_PROCESS) & dowtmp;
#endif
#ifdef SUPPORT_UTMP
okwtmp = ftpd_logout(ttyline) & dowtmp;
2002-08-20 17:51:09 +04:00
#endif
}
if (okwtmp) {
#ifdef SUPPORT_UTMPX
ftpd_logwtmpx(ttyline, "", "", 0, DEAD_PROCESS);
2002-08-20 17:51:09 +04:00
#endif
#ifdef SUPPORT_UTMP
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
{
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);
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)
1993-03-21 12:45:37 +03:00
{
int rval;
char root[MAXPATHLEN];
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 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 = xstrdup(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.");
if (logging) {
1994-06-29 05:49:37 +04:00
syslog(LOG_NOTICE,
"FTP LOGIN FAILED FROM %s", remotehost);
syslog(LOG_AUTHPRIV | LOG_NOTICE,
1994-06-29 05:49:37 +04:00
"FTP LOGIN FAILED FROM %s, %s",
remotehost, curname);
}
1993-03-21 12:45:37 +03:00
pw = NULL;
if (login_attempts++ >= 5) {
syslog(LOG_NOTICE,
"repeated login failures from %s",
remotehost);
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",
remotehost, 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
}
1993-03-21 12:45:37 +03:00
(void) initgroups(pw->pw_name, pw->pw_gid);
/* cache groups for cmds.c::matchgroup() */
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);
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:
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
/* only chroot REAL if explictly requested */
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;
}
setsid();
setlogin(pw->pw_name);
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 HAVE_SETPROCTITLE
1994-06-29 05:49:37 +04:00
snprintf(proctitle, sizeof(proctitle),
"%s: anonymous/%s", remotehost, passwd);
setproctitle("%s", proctitle);
#endif /* 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)",
remotehost, 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, xstrdup(passwd));
for (p = pw->pw_passwd; *p; p++)
if (!isgraph(*p))
*p = '_';
1993-03-21 12:45:37 +03:00
} else {
reply(230, "User %s logged in.", pw->pw_name);
#if HAVE_SETPROCTITLE
1994-06-29 05:49:37 +04:00
snprintf(proctitle, sizeof(proctitle),
"%s: %s", remotehost, pw->pw_name);
setproctitle("%s", proctitle);
#endif /* 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)",
remotehost, pw->pw_name,
curclass.classname, CURCLASSTYPE);
1993-03-21 12:45:37 +03:00
}
(void) umask(curclass.umask);
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:
/* Forget all about it... */
1993-03-21 12:45:37 +03:00
end_login();
}
1994-06-29 05:49:37 +04:00
void
2000-05-20 06:20:18 +04:00
retrieve(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;
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;
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);
1993-03-21 12:45:37 +03:00
(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, 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);
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;
size_t readsize;
char *buf;
int c, error;
if (curclass.readsize)
readsize = curclass.readsize;
else
readsize = (size_t)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);
}
while (1) {
(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
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;
size_t mapsize, winsize;
int error, sendbufsize, sendlowat;
void *win;
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 (debug)
syslog(LOG_INFO, "mmapsize = %ld, writesize = %ld",
(long)winsize, (long)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);
}
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 (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
/*
1994-06-29 05:49:37 +04:00
* Tranfer 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
transflag = 1;
rval = -1;
if (setjmp(urgcatch))
goto cleanup_send_data;
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) {
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_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");
/* FALLTHROUGH */
cleanup_send_data:
(void) alarm(0);
transflag = 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, bare_lfs, netfd, filefd, rval;
- 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[BUFSIZ];
#ifdef __GNUC__
(void) &bare_lfs;
#endif
1993-03-21 12:45:37 +03:00
bare_lfs = 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;
if (setjmp(urgcatch))
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
#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.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(sizeof(buf), bufrem))) <= 0)
goto recvdone;
- 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, sizeof(buf))) > 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
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) {
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);
transflag = 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];
u_char *a, *p;
int ispassive, af;
off_t otbi, otbo, otb;
1993-03-21 12:45:37 +03:00
a = p = (u_char *)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) {
if (epsvall) {
reply(0, "EPSV only mode (EPSV ALL)");
goto epsvonly;
}
su = (struct sockinet *)&data_dest;
printaddr:
/* PASV/PORT */
if (su->su_family == AF_INET) {
a = (u_char *) &su->su_addr;
p = (u_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 = (u_char *) &su->su_addr;
p = (u_char *) &su->su_port;
alen = sizeof(su->su_addr);
af = 4;
break;
#ifdef INET6
case AF_INET6:
a = (u_char *) &su->su_6addr;
p = (u_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.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
{
off_t b;
1994-06-29 05:49:37 +04:00
va_list ap;
2000-05-20 06:20:18 +04:00
1994-06-29 05:49:37 +04:00
va_start(ap, fmt);
b = 0;
if (n == 0)
cprintf(stdout, " ");
else if (n < 0)
cprintf(stdout, "%d-", -n);
else
cprintf(stdout, "%d ", n);
b = vprintf(fmt, ap);
va_end(ap);
total_bytes += b;
total_bytes_out += b;
cprintf(stdout, "\r\n");
1993-03-21 12:45:37 +03:00
(void)fflush(stdout);
if (debug) {
syslog(LOG_DEBUG, "<--- %d%c", abs(n), (n < 0) ? '-' : ' ');
va_start(ap, fmt);
1994-06-29 05:49:37 +04:00
vsyslog(LOG_DEBUG, fmt, ap);
va_end(ap);
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 (getnameinfo((struct sockaddr *)&who->si_su,
who->su_len, remotehost, sizeof(remotehost), NULL, 0, 0))
strlcpy(remotehost, "?", sizeof(remotehost));
#if HAVE_SETPROCTITLE
1994-06-29 05:49:37 +04:00
snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
setproctitle("%s", proctitle);
#endif /* HAVE_SETPROCTITLE */
1994-06-29 05:49:37 +04:00
if (logging)
syslog(LOG_INFO, "connection from %s to %s",
remotehost, 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.
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
tmpline[0] = '\0';
is_oob = 0;
reply(426, "Transfer aborted. Data connection closed.");
reply(226, "Abort successful");
longjmp(urgcatch, 1);
}
2001-04-12 06:28:59 +04:00
void
statxfer(void)
{
2001-04-12 06:28:59 +04:00
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));
}
1994-06-29 05:49:37 +04:00
static void
2000-05-20 06:20:18 +04:00
myoob(int signo)
1993-03-21 12:45:37 +03:00
{
char *cp;
/* only process if transfer occurring */
if (!transflag)
return;
cp = tmpline;
if (getline(cp, sizeof(tmpline), stdin) == NULL) {
1993-03-21 12:45:37 +03:00
reply(221, "You could at least say goodbye.");
dologout(0);
}
is_oob = 1;
ftp_handle_line(cp);
is_oob = 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
{
int len;
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;
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(char *cmd, int pf)
{
int 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 = xstrdup(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);
if (res)
freeaddrinfo(res);
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[] = {
"",
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 = NULL;
struct dirent *dir;
FILE *dout = NULL;
char **dirlist, *dirname, *p;
char *notglob = NULL;
1993-03-21 12:45:37 +03:00
int simple = 0;
1994-06-29 05:49:37 +04:00
int freeglob = 0;
glob_t gl;
#ifdef __GNUC__
(void) &dout;
(void) &dirlist;
(void) &simple;
(void) &freeglob;
#endif
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(550, "not found");
goto out;
} else if (gl.gl_pathc == 0) {
1993-03-21 12:45:37 +03:00
errno = ENOENT;
1994-06-29 05:49:37 +04:00
perror_reply(550, whichf);
goto out;
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 = xstrdup(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
if (setjmp(urgcatch)) {
transflag = 0;
1994-06-29 05:49:37 +04:00
goto out;
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) {
char *argv[] = { INTERNAL_LS, "", NULL };
argv[1] = dirname;
retrieve(argv, dirname);
1994-06-29 05:49:37 +04:00
goto out;
1993-03-21 12:45:37 +03:00
}
1994-06-29 05:49:37 +04:00
perror_reply(550, 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)
1994-06-29 05:49:37 +04:00
goto out;
1993-03-21 12:45:37 +03:00
transflag++;
}
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
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");
if (dout == NULL)
1994-06-29 05:49:37 +04:00
goto out;
1993-03-21 12:45:37 +03:00
transflag++;
}
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(550, "No files found.");
else if (ferror(dout) != 0)
perror_reply(550, "Data connection");
else
reply(226, "Transfer complete.");
cleanup_send_file_list:
1993-03-21 12:45:37 +03:00
transflag = 0;
closedataconn(dout);
out:
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)
{
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 buf[MAXPATHLEN * 2 + 100], realfile[MAXPATHLEN];
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, realfile)) == NULL)
r1 = file1;
if (file2 != NULL)
if ((r2 = realpath(file2, realfile)) == NULL)
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 %ld.%.03d seconds", elapsed->tv_sec,
(int)(elapsed->tv_usec / 1000));
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 %ld %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),
elapsed == NULL ? 0 : elapsed->tv_sec + (elapsed->tv_usec > 0),
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, "%ld.%.03du %ld.%.03ds %ld+%ldio %ldpf+%ldw",
usrtime.tv_sec, (int)(usrtime.tv_usec / 1000),
systime.tv_sec, (int)(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)
{
char *orig, *new;
time_t expire;
expire = 0;
if (pwent == NULL)
return 1;
orig = pwent->pw_passwd; /* save existing password */
expire = pwent->pw_expire;
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 && time(NULL) >= expire)
return 2; /* check if expired */
return 0; /* OK! */
}
char *
2000-05-20 06:20:18 +04:00
xstrdup(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;
}