- 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
This commit is contained in:
parent
3f648dea6e
commit
999fd3d617
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: cmds.c,v 1.7 2000/11/15 02:32:30 lukem Exp $ */
|
||||
/* $NetBSD: cmds.c,v 1.8 2000/11/16 13:15:13 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.7 2000/11/15 02:32:30 lukem Exp $");
|
||||
__RCSID("$NetBSD: cmds.c,v 1.8 2000/11/16 13:15:13 lukem Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
|
@ -602,7 +602,7 @@ fact_perm(const char *fact, FILE *fd, factelem *fe)
|
|||
* since we only need this info in such a case.
|
||||
*/
|
||||
pdir = fe->pdirstat;
|
||||
if (pdir == NULL && curclass.modify) {
|
||||
if (pdir == NULL && CURCLASS_FLAGS_ISSET(modify)) {
|
||||
size_t len;
|
||||
char realdir[MAXPATHLEN], *p;
|
||||
struct stat dir;
|
||||
|
@ -636,15 +636,15 @@ fact_perm(const char *fact, FILE *fd, factelem *fe)
|
|||
}
|
||||
|
||||
/* 'a': can APPE to file */
|
||||
if (wok && curclass.upload && S_ISREG(fe->stat->st_mode))
|
||||
if (wok && CURCLASS_FLAGS_ISSET(upload) && S_ISREG(fe->stat->st_mode))
|
||||
CPUTC('a', fd);
|
||||
|
||||
/* 'c': can create or append to files in directory */
|
||||
if (wok && curclass.modify && S_ISDIR(fe->stat->st_mode))
|
||||
if (wok && CURCLASS_FLAGS_ISSET(modify) && S_ISDIR(fe->stat->st_mode))
|
||||
CPUTC('c', fd);
|
||||
|
||||
/* 'd': can delete file or directory */
|
||||
if (pdirwok && curclass.modify) {
|
||||
if (pdirwok && CURCLASS_FLAGS_ISSET(modify)) {
|
||||
int candel;
|
||||
|
||||
candel = 1;
|
||||
|
@ -674,7 +674,7 @@ fact_perm(const char *fact, FILE *fd, factelem *fe)
|
|||
CPUTC('e', fd);
|
||||
|
||||
/* 'f': can rename file or directory */
|
||||
if (pdirwok && curclass.modify)
|
||||
if (pdirwok && CURCLASS_FLAGS_ISSET(modify))
|
||||
CPUTC('f', fd);
|
||||
|
||||
/* 'l': can list directory */
|
||||
|
@ -682,11 +682,11 @@ fact_perm(const char *fact, FILE *fd, factelem *fe)
|
|||
CPUTC('l', fd);
|
||||
|
||||
/* 'm': can create directory */
|
||||
if (wok && curclass.modify && S_ISDIR(fe->stat->st_mode))
|
||||
if (wok && CURCLASS_FLAGS_ISSET(modify) && S_ISDIR(fe->stat->st_mode))
|
||||
CPUTC('m', fd);
|
||||
|
||||
/* 'p': can remove files in directory */
|
||||
if (wok && curclass.modify && S_ISDIR(fe->stat->st_mode))
|
||||
if (wok && CURCLASS_FLAGS_ISSET(modify) && S_ISDIR(fe->stat->st_mode))
|
||||
CPUTC('p', fd);
|
||||
|
||||
/* 'r': can RETR file */
|
||||
|
@ -694,7 +694,7 @@ fact_perm(const char *fact, FILE *fd, factelem *fe)
|
|||
CPUTC('r', fd);
|
||||
|
||||
/* 'w': can STOR file */
|
||||
if (wok && curclass.upload && S_ISREG(fe->stat->st_mode))
|
||||
if (wok && CURCLASS_FLAGS_ISSET(upload) && S_ISREG(fe->stat->st_mode))
|
||||
CPUTC('w', fd);
|
||||
|
||||
CPUTC(';', fd);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: conf.c,v 1.35 2000/11/15 02:32:30 lukem Exp $ */
|
||||
/* $NetBSD: conf.c,v 1.36 2000/11/16 13:15:13 lukem Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
|
||||
|
@ -38,7 +38,7 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: conf.c,v 1.35 2000/11/15 02:32:30 lukem Exp $");
|
||||
__RCSID("$NetBSD: conf.c,v 1.36 2000/11/16 13:15:13 lukem Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
@ -88,7 +88,6 @@ init_curclass(void)
|
|||
free(conv);
|
||||
}
|
||||
|
||||
curclass.checkportcmd = 1;
|
||||
REASSIGN(curclass.chroot, NULL);
|
||||
REASSIGN(curclass.classname, NULL);
|
||||
curclass.conversions = NULL;
|
||||
|
@ -96,13 +95,12 @@ init_curclass(void)
|
|||
REASSIGN(curclass.homedir, NULL);
|
||||
curclass.limit = -1; /* unlimited connections */
|
||||
REASSIGN(curclass.limitfile, NULL);
|
||||
curclass.maxfilesize = -1; /* unlimited file size */
|
||||
curclass.maxrateget = 0;
|
||||
curclass.maxrateput = 0;
|
||||
curclass.maxtimeout = 7200; /* 2 hours */
|
||||
curclass.modify = 1;
|
||||
REASSIGN(curclass.motd, xstrdup(_PATH_FTPLOGINMESG));
|
||||
REASSIGN(curclass.notify, NULL);
|
||||
curclass.passive = 1;
|
||||
curclass.portmin = 0;
|
||||
curclass.portmax = 0;
|
||||
curclass.rateget = 0;
|
||||
|
@ -110,7 +108,12 @@ init_curclass(void)
|
|||
curclass.timeout = 900; /* 15 minutes */
|
||||
/* curclass.type is set elsewhere */
|
||||
curclass.umask = 027;
|
||||
curclass.upload = 1;
|
||||
|
||||
CURCLASS_FLAGS_SET(checkportcmd);
|
||||
CURCLASS_FLAGS_SET(modify);
|
||||
CURCLASS_FLAGS_SET(passive);
|
||||
CURCLASS_FLAGS_CLR(sanenames);
|
||||
CURCLASS_FLAGS_SET(upload);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -123,7 +126,8 @@ parse_conf(const char *findclass)
|
|||
FILE *f;
|
||||
char *buf, *p;
|
||||
size_t len;
|
||||
int none, match, rate;
|
||||
LLT llval;
|
||||
int none, match;
|
||||
char *endp;
|
||||
char *class, *word, *arg, *template;
|
||||
const char *infile;
|
||||
|
@ -134,7 +138,7 @@ parse_conf(const char *findclass)
|
|||
init_curclass();
|
||||
REASSIGN(curclass.classname, xstrdup(findclass));
|
||||
if (strcasecmp(findclass, "guest") == 0) {
|
||||
curclass.modify = 0;
|
||||
CURCLASS_FLAGS_CLR(modify);
|
||||
curclass.umask = 0707;
|
||||
}
|
||||
|
||||
|
@ -170,19 +174,29 @@ parse_conf(const char *findclass)
|
|||
strcasecmp(class, "all") == 0) )
|
||||
continue;
|
||||
|
||||
#define CONF_FLAG(x) \
|
||||
do { \
|
||||
if (none || \
|
||||
(!EMPTYSTR(arg) && strcasecmp(arg, "off") == 0)) \
|
||||
CURCLASS_FLAGS_CLR(x); \
|
||||
else \
|
||||
CURCLASS_FLAGS_SET(x); \
|
||||
} while (0)
|
||||
|
||||
#define CONF_STRING(x) \
|
||||
do { \
|
||||
if (none || EMPTYSTR(arg)) \
|
||||
arg = NULL; \
|
||||
else \
|
||||
arg = xstrdup(arg); \
|
||||
REASSIGN(curclass.x, arg); \
|
||||
} while (0)
|
||||
|
||||
if (strcasecmp(word, "checkportcmd") == 0) {
|
||||
if (none ||
|
||||
(!EMPTYSTR(arg) && strcasecmp(arg, "off") == 0))
|
||||
curclass.checkportcmd = 0;
|
||||
else
|
||||
curclass.checkportcmd = 1;
|
||||
CONF_FLAG(checkportcmd);
|
||||
|
||||
} else if (strcasecmp(word, "chroot") == 0) {
|
||||
if (none || EMPTYSTR(arg))
|
||||
arg = NULL;
|
||||
else
|
||||
arg = xstrdup(arg);
|
||||
REASSIGN(curclass.chroot, arg);
|
||||
CONF_STRING(chroot);
|
||||
|
||||
} else if (strcasecmp(word, "classtype") == 0) {
|
||||
if (!none && !EMPTYSTR(arg)) {
|
||||
|
@ -253,18 +267,22 @@ parse_conf(const char *findclass)
|
|||
REASSIGN(conv->command, convcmd);
|
||||
|
||||
} else if (strcasecmp(word, "display") == 0) {
|
||||
if (none || EMPTYSTR(arg))
|
||||
arg = NULL;
|
||||
else
|
||||
arg = xstrdup(arg);
|
||||
REASSIGN(curclass.display, arg);
|
||||
CONF_STRING(display);
|
||||
|
||||
} else if (strcasecmp(word, "homedir") == 0) {
|
||||
CONF_STRING(homedir);
|
||||
|
||||
} else if (strcasecmp(word, "maxfilesize") == 0) {
|
||||
if (none || EMPTYSTR(arg))
|
||||
arg = NULL;
|
||||
else
|
||||
arg = xstrdup(arg);
|
||||
REASSIGN(curclass.homedir, 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;
|
||||
|
@ -308,33 +326,16 @@ parse_conf(const char *findclass)
|
|||
curclass.maxtimeout = timeout;
|
||||
|
||||
} else if (strcasecmp(word, "modify") == 0) {
|
||||
if (none ||
|
||||
(!EMPTYSTR(arg) && strcasecmp(arg, "off") == 0))
|
||||
curclass.modify = 0;
|
||||
else
|
||||
curclass.modify = 1;
|
||||
CONF_FLAG(modify);
|
||||
|
||||
} else if (strcasecmp(word, "motd") == 0) {
|
||||
if (none || EMPTYSTR(arg))
|
||||
arg = NULL;
|
||||
else
|
||||
arg = xstrdup(arg);
|
||||
REASSIGN(curclass.motd, arg);
|
||||
|
||||
CONF_STRING(motd);
|
||||
|
||||
} else if (strcasecmp(word, "notify") == 0) {
|
||||
if (none || EMPTYSTR(arg))
|
||||
arg = NULL;
|
||||
else
|
||||
arg = xstrdup(arg);
|
||||
REASSIGN(curclass.notify, arg);
|
||||
CONF_STRING(notify);
|
||||
|
||||
} else if (strcasecmp(word, "passive") == 0) {
|
||||
if (none ||
|
||||
(!EMPTYSTR(arg) && strcasecmp(arg, "off") == 0))
|
||||
curclass.passive = 0;
|
||||
else
|
||||
curclass.passive = 1;
|
||||
CONF_FLAG(passive);
|
||||
|
||||
} else if (strcasecmp(word, "portrange") == 0) {
|
||||
int minport, maxport;
|
||||
|
@ -383,28 +384,31 @@ parse_conf(const char *findclass)
|
|||
} else if (strcasecmp(word, "rateget") == 0) {
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
rate = strsuftoi(arg);
|
||||
if (rate == -1) {
|
||||
llval = strsuftoll(arg);
|
||||
if (llval == -1) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: invalid rateget %s",
|
||||
infile, (int)line, arg);
|
||||
continue;
|
||||
}
|
||||
curclass.maxrateget = rate;
|
||||
curclass.rateget = rate;
|
||||
curclass.maxrateget = llval;
|
||||
curclass.rateget = llval;
|
||||
|
||||
} else if (strcasecmp(word, "rateput") == 0) {
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
rate = strsuftoi(arg);
|
||||
if (rate == -1) {
|
||||
llval = strsuftoll(arg);
|
||||
if (llval == -1) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: invalid rateput %s",
|
||||
infile, (int)line, arg);
|
||||
continue;
|
||||
}
|
||||
curclass.maxrateput = rate;
|
||||
curclass.rateput = rate;
|
||||
curclass.maxrateput = llval;
|
||||
curclass.rateput = llval;
|
||||
|
||||
} else if (strcasecmp(word, "sanenames") == 0) {
|
||||
CONF_FLAG(sanenames);
|
||||
|
||||
} else if (strcasecmp(word, "timeout") == 0) {
|
||||
if (none || EMPTYSTR(arg))
|
||||
|
@ -451,12 +455,9 @@ parse_conf(const char *findclass)
|
|||
curclass.umask = umask;
|
||||
|
||||
} else if (strcasecmp(word, "upload") == 0) {
|
||||
if (none ||
|
||||
(!EMPTYSTR(arg) && strcasecmp(arg, "off") == 0)) {
|
||||
curclass.modify = 0;
|
||||
curclass.upload = 0;
|
||||
} else
|
||||
curclass.upload = 1;
|
||||
CONF_FLAG(upload);
|
||||
if (! CURCLASS_FLAGS_ISSET(upload))
|
||||
CURCLASS_FLAGS_CLR(modify);
|
||||
|
||||
} else {
|
||||
syslog(LOG_WARNING,
|
||||
|
@ -547,8 +548,10 @@ display_file(const char *file, int code)
|
|||
FILE *f;
|
||||
char *buf, *p, *cwd;
|
||||
size_t len;
|
||||
off_t lastnum;
|
||||
time_t now;
|
||||
|
||||
lastnum = 0;
|
||||
if (quietmessages)
|
||||
return (0);
|
||||
|
||||
|
@ -587,7 +590,9 @@ display_file(const char *file, int code)
|
|||
break;
|
||||
|
||||
case 'E':
|
||||
/* XXXX email address */
|
||||
if (! EMPTYSTR(emailaddr))
|
||||
cprintf(stdout, "%s",
|
||||
emailaddr);
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
|
@ -595,23 +600,35 @@ display_file(const char *file, int code)
|
|||
break;
|
||||
|
||||
case 'M':
|
||||
if (curclass.limit == -1)
|
||||
if (curclass.limit == -1) {
|
||||
cprintf(stdout, "unlimited");
|
||||
else
|
||||
lastnum = 0;
|
||||
} else {
|
||||
cprintf(stdout, "%d",
|
||||
curclass.limit);
|
||||
lastnum = curclass.limit;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
if (connections > 0)
|
||||
cprintf(stdout, "%d",
|
||||
connections);
|
||||
cprintf(stdout, "%d", connections);
|
||||
lastnum = connections;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
cprintf(stdout, "%s", remotehost);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (lastnum != 1)
|
||||
cprintf(stdout, "s");
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
if (lastnum != 1)
|
||||
cprintf(stdout, "S");
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
now = time(NULL);
|
||||
cprintf(stdout, "%.24s", ctime(&now));
|
||||
|
@ -810,19 +827,19 @@ do_conversion(const char *fname)
|
|||
}
|
||||
|
||||
/*
|
||||
* Convert the string `arg' to an int, which may have an optional SI suffix
|
||||
* (`b', `k', `m', `g'). Returns the number for success, -1 otherwise.
|
||||
* Convert the string `arg' to a long long, which may have an optional SI suffix
|
||||
* (`b', `k', `m', `g', `t'). Returns the number for success, -1 otherwise.
|
||||
*/
|
||||
int
|
||||
strsuftoi(const char *arg)
|
||||
LLT
|
||||
strsuftoll(const char *arg)
|
||||
{
|
||||
char *cp;
|
||||
long val;
|
||||
LLT val;
|
||||
|
||||
if (!isdigit((unsigned char)arg[0]))
|
||||
return (-1);
|
||||
|
||||
val = strtol(arg, &cp, 10);
|
||||
val = STRTOLL(arg, &cp, 10);
|
||||
if (cp != NULL) {
|
||||
if (cp[0] != '\0' && cp[1] != '\0')
|
||||
return (-1);
|
||||
|
@ -839,11 +856,14 @@ strsuftoi(const char *arg)
|
|||
case 'g':
|
||||
val <<= 30;
|
||||
break;
|
||||
case 't':
|
||||
val <<= 40;
|
||||
break;
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
if (val < 0 || val > INT_MAX)
|
||||
if (val < 0)
|
||||
return (-1);
|
||||
|
||||
return (val);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: extern.h,v 1.34 2000/11/15 02:32:30 lukem Exp $ */
|
||||
/* $NetBSD: extern.h,v 1.35 2000/11/16 13:15:13 lukem Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992, 1993
|
||||
|
@ -100,6 +100,24 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef NO_LONG_LONG
|
||||
# define LLF "%ld"
|
||||
# define LLFP(x) "%" x "ld"
|
||||
# define LLT long
|
||||
# define ULLF "%lu"
|
||||
# define ULLFP(x) "%" x "lu"
|
||||
# define ULLT unsigned long
|
||||
# define STRTOLL(x,y,z) strtol(x,y,z)
|
||||
#else
|
||||
# define LLF "%lld"
|
||||
# define LLFP(x) "%" x "lld"
|
||||
# define LLT long long
|
||||
# define ULLF "%llu"
|
||||
# define ULLFP(x) "%" x "llu"
|
||||
# define ULLT unsigned long long
|
||||
# define STRTOLL(x,y,z) strtoll(x,y,z)
|
||||
#endif
|
||||
|
||||
void blkfree(char **);
|
||||
void closedataconn(FILE *);
|
||||
char *conffilename(const char *);
|
||||
|
@ -152,17 +170,11 @@ void sizecmd(const char *);
|
|||
void statcmd(void);
|
||||
void statfilecmd(const char *);
|
||||
void store(const char *, const char *, int);
|
||||
int strsuftoi(const char *);
|
||||
LLT strsuftoll(const char *);
|
||||
void user(const char *);
|
||||
char *xstrdup(const char *);
|
||||
void yyerror(char *);
|
||||
|
||||
typedef enum {
|
||||
CLASS_GUEST,
|
||||
CLASS_CHROOT,
|
||||
CLASS_REAL
|
||||
} class_ft;
|
||||
|
||||
struct tab {
|
||||
char *name;
|
||||
short token;
|
||||
|
@ -180,32 +192,48 @@ struct ftpconv {
|
|||
char *command; /* Command to do the conversion */
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
CLASS_GUEST,
|
||||
CLASS_CHROOT,
|
||||
CLASS_REAL
|
||||
} class_ft;
|
||||
|
||||
typedef enum {
|
||||
FLAG_checkportcmd = 1<<0, /* Check port commands */
|
||||
FLAG_modify = 1<<1, /* Allow CHMOD, DELE, MKD, RMD, RNFR,
|
||||
UMASK */
|
||||
FLAG_passive = 1<<2, /* Allow PASV mode */
|
||||
FLAG_sanenames = 1<<3, /* Restrict names of uploaded files */
|
||||
FLAG_upload = 1<<4 /* As per modify, but also allow
|
||||
APPE, STOR, STOU */
|
||||
} classflag_t;
|
||||
|
||||
#define CURCLASS_FLAGS_SET(x) (curclass.flags |= (FLAG_ ## x))
|
||||
#define CURCLASS_FLAGS_CLR(x) (curclass.flags &= ~(FLAG_ ## x))
|
||||
#define CURCLASS_FLAGS_ISSET(x) (curclass.flags & (FLAG_ ## x))
|
||||
|
||||
struct ftpclass {
|
||||
int checkportcmd; /* Check PORT commands are valid */
|
||||
char *chroot; /* Directory to chroot(2) to at login */
|
||||
char *classname; /* Current class */
|
||||
struct ftpconv *conversions; /* List of conversions */
|
||||
char *display; /* Files to display upon chdir */
|
||||
char *display; /* File to display upon chdir */
|
||||
char *homedir; /* Directory to chdir(2) to at login */
|
||||
classflag_t flags; /* Flags; see classflag_t above */
|
||||
int limit; /* Max connections (-1 = unlimited) */
|
||||
char *limitfile; /* File to display if limit reached */
|
||||
int maxrateget; /* Maximum get transfer rate throttle */
|
||||
int maxrateput; /* Maximum put transfer rate throttle */
|
||||
LLT maxfilesize; /* Maximum file size of uploads */
|
||||
LLT maxrateget; /* Maximum get transfer rate throttle */
|
||||
LLT maxrateput; /* Maximum put transfer rate throttle */
|
||||
unsigned int maxtimeout; /* Maximum permitted timeout */
|
||||
int modify; /* Allow CHMOD, DELE, MKD, RMD, RNFR,
|
||||
UMASK */
|
||||
char *motd; /* MotD file to display after login */
|
||||
char *notify; /* Files to notify about upon chdir */
|
||||
int passive; /* Allow PASV mode */
|
||||
int portmin; /* Minumum port for passive mode */
|
||||
int portmax; /* Maximum port for passive mode */
|
||||
int rateget; /* Get (RETR) transfer rate throttle */
|
||||
int rateput; /* Put (STOR) transfer rate throttle */
|
||||
LLT rateget; /* Get (RETR) transfer rate throttle */
|
||||
LLT rateput; /* Put (STOR) transfer rate throttle */
|
||||
unsigned int timeout; /* Default timeout */
|
||||
class_ft type; /* Class type */
|
||||
mode_t umask; /* Umask to use */
|
||||
int upload; /* As per modify, but also allow
|
||||
APPE, STOR, STOU */
|
||||
};
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
@ -255,6 +283,7 @@ GLOBAL int connections;
|
|||
GLOBAL struct ftpclass curclass;
|
||||
GLOBAL int debug;
|
||||
GLOBAL jmp_buf errcatch;
|
||||
GLOBAL char *emailaddr;
|
||||
GLOBAL int form;
|
||||
GLOBAL int gidcount; /* number of entries in gidlist[] */
|
||||
GLOBAL gid_t gidlist[NGROUPS_MAX];
|
||||
|
@ -319,21 +348,3 @@ extern struct tab cmdtab[];
|
|||
#ifndef IPPORT_ANONMAX
|
||||
# define IPPORT_ANONMAX 65535
|
||||
#endif
|
||||
|
||||
#ifdef NO_LONG_LONG
|
||||
# define LLF "%ld"
|
||||
# define LLFP(x) "%" x "ld"
|
||||
# define LLT long
|
||||
# define ULLF "%lu"
|
||||
# define ULLFP(x) "%" x "lu"
|
||||
# define ULLT unsigned long
|
||||
# define STRTOLL(x,y,z) strtol(x,y,z)
|
||||
#else
|
||||
# define LLF "%lld"
|
||||
# define LLFP(x) "%" x "lld"
|
||||
# define LLT long long
|
||||
# define ULLF "%llu"
|
||||
# define ULLFP(x) "%" x "llu"
|
||||
# define ULLT unsigned long long
|
||||
# define STRTOLL(x,y,z) strtoll(x,y,z)
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ftpcmd.y,v 1.55 2000/11/15 02:32:30 lukem Exp $ */
|
||||
/* $NetBSD: ftpcmd.y,v 1.56 2000/11/16 13:15:14 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.55 2000/11/15 02:32:30 lukem Exp $");
|
||||
__RCSID("$NetBSD: ftpcmd.y,v 1.56 2000/11/16 13:15:14 lukem Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -165,7 +165,7 @@ char *fromname;
|
|||
%token <s> ALL
|
||||
%token <i> NUMBER
|
||||
|
||||
%type <i> check_login check_modify check_upload octal_number byte_size
|
||||
%type <i> check_login octal_number byte_size
|
||||
%type <i> struct_code mode_code type_code form_code decimal_integer
|
||||
%type <s> pathstring pathname password username
|
||||
%type <s> mechanism_name base64data prot_code
|
||||
|
@ -282,7 +282,7 @@ cmd
|
|||
| PASV check_login CRLF
|
||||
{
|
||||
if ($2) {
|
||||
if (curclass.passive)
|
||||
if (CURCLASS_FLAGS_ISSET(passive))
|
||||
passive();
|
||||
else
|
||||
reply(500, "PASV mode not available.");
|
||||
|
@ -398,28 +398,28 @@ cmd
|
|||
free($4);
|
||||
}
|
||||
|
||||
| STOR check_upload SP pathname CRLF
|
||||
| STOR SP pathname CRLF
|
||||
{
|
||||
if ($2 && $4 != NULL)
|
||||
store($4, "w", 0);
|
||||
if ($4 != NULL)
|
||||
free($4);
|
||||
if (check_write($3, 1))
|
||||
store($3, "w", 0);
|
||||
if ($3 != NULL)
|
||||
free($3);
|
||||
}
|
||||
|
||||
| STOU check_upload SP pathname CRLF
|
||||
| STOU SP pathname CRLF
|
||||
{
|
||||
if ($2 && $4 != NULL)
|
||||
store($4, "w", 1);
|
||||
if ($4 != NULL)
|
||||
free($4);
|
||||
if (check_write($3, 1))
|
||||
store($3, "w", 1);
|
||||
if ($3 != NULL)
|
||||
free($3);
|
||||
}
|
||||
|
||||
| APPE check_upload SP pathname CRLF
|
||||
| APPE SP pathname CRLF
|
||||
{
|
||||
if ($2 && $4 != NULL)
|
||||
store($4, "a", 0);
|
||||
if ($4 != NULL)
|
||||
free($4);
|
||||
if (check_write($3, 1))
|
||||
store($3, "a", 0);
|
||||
if ($3 != NULL)
|
||||
free($3);
|
||||
}
|
||||
|
||||
| ALLO check_login SP NUMBER CRLF
|
||||
|
@ -434,18 +434,19 @@ cmd
|
|||
reply(202, "ALLO command ignored.");
|
||||
}
|
||||
|
||||
| RNTO check_login SP pathname CRLF
|
||||
| RNTO SP pathname CRLF
|
||||
{
|
||||
if ($2) {
|
||||
if (check_write($3, 0)) {
|
||||
if (fromname) {
|
||||
renamecmd(fromname, $4);
|
||||
renamecmd(fromname, $3);
|
||||
free(fromname);
|
||||
fromname = NULL;
|
||||
} else {
|
||||
reply(503, "Bad sequence of commands.");
|
||||
}
|
||||
}
|
||||
free($4);
|
||||
if ($3 != NULL)
|
||||
free($3);
|
||||
}
|
||||
|
||||
| ABOR check_login CRLF
|
||||
|
@ -454,28 +455,28 @@ cmd
|
|||
reply(225, "ABOR command successful.");
|
||||
}
|
||||
|
||||
| DELE check_modify SP pathname CRLF
|
||||
| DELE SP pathname CRLF
|
||||
{
|
||||
if ($2 && $4 != NULL)
|
||||
delete($4);
|
||||
if ($4 != NULL)
|
||||
free($4);
|
||||
if (check_write($3, 0))
|
||||
delete($3);
|
||||
if ($3 != NULL)
|
||||
free($3);
|
||||
}
|
||||
|
||||
| RMD check_modify SP pathname CRLF
|
||||
| RMD SP pathname CRLF
|
||||
{
|
||||
if ($2 && $4 != NULL)
|
||||
removedir($4);
|
||||
if ($4 != NULL)
|
||||
free($4);
|
||||
if (check_write($3, 0))
|
||||
removedir($3);
|
||||
if ($3 != NULL)
|
||||
free($3);
|
||||
}
|
||||
|
||||
| MKD check_modify SP pathname CRLF
|
||||
| MKD SP pathname CRLF
|
||||
{
|
||||
if ($2 && $4 != NULL)
|
||||
makedir($4);
|
||||
if ($4 != NULL)
|
||||
free($4);
|
||||
if (check_write($3, 0))
|
||||
makedir($3);
|
||||
if ($3 != NULL)
|
||||
free($3);
|
||||
}
|
||||
|
||||
| PWD check_login CRLF
|
||||
|
@ -522,19 +523,19 @@ cmd
|
|||
help(sitetab, NULL);
|
||||
}
|
||||
|
||||
| SITE SP CHMOD check_modify SP octal_number SP pathname CRLF
|
||||
| SITE SP CHMOD SP octal_number SP pathname CRLF
|
||||
{
|
||||
if ($4 && ($8 != NULL)) {
|
||||
if ($6 > 0777)
|
||||
if (check_write($7, 0)) {
|
||||
if ($5 > 0777)
|
||||
reply(501,
|
||||
"CHMOD: Mode value must be between 0 and 0777");
|
||||
else if (chmod($8, $6) < 0)
|
||||
perror_reply(550, $8);
|
||||
else if (chmod($7, $5) < 0)
|
||||
perror_reply(550, $7);
|
||||
else
|
||||
reply(200, "CHMOD command successful.");
|
||||
}
|
||||
if ($8 != NULL)
|
||||
free($8);
|
||||
if ($7 != NULL)
|
||||
free($7);
|
||||
}
|
||||
|
||||
| SITE SP HELP SP STRING CRLF
|
||||
|
@ -572,30 +573,32 @@ cmd
|
|||
| SITE SP RATEGET check_login CRLF
|
||||
{
|
||||
if ($4) {
|
||||
reply(200, "Current RATEGET is %d bytes/sec",
|
||||
curclass.rateget);
|
||||
reply(200,
|
||||
"Current RATEGET is " LLF " bytes/sec",
|
||||
(LLT)curclass.rateget);
|
||||
}
|
||||
}
|
||||
|
||||
| SITE SP RATEGET check_login SP STRING CRLF
|
||||
{
|
||||
char *p = $6;
|
||||
int rate;
|
||||
LLT rate;
|
||||
|
||||
if ($4) {
|
||||
rate = strsuftoi(p);
|
||||
rate = strsuftoll(p);
|
||||
if (rate == -1)
|
||||
reply(501, "Invalid RATEGET %s", p);
|
||||
else if (curclass.maxrateget &&
|
||||
rate > curclass.maxrateget)
|
||||
reply(501,
|
||||
"RATEGET %d is larger than maximum RATEGET %d",
|
||||
rate, curclass.maxrateget);
|
||||
"RATEGET " LLF " is larger than maximum RATEGET " LLF,
|
||||
(LLT)rate,
|
||||
(LLT)curclass.maxrateget);
|
||||
else {
|
||||
curclass.rateget = rate;
|
||||
reply(200,
|
||||
"RATEGET set to %d bytes/sec",
|
||||
curclass.rateget);
|
||||
"RATEGET set to " LLF " bytes/sec",
|
||||
(LLT)curclass.rateget);
|
||||
}
|
||||
}
|
||||
free($6);
|
||||
|
@ -604,30 +607,32 @@ cmd
|
|||
| SITE SP RATEPUT check_login CRLF
|
||||
{
|
||||
if ($4) {
|
||||
reply(200, "Current RATEPUT is %d bytes/sec",
|
||||
curclass.rateput);
|
||||
reply(200,
|
||||
"Current RATEPUT is " LLF " bytes/sec",
|
||||
(LLT)curclass.rateput);
|
||||
}
|
||||
}
|
||||
|
||||
| SITE SP RATEPUT check_login SP STRING CRLF
|
||||
{
|
||||
char *p = $6;
|
||||
int rate;
|
||||
LLT rate;
|
||||
|
||||
if ($4) {
|
||||
rate = strsuftoi(p);
|
||||
rate = strsuftoll(p);
|
||||
if (rate == -1)
|
||||
reply(501, "Invalid RATEPUT %s", p);
|
||||
else if (curclass.maxrateput &&
|
||||
rate > curclass.maxrateput)
|
||||
reply(501,
|
||||
"RATEPUT %d is larger than maximum RATEPUT %d",
|
||||
rate, curclass.maxrateput);
|
||||
"RATEPUT " LLF " is larger than maximum RATEPUT " LLF,
|
||||
(LLT)rate,
|
||||
(LLT)curclass.maxrateput);
|
||||
else {
|
||||
curclass.rateput = rate;
|
||||
reply(200,
|
||||
"RATEPUT set to %d bytes/sec",
|
||||
curclass.rateput);
|
||||
"RATEPUT set to " LLF " bytes/sec",
|
||||
(LLT)curclass.rateput);
|
||||
}
|
||||
}
|
||||
free($6);
|
||||
|
@ -644,11 +649,11 @@ cmd
|
|||
}
|
||||
}
|
||||
|
||||
| SITE SP UMASK check_modify SP octal_number CRLF
|
||||
| SITE SP UMASK check_login SP octal_number CRLF
|
||||
{
|
||||
int oldmask;
|
||||
|
||||
if ($4) {
|
||||
if ($4 && CURCLASS_FLAGS_ISSET(modify)) {
|
||||
if (($6 == -1) || ($6 > 0777)) {
|
||||
reply(501, "Bad UMASK value");
|
||||
} else {
|
||||
|
@ -854,21 +859,20 @@ rcmd
|
|||
{
|
||||
if ($2) {
|
||||
fromname = NULL;
|
||||
restart_point = $4; /* XXX $3 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);
|
||||
}
|
||||
}
|
||||
|
||||
| RNFR check_modify SP pathname CRLF
|
||||
| RNFR SP pathname CRLF
|
||||
{
|
||||
restart_point = (off_t) 0;
|
||||
if ($2 && $4) {
|
||||
fromname = renamefrom($4);
|
||||
}
|
||||
if ($4)
|
||||
free($4);
|
||||
if (check_write($3, 0))
|
||||
fromname = renamefrom($3);
|
||||
if ($3 != NULL)
|
||||
free($3);
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -1151,45 +1155,6 @@ check_login
|
|||
}
|
||||
;
|
||||
|
||||
check_modify
|
||||
: /* empty */
|
||||
{
|
||||
if (logged_in) {
|
||||
if (curclass.modify)
|
||||
$$ = 1;
|
||||
else {
|
||||
reply(502,
|
||||
"No permission to use this command.");
|
||||
$$ = 0;
|
||||
hasyyerrored = 1;
|
||||
}
|
||||
} else {
|
||||
reply(530, "Please login with USER and PASS.");
|
||||
$$ = 0;
|
||||
hasyyerrored = 1;
|
||||
}
|
||||
}
|
||||
|
||||
check_upload
|
||||
: /* empty */
|
||||
{
|
||||
if (logged_in) {
|
||||
if (curclass.upload)
|
||||
$$ = 1;
|
||||
else {
|
||||
reply(502,
|
||||
"No permission to use this command.");
|
||||
$$ = 0;
|
||||
hasyyerrored = 1;
|
||||
}
|
||||
} else {
|
||||
reply(530, "Please login with USER and PASS.");
|
||||
$$ = 0;
|
||||
hasyyerrored = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
%%
|
||||
|
||||
#define CMD 0 /* beginning of command */
|
||||
|
@ -1290,13 +1255,55 @@ struct tab sitetab[] = {
|
|||
{ NULL, 0, 0, 0, NULL }
|
||||
};
|
||||
|
||||
static void help(struct tab *, const char *);
|
||||
static void port_check(const char *, int);
|
||||
static void toolong(int);
|
||||
static int yylex(void);
|
||||
static int check_write(const char *, int);
|
||||
static void help(struct tab *, const char *);
|
||||
static void port_check(const char *, int);
|
||||
static void toolong(int);
|
||||
static int yylex(void);
|
||||
|
||||
extern int epsvall;
|
||||
|
||||
/*
|
||||
* Check if a filename is allowed to be modified (isupload == 0) or
|
||||
* uploaded (isupload == 1), and if necessary, check the filename is `sane'.
|
||||
*/
|
||||
static int
|
||||
check_write(const char *file, int isupload)
|
||||
{
|
||||
if (file == NULL)
|
||||
return (0);
|
||||
if (! logged_in) {
|
||||
reply(530, "Please login with USER and PASS.");
|
||||
return (0);
|
||||
}
|
||||
/* checking modify */
|
||||
if (! isupload && ! CURCLASS_FLAGS_ISSET(modify)) {
|
||||
reply(502, "No permission to use this command.");
|
||||
return (0);
|
||||
}
|
||||
/* checking upload */
|
||||
if (isupload && ! CURCLASS_FLAGS_ISSET(upload)) {
|
||||
reply(502, "No permission to use this command.");
|
||||
return (0);
|
||||
}
|
||||
/* checking sanenames */
|
||||
if (CURCLASS_FLAGS_ISSET(sanenames)) {
|
||||
const char *p;
|
||||
|
||||
if (file[0] == '.')
|
||||
goto insane_name;
|
||||
for (p = file; *p; p++) {
|
||||
if (isalnum(*p) || *p == '-' || *p == '+' ||
|
||||
*p == ',' || *p == '.' || *p == '_')
|
||||
continue;
|
||||
insane_name:
|
||||
reply(553, "File name `%s' not allowed.", file);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
struct tab *
|
||||
lookup(struct tab *p, const char *cmd)
|
||||
{
|
||||
|
@ -1750,7 +1757,7 @@ port_check(const char *cmd, int family)
|
|||
goto port_check_fail;
|
||||
|
||||
/* be paranoid, if told so */
|
||||
if (curclass.checkportcmd) {
|
||||
if (CURCLASS_FLAGS_ISSET(checkportcmd)) {
|
||||
if ((ntohs(data_dest.su_port) < IPPORT_RESERVED) ||
|
||||
(data_dest.su_len != his_addr.su_len))
|
||||
goto port_check_fail;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: ftpd.8,v 1.60 2000/07/28 12:54:01 lukem Exp $
|
||||
.\" $NetBSD: ftpd.8,v 1.61 2000/11/16 13:15:14 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 July 26, 2000
|
||||
.Dd November 16, 2000
|
||||
.Dt FTPD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -76,11 +76,13 @@
|
|||
Internet File Transfer Protocol server
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl dHlrsUW
|
||||
.Op Fl dHlqQrsuUwW
|
||||
.Op Fl a Ar anondir
|
||||
.Op Fl c Ar confdir
|
||||
.Op Fl C Ar user
|
||||
.Op Fl e Ar emailaddr
|
||||
.Op Fl h Ar hostname
|
||||
.Op Fl P Ar dataport
|
||||
.Op Fl V Ar version
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
|
@ -119,6 +121,13 @@ This can be useful for testing configurations.
|
|||
.It Fl d
|
||||
Debugging information is written to the syslog using
|
||||
.Dv LOG_FTP .
|
||||
.It Fl e Ar emailaddr
|
||||
Use
|
||||
.Ar emailaddr
|
||||
for the
|
||||
.Dq "\&%E"
|
||||
escape sequence (see
|
||||
.Sx Display file escape sequences )
|
||||
.It Fl h Ar hostname
|
||||
Explicitly set the hostname to advertise as to
|
||||
.Ar hostname .
|
||||
|
@ -149,7 +158,24 @@ 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
|
||||
their filename arguments are also logged.
|
||||
their file name arguments are also logged.
|
||||
.It Fl P Ar dataport
|
||||
Use
|
||||
.Ar dataport
|
||||
as the data port, overriding the default of using the port one less
|
||||
that the port
|
||||
.Nm
|
||||
is listening on.
|
||||
.It Fl q
|
||||
Enable the use of pid files for keeping track of the number of logged-in
|
||||
users per class.
|
||||
This is the default.
|
||||
.It Fl Q
|
||||
Disable the use of pid files for keeping track of the number of logged-in
|
||||
users per class.
|
||||
This may reduce the load on heavily loaded
|
||||
.Tn FTP
|
||||
servers.
|
||||
.It Fl r
|
||||
Permanently drop root privileges once the user is logged in.
|
||||
The use of this option may result in the server using a port other
|
||||
|
@ -163,13 +189,19 @@ See
|
|||
below for more details.
|
||||
.It Fl s
|
||||
Require a secure authentication mechanism like Kerberos or S/Key to be used.
|
||||
.It Fl U
|
||||
Each concurrent
|
||||
.It Fl u
|
||||
Log each concurrent
|
||||
.Tn FTP
|
||||
session is logged to the file
|
||||
session to
|
||||
.Pa /var/run/utmp ,
|
||||
making them visible to commands such as
|
||||
.Xr who 1 .
|
||||
.It Fl U
|
||||
Don't log each concurrent
|
||||
.Tn FTP
|
||||
session to
|
||||
.Pa /var/run/utmp .
|
||||
This is the default.
|
||||
.It Fl V Ar version
|
||||
Use
|
||||
.Ar version
|
||||
|
@ -183,14 +215,19 @@ If
|
|||
is empty or
|
||||
.Sq -
|
||||
then don't display any version information.
|
||||
.It Fl W
|
||||
By default each
|
||||
.It Fl w
|
||||
Log each
|
||||
.Tn FTP
|
||||
session is logged to
|
||||
session to
|
||||
.Pa /var/log/wtmp ,
|
||||
making them visible to commands such as
|
||||
.Xr last 1 .
|
||||
This option prevents that from occurring.
|
||||
This is the default.
|
||||
.It Fl W
|
||||
Don't log each
|
||||
.Tn FTP
|
||||
session to
|
||||
.Pa /var/log/wtmp .
|
||||
.El
|
||||
.Pp
|
||||
The file
|
||||
|
@ -443,6 +480,9 @@ The supported escape strings are:
|
|||
Class name.
|
||||
.It "\&%C"
|
||||
Current working directory.
|
||||
.It "\&%E"
|
||||
Email address given with
|
||||
.Fl e .
|
||||
.It "\&%L"
|
||||
Local hostname.
|
||||
.It "\&%M"
|
||||
|
@ -454,6 +494,24 @@ if there's no limit.
|
|||
Current number of users for this class.
|
||||
.It "\&%R"
|
||||
Remote hostname.
|
||||
.It "\&%s"
|
||||
If the result of the most recent
|
||||
.Dq "\&%M"
|
||||
or
|
||||
.Dq "\&%N"
|
||||
was not
|
||||
.Dq Li 1 ,
|
||||
print an
|
||||
.Dq s .
|
||||
.It "\&%S"
|
||||
If the result of the most recent
|
||||
.Dq "\&%M"
|
||||
or
|
||||
.Dq "\&%N"
|
||||
was not
|
||||
.Dq Li 1 ,
|
||||
print an
|
||||
.Dq S .
|
||||
.It "\&%T"
|
||||
Current time.
|
||||
.It "\&%U"
|
||||
|
@ -532,9 +590,15 @@ users to be able to see the names of the
|
|||
files in this directory the permissions should be 770, otherwise
|
||||
they should be 370.
|
||||
.Pp
|
||||
Anonymous users will be able to upload files to this directory,
|
||||
but they will not be able to download them, delete them, or overwrite
|
||||
them, due to the umask and disabling of the commands mentioned
|
||||
The following
|
||||
.Xr ftpd.conf 5
|
||||
directives should be used:
|
||||
.Dl "modify guest off"
|
||||
.Dl "umask guest 0707"
|
||||
.Pp
|
||||
This will result in anonymous users being able to upload files to this
|
||||
directory, but they will not be able to download them, delete them, or
|
||||
overwrite them, due to the umask and disabling of the commands mentioned
|
||||
above.
|
||||
.It Pa ~ftp/tmp
|
||||
This directory is used to create temporary files which contain
|
||||
|
@ -596,10 +660,10 @@ State file of logged-in processes for the
|
|||
.Nm
|
||||
class
|
||||
.Sq CLASS .
|
||||
.It Pa /var/log/wtmp
|
||||
Login history database.
|
||||
.It Pa /var/run/utmp
|
||||
List of logged-in users on the system.
|
||||
.It Pa /var/log/wtmp
|
||||
Login history database.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr ftp 1 ,
|
||||
|
@ -696,7 +760,8 @@ communicate back to the client for the
|
|||
.Sy LPTR ,
|
||||
and
|
||||
.Sy PORT
|
||||
commands.
|
||||
commands, unless overridden with
|
||||
.Fl P Ar dataport .
|
||||
As the default port for
|
||||
.Nm
|
||||
(21) is a privileged port below
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ftpd.c,v 1.110 2000/11/15 04:07:07 itojun Exp $ */
|
||||
/* $NetBSD: ftpd.c,v 1.111 2000/11/16 13:15:14 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.110 2000/11/15 04:07:07 itojun Exp $");
|
||||
__RCSID("$NetBSD: ftpd.c,v 1.111 2000/11/16 13:15:14 lukem Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -172,6 +172,8 @@ struct passwd *pw;
|
|||
int sflag;
|
||||
int stru; /* avoid C keyword */
|
||||
int mode;
|
||||
int dataport; /* use specific data port */
|
||||
int dopidfile; /* maintain pid file */
|
||||
int doutmp; /* update utmp file */
|
||||
int dowtmp; /* update wtmp file */
|
||||
int dropprivs; /* if privileges should or have been dropped */
|
||||
|
@ -181,8 +183,8 @@ off_t byte_count;
|
|||
static char ttyline[20];
|
||||
static struct utmp utmp; /* for utmp */
|
||||
|
||||
static char *anondir = NULL;
|
||||
static char confdir[MAXPATHLEN];
|
||||
static const char *anondir = NULL;
|
||||
static const char *confdir = NULL;
|
||||
|
||||
#if defined(KERBEROS) || defined(KERBEROS5)
|
||||
int has_ccache = 0;
|
||||
|
@ -236,31 +238,41 @@ main(int argc, char *argv[])
|
|||
#ifdef KERBEROS5
|
||||
krb5_error_code kerror;
|
||||
#endif
|
||||
char *p;
|
||||
|
||||
connections = 1;
|
||||
debug = 0;
|
||||
logging = 0;
|
||||
pdata = -1;
|
||||
sflag = 0;
|
||||
dataport = 0;
|
||||
dopidfile = 1; /* default: DO use a pid file to count users */
|
||||
doutmp = 0; /* default: don't log to utmp */
|
||||
dowtmp = 1; /* default: DO log to wtmp */
|
||||
dropprivs = 0;
|
||||
mapped = 0;
|
||||
usedefault = 1;
|
||||
(void)strcpy(confdir, _DEFAULT_CONFDIR);
|
||||
emailaddr = NULL;
|
||||
hostname[0] = '\0';
|
||||
homedir[0] = '\0';
|
||||
gidcount = 0;
|
||||
|
||||
version = FTPD_VERSION;
|
||||
while ((ch = getopt(argc, argv, "a:c:C:dh:Hlrst:T:u:UvV:W")) != -1) {
|
||||
|
||||
/*
|
||||
* 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:HlP:qQrst:T:uUvV:wW"))
|
||||
!= -1) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
anondir = optarg;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
(void)strlcpy(confdir, optarg, sizeof(confdir));
|
||||
confdir = optarg;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
|
@ -273,6 +285,10 @@ main(int argc, char *argv[])
|
|||
debug = 1;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
emailaddr = optarg;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
strlcpy(hostname, optarg, sizeof(hostname));
|
||||
break;
|
||||
|
@ -287,6 +303,24 @@ main(int argc, char *argv[])
|
|||
logging++; /* > 1 == extra logging */
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
dataport = (int)strtol(optarg, &p, 10);
|
||||
if (*p != '\0' || dataport < IPPORT_RESERVED ||
|
||||
dataport > IPPORT_ANONMAX) {
|
||||
syslog(LOG_WARNING, "Invalid dataport %s",
|
||||
optarg);
|
||||
dataport = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
dopidfile = 1;
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
dopidfile = 0;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
dropprivs = 1;
|
||||
break;
|
||||
|
@ -297,15 +331,19 @@ main(int argc, char *argv[])
|
|||
|
||||
case 't':
|
||||
case 'T':
|
||||
case 'u':
|
||||
warnx("-%c has been deprecated in favour of ftpd.conf",
|
||||
syslog(LOG_ERR,
|
||||
"-%c has been deprecated in favour of ftpd.conf",
|
||||
ch);
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
case 'u':
|
||||
doutmp = 1;
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
doutmp = 0;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
if (EMPTYSTR(optarg) || strcmp(optarg, "-") == 0)
|
||||
version = NULL;
|
||||
|
@ -313,6 +351,10 @@ main(int argc, char *argv[])
|
|||
version = xstrdup(optarg);
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
dowtmp = 1;
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
dowtmp = 0;
|
||||
break;
|
||||
|
@ -320,16 +362,13 @@ main(int argc, char *argv[])
|
|||
default:
|
||||
if (optopt == 'a' || optopt == 'C')
|
||||
exit(1);
|
||||
warnx("unknown flag -%c ignored", optopt);
|
||||
syslog(LOG_ERR, "unknown flag -%c ignored", optopt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (EMPTYSTR(confdir))
|
||||
confdir = _DEFAULT_CONFDIR;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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) {
|
||||
|
@ -938,7 +977,9 @@ pass(const char *passwd)
|
|||
|
||||
/* parse ftpd.conf, setting up various parameters */
|
||||
parse_conf(class);
|
||||
count_users();
|
||||
connections = 1;
|
||||
if (dopidfile)
|
||||
count_users();
|
||||
if (curclass.limit != -1 && connections > curclass.limit) {
|
||||
if (! EMPTYSTR(curclass.limitfile))
|
||||
(void)display_file(conffilename(curclass.limitfile),
|
||||
|
@ -1090,9 +1131,11 @@ pass(const char *passwd)
|
|||
}
|
||||
(void) umask(curclass.umask);
|
||||
goto cleanuppass;
|
||||
|
||||
bad:
|
||||
/* Forget all about it... */
|
||||
end_login();
|
||||
|
||||
cleanuppass:
|
||||
if (class)
|
||||
free(class);
|
||||
|
@ -1338,7 +1381,10 @@ getdatasock(const char *mode)
|
|||
* would be < IPPORT_RESERVED, use a random port
|
||||
* instead.
|
||||
*/
|
||||
port = ntohs(ctrl_addr.su_port) - 1;
|
||||
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);
|
||||
|
@ -1632,6 +1678,7 @@ static int
|
|||
receive_data(FILE *instr, FILE *outstr)
|
||||
{
|
||||
int c, bare_lfs, netfd, filefd, rval;
|
||||
off_t byteswritten;
|
||||
char buf[BUFSIZ];
|
||||
#ifdef __GNUC__
|
||||
(void) &bare_lfs;
|
||||
|
@ -1640,9 +1687,19 @@ receive_data(FILE *instr, FILE *outstr)
|
|||
bare_lfs = 0;
|
||||
transflag = 1;
|
||||
rval = -1;
|
||||
byteswritten = 0;
|
||||
if (setjmp(urgcatch))
|
||||
goto cleanup_recv_data;
|
||||
|
||||
#define FILESIZECHECK(x) \
|
||||
do { \
|
||||
if (curclass.maxfilesize != -1 && \
|
||||
(x) > curclass.maxfilesize) { \
|
||||
errno = EFBIG; \
|
||||
goto file_err; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
switch (type) {
|
||||
|
||||
case TYPE_I:
|
||||
|
@ -1662,8 +1719,9 @@ receive_data(FILE *instr, FILE *outstr)
|
|||
if ((c = read(netfd, buf,
|
||||
MIN(sizeof(buf), bufrem))) <= 0)
|
||||
goto recvdone;
|
||||
FILESIZECHECK(byte_count + c);
|
||||
if ((d = write(filefd, buf, c)) != c)
|
||||
goto recvdone;
|
||||
goto file_err;
|
||||
(void) alarm(curclass.timeout);
|
||||
bufrem -= c;
|
||||
byte_count += c;
|
||||
|
@ -1679,6 +1737,7 @@ receive_data(FILE *instr, FILE *outstr)
|
|||
}
|
||||
} else {
|
||||
while ((c = read(netfd, buf, sizeof(buf))) > 0) {
|
||||
FILESIZECHECK(byte_count + c);
|
||||
if (write(filefd, buf, c) != c)
|
||||
goto file_err;
|
||||
(void) alarm(curclass.timeout);
|
||||
|
@ -1723,13 +1782,17 @@ receive_data(FILE *instr, FILE *outstr)
|
|||
total_bytes++;
|
||||
if ((byte_count % 4096) == 0)
|
||||
(void) alarm(curclass.timeout);
|
||||
byteswritten++;
|
||||
FILESIZECHECK(byteswritten);
|
||||
(void) putc ('\r', outstr);
|
||||
if (c == '\0' || c == EOF)
|
||||
goto contin2;
|
||||
}
|
||||
}
|
||||
byteswritten++;
|
||||
FILESIZECHECK(byteswritten);
|
||||
(void) putc(c, outstr);
|
||||
contin2: ;
|
||||
contin2: ;
|
||||
}
|
||||
(void) alarm(0);
|
||||
fflush(outstr);
|
||||
|
@ -1750,6 +1813,7 @@ receive_data(FILE *instr, FILE *outstr)
|
|||
reply(550, "Unimplemented TYPE %d in receive_data", type);
|
||||
goto cleanup_recv_data;
|
||||
}
|
||||
#undef FILESIZECHECK(x)
|
||||
|
||||
data_err:
|
||||
(void) alarm(0);
|
||||
|
@ -1925,7 +1989,7 @@ statcmd(void)
|
|||
reply(0, "Class: %s, type: %s",
|
||||
curclass.classname, CURCLASSTYPE);
|
||||
reply(0, "Check PORT/LPRT commands: %sabled",
|
||||
curclass.checkportcmd ? "en" : "dis");
|
||||
CURCLASS_FLAGS_ISSET(checkportcmd) ? "en" : "dis");
|
||||
if (! EMPTYSTR(curclass.display))
|
||||
reply(0, "Display file: %s", curclass.display);
|
||||
if (! EMPTYSTR(curclass.notify))
|
||||
|
@ -1938,30 +2002,39 @@ statcmd(void)
|
|||
else
|
||||
reply(0, "Maximum connections: %d", curclass.limit);
|
||||
if (curclass.limitfile)
|
||||
reply(0, "Connection limit exceeded file: %s",
|
||||
reply(0, "Connection limit exceeded message file: %s",
|
||||
curclass.limitfile);
|
||||
if (! EMPTYSTR(curclass.chroot))
|
||||
reply(0, "Chroot format: %s", curclass.chroot);
|
||||
if (! EMPTYSTR(curclass.homedir))
|
||||
reply(0, "Homedir format: %s", curclass.homedir);
|
||||
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", curclass.motd);
|
||||
reply(0,
|
||||
"Modify commands (CHMOD, DELE, MKD, RMD, RNFR, UMASK): %sabled",
|
||||
curclass.modify ? "en" : "dis");
|
||||
CURCLASS_FLAGS_ISSET(modify) ? "en" : "dis");
|
||||
reply(0, "Upload commands (APPE, STOR, STOU): %sabled",
|
||||
curclass.upload ? "en" : "dis");
|
||||
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");
|
||||
if (curclass.portmin && curclass.portmax)
|
||||
reply(0, "PASV port range: %d - %d",
|
||||
curclass.portmin, curclass.portmax);
|
||||
if (curclass.rateget)
|
||||
reply(0, "Rate get limit: %d bytes/sec",
|
||||
curclass.rateget);
|
||||
reply(0, "Rate get limit: " LLF " bytes/sec",
|
||||
(LLT)curclass.rateget);
|
||||
else
|
||||
reply(0, "Rate get limit: disabled");
|
||||
if (curclass.rateput)
|
||||
reply(0, "Rate put limit: %d bytes/sec",
|
||||
curclass.rateput);
|
||||
reply(0, "Rate put limit: " LLF " bytes/sec",
|
||||
(LLT)curclass.rateput);
|
||||
else
|
||||
reply(0, "Rate put limit: disabled");
|
||||
reply(0, "Umask: %.04o", curclass.umask);
|
||||
|
@ -2262,8 +2335,7 @@ long_passive(char *cmd, int pf)
|
|||
|
||||
if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
|
||||
/*
|
||||
* XXX
|
||||
* only EPRT/EPSV ready clients will understand this
|
||||
* XXX: only EPRT/EPSV ready clients will understand this
|
||||
*/
|
||||
if (strcmp(cmd, "EPSV") != 0)
|
||||
reply(501, "Network protocol mismatch"); /*XXX*/
|
||||
|
@ -2364,7 +2436,7 @@ extended_port(const char *arg)
|
|||
p = q;
|
||||
}
|
||||
|
||||
/* some more sanity check */
|
||||
/* some more sanity checks */
|
||||
p = NULL;
|
||||
(void)strtoul(result[2], &p, 10);
|
||||
if (!*result[2] || *p)
|
||||
|
@ -2389,7 +2461,7 @@ extended_port(const char *arg)
|
|||
memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
|
||||
if (his_addr.su_family == AF_INET6 &&
|
||||
data_dest.su_family == AF_INET6) {
|
||||
/* XXX more sanity checks! */
|
||||
/* XXX: more sanity checks! */
|
||||
data_dest.su_scope_id = his_addr.su_scope_id;
|
||||
}
|
||||
|
||||
|
@ -2431,7 +2503,7 @@ epsv_protounsupp(const char *message)
|
|||
|
||||
proto = af2epsvproto(ctrl_addr.su_family);
|
||||
if (proto < 0)
|
||||
reply(501, "%s", message); /*XXX*/
|
||||
reply(501, "%s", message); /* XXX */
|
||||
else
|
||||
reply(522, "%s, use (%d)", message, proto);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: ftpd.conf.5,v 1.13 2000/11/07 06:58:08 lukem Exp $
|
||||
.\" $NetBSD: ftpd.conf.5,v 1.14 2000/11/16 13:15:14 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 7, 2000
|
||||
.Dd November 16, 2000
|
||||
.Dt FTPD.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -58,7 +58,7 @@ This allows
|
|||
.Sq wildcard
|
||||
entries to define defaults, and then have class-specific overrides.
|
||||
.Pp
|
||||
A directive line has the format
|
||||
A directive line has the format:
|
||||
.Dl command class [arguments]
|
||||
.Pp
|
||||
A
|
||||
|
@ -211,7 +211,7 @@ Valid types are:
|
|||
(directory).
|
||||
.It Ar disable
|
||||
The name of file that will prevent conversion if it exists.
|
||||
A filename of
|
||||
A file name of
|
||||
.Dq Pa \&.
|
||||
will prevent this disabling action
|
||||
(i.e., the conversion is always permitted.)
|
||||
|
@ -295,6 +295,9 @@ for
|
|||
and
|
||||
.Sy CHROOT
|
||||
users.
|
||||
.It Sy maxfilesize Ar class Ar size
|
||||
Set the maximum size of an uploaded file to
|
||||
.Ar size .
|
||||
.It Sy maxtimeout Ar class Ar time
|
||||
Set the maximum timeout period that a client may request,
|
||||
defaulting to two hours.
|
||||
|
@ -392,6 +395,19 @@ to
|
|||
bytes per second,
|
||||
which is parsed as per
|
||||
.Sy rateget Ar rate .
|
||||
.It Sy sanenames Ar class Op Sy off
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Sy off
|
||||
is given, allow uploaded file names to contain any characters valid for a
|
||||
file name.
|
||||
Otherwise, only permit file names which don't start with a
|
||||
.Sq \&.
|
||||
and only comprise of characters from the set
|
||||
.Dq [-+,._A-Za-z0-9] .
|
||||
.It Sy template Ar class Op Ar refclass
|
||||
Define
|
||||
.Ar refclass
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: version.h,v 1.21 2000/11/15 02:32:30 lukem Exp $ */
|
||||
/* $NetBSD: version.h,v 1.22 2000/11/16 13:15:14 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 20001115"
|
||||
#define FTPD_VERSION "NetBSD-ftpd 20001116"
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue