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.
This commit is contained in:
parent
c25ab2f1ec
commit
5015048190
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: cmds.c,v 1.9 2000/12/04 10:50:39 itojun Exp $ */
|
||||
/* $NetBSD: cmds.c,v 1.10 2000/12/18 02:32:50 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999-2000 The NetBSD Foundation, Inc.
|
||||
|
@ -101,7 +101,7 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: cmds.c,v 1.9 2000/12/04 10:50:39 itojun Exp $");
|
||||
__RCSID("$NetBSD: cmds.c,v 1.10 2000/12/18 02:32:50 lukem Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
|
@ -188,7 +188,7 @@ delete(const char *name)
|
|||
perror_reply(550, name);
|
||||
} else
|
||||
ack("DELE");
|
||||
logcmd("delete", -1, name, NULL, NULL, p);
|
||||
logxfer("delete", -1, name, NULL, NULL, p);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -219,7 +219,7 @@ makedir(const char *name)
|
|||
perror_reply(550, name);
|
||||
} else
|
||||
replydirname(name, "directory created.");
|
||||
logcmd("mkdir", -1, name, NULL, NULL, p);
|
||||
logxfer("mkdir", -1, name, NULL, NULL, p);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -412,7 +412,7 @@ removedir(const char *name)
|
|||
perror_reply(550, name);
|
||||
} else
|
||||
ack("RMD");
|
||||
logcmd("rmdir", -1, name, NULL, NULL, p);
|
||||
logxfer("rmdir", -1, name, NULL, NULL, p);
|
||||
}
|
||||
|
||||
char *
|
||||
|
@ -438,7 +438,7 @@ renamecmd(const char *from, const char *to)
|
|||
perror_reply(550, "rename");
|
||||
} else
|
||||
ack("RNTO");
|
||||
logcmd("rename", -1, from, to, NULL, p);
|
||||
logxfer("rename", -1, from, to, NULL, p);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -446,14 +446,17 @@ sizecmd(const char *filename)
|
|||
{
|
||||
switch (type) {
|
||||
case TYPE_L:
|
||||
case TYPE_I: {
|
||||
case TYPE_I:
|
||||
{
|
||||
struct stat stbuf;
|
||||
if (stat(filename, &stbuf) < 0 || !S_ISREG(stbuf.st_mode))
|
||||
reply(550, "%s: not a plain file.", filename);
|
||||
else
|
||||
reply(213, ULLF, (ULLT)stbuf.st_size);
|
||||
break; }
|
||||
case TYPE_A: {
|
||||
break;
|
||||
}
|
||||
case TYPE_A:
|
||||
{
|
||||
FILE *fin;
|
||||
int c;
|
||||
off_t count;
|
||||
|
@ -478,7 +481,8 @@ sizecmd(const char *filename)
|
|||
(void) fclose(fin);
|
||||
|
||||
reply(213, LLF, (LLT)count);
|
||||
break; }
|
||||
break;
|
||||
}
|
||||
default:
|
||||
reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: conf.c,v 1.36 2000/11/16 13:15:13 lukem Exp $ */
|
||||
/* $NetBSD: conf.c,v 1.37 2000/12/18 02:32:50 lukem Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
|
||||
|
@ -38,17 +38,19 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: conf.c,v 1.36 2000/11/16 13:15:13 lukem Exp $");
|
||||
__RCSID("$NetBSD: conf.c,v 1.37 2000/12/18 02:32:50 lukem Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <glob.h>
|
||||
#include <netdb.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
@ -71,6 +73,13 @@ static char *strend(const char *, char *);
|
|||
static int filetypematch(char *, int);
|
||||
|
||||
|
||||
/* class defaults */
|
||||
#define DEFAULT_LIMIT -1 /* unlimited connections */
|
||||
#define DEFAULT_MAXFILESIZE -1 /* unlimited file size */
|
||||
#define DEFAULT_MAXTIMEOUT 7200 /* 2 hours */
|
||||
#define DEFAULT_TIMEOUT 900 /* 15 minutes */
|
||||
#define DEFAULT_UMASK 027 /* 15 minutes */
|
||||
|
||||
/*
|
||||
* Initialise curclass to an `empty' state
|
||||
*/
|
||||
|
@ -88,26 +97,28 @@ init_curclass(void)
|
|||
free(conv);
|
||||
}
|
||||
|
||||
memset((char *)&curclass.advertise, 0, sizeof(curclass.advertise));
|
||||
curclass.advertise.su_len = 0; /* `not used' */
|
||||
REASSIGN(curclass.chroot, NULL);
|
||||
REASSIGN(curclass.classname, NULL);
|
||||
curclass.conversions = NULL;
|
||||
REASSIGN(curclass.display, NULL);
|
||||
REASSIGN(curclass.homedir, NULL);
|
||||
curclass.limit = -1; /* unlimited connections */
|
||||
curclass.limit = DEFAULT_LIMIT;
|
||||
REASSIGN(curclass.limitfile, NULL);
|
||||
curclass.maxfilesize = -1; /* unlimited file size */
|
||||
curclass.maxfilesize = DEFAULT_MAXFILESIZE;
|
||||
curclass.maxrateget = 0;
|
||||
curclass.maxrateput = 0;
|
||||
curclass.maxtimeout = 7200; /* 2 hours */
|
||||
curclass.maxtimeout = DEFAULT_MAXTIMEOUT;
|
||||
REASSIGN(curclass.motd, xstrdup(_PATH_FTPLOGINMESG));
|
||||
REASSIGN(curclass.notify, NULL);
|
||||
curclass.portmin = 0;
|
||||
curclass.portmax = 0;
|
||||
curclass.rateget = 0;
|
||||
curclass.rateput = 0;
|
||||
curclass.timeout = 900; /* 15 minutes */
|
||||
curclass.timeout = DEFAULT_TIMEOUT;
|
||||
/* curclass.type is set elsewhere */
|
||||
curclass.umask = 027;
|
||||
curclass.umask = DEFAULT_UMASK;
|
||||
|
||||
CURCLASS_FLAGS_SET(checkportcmd);
|
||||
CURCLASS_FLAGS_SET(modify);
|
||||
|
@ -137,6 +148,7 @@ parse_conf(const char *findclass)
|
|||
|
||||
init_curclass();
|
||||
REASSIGN(curclass.classname, xstrdup(findclass));
|
||||
/* set more guest defaults */
|
||||
if (strcasecmp(findclass, "guest") == 0) {
|
||||
CURCLASS_FLAGS_CLR(modify);
|
||||
curclass.umask = 0707;
|
||||
|
@ -192,7 +204,58 @@ parse_conf(const char *findclass)
|
|||
REASSIGN(curclass.x, arg); \
|
||||
} while (0)
|
||||
|
||||
if (strcasecmp(word, "checkportcmd") == 0) {
|
||||
|
||||
if (0) {
|
||||
/* no-op */
|
||||
|
||||
} else if (strcasecmp(word, "advertise") == 0) {
|
||||
struct addrinfo hints, *res;
|
||||
int error;
|
||||
|
||||
memset((char *)&curclass.advertise, 0,
|
||||
sizeof(curclass.advertise));
|
||||
curclass.advertise.su_len = 0;
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
res = NULL;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
/*
|
||||
* only get addresses of the family
|
||||
* that we're listening on
|
||||
*/
|
||||
hints.ai_family = ctrl_addr.su_family;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
error = getaddrinfo(arg, "0", &hints, &res);
|
||||
if (error) {
|
||||
syslog(LOG_WARNING, "%s line %d: %s",
|
||||
infile, (int)line, gai_strerror(error));
|
||||
advertiseparsefail:
|
||||
if (res)
|
||||
freeaddrinfo(res);
|
||||
continue;
|
||||
}
|
||||
if (res->ai_next) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: multiple addresses returned for `%s'; please be more specific",
|
||||
infile, (int)line, arg);
|
||||
goto advertiseparsefail;
|
||||
}
|
||||
if (sizeof(curclass.advertise) < res->ai_addrlen || (
|
||||
#ifdef INET6
|
||||
res->ai_family != AF_INET6 &&
|
||||
#endif
|
||||
res->ai_family != AF_INET)) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: unsupported protocol %d for `%s'",
|
||||
infile, (int)line, res->ai_family, arg);
|
||||
goto advertiseparsefail;
|
||||
}
|
||||
memcpy(&curclass.advertise, res->ai_addr,
|
||||
res->ai_addrlen);
|
||||
curclass.advertise.su_len = res->ai_addrlen;
|
||||
freeaddrinfo(res);
|
||||
|
||||
} else if (strcasecmp(word, "checkportcmd") == 0) {
|
||||
CONF_FLAG(checkportcmd);
|
||||
|
||||
} else if (strcasecmp(word, "chroot") == 0) {
|
||||
|
@ -272,21 +335,11 @@ parse_conf(const char *findclass)
|
|||
} else if (strcasecmp(word, "homedir") == 0) {
|
||||
CONF_STRING(homedir);
|
||||
|
||||
} else if (strcasecmp(word, "maxfilesize") == 0) {
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
llval = strsuftoll(arg);
|
||||
if (llval == -1) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: invalid maxfilesize %s",
|
||||
infile, (int)line, arg);
|
||||
continue;
|
||||
}
|
||||
curclass.maxfilesize = llval;
|
||||
|
||||
} else if (strcasecmp(word, "limit") == 0) {
|
||||
int limit;
|
||||
|
||||
curclass.limit = DEFAULT_LIMIT;
|
||||
REASSIGN(curclass.limitfile, NULL);
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
limit = (int)strtol(arg, &endp, 10);
|
||||
|
@ -300,7 +353,21 @@ parse_conf(const char *findclass)
|
|||
REASSIGN(curclass.limitfile,
|
||||
EMPTYSTR(p) ? NULL : xstrdup(p));
|
||||
|
||||
} else if (strcasecmp(word, "maxfilesize") == 0) {
|
||||
curclass.maxfilesize = DEFAULT_MAXFILESIZE;
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
llval = strsuftoll(arg);
|
||||
if (llval == -1) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: invalid maxfilesize %s",
|
||||
infile, (int)line, arg);
|
||||
continue;
|
||||
}
|
||||
curclass.maxfilesize = llval;
|
||||
|
||||
} else if (strcasecmp(word, "maxtimeout") == 0) {
|
||||
curclass.maxtimeout = DEFAULT_MAXTIMEOUT;
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
timeout = (unsigned int)strtoul(arg, &endp, 10);
|
||||
|
@ -341,12 +408,9 @@ parse_conf(const char *findclass)
|
|||
int minport, maxport;
|
||||
char *min, *max;
|
||||
|
||||
if (none) {
|
||||
curclass.portmin = 0;
|
||||
curclass.portmax = 0;
|
||||
continue;
|
||||
}
|
||||
if (EMPTYSTR(arg))
|
||||
curclass.portmin = 0;
|
||||
curclass.portmax = 0;
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
min = arg;
|
||||
NEXTWORD(p, max);
|
||||
|
@ -382,6 +446,8 @@ parse_conf(const char *findclass)
|
|||
curclass.portmax = maxport;
|
||||
|
||||
} else if (strcasecmp(word, "rateget") == 0) {
|
||||
curclass.maxrateget = 0;
|
||||
curclass.rateget = 0;
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
llval = strsuftoll(arg);
|
||||
|
@ -395,6 +461,8 @@ parse_conf(const char *findclass)
|
|||
curclass.rateget = llval;
|
||||
|
||||
} else if (strcasecmp(word, "rateput") == 0) {
|
||||
curclass.maxrateput = 0;
|
||||
curclass.rateput = 0;
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
llval = strsuftoll(arg);
|
||||
|
@ -411,6 +479,7 @@ parse_conf(const char *findclass)
|
|||
CONF_FLAG(sanenames);
|
||||
|
||||
} else if (strcasecmp(word, "timeout") == 0) {
|
||||
curclass.timeout = DEFAULT_TIMEOUT;
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
timeout = (unsigned int)strtoul(arg, &endp, 10);
|
||||
|
@ -443,6 +512,7 @@ parse_conf(const char *findclass)
|
|||
} else if (strcasecmp(word, "umask") == 0) {
|
||||
mode_t umask;
|
||||
|
||||
curclass.umask = DEFAULT_UMASK;
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
umask = (mode_t)strtoul(arg, &endp, 8);
|
||||
|
@ -472,8 +542,9 @@ parse_conf(const char *findclass)
|
|||
|
||||
/*
|
||||
* Show file listed in curclass.display first time in, and list all the
|
||||
* files named in curclass.notify in the current directory. Send back
|
||||
* responses with the prefix `code' + "-".
|
||||
* files named in curclass.notify in the current directory.
|
||||
* Send back responses with the prefix `code' + "-".
|
||||
* If code == -1, flush the internal cache of directory names and return.
|
||||
*/
|
||||
void
|
||||
show_chdir_messages(int code)
|
||||
|
@ -488,6 +559,13 @@ show_chdir_messages(int code)
|
|||
char cwd[MAXPATHLEN];
|
||||
char *cp, **rlist;
|
||||
|
||||
if (code == -1) {
|
||||
if (slist != NULL)
|
||||
sl_free(slist, 1);
|
||||
slist = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (quietmessages)
|
||||
return;
|
||||
|
||||
|
@ -669,7 +747,6 @@ format_path(char *dst, const char *src)
|
|||
len = 0;
|
||||
if (src == NULL)
|
||||
return;
|
||||
|
||||
for (p = src; *p && len < MAXPATHLEN; p++) {
|
||||
if (*p == '%') {
|
||||
p++;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: extern.h,v 1.36 2000/11/30 02:59:11 lukem Exp $ */
|
||||
/* $NetBSD: extern.h,v 1.37 2000/12/18 02:32:51 lukem Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992, 1993
|
||||
|
@ -138,7 +138,7 @@ int ftpd_pclose(FILE *);
|
|||
FILE *ftpd_popen(char *[], const char *, int);
|
||||
char *getline(char *, int, FILE *);
|
||||
void init_curclass(void);
|
||||
void logcmd(const char *, off_t, const char *, const char *,
|
||||
void logxfer(const char *, off_t, const char *, const char *,
|
||||
const struct timeval *, const char *);
|
||||
void logwtmp(const char *, const char *, const char *);
|
||||
struct tab *lookup(struct tab *, const char *);
|
||||
|
@ -175,6 +175,38 @@ void user(const char *);
|
|||
char *xstrdup(const char *);
|
||||
void yyerror(char *);
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#ifdef BSD4_4
|
||||
# define HAVE_SETPROCTITLE 1
|
||||
# define HAVE_SOCKADDR_SA_LEN 1
|
||||
#endif
|
||||
|
||||
struct sockinet {
|
||||
union sockunion {
|
||||
struct sockaddr_in su_sin;
|
||||
#ifdef INET6
|
||||
struct sockaddr_in6 su_sin6;
|
||||
#endif
|
||||
} si_su;
|
||||
#if !HAVE_SOCKADDR_SA_LEN
|
||||
int si_len;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !HAVE_SOCKADDR_SA_LEN
|
||||
# define su_len si_len
|
||||
#else
|
||||
# define su_len si_su.su_sin.sin_len
|
||||
#endif
|
||||
#define su_addr si_su.su_sin.sin_addr
|
||||
#define su_family si_su.su_sin.sin_family
|
||||
#define su_port si_su.su_sin.sin_port
|
||||
#ifdef INET6
|
||||
# define su_6addr si_su.su_sin6.sin6_addr
|
||||
# define su_scope_id si_su.su_sin6.sin6_scope_id
|
||||
#endif
|
||||
|
||||
struct tab {
|
||||
char *name;
|
||||
short token;
|
||||
|
@ -213,6 +245,7 @@ typedef enum {
|
|||
#define CURCLASS_FLAGS_ISSET(x) (curclass.flags & (FLAG_ ## x))
|
||||
|
||||
struct ftpclass {
|
||||
struct sockinet advertise; /* PASV address to advertise as */
|
||||
char *chroot; /* Directory to chroot(2) to at login */
|
||||
char *classname; /* Current class */
|
||||
struct ftpconv *conversions; /* List of conversions */
|
||||
|
@ -236,38 +269,6 @@ struct ftpclass {
|
|||
mode_t umask; /* Umask to use */
|
||||
};
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#ifdef BSD4_4
|
||||
# define HAVE_SETPROCTITLE 1
|
||||
# define HAVE_SOCKADDR_SA_LEN 1
|
||||
#endif
|
||||
|
||||
struct sockinet {
|
||||
union sockunion {
|
||||
struct sockaddr_in su_sin;
|
||||
#ifdef INET6
|
||||
struct sockaddr_in6 su_sin6;
|
||||
#endif
|
||||
} si_su;
|
||||
#if !HAVE_SOCKADDR_SA_LEN
|
||||
int si_len;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !HAVE_SOCKADDR_SA_LEN
|
||||
# define su_len si_len
|
||||
#else
|
||||
# define su_len si_su.su_sin.sin_len
|
||||
#endif
|
||||
#define su_addr si_su.su_sin.sin_addr
|
||||
#define su_family si_su.su_sin.sin_family
|
||||
#define su_port si_su.su_sin.sin_port
|
||||
#ifdef INET6
|
||||
# define su_6addr si_su.su_sin6.sin6_addr
|
||||
# define su_scope_id si_su.su_sin6.sin6_scope_id
|
||||
#endif
|
||||
|
||||
extern int yyparse(void);
|
||||
|
||||
#ifndef GLOBAL
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ftpcmd.y,v 1.58 2000/11/30 02:59:11 lukem Exp $ */
|
||||
/* $NetBSD: ftpcmd.y,v 1.59 2000/12/18 02:32:51 lukem Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
|
||||
|
@ -83,7 +83,7 @@
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)ftpcmd.y 8.3 (Berkeley) 4/6/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: ftpcmd.y,v 1.58 2000/11/30 02:59:11 lukem Exp $");
|
||||
__RCSID("$NetBSD: ftpcmd.y,v 1.59 2000/12/18 02:32:51 lukem Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -237,7 +237,7 @@ cmd
|
|||
reply(221,
|
||||
"Thank you for using the FTP service on %s.",
|
||||
hostname);
|
||||
if (logged_in) {
|
||||
if (logged_in && logging) {
|
||||
syslog(LOG_INFO,
|
||||
"Data traffic: " LLF " byte%s in " LLF " file%s",
|
||||
(LLT)total_data, PLURAL(total_data),
|
||||
|
@ -862,7 +862,7 @@ rcmd
|
|||
{
|
||||
if ($2) {
|
||||
fromname = NULL;
|
||||
restart_point = $4; /* XXX $4 is only "int" */
|
||||
restart_point = $4; /* XXX: $4 is only "int" */
|
||||
reply(350,
|
||||
"Restarting at " LLF ". Send STORE or RETRIEVE to initiate transfer.",
|
||||
(LLT)restart_point);
|
||||
|
@ -955,7 +955,7 @@ host_long_port6
|
|||
a[8] = $21; a[9] = $23; a[10] = $25; a[11] = $27;
|
||||
a[12] = $29; a[13] = $31; a[14] = $33; a[15] = $35;
|
||||
if (his_addr.su_family == AF_INET6) {
|
||||
/* XXX more sanity checks! */
|
||||
/* XXX: more sanity checks! */
|
||||
data_dest.su_scope_id = his_addr.su_scope_id;
|
||||
}
|
||||
#else
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: ftpd.8,v 1.62 2000/12/01 07:59:47 lukem Exp $
|
||||
.\" $NetBSD: ftpd.8,v 1.63 2000/12/18 02:32:51 lukem Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
|
@ -67,7 +67,7 @@
|
|||
.\"
|
||||
.\" @(#)ftpd.8 8.2 (Berkeley) 4/19/94
|
||||
.\"
|
||||
.Dd December 1, 2000
|
||||
.Dd December 18, 2000
|
||||
.Dt FTPD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -76,7 +76,7 @@
|
|||
Internet File Transfer Protocol server
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl dHlqQrsuUwW
|
||||
.Op Fl dHlqQrsuUwWX
|
||||
.Op Fl a Ar anondir
|
||||
.Op Fl c Ar confdir
|
||||
.Op Fl C Ar user
|
||||
|
@ -103,11 +103,24 @@ as the directory to
|
|||
.Xr chroot 2
|
||||
into for anonymous logins.
|
||||
Default is the home directory for the ftp user.
|
||||
This can also be specified with the
|
||||
.Xr ftpd.conf 5
|
||||
.Sy chroot
|
||||
directive.
|
||||
.It Fl c Ar confdir
|
||||
Change the root directory of the configuration files from
|
||||
.Dq Pa /etc
|
||||
to
|
||||
.Ar confdir .
|
||||
This changes the directory for the following files:
|
||||
.Pa /etc/ftpchroot ,
|
||||
.Pa /etc/ftpusers ,
|
||||
.Pa /etc/ftpwelcome ,
|
||||
.Pa /etc/motd ,
|
||||
and the file specified by the
|
||||
.Xr ftpd.conf 5
|
||||
.Sy limit
|
||||
directive.
|
||||
.It Fl C Ar user
|
||||
Check whether
|
||||
.Ar user
|
||||
|
@ -119,7 +132,7 @@ and exit without attempting a connection.
|
|||
exits with an exit code of 0 if access would be granted, or 1 otherwise.
|
||||
This can be useful for testing configurations.
|
||||
.It Fl d
|
||||
Debugging information is written to the syslog using
|
||||
Debugging information is written to the syslog using a facility of
|
||||
.Dv LOG_FTP .
|
||||
.It Fl e Ar emailaddr
|
||||
Use
|
||||
|
@ -156,8 +169,8 @@ Each successful and failed
|
|||
.Tn FTP
|
||||
session is logged using syslog with a facility of
|
||||
.Dv LOG_FTP .
|
||||
If this option is specified twice, the retrieve (get), store (put), append,
|
||||
delete, make directory, remove directory and rename operations and
|
||||
If this option is specified more than once, the retrieve (get), store (put),
|
||||
append, delete, make directory, remove directory and rename operations and
|
||||
their file name arguments are also logged.
|
||||
.It Fl P Ar dataport
|
||||
Use
|
||||
|
@ -228,6 +241,23 @@ Don't log each
|
|||
.Tn FTP
|
||||
session to
|
||||
.Pa /var/log/wtmp .
|
||||
.It Fl X
|
||||
Log
|
||||
.Tn wu-ftpd
|
||||
style
|
||||
.Sq xferlog
|
||||
entries to the syslog, prefixed with
|
||||
.Dq "xferlog:\ " ,
|
||||
using a facility of
|
||||
.Dv LOG_FTP .
|
||||
These syslog entries can be converted to a
|
||||
.Tn wu-ftpd
|
||||
style
|
||||
.Pa xferlog
|
||||
file suitable for input into a third-party log analysis tool with a command
|
||||
similar to:
|
||||
.Dl "grep 'xferlog: ' /var/log/xferlog | \e"
|
||||
.Dl "\ \ \ sed -e 's/^.*xferlog: //' > wuxferlog"
|
||||
.El
|
||||
.Pp
|
||||
The file
|
||||
|
@ -247,13 +277,13 @@ prints it before issuing the
|
|||
message.
|
||||
If the file
|
||||
.Pa /etc/motd
|
||||
exists,
|
||||
exists (under the chroot directory if applicable),
|
||||
.Nm
|
||||
prints it after a successful login.
|
||||
(This may be changed with the
|
||||
This may be changed with the
|
||||
.Xr ftpd.conf 5
|
||||
directive
|
||||
.Sy upload . )
|
||||
.Sy motd .
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ftpd.c,v 1.117 2000/11/30 08:33:33 lukem Exp $ */
|
||||
/* $NetBSD: ftpd.c,v 1.118 2000/12/18 02:32:51 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
|
||||
|
@ -109,7 +109,7 @@ __COPYRIGHT(
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: ftpd.c,v 1.117 2000/11/30 08:33:33 lukem Exp $");
|
||||
__RCSID("$NetBSD: ftpd.c,v 1.118 2000/12/18 02:32:51 lukem Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -150,6 +150,7 @@ __RCSID("$NetBSD: ftpd.c,v 1.117 2000/11/30 08:33:33 lukem Exp $");
|
|||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <tzfile.h>
|
||||
#include <unistd.h>
|
||||
#include <util.h>
|
||||
#include <utmp.h>
|
||||
|
@ -176,6 +177,7 @@ int dataport; /* use specific data port */
|
|||
int dopidfile; /* maintain pid file */
|
||||
int doutmp; /* update utmp file */
|
||||
int dowtmp; /* update wtmp file */
|
||||
int doxferlog; /* syslog wu-ftpd style xferlog entries */
|
||||
int dropprivs; /* if privileges should or have been dropped */
|
||||
int mapped; /* IPv4 connection on AF_INET6 socket */
|
||||
off_t file_size;
|
||||
|
@ -211,10 +213,10 @@ static int bind_pasv_addr(void);
|
|||
static int checkuser(const char *, const char *, int, int, char **);
|
||||
static int checkaccess(const char *);
|
||||
static int checkpassword(const struct passwd *, const char *);
|
||||
static void dolog(struct sockinet *);
|
||||
static void end_login(void);
|
||||
static FILE *getdatasock(const char *);
|
||||
static char *gunique(const char *);
|
||||
static void logremotehost(struct sockinet *);
|
||||
static void lostconn(int);
|
||||
static void myoob(int);
|
||||
static int receive_data(FILE *, FILE *);
|
||||
|
@ -248,8 +250,9 @@ main(int argc, char *argv[])
|
|||
sflag = 0;
|
||||
dataport = 0;
|
||||
dopidfile = 1; /* default: DO use a pid file to count users */
|
||||
doutmp = 0; /* default: don't log to utmp */
|
||||
doutmp = 0; /* default: Do NOT log to utmp */
|
||||
dowtmp = 1; /* default: DO log to wtmp */
|
||||
doxferlog = 0; /* default: Do NOT syslog xferlog */
|
||||
dropprivs = 0;
|
||||
mapped = 0;
|
||||
usedefault = 1;
|
||||
|
@ -265,7 +268,7 @@ main(int argc, char *argv[])
|
|||
*/
|
||||
openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
|
||||
|
||||
while ((ch = getopt(argc, argv, "a:c:C:de:h:HlP:qQrst:T:uUvV:wW"))
|
||||
while ((ch = getopt(argc, argv, "a:c:C:de:h:HlP:qQrst:T:uUvV:wWX"))
|
||||
!= -1) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
|
@ -360,6 +363,10 @@ main(int argc, char *argv[])
|
|||
dowtmp = 0;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
doxferlog = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (optopt == 'a' || optopt == 'C')
|
||||
exit(1);
|
||||
|
@ -370,14 +377,14 @@ main(int argc, char *argv[])
|
|||
if (EMPTYSTR(confdir))
|
||||
confdir = _DEFAULT_CONFDIR;
|
||||
|
||||
memset((char *)&his_addr, 0, sizeof (his_addr));
|
||||
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;
|
||||
memset((char *)&ctrl_addr, 0, sizeof (ctrl_addr));
|
||||
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]);
|
||||
|
@ -472,7 +479,7 @@ main(int argc, char *argv[])
|
|||
if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
|
||||
syslog(LOG_ERR, "fcntl F_SETOWN: %m");
|
||||
#endif
|
||||
dolog(&his_addr);
|
||||
logremotehost(&his_addr);
|
||||
/*
|
||||
* Set up default state
|
||||
*/
|
||||
|
@ -664,7 +671,7 @@ user(const char *name)
|
|||
*
|
||||
* NOTE: needs struct passwd *pw setup before use.
|
||||
*/
|
||||
int
|
||||
static int
|
||||
checkuser(const char *fname, const char *name, int def, int nofile,
|
||||
char **retclass)
|
||||
{
|
||||
|
@ -790,7 +797,7 @@ checkuser(const char *fname, const char *name, int def, int nofile,
|
|||
*
|
||||
* NOTE: needs struct passwd *pw setup (for checkuser())
|
||||
*/
|
||||
int
|
||||
static int
|
||||
checkaccess(const char *name)
|
||||
{
|
||||
|
||||
|
@ -798,7 +805,7 @@ checkaccess(const char *name)
|
|||
}
|
||||
|
||||
/*
|
||||
* Terminate login as previous user, if any, resetting state;
|
||||
* Terminate login as previous user (if any), resetting state;
|
||||
* used when USER command is given or login fails.
|
||||
*/
|
||||
static void
|
||||
|
@ -812,12 +819,15 @@ end_login(void)
|
|||
logout(utmp.ut_line);
|
||||
}
|
||||
/* reset login state */
|
||||
(void) seteuid((uid_t)0);
|
||||
show_chdir_messages(-1); /* flush chdir cache */
|
||||
if (pw != NULL && pw->pw_passwd != NULL)
|
||||
memset(pw->pw_passwd, 0, strlen(pw->pw_passwd));
|
||||
pw = NULL;
|
||||
logged_in = 0;
|
||||
quietmessages = 0;
|
||||
gidcount = 0;
|
||||
curclass.type = CLASS_REAL;
|
||||
(void) seteuid((uid_t)0);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -968,6 +978,8 @@ pass(const char *passwd)
|
|||
class = xstrdup("real");
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_ERR, "unknown curclass.type %d; aborting",
|
||||
curclass.type);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
@ -1047,6 +1059,16 @@ pass(const char *passwd)
|
|||
}
|
||||
break;
|
||||
case CLASS_REAL:
|
||||
/* 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);
|
||||
|
@ -1100,6 +1122,8 @@ pass(const char *passwd)
|
|||
(void)display_file(conffilename(curclass.motd), 230);
|
||||
show_chdir_messages(230);
|
||||
if (curclass.type == CLASS_GUEST) {
|
||||
char *p;
|
||||
|
||||
reply(230, "Guest login ok, access restrictions apply.");
|
||||
#if HAVE_SETPROCTITLE
|
||||
snprintf(proctitle, sizeof(proctitle),
|
||||
|
@ -1113,6 +1137,11 @@ pass(const char *passwd)
|
|||
"ANONYMOUS FTP LOGIN FROM %s, %s (class: %s, type: %s)",
|
||||
remotehost, passwd,
|
||||
curclass.classname, CURCLASSTYPE);
|
||||
/* store guest password reply into pw_passwd */
|
||||
REASSIGN(pw->pw_passwd, xstrdup(passwd));
|
||||
for (p = pw->pw_passwd; *p; p++)
|
||||
if (!isgraph(*p))
|
||||
*p = '_';
|
||||
} else {
|
||||
reply(230, "User %s logged in.", pw->pw_name);
|
||||
#if HAVE_SETPROCTITLE
|
||||
|
@ -1153,16 +1182,16 @@ retrieve(char *argv[], const char *name)
|
|||
tdp = NULL;
|
||||
dispname = name;
|
||||
fin = dout = NULL;
|
||||
if (argv == NULL) {
|
||||
if (argv == NULL) { /* if not running a command ... */
|
||||
log = 1;
|
||||
isdata = 1;
|
||||
fin = fopen(name, "r");
|
||||
closefunc = fclose;
|
||||
if (fin == NULL)
|
||||
if (fin == NULL) /* doesn't exist?; try a conversion */
|
||||
argv = do_conversion(name);
|
||||
if (argv != NULL) {
|
||||
isconversion++;
|
||||
syslog(LOG_INFO, "get command: '%s' on '%s'",
|
||||
syslog(LOG_DEBUG, "get command: '%s' on '%s'",
|
||||
argv[0], name);
|
||||
}
|
||||
}
|
||||
|
@ -1188,7 +1217,7 @@ retrieve(char *argv[], const char *name)
|
|||
if (errno != 0) {
|
||||
perror_reply(550, dispname);
|
||||
if (log)
|
||||
logcmd("get", -1, name, NULL, NULL,
|
||||
logxfer("get", -1, name, NULL, NULL,
|
||||
strerror(errno));
|
||||
}
|
||||
goto cleanupretrieve;
|
||||
|
@ -1230,7 +1259,7 @@ retrieve(char *argv[], const char *name)
|
|||
tdp = &td;
|
||||
done:
|
||||
if (log)
|
||||
logcmd("get", byte_count, name, NULL, tdp, NULL);
|
||||
logxfer("get", byte_count, name, NULL, tdp, NULL);
|
||||
closerv = (*closefunc)(fin);
|
||||
if (sendrv == 0) {
|
||||
FILE *err;
|
||||
|
@ -1284,7 +1313,8 @@ store(const char *name, const char *mode, int unique)
|
|||
desc = (*mode == 'w') ? "put" : "append";
|
||||
if (unique && stat(name, &st) == 0 &&
|
||||
(name = gunique(name)) == NULL) {
|
||||
logcmd(desc, -1, name, NULL, NULL, "cannot create unique file");
|
||||
logxfer(desc, -1, name, NULL, NULL,
|
||||
"cannot create unique file");
|
||||
goto cleanupstore;
|
||||
}
|
||||
|
||||
|
@ -1295,7 +1325,7 @@ store(const char *name, const char *mode, int unique)
|
|||
tdp = NULL;
|
||||
if (fout == NULL) {
|
||||
perror_reply(553, name);
|
||||
logcmd(desc, -1, name, NULL, NULL, strerror(errno));
|
||||
logxfer(desc, -1, name, NULL, NULL, strerror(errno));
|
||||
goto cleanupstore;
|
||||
}
|
||||
byte_count = -1;
|
||||
|
@ -1343,7 +1373,7 @@ store(const char *name, const char *mode, int unique)
|
|||
timersub(&finish, &start, &td);
|
||||
tdp = &td;
|
||||
done:
|
||||
logcmd(desc, byte_count, name, NULL, tdp, NULL);
|
||||
logxfer(desc, byte_count, name, NULL, tdp, NULL);
|
||||
(*closefunc)(fout);
|
||||
cleanupstore:
|
||||
closedataconn(din);
|
||||
|
@ -1883,7 +1913,10 @@ statcmd(void)
|
|||
su = NULL;
|
||||
} else if (pdata != -1) {
|
||||
reply(0, "in Passive mode");
|
||||
su = (struct sockinet *)&pasv_addr;
|
||||
if (curclass.advertise.su_len != 0)
|
||||
su = &curclass.advertise;
|
||||
else
|
||||
su = &pasv_addr;
|
||||
ispassive = 1;
|
||||
goto printaddr;
|
||||
} else if (usedefault == 0) {
|
||||
|
@ -2030,6 +2063,16 @@ statcmd(void)
|
|||
CURCLASS_FLAGS_ISSET(sanenames) ? "en" : "dis");
|
||||
reply(0, "PASV/LPSV/EPSV connections: %sabled",
|
||||
CURCLASS_FLAGS_ISSET(passive) ? "en" : "dis");
|
||||
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);
|
||||
}
|
||||
if (curclass.portmin && curclass.portmax)
|
||||
reply(0, "PASV port range: %d - %d",
|
||||
curclass.portmin, curclass.portmax);
|
||||
|
@ -2100,7 +2143,7 @@ reply(int n, const char *fmt, ...)
|
|||
}
|
||||
|
||||
static void
|
||||
dolog(struct sockinet *who)
|
||||
logremotehost(struct sockinet *who)
|
||||
{
|
||||
|
||||
if (getnameinfo((struct sockaddr *)&who->si_su,
|
||||
|
@ -2117,8 +2160,7 @@ dolog(struct sockinet *who)
|
|||
}
|
||||
|
||||
/*
|
||||
* Record logout in wtmp file
|
||||
* and exit with supplied status.
|
||||
* Record logout in wtmp file and exit with supplied status.
|
||||
*/
|
||||
void
|
||||
dologout(int status)
|
||||
|
@ -2241,7 +2283,10 @@ passive(void)
|
|||
pasv_addr.su_len = len;
|
||||
if (listen(pdata, 1) < 0)
|
||||
goto pasv_error;
|
||||
a = (char *) &pasv_addr.su_addr;
|
||||
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;
|
||||
|
||||
#define UC(b) (((int) b) & 0xff)
|
||||
|
@ -2373,9 +2418,15 @@ long_passive(char *cmd, int pf)
|
|||
#define UC(b) (((int) b) & 0xff)
|
||||
|
||||
if (strcmp(cmd, "LPSV") == 0) {
|
||||
switch (pasv_addr.su_family) {
|
||||
struct sockinet *advert;
|
||||
|
||||
if (curclass.advertise.su_len != 0)
|
||||
advert = &curclass.advertise;
|
||||
else
|
||||
advert = &pasv_addr;
|
||||
switch (advert->su_family) {
|
||||
case AF_INET:
|
||||
a = (char *) &pasv_addr.su_addr;
|
||||
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]),
|
||||
|
@ -2383,7 +2434,7 @@ long_passive(char *cmd, int pf)
|
|||
return;
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
a = (char *) &pasv_addr.su_6addr;
|
||||
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,
|
||||
|
@ -2465,7 +2516,8 @@ extended_port(const char *arg)
|
|||
goto parsefail;
|
||||
if (sizeof(data_dest) < res->ai_addrlen)
|
||||
goto parsefail;
|
||||
memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
|
||||
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) {
|
||||
|
@ -2580,7 +2632,6 @@ send_file_list(const char *whichf)
|
|||
int simple = 0;
|
||||
int freeglob = 0;
|
||||
glob_t gl;
|
||||
off_t b;
|
||||
|
||||
#ifdef __GNUC__
|
||||
(void) &dout;
|
||||
|
@ -2638,16 +2689,19 @@ send_file_list(const char *whichf)
|
|||
}
|
||||
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
/*
|
||||
* XXXRFC:
|
||||
* should we follow RFC959 and not work
|
||||
* for non directories?
|
||||
*/
|
||||
if (dout == NULL) {
|
||||
dout = dataconn("file list", (off_t)-1, "w");
|
||||
if (dout == NULL)
|
||||
goto out;
|
||||
transflag++;
|
||||
}
|
||||
b = fprintf(dout, "%s%s\n", dirname,
|
||||
cprintf(dout, "%s%s\n", dirname,
|
||||
type == TYPE_A ? "\r" : "");
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
byte_count += strlen(dirname) + 1;
|
||||
continue;
|
||||
} else if (!S_ISDIR(st.st_mode))
|
||||
|
@ -2672,7 +2726,12 @@ send_file_list(const char *whichf)
|
|||
* We have to do a stat to ensure it's
|
||||
* not a directory or special file.
|
||||
*/
|
||||
/* XXX: follow RFC959 and filter out non files ? */
|
||||
/*
|
||||
* XXXRFC:
|
||||
* should we follow RFC959 and filter out
|
||||
* non files ? lukem - NO!, or not until
|
||||
* our ftp client uses MLS{T,D} for completion.
|
||||
*/
|
||||
if (simple || (stat(nbuf, &st) == 0 &&
|
||||
S_ISREG(st.st_mode))) {
|
||||
char *p;
|
||||
|
@ -2687,10 +2746,8 @@ send_file_list(const char *whichf)
|
|||
p = nbuf;
|
||||
if (nbuf[0] == '.' && nbuf[1] == '/')
|
||||
p = &nbuf[2];
|
||||
b = fprintf(dout, "%s%s\n", p,
|
||||
cprintf(dout, "%s%s\n", p,
|
||||
type == TYPE_A ? "\r" : "");
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
byte_count += strlen(nbuf) + 1;
|
||||
}
|
||||
}
|
||||
|
@ -2729,48 +2786,102 @@ conffilename(const char *s)
|
|||
}
|
||||
|
||||
/*
|
||||
* logcmd --
|
||||
* based on the arguments, syslog a message:
|
||||
* 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
|
||||
*
|
||||
* if doxferlog != 0, syslog a wu-ftpd style xferlog entry
|
||||
*/
|
||||
void
|
||||
logcmd(const char *command, off_t bytes, const char *file1, const char *file2,
|
||||
logxfer(const char *command, off_t bytes, const char *file1, const char *file2,
|
||||
const struct timeval *elapsed, const char *error)
|
||||
{
|
||||
char buf[MAXPATHLEN * 2 + 100], realfile[MAXPATHLEN];
|
||||
const char *p;
|
||||
size_t len;
|
||||
char buf[MAXPATHLEN * 2 + 100], realfile[MAXPATHLEN];
|
||||
const char *r1, *r2;
|
||||
char direction;
|
||||
size_t len;
|
||||
time_t now;
|
||||
|
||||
if (logging <=1)
|
||||
if (logging <=1 && !doxferlog)
|
||||
return;
|
||||
|
||||
if ((p = realpath(file1, realfile)) == NULL)
|
||||
p = file1;
|
||||
len = snprintf(buf, sizeof(buf), "%s %s", command, p);
|
||||
r1 = r2 = NULL;
|
||||
if ((r1 = realpath(file1, realfile)) == NULL)
|
||||
r1 = file1;
|
||||
if (file2 != NULL)
|
||||
if ((r2 = realpath(file2, realfile)) == NULL)
|
||||
r2 = file2;
|
||||
|
||||
if (bytes != (off_t)-1) {
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
" = " LLF " byte%s", (LLT) bytes, PLURAL(bytes));
|
||||
} else if (file2 != NULL) {
|
||||
if ((p = realpath(file2, realfile)) == NULL)
|
||||
p = file2;
|
||||
len += snprintf(buf + len, sizeof(buf) - len, " %s", p);
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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 wu-ftpd style log entry, prefixed with "xferlog: "
|
||||
*/
|
||||
if (!doxferlog)
|
||||
return;
|
||||
|
||||
syslog(LOG_INFO, "%s", buf);
|
||||
if (strcmp(command, "get") == 0)
|
||||
direction = 'o';
|
||||
else if (strcmp(command, "put") == 0 || strcmp(command, "append") == 0)
|
||||
direction = 'i';
|
||||
else
|
||||
return;
|
||||
|
||||
time(&now);
|
||||
syslog(LOG_INFO,
|
||||
"xferlog%s: %.24s %ld %s " LLF " %s %c %s %c %c %s FTP 0 * %c",
|
||||
|
||||
/*
|
||||
* XXX: wu-ftpd puts (send) or (recv) in the syslog message, and removes
|
||||
* the full date. This may be problematic for accurate log parsing,
|
||||
* given that syslog messages don't contain the full date.
|
||||
*/
|
||||
#if 1 /* lukem's method; easier to convert to actual xferlog file */
|
||||
"",
|
||||
ctime(&now),
|
||||
#else /* wu-ftpd's syslog method, with an extra unneeded space */
|
||||
(direction == 'i') ? " (recv)" : " (send)",
|
||||
"",
|
||||
#endif
|
||||
elapsed == NULL ? 0 : elapsed->tv_sec + (elapsed->tv_usec > 0),
|
||||
remotehost,
|
||||
bytes == (off_t)-1 ? 0 : (LLT) bytes,
|
||||
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'
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: ftpd.conf.5,v 1.14 2000/11/16 13:15:14 lukem Exp $
|
||||
.\" $NetBSD: ftpd.conf.5,v 1.15 2000/12/18 02:32:51 lukem Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
|
@ -34,7 +34,7 @@
|
|||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd November 16, 2000
|
||||
.Dd December 18, 2000
|
||||
.Dt FTPD.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -118,12 +118,28 @@ command will return the class settings for the current user as defined by
|
|||
.Pp
|
||||
Each configuration line may be one of:
|
||||
.Bl -tag -width 4n
|
||||
.It Sy advertise Ar class Ar host
|
||||
Set the address to advertise in the response to the
|
||||
.Sy PASV
|
||||
and
|
||||
.Sy LPSV
|
||||
commands to the address for
|
||||
.Ar host
|
||||
(which may be either a host name or IP address).
|
||||
This may be useful in some firewall configurations, although many
|
||||
ftp clients may not work if the address being advertised is different
|
||||
to the address that they've connected to.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or no argument is given, disable this.
|
||||
.It Sy checkportcmd Ar class Op Sy off
|
||||
Check the
|
||||
PORT
|
||||
.Sy PORT
|
||||
command for validity.
|
||||
The
|
||||
PORT
|
||||
.Sy PORT
|
||||
command will fail if the IP address specified does not match the
|
||||
.Tn FTP
|
||||
command connection, or if the remote TCP port number is less than
|
||||
|
@ -172,15 +188,23 @@ A
|
|||
character.
|
||||
.El
|
||||
.Pp
|
||||
The default root directory is
|
||||
.Pa /
|
||||
for
|
||||
.Sy REAL
|
||||
users, and the user's home directory for
|
||||
.Sy GUEST
|
||||
and
|
||||
.Sy CHROOT
|
||||
users.
|
||||
The default root directory is:
|
||||
.Bl -tag -width "CHROOT" -offset indent -compact
|
||||
.It Sy CHROOT
|
||||
The user's home directory.
|
||||
.It Sy GUEST
|
||||
If
|
||||
.Fl a Ar anondir
|
||||
is given, use
|
||||
.Ar anondir ,
|
||||
otherwise the home directory of the
|
||||
.Sq ftp
|
||||
user.
|
||||
.It Sy REAL
|
||||
By default no
|
||||
.Xr chroot 2
|
||||
is performed.
|
||||
.El
|
||||
.It Sy classtype Ar class Ar type
|
||||
Set the class type of
|
||||
.Ar class
|
||||
|
@ -247,26 +271,6 @@ Escape sequences are supported; refer to
|
|||
in
|
||||
.Xr ftpd 8
|
||||
for more information.
|
||||
.It Xo Sy limit Ar class
|
||||
.Ar count Op Ar file
|
||||
.Xc
|
||||
Limit the maximum number of concurrent connections for
|
||||
.Ar class
|
||||
to
|
||||
.Ar count ,
|
||||
with
|
||||
.Sq 0
|
||||
meaning unlimited connections.
|
||||
If the limit is exceeded and
|
||||
.Ar file
|
||||
is given, display its contents to the user.
|
||||
Ignored if
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar count
|
||||
is not specified.
|
||||
.It Sy homedir Ar class Op Sy pathformat
|
||||
If
|
||||
.Ar pathformat
|
||||
|
@ -295,21 +299,52 @@ for
|
|||
and
|
||||
.Sy CHROOT
|
||||
users.
|
||||
.It Xo Sy limit Ar class
|
||||
.Ar count Op Ar file
|
||||
.Xc
|
||||
Limit the maximum number of concurrent connections for
|
||||
.Ar class
|
||||
to
|
||||
.Ar count ,
|
||||
with
|
||||
.Sq 0
|
||||
meaning unlimited connections.
|
||||
If the limit is exceeded and
|
||||
.Ar file
|
||||
is given, display its contents to the user.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar count
|
||||
is not specified, disable this.
|
||||
If
|
||||
.Ar file
|
||||
is a relative path, it will be searched for in
|
||||
.Pa /etc
|
||||
(which can be overridden with
|
||||
.Fl c Ar confdir ) .
|
||||
.It Sy maxfilesize Ar class Ar size
|
||||
Set the maximum size of an uploaded file to
|
||||
.Ar size .
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or no argument is given, disable this.
|
||||
.It Sy maxtimeout Ar class Ar time
|
||||
Set the maximum timeout period that a client may request,
|
||||
defaulting to two hours.
|
||||
This cannot be less than 30 seconds, or the value for
|
||||
.Sy timeout .
|
||||
Ignored if
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar time
|
||||
is not specified.
|
||||
is not specified, set to default of 2 hours.
|
||||
.It Sy modify Ar class Op Sy off
|
||||
If
|
||||
.Ar class
|
||||
|
@ -318,7 +353,13 @@ is
|
|||
or
|
||||
.Sy off
|
||||
is given, disable the following commands:
|
||||
CHMOD, DELE, MKD, RMD, RNFR, and UMASK.
|
||||
.Sy CHMOD ,
|
||||
.Sy DELE ,
|
||||
.Sy MKD ,
|
||||
.Sy RMD ,
|
||||
.Sy RNFR ,
|
||||
and
|
||||
.Sy UMASK .
|
||||
Otherwise, enable them.
|
||||
.It Sy motd Ar class Op Ar file
|
||||
If
|
||||
|
@ -336,6 +377,12 @@ Escape sequences are supported; refer to
|
|||
in
|
||||
.Xr ftpd 8
|
||||
for more information.
|
||||
If
|
||||
.Ar file
|
||||
is a relative path, it will be searched for in
|
||||
.Pa /etc
|
||||
(which can be overridden with
|
||||
.Fl c Ar confdir ) .
|
||||
.It Sy notify Ar class Op Ar fileglob
|
||||
If
|
||||
.Ar fileglob
|
||||
|
@ -354,7 +401,12 @@ is
|
|||
.Dq none
|
||||
or
|
||||
.Sy off
|
||||
is given, disallow passive (PASV/LPSV/EPSV) connections.
|
||||
is given, disallow passive
|
||||
.Sy ( PASV ,
|
||||
.Sy LPSV ,
|
||||
and
|
||||
.Sy EPSV )
|
||||
connections.
|
||||
Otherwise, enable them.
|
||||
.It Sy portrange Ar class Ar min Ar max
|
||||
Set the range of port number which will be used for the passive data port.
|
||||
|
@ -364,8 +416,15 @@ must be greater than
|
|||
and both numbers must be be between
|
||||
.Dv IPPORT_RESERVED
|
||||
(1024) and 65535.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or no arguments are given, disable this.
|
||||
.It Sy rateget Ar class Ar rate
|
||||
Set the maximum get (RETR) transfer rate throttle for
|
||||
Set the maximum get
|
||||
.Pq Sy RETR
|
||||
transfer rate throttle for
|
||||
.Ar class
|
||||
to
|
||||
.Ar rate
|
||||
|
@ -373,28 +432,42 @@ bytes per second.
|
|||
If
|
||||
.Ar rate
|
||||
is 0, the throttle is disabled.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or no arguments are given, disable this.
|
||||
.Pp
|
||||
An optional suffix may be provided, which changes the intrepretation of
|
||||
.Ar rate
|
||||
as follows:
|
||||
.Bl -tag -width 3n -offset indent -compact
|
||||
.It b
|
||||
Causes no modification. (Optional)
|
||||
Causes no modification. (Default; optional)
|
||||
.It k
|
||||
Kilo; multiply the argument by 1024
|
||||
.It m
|
||||
Mega; multiply the argument by 1048576
|
||||
.It g
|
||||
Giga; multiply the argument by 1073741824
|
||||
.It t
|
||||
Tera; multiply the argument by 1099511627776
|
||||
.El
|
||||
.It Sy rateput Ar class Ar rate
|
||||
Set the maximum put (STOR) transfer rate throttle for
|
||||
Set the maximum put
|
||||
.Pq Sy STOR
|
||||
transfer rate throttle for
|
||||
.Ar class
|
||||
to
|
||||
.Ar rate
|
||||
bytes per second,
|
||||
which is parsed as per
|
||||
.Sy rateget Ar rate .
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or no arguments are given, disable this.
|
||||
.It Sy sanenames Ar class Op Sy off
|
||||
If
|
||||
.Ar class
|
||||
|
@ -432,23 +505,24 @@ Set the inactivity timeout period.
|
|||
(the default is fifteen minutes).
|
||||
This cannot be less than 30 seconds, or greater than the value for
|
||||
.Sy maxtimeout .
|
||||
Ignored if
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar time
|
||||
is not specified.
|
||||
is not specified, set to the default of 15 minutes.
|
||||
.It Sy umask Ar class Ar umaskval
|
||||
Set the umask to
|
||||
.Ar umaskval .
|
||||
Ignored if
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar umaskval
|
||||
is not specified.
|
||||
is not specified, set to the default of
|
||||
.Li 027 .
|
||||
.It Sy upload Ar class Op Sy off
|
||||
If
|
||||
.Ar class
|
||||
|
@ -457,9 +531,18 @@ is
|
|||
or
|
||||
.Sy off
|
||||
is given, disable the following commands:
|
||||
APPE, STOR, and STOU,
|
||||
.Sy APPE ,
|
||||
.Sy STOR ,
|
||||
and
|
||||
.Sy STOU ,
|
||||
as well as the modify commands:
|
||||
CHMOD, DELE, MKD, RMD, RNFR, and UMASK.
|
||||
.Sy CHMOD ,
|
||||
.Sy DELE ,
|
||||
.Sy MKD ,
|
||||
.Sy RMD ,
|
||||
.Sy RNFR ,
|
||||
and
|
||||
.Sy UMASK .
|
||||
Otherwise, enable them.
|
||||
.El
|
||||
.Sh DEFAULTS
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: version.h,v 1.26 2000/12/04 10:50:39 itojun Exp $ */
|
||||
/* $NetBSD: version.h,v 1.27 2000/12/18 02:32:51 lukem Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
|
@ -36,5 +36,5 @@
|
|||
*/
|
||||
|
||||
#ifndef FTPD_VERSION
|
||||
#define FTPD_VERSION "NetBSD-ftpd 20001204"
|
||||
#define FTPD_VERSION "NetBSD-ftpd 20001218"
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue