import netbsd ftpd
Change-Id: Id7a3dbd40a6f37c55bcbb0d1456301f60626298f
This commit is contained in:
parent
eb1e5bf042
commit
62da011387
19 changed files with 13250 additions and 2 deletions
|
@ -128,6 +128,7 @@
|
|||
./lib minix-sys
|
||||
./lib/cpp minix-sys
|
||||
./libexec minix-sys
|
||||
./usr/libexec/ftpd minix-sys
|
||||
./libexec/ld.elf_so minix-sys
|
||||
./libexec/ld-elf.so.1 minix-sys
|
||||
./mnt minix-sys
|
||||
|
@ -3667,6 +3668,10 @@
|
|||
./usr/man/man5/editrc.5 minix-sys
|
||||
./usr/man/man5/ethers.5 minix-sys
|
||||
./usr/man/man5/fstab.5 minix-sys
|
||||
./usr/man/man5/ftpchroot.5 minix-sys
|
||||
./usr/man/man5/ftpd.conf.5 minix-sys
|
||||
./usr/man/man5/ftpusers.5 minix-sys
|
||||
./usr/man/man8/ftpd.8 minix-sys
|
||||
./usr/man/man5/group.5 minix-sys
|
||||
./usr/man/man5/hosts.5 minix-sys
|
||||
./usr/man/man5/httpd.conf.5 minix-sys
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
daemonize talkd
|
||||
daemonize tcpd shell in.rshd
|
||||
daemonize tcpd telnet in.telnetd
|
||||
daemonize tcpd ftp in.ftpd
|
||||
daemonize tcpd ftp /usr/libexec/ftpd
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
.include <bsd.own.mk>
|
||||
|
||||
SUBDIR= \
|
||||
\
|
||||
ftpd \
|
||||
ld.elf_so
|
||||
|
||||
.if defined(__MINIX)
|
||||
|
|
58
libexec/ftpd/Makefile
Normal file
58
libexec/ftpd/Makefile
Normal file
|
@ -0,0 +1,58 @@
|
|||
# $NetBSD: Makefile,v 1.63 2011/08/14 11:46:28 christos Exp $
|
||||
# @(#)Makefile 8.2 (Berkeley) 4/4/94
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
PROG= ftpd
|
||||
SRCS= cmds.c conf.c ftpd.c ftpcmd.y logutmp.c logwtmp.c popen.c
|
||||
.ifdef __MINIX
|
||||
CPPFLAGS+=-I${.CURDIR}
|
||||
.else
|
||||
CPPFLAGS+=-I${.CURDIR} -DSUPPORT_UTMP -DSUPPORT_UTMPX -DLOGIN_CAP
|
||||
.endif
|
||||
DPADD+= ${LIBCRYPT} ${LIBUTIL}
|
||||
LDADD+= -lcrypt -lutil
|
||||
MAN= ftpd.conf.5 ftpusers.5 ftpd.8
|
||||
MLINKS= ftpusers.5 ftpchroot.5
|
||||
|
||||
.if defined(NO_INTERNAL_LS)
|
||||
CPPFLAGS+=-DNO_INTERNAL_LS
|
||||
.else
|
||||
# for `internal' ls
|
||||
SRCS+= ls.c cmp.c print.c util.c
|
||||
.PATH: ${NETBSDSRCDIR}/bin/ls
|
||||
.endif
|
||||
|
||||
.if (${USE_INET6} != "no")
|
||||
CPPFLAGS+=-DINET6
|
||||
.endif
|
||||
|
||||
.if (${USE_PAM} != "no")
|
||||
CPPFLAGS+=-DUSE_PAM
|
||||
DPADD+= ${LIBPAM} ${PAM_STATIC_DPADD}
|
||||
LDADD+= -lpam ${PAM_STATIC_LDADD}
|
||||
.else # USE_PAM == no
|
||||
.if (${USE_SKEY} != "no")
|
||||
CPPFLAGS+=-DSKEY
|
||||
DPADD+= ${LIBSKEY}
|
||||
LDADD+= -lskey
|
||||
.endif
|
||||
.endif # USE_PAM == no
|
||||
|
||||
ftpd.o ftpcmd.o: version.h
|
||||
|
||||
#.if (${USE_KERBEROS} != "no")
|
||||
#
|
||||
#.PATH: ${NETBSDSRCDIR}/usr.bin/login
|
||||
#
|
||||
#SRCS+= k5login.c
|
||||
#CPPFLAGS+=-DKERBEROS5
|
||||
#DPADD+= ${LIBKRB5} ${LIBASN1}
|
||||
#LDADD+= -lkrb5 -lasn1
|
||||
#
|
||||
#DPADD+= ${LIBCRYPTO} ${{LIBCRYPT} ${LIBROKEN} ${LIBCOM_ERR}
|
||||
#LDADD+= -lcrypto -lcrypt -lroken -lcom_err
|
||||
#
|
||||
#.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
967
libexec/ftpd/cmds.c
Normal file
967
libexec/ftpd/cmds.c
Normal file
|
@ -0,0 +1,967 @@
|
|||
/* $NetBSD: cmds.c,v 1.31 2012/06/19 06:06:34 dholland Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999-2009 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Luke Mewburn.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1997 and 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: cmds.c,v 1.31 2012/06/19 06:06:34 dholland Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <arpa/ftp.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <tzfile.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef KERBEROS5
|
||||
#include <krb5/krb5.h>
|
||||
#endif
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
typedef enum {
|
||||
FE_MLSD = 1<<0, /* if op is MLSD (MLST otherwise ) */
|
||||
FE_ISCURDIR = 1<<1, /* if name is the current directory */
|
||||
} factflag_t;
|
||||
|
||||
typedef struct {
|
||||
const char *path; /* full pathname */
|
||||
const char *display; /* name to display */
|
||||
struct stat *stat; /* stat of path */
|
||||
struct stat *pdirstat; /* stat of path's parent dir */
|
||||
factflag_t flags; /* flags */
|
||||
} factelem;
|
||||
|
||||
static void ack(const char *);
|
||||
static void base64_encode(const char *, size_t, char *, int);
|
||||
static void fact_type(const char *, FILE *, factelem *);
|
||||
static void fact_size(const char *, FILE *, factelem *);
|
||||
static void fact_modify(const char *, FILE *, factelem *);
|
||||
static void fact_perm(const char *, FILE *, factelem *);
|
||||
static void fact_unique(const char *, FILE *, factelem *);
|
||||
static int matchgroup(gid_t);
|
||||
static void mlsname(FILE *, factelem *);
|
||||
static void replydirname(const char *, const char *);
|
||||
|
||||
struct ftpfact {
|
||||
const char *name; /* name of fact */
|
||||
int enabled; /* if fact is enabled */
|
||||
void (*display)(const char *, FILE *, factelem *);
|
||||
/* function to display fact */
|
||||
};
|
||||
|
||||
struct ftpfact facttab[] = {
|
||||
{ "Type", 1, fact_type },
|
||||
#define FACT_TYPE 0
|
||||
{ "Size", 1, fact_size },
|
||||
{ "Modify", 1, fact_modify },
|
||||
{ "Perm", 1, fact_perm },
|
||||
{ "Unique", 1, fact_unique },
|
||||
/* "Create" */
|
||||
/* "Lang" */
|
||||
/* "Media-Type" */
|
||||
/* "CharSet" */
|
||||
};
|
||||
|
||||
#define FACTTABSIZE (sizeof(facttab) / sizeof(struct ftpfact))
|
||||
|
||||
static char cached_path[MAXPATHLEN + 1] = "/";
|
||||
static void discover_path(char *, const char *);
|
||||
|
||||
void
|
||||
cwd(const char *path)
|
||||
{
|
||||
|
||||
if (chdir(path) < 0)
|
||||
perror_reply(550, path);
|
||||
else {
|
||||
show_chdir_messages(250);
|
||||
ack("CWD");
|
||||
if (getcwd(cached_path, MAXPATHLEN) == NULL) {
|
||||
discover_path(cached_path, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
delete(const char *name)
|
||||
{
|
||||
char *p = NULL;
|
||||
|
||||
if (remove(name) < 0) {
|
||||
p = strerror(errno);
|
||||
perror_reply(550, name);
|
||||
} else
|
||||
ack("DELE");
|
||||
logxfer("delete", -1, name, NULL, NULL, p);
|
||||
}
|
||||
|
||||
void
|
||||
feat(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
reply(-211, "Features supported");
|
||||
cprintf(stdout, " MDTM\r\n");
|
||||
cprintf(stdout, " MLST ");
|
||||
for (i = 0; i < FACTTABSIZE; i++)
|
||||
cprintf(stdout, "%s%s;", facttab[i].name,
|
||||
facttab[i].enabled ? "*" : "");
|
||||
cprintf(stdout, "\r\n");
|
||||
cprintf(stdout, " REST STREAM\r\n");
|
||||
cprintf(stdout, " SIZE\r\n");
|
||||
cprintf(stdout, " TVFS\r\n");
|
||||
reply(211, "End");
|
||||
}
|
||||
|
||||
void
|
||||
makedir(const char *name)
|
||||
{
|
||||
char *p = NULL;
|
||||
|
||||
if (mkdir(name, 0777) < 0) {
|
||||
p = strerror(errno);
|
||||
perror_reply(550, name);
|
||||
} else
|
||||
replydirname(name, "directory created.");
|
||||
logxfer("mkdir", -1, name, NULL, NULL, p);
|
||||
}
|
||||
|
||||
void
|
||||
mlsd(const char *path)
|
||||
{
|
||||
struct dirent *dp;
|
||||
struct stat sb, pdirstat;
|
||||
factelem f;
|
||||
FILE *dout;
|
||||
DIR *dirp;
|
||||
char name[MAXPATHLEN];
|
||||
int hastypefact;
|
||||
|
||||
hastypefact = facttab[FACT_TYPE].enabled;
|
||||
if (path == NULL)
|
||||
path = ".";
|
||||
if (stat(path, &pdirstat) == -1) {
|
||||
mlsdperror:
|
||||
perror_reply(550, path);
|
||||
return;
|
||||
}
|
||||
if (! S_ISDIR(pdirstat.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
perror_reply(501, path);
|
||||
return;
|
||||
}
|
||||
if ((dirp = opendir(path)) == NULL)
|
||||
goto mlsdperror;
|
||||
|
||||
dout = dataconn("MLSD", (off_t)-1, "w");
|
||||
if (dout == NULL)
|
||||
return;
|
||||
|
||||
memset(&f, 0, sizeof(f));
|
||||
f.stat = &sb;
|
||||
f.flags |= FE_MLSD;
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
snprintf(name, sizeof(name), "%s/%s", path, dp->d_name);
|
||||
if (ISDOTDIR(dp->d_name)) { /* special case curdir: */
|
||||
if (! hastypefact)
|
||||
continue;
|
||||
f.pdirstat = NULL; /* require stat of parent */
|
||||
f.display = path; /* set name to real name */
|
||||
f.flags |= FE_ISCURDIR; /* flag name is curdir */
|
||||
} else {
|
||||
if (ISDOTDOTDIR(dp->d_name)) {
|
||||
if (! hastypefact)
|
||||
continue;
|
||||
f.pdirstat = NULL;
|
||||
} else
|
||||
f.pdirstat = &pdirstat; /* cache parent stat */
|
||||
f.display = dp->d_name;
|
||||
f.flags &= ~FE_ISCURDIR;
|
||||
}
|
||||
if (stat(name, &sb) == -1)
|
||||
continue;
|
||||
f.path = name;
|
||||
mlsname(dout, &f);
|
||||
}
|
||||
(void)closedir(dirp);
|
||||
|
||||
if (ferror(dout) != 0)
|
||||
perror_reply(550, "Data connection");
|
||||
else
|
||||
reply(226, "MLSD complete.");
|
||||
closedataconn(dout);
|
||||
total_xfers_out++;
|
||||
total_xfers++;
|
||||
}
|
||||
|
||||
void
|
||||
mlst(const char *path)
|
||||
{
|
||||
struct stat sb;
|
||||
factelem f;
|
||||
|
||||
if (path == NULL)
|
||||
path = ".";
|
||||
if (stat(path, &sb) == -1) {
|
||||
perror_reply(550, path);
|
||||
return;
|
||||
}
|
||||
reply(-250, "MLST %s", path);
|
||||
memset(&f, 0, sizeof(f));
|
||||
f.path = path;
|
||||
f.display = path;
|
||||
f.stat = &sb;
|
||||
f.pdirstat = NULL;
|
||||
CPUTC(' ', stdout);
|
||||
mlsname(stdout, &f);
|
||||
reply(250, "End");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
opts(const char *command)
|
||||
{
|
||||
struct tab *c;
|
||||
char *ep;
|
||||
|
||||
if ((ep = strchr(command, ' ')) != NULL)
|
||||
*ep++ = '\0';
|
||||
c = lookup(cmdtab, command);
|
||||
if (c == NULL) {
|
||||
reply(502, "Unknown command '%s'.", command);
|
||||
return;
|
||||
}
|
||||
if (! CMD_IMPLEMENTED(c)) {
|
||||
reply(502, "%s command not implemented.", c->name);
|
||||
return;
|
||||
}
|
||||
if (! CMD_HAS_OPTIONS(c)) {
|
||||
reply(501, "%s command does not support persistent options.",
|
||||
c->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* special case: MLST */
|
||||
if (strcasecmp(command, "MLST") == 0) {
|
||||
int enabled[FACTTABSIZE];
|
||||
size_t i, onedone;
|
||||
size_t len;
|
||||
char *p;
|
||||
|
||||
for (i = 0; i < sizeof(enabled) / sizeof(int); i++)
|
||||
enabled[i] = 0;
|
||||
if (ep == NULL || *ep == '\0')
|
||||
goto displaymlstopts;
|
||||
|
||||
/* don't like spaces, and need trailing ; */
|
||||
len = strlen(ep);
|
||||
if (strchr(ep, ' ') != NULL || ep[len - 1] != ';') {
|
||||
badmlstopt:
|
||||
reply(501, "Invalid MLST options");
|
||||
return;
|
||||
}
|
||||
ep[len - 1] = '\0';
|
||||
while ((p = strsep(&ep, ";")) != NULL) {
|
||||
if (*p == '\0')
|
||||
goto badmlstopt;
|
||||
for (i = 0; i < FACTTABSIZE; i++)
|
||||
if (strcasecmp(p, facttab[i].name) == 0) {
|
||||
enabled[i] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
displaymlstopts:
|
||||
for (i = 0; i < FACTTABSIZE; i++)
|
||||
facttab[i].enabled = enabled[i];
|
||||
cprintf(stdout, "200 MLST OPTS");
|
||||
for (i = onedone = 0; i < FACTTABSIZE; i++) {
|
||||
if (facttab[i].enabled) {
|
||||
cprintf(stdout, "%s%s;", onedone ? "" : " ",
|
||||
facttab[i].name);
|
||||
onedone++;
|
||||
}
|
||||
}
|
||||
cprintf(stdout, "\r\n");
|
||||
fflush(stdout);
|
||||
return;
|
||||
}
|
||||
|
||||
/* default cases */
|
||||
if (ep != NULL && *ep != '\0')
|
||||
REASSIGN(c->options, ftpd_strdup(ep));
|
||||
if (c->options != NULL)
|
||||
reply(200, "Options for %s are '%s'.", c->name,
|
||||
c->options);
|
||||
else
|
||||
reply(200, "No options defined for %s.", c->name);
|
||||
}
|
||||
|
||||
void
|
||||
pwd(void)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
if (getcwd(path, sizeof(path) - 1) == NULL) {
|
||||
if (chdir(cached_path) < 0) {
|
||||
reply(550, "Can't get the current directory: %s.",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
(void)strlcpy(path, cached_path, MAXPATHLEN);
|
||||
}
|
||||
replydirname(path, "is the current directory.");
|
||||
}
|
||||
|
||||
void
|
||||
removedir(const char *name)
|
||||
{
|
||||
char *p = NULL;
|
||||
|
||||
if (rmdir(name) < 0) {
|
||||
p = strerror(errno);
|
||||
perror_reply(550, name);
|
||||
} else
|
||||
ack("RMD");
|
||||
logxfer("rmdir", -1, name, NULL, NULL, p);
|
||||
}
|
||||
|
||||
char *
|
||||
renamefrom(const char *name)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(name, &st) < 0) {
|
||||
perror_reply(550, name);
|
||||
return (NULL);
|
||||
}
|
||||
reply(350, "File exists, ready for destination name");
|
||||
return (ftpd_strdup(name));
|
||||
}
|
||||
|
||||
void
|
||||
renamecmd(const char *from, const char *to)
|
||||
{
|
||||
char *p = NULL;
|
||||
|
||||
if (rename(from, to) < 0) {
|
||||
p = strerror(errno);
|
||||
perror_reply(550, "rename");
|
||||
} else
|
||||
ack("RNTO");
|
||||
logxfer("rename", -1, from, to, NULL, p);
|
||||
}
|
||||
|
||||
void
|
||||
sizecmd(const char *filename)
|
||||
{
|
||||
switch (type) {
|
||||
case TYPE_L:
|
||||
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:
|
||||
{
|
||||
FILE *fin;
|
||||
int c;
|
||||
off_t count;
|
||||
struct stat stbuf;
|
||||
fin = fopen(filename, "r");
|
||||
if (fin == NULL) {
|
||||
perror_reply(550, filename);
|
||||
return;
|
||||
}
|
||||
if (fstat(fileno(fin), &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) {
|
||||
reply(550, "%s: not a plain file.", filename);
|
||||
(void) fclose(fin);
|
||||
return;
|
||||
}
|
||||
if (stbuf.st_size > 10240) {
|
||||
reply(550, "%s: file too large for SIZE.", filename);
|
||||
(void) fclose(fin);
|
||||
return;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
while((c = getc(fin)) != EOF) {
|
||||
if (c == '\n') /* will get expanded to \r\n */
|
||||
count++;
|
||||
count++;
|
||||
}
|
||||
(void) fclose(fin);
|
||||
|
||||
reply(213, LLF, (LLT)count);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
statfilecmd(const char *filename)
|
||||
{
|
||||
FILE *fin;
|
||||
int c;
|
||||
int atstart;
|
||||
const char *argv[] = { INTERNAL_LS, "-lgA", "", NULL };
|
||||
|
||||
argv[2] = filename;
|
||||
fin = ftpd_popen(argv, "r", STDOUT_FILENO);
|
||||
reply(-211, "status of %s:", filename);
|
||||
/* XXX: use fgetln() or fparseln() here? */
|
||||
atstart = 1;
|
||||
while ((c = getc(fin)) != EOF) {
|
||||
if (c == '\n') {
|
||||
if (ferror(stdout)){
|
||||
perror_reply(421, "control connection");
|
||||
(void) ftpd_pclose(fin);
|
||||
dologout(1);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
if (ferror(fin)) {
|
||||
perror_reply(551, filename);
|
||||
(void) ftpd_pclose(fin);
|
||||
return;
|
||||
}
|
||||
CPUTC('\r', stdout);
|
||||
}
|
||||
if (atstart && isdigit(c))
|
||||
CPUTC(' ', stdout);
|
||||
CPUTC(c, stdout);
|
||||
atstart = (c == '\n');
|
||||
}
|
||||
(void) ftpd_pclose(fin);
|
||||
reply(211, "End of Status");
|
||||
}
|
||||
|
||||
/* -- */
|
||||
|
||||
static void
|
||||
ack(const char *s)
|
||||
{
|
||||
|
||||
reply(250, "%s command successful.", s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode len bytes starting at clear using base64 encoding into encoded,
|
||||
* which should be at least ((len + 2) * 4 / 3 + 1) in size.
|
||||
* If nulterm is non-zero, terminate with \0 otherwise pad to 3 byte boundary
|
||||
* with `='.
|
||||
*/
|
||||
static void
|
||||
base64_encode(const char *clear, size_t len, char *encoded, int nulterm)
|
||||
{
|
||||
static const char base64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
const char *c;
|
||||
char *e, termchar;
|
||||
int i;
|
||||
|
||||
/* determine whether to pad with '=' or NUL terminate */
|
||||
termchar = nulterm ? '\0' : '=';
|
||||
c = clear;
|
||||
e = encoded;
|
||||
/* convert all but last 2 bytes */
|
||||
for (i = len; i > 2; i -= 3, c += 3) {
|
||||
*e++ = base64[(c[0] >> 2) & 0x3f];
|
||||
*e++ = base64[((c[0] << 4) & 0x30) | ((c[1] >> 4) & 0x0f)];
|
||||
*e++ = base64[((c[1] << 2) & 0x3c) | ((c[2] >> 6) & 0x03)];
|
||||
*e++ = base64[(c[2]) & 0x3f];
|
||||
}
|
||||
/* handle slop at end */
|
||||
if (i > 0) {
|
||||
*e++ = base64[(c[0] >> 2) & 0x3f];
|
||||
*e++ = base64[((c[0] << 4) & 0x30) |
|
||||
(i > 1 ? ((c[1] >> 4) & 0x0f) : 0)];
|
||||
*e++ = (i > 1) ? base64[(c[1] << 2) & 0x3c] : termchar;
|
||||
*e++ = termchar;
|
||||
}
|
||||
*e = '\0';
|
||||
}
|
||||
|
||||
static void
|
||||
fact_modify(const char *fact, FILE *fd, factelem *fe)
|
||||
{
|
||||
struct tm *t;
|
||||
|
||||
t = gmtime(&(fe->stat->st_mtime));
|
||||
cprintf(fd, "%s=%04d%02d%02d%02d%02d%02d;", fact,
|
||||
TM_YEAR_BASE + t->tm_year,
|
||||
t->tm_mon+1, t->tm_mday,
|
||||
t->tm_hour, t->tm_min, t->tm_sec);
|
||||
}
|
||||
|
||||
static void
|
||||
fact_perm(const char *fact, FILE *fd, factelem *fe)
|
||||
{
|
||||
int rok, wok, xok, pdirwok;
|
||||
struct stat *pdir;
|
||||
|
||||
if (fe->stat->st_uid == geteuid()) {
|
||||
rok = ((fe->stat->st_mode & S_IRUSR) != 0);
|
||||
wok = ((fe->stat->st_mode & S_IWUSR) != 0);
|
||||
xok = ((fe->stat->st_mode & S_IXUSR) != 0);
|
||||
} else if (matchgroup(fe->stat->st_gid)) {
|
||||
rok = ((fe->stat->st_mode & S_IRGRP) != 0);
|
||||
wok = ((fe->stat->st_mode & S_IWGRP) != 0);
|
||||
xok = ((fe->stat->st_mode & S_IXGRP) != 0);
|
||||
} else {
|
||||
rok = ((fe->stat->st_mode & S_IROTH) != 0);
|
||||
wok = ((fe->stat->st_mode & S_IWOTH) != 0);
|
||||
xok = ((fe->stat->st_mode & S_IXOTH) != 0);
|
||||
}
|
||||
|
||||
cprintf(fd, "%s=", fact);
|
||||
|
||||
/*
|
||||
* if parent info not provided, look it up, but
|
||||
* only if the current class has modify rights,
|
||||
* since we only need this info in such a case.
|
||||
*/
|
||||
pdir = fe->pdirstat;
|
||||
if (pdir == NULL && CURCLASS_FLAGS_ISSET(modify)) {
|
||||
size_t len;
|
||||
char realdir[MAXPATHLEN], *p;
|
||||
struct stat dir;
|
||||
|
||||
len = strlcpy(realdir, fe->path, sizeof(realdir));
|
||||
if (len < sizeof(realdir) - 4) {
|
||||
if (S_ISDIR(fe->stat->st_mode))
|
||||
strlcat(realdir, "/..", sizeof(realdir));
|
||||
else {
|
||||
/* if has a /, move back to it */
|
||||
/* otherwise use '..' */
|
||||
if ((p = strrchr(realdir, '/')) != NULL) {
|
||||
if (p == realdir)
|
||||
p++;
|
||||
*p = '\0';
|
||||
} else
|
||||
strlcpy(realdir, "..", sizeof(realdir));
|
||||
}
|
||||
if (stat(realdir, &dir) == 0)
|
||||
pdir = &dir;
|
||||
}
|
||||
}
|
||||
pdirwok = 0;
|
||||
if (pdir != NULL) {
|
||||
if (pdir->st_uid == geteuid())
|
||||
pdirwok = ((pdir->st_mode & S_IWUSR) != 0);
|
||||
else if (matchgroup(pdir->st_gid))
|
||||
pdirwok = ((pdir->st_mode & S_IWGRP) != 0);
|
||||
else
|
||||
pdirwok = ((pdir->st_mode & S_IWOTH) != 0);
|
||||
}
|
||||
|
||||
/* 'a': can APPE to file */
|
||||
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_FLAGS_ISSET(modify) && S_ISDIR(fe->stat->st_mode))
|
||||
CPUTC('c', fd);
|
||||
|
||||
/* 'd': can delete file or directory */
|
||||
if (pdirwok && CURCLASS_FLAGS_ISSET(modify)) {
|
||||
int candel;
|
||||
|
||||
candel = 1;
|
||||
if (S_ISDIR(fe->stat->st_mode)) {
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
|
||||
if ((dirp = opendir(fe->display)) == NULL)
|
||||
candel = 0;
|
||||
else {
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
if (ISDOTDIR(dp->d_name) ||
|
||||
ISDOTDOTDIR(dp->d_name))
|
||||
continue;
|
||||
candel = 0;
|
||||
break;
|
||||
}
|
||||
closedir(dirp);
|
||||
}
|
||||
}
|
||||
if (candel)
|
||||
CPUTC('d', fd);
|
||||
}
|
||||
|
||||
/* 'e': can enter directory */
|
||||
if (xok && S_ISDIR(fe->stat->st_mode))
|
||||
CPUTC('e', fd);
|
||||
|
||||
/* 'f': can rename file or directory */
|
||||
if (pdirwok && CURCLASS_FLAGS_ISSET(modify))
|
||||
CPUTC('f', fd);
|
||||
|
||||
/* 'l': can list directory */
|
||||
if (rok && xok && S_ISDIR(fe->stat->st_mode))
|
||||
CPUTC('l', fd);
|
||||
|
||||
/* 'm': can create directory */
|
||||
if (wok && CURCLASS_FLAGS_ISSET(modify) && S_ISDIR(fe->stat->st_mode))
|
||||
CPUTC('m', fd);
|
||||
|
||||
/* 'p': can remove files in directory */
|
||||
if (wok && CURCLASS_FLAGS_ISSET(modify) && S_ISDIR(fe->stat->st_mode))
|
||||
CPUTC('p', fd);
|
||||
|
||||
/* 'r': can RETR file */
|
||||
if (rok && S_ISREG(fe->stat->st_mode))
|
||||
CPUTC('r', fd);
|
||||
|
||||
/* 'w': can STOR file */
|
||||
if (wok && CURCLASS_FLAGS_ISSET(upload) && S_ISREG(fe->stat->st_mode))
|
||||
CPUTC('w', fd);
|
||||
|
||||
CPUTC(';', fd);
|
||||
}
|
||||
|
||||
static void
|
||||
fact_size(const char *fact, FILE *fd, factelem *fe)
|
||||
{
|
||||
|
||||
if (S_ISREG(fe->stat->st_mode))
|
||||
cprintf(fd, "%s=" LLF ";", fact, (LLT)fe->stat->st_size);
|
||||
}
|
||||
|
||||
static void
|
||||
fact_type(const char *fact, FILE *fd, factelem *fe)
|
||||
{
|
||||
|
||||
cprintf(fd, "%s=", fact);
|
||||
switch (fe->stat->st_mode & S_IFMT) {
|
||||
case S_IFDIR:
|
||||
if (fe->flags & FE_MLSD) {
|
||||
if ((fe->flags & FE_ISCURDIR) || ISDOTDIR(fe->display))
|
||||
cprintf(fd, "cdir");
|
||||
else if (ISDOTDOTDIR(fe->display))
|
||||
cprintf(fd, "pdir");
|
||||
else
|
||||
cprintf(fd, "dir");
|
||||
} else {
|
||||
cprintf(fd, "dir");
|
||||
}
|
||||
break;
|
||||
case S_IFREG:
|
||||
cprintf(fd, "file");
|
||||
break;
|
||||
case S_IFIFO:
|
||||
cprintf(fd, "OS.unix=fifo");
|
||||
break;
|
||||
case S_IFLNK: /* XXX: probably a NO-OP with stat() */
|
||||
cprintf(fd, "OS.unix=slink");
|
||||
break;
|
||||
case S_IFSOCK:
|
||||
cprintf(fd, "OS.unix=socket");
|
||||
break;
|
||||
case S_IFBLK:
|
||||
case S_IFCHR:
|
||||
cprintf(fd, "OS.unix=%s-" ULLF "/" ULLF,
|
||||
S_ISBLK(fe->stat->st_mode) ? "blk" : "chr",
|
||||
(ULLT)major(fe->stat->st_rdev),
|
||||
(ULLT)minor(fe->stat->st_rdev));
|
||||
break;
|
||||
default:
|
||||
cprintf(fd, "OS.unix=UNKNOWN(0%o)", fe->stat->st_mode & S_IFMT);
|
||||
break;
|
||||
}
|
||||
CPUTC(';', fd);
|
||||
}
|
||||
|
||||
static void
|
||||
fact_unique(const char *fact, FILE *fd, factelem *fe)
|
||||
{
|
||||
char obuf[(sizeof(dev_t) + sizeof(ino_t) + 2) * 4 / 3 + 2];
|
||||
char tbuf[sizeof(dev_t) + sizeof(ino_t)];
|
||||
|
||||
memcpy(tbuf,
|
||||
(char *)&(fe->stat->st_dev), sizeof(dev_t));
|
||||
memcpy(tbuf + sizeof(dev_t),
|
||||
(char *)&(fe->stat->st_ino), sizeof(ino_t));
|
||||
base64_encode(tbuf, sizeof(dev_t) + sizeof(ino_t), obuf, 1);
|
||||
cprintf(fd, "%s=%s;", fact, obuf);
|
||||
}
|
||||
|
||||
static int
|
||||
matchgroup(gid_t gid)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < gidcount; i++)
|
||||
if (gid == gidlist[i])
|
||||
return(1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
mlsname(FILE *fp, factelem *fe)
|
||||
{
|
||||
char realfile[MAXPATHLEN];
|
||||
int userf = 0;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < FACTTABSIZE; i++) {
|
||||
if (facttab[i].enabled)
|
||||
(facttab[i].display)(facttab[i].name, fp, fe);
|
||||
}
|
||||
if ((fe->flags & FE_MLSD) &&
|
||||
!(fe->flags & FE_ISCURDIR) && !ISDOTDIR(fe->display)) {
|
||||
/* if MLSD and not "." entry, display as-is */
|
||||
userf = 0;
|
||||
} else {
|
||||
/* if MLST, or MLSD and "." entry, realpath(3) it */
|
||||
if (realpath(fe->display, realfile) != NULL)
|
||||
userf = 1;
|
||||
}
|
||||
cprintf(fp, " %s\r\n", userf ? realfile : fe->display);
|
||||
}
|
||||
|
||||
static void
|
||||
replydirname(const char *name, const char *message)
|
||||
{
|
||||
char *p, *ep;
|
||||
char npath[MAXPATHLEN * 2];
|
||||
|
||||
p = npath;
|
||||
ep = &npath[sizeof(npath) - 1];
|
||||
while (*name) {
|
||||
if (*name == '"') {
|
||||
if (ep - p < 2)
|
||||
break;
|
||||
*p++ = *name++;
|
||||
*p++ = '"';
|
||||
} else {
|
||||
if (ep - p < 1)
|
||||
break;
|
||||
*p++ = *name++;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
reply(257, "\"%s\" %s", npath, message);
|
||||
}
|
||||
|
||||
static void
|
||||
discover_path(char *last_path, const char *new_path)
|
||||
{
|
||||
char tp[MAXPATHLEN + 1] = "";
|
||||
char tq[MAXPATHLEN + 1] = "";
|
||||
char *cp;
|
||||
char *cq;
|
||||
int sz1, sz2;
|
||||
int nomorelink;
|
||||
struct stat st1, st2;
|
||||
|
||||
if (new_path[0] != '/') {
|
||||
(void)strlcpy(tp, last_path, MAXPATHLEN);
|
||||
(void)strlcat(tp, "/", MAXPATHLEN);
|
||||
}
|
||||
(void)strlcat(tp, new_path, MAXPATHLEN);
|
||||
(void)strlcat(tp, "/", MAXPATHLEN);
|
||||
|
||||
/*
|
||||
* resolve symlinks. A symlink may introduce another symlink, so we
|
||||
* loop trying to resolve symlinks until we don't find any of them.
|
||||
*/
|
||||
do {
|
||||
/* Collapse any // into / */
|
||||
while ((cp = strstr(tp, "//")) != NULL)
|
||||
(void)memmove(cp, cp + 1, strlen(cp) - 1 + 1);
|
||||
|
||||
/* Collapse any /./ into / */
|
||||
while ((cp = strstr(tp, "/./")) != NULL)
|
||||
(void)memmove(cp, cp + 2, strlen(cp) - 2 + 1);
|
||||
|
||||
cp = tp;
|
||||
nomorelink = 1;
|
||||
|
||||
while ((cp = strstr(++cp, "/")) != NULL) {
|
||||
sz1 = (unsigned long)cp - (unsigned long)tp;
|
||||
if (sz1 > MAXPATHLEN)
|
||||
goto bad;
|
||||
*cp = 0;
|
||||
sz2 = readlink(tp, tq, MAXPATHLEN);
|
||||
*cp = '/';
|
||||
|
||||
/* If this is not a symlink, move to next / */
|
||||
if (sz2 <= 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We found a symlink, so we will have to
|
||||
* do one more pass to check there is no
|
||||
* more symlink in the path
|
||||
*/
|
||||
nomorelink = 0;
|
||||
|
||||
/*
|
||||
* Null terminate the string and remove trailing /
|
||||
*/
|
||||
tq[sz2] = 0;
|
||||
sz2 = strlen(tq);
|
||||
if (tq[sz2 - 1] == '/')
|
||||
tq[--sz2] = 0;
|
||||
|
||||
/*
|
||||
* Is this an absolute link or a relative link?
|
||||
*/
|
||||
if (tq[0] == '/') {
|
||||
/* absolute link */
|
||||
if (strlen(cp) + sz2 > MAXPATHLEN)
|
||||
goto bad;
|
||||
memmove(tp + sz2, cp, strlen(cp) + 1);
|
||||
memcpy(tp, tq, sz2);
|
||||
} else {
|
||||
/* relative link */
|
||||
for (cq = cp - 1; *cq != '/'; cq--);
|
||||
if (strlen(tp) -
|
||||
((unsigned long)cq - (unsigned long)cp)
|
||||
+ 1 + sz2 > MAXPATHLEN)
|
||||
goto bad;
|
||||
(void)memmove(cq + 1 + sz2,
|
||||
cp, strlen(cp) + 1);
|
||||
(void)memcpy(cq + 1, tq, sz2);
|
||||
}
|
||||
|
||||
/*
|
||||
* start over, looking for new symlinks
|
||||
*/
|
||||
break;
|
||||
}
|
||||
} while (nomorelink == 0);
|
||||
|
||||
/* Collapse any /foo/../ into /foo/ */
|
||||
while ((cp = strstr(tp, "/../")) != NULL) {
|
||||
/* ^/../foo/ becomes ^/foo/ */
|
||||
if (cp == tp) {
|
||||
(void)memmove(cp, cp + 3,
|
||||
strlen(cp) - 3 + 1);
|
||||
} else {
|
||||
for (cq = cp - 1; *cq != '/'; cq--);
|
||||
(void)memmove(cq, cp + 3,
|
||||
strlen(cp) - 3 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* strip strailing / */
|
||||
if (strlen(tp) != 1)
|
||||
tp[strlen(tp) - 1] = '\0';
|
||||
|
||||
/* check that the path is correct */
|
||||
stat(tp, &st1);
|
||||
stat(".", &st2);
|
||||
if ((st1.st_dev != st2.st_dev) || (st1.st_ino != st2.st_ino))
|
||||
goto bad;
|
||||
|
||||
(void)strlcpy(last_path, tp, MAXPATHLEN);
|
||||
return;
|
||||
|
||||
bad:
|
||||
(void)strlcat(last_path, "/", MAXPATHLEN);
|
||||
(void)strlcat(last_path, new_path, MAXPATHLEN);
|
||||
return;
|
||||
}
|
||||
|
953
libexec/ftpd/conf.c
Normal file
953
libexec/ftpd/conf.c
Normal file
|
@ -0,0 +1,953 @@
|
|||
/* $NetBSD: conf.c,v 1.63 2011/08/14 11:46:28 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Simon Burge and Luke Mewburn.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: conf.c,v 1.63 2011/08/14 11:46:28 christos 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 <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stringlist.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <util.h>
|
||||
|
||||
#ifdef KERBEROS5
|
||||
#include <krb5/krb5.h>
|
||||
#endif
|
||||
|
||||
#include "extern.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
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 /* rw-r----- */
|
||||
|
||||
/*
|
||||
* Initialise curclass to an `empty' state
|
||||
*/
|
||||
void
|
||||
init_curclass(void)
|
||||
{
|
||||
struct ftpconv *conv, *cnext;
|
||||
|
||||
for (conv = curclass.conversions; conv != NULL; conv = cnext) {
|
||||
REASSIGN(conv->suffix, NULL);
|
||||
REASSIGN(conv->types, NULL);
|
||||
REASSIGN(conv->disable, NULL);
|
||||
REASSIGN(conv->command, NULL);
|
||||
cnext = conv->next;
|
||||
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 = DEFAULT_LIMIT;
|
||||
REASSIGN(curclass.limitfile, NULL);
|
||||
curclass.maxfilesize = DEFAULT_MAXFILESIZE;
|
||||
curclass.maxrateget = 0;
|
||||
curclass.maxrateput = 0;
|
||||
curclass.maxtimeout = DEFAULT_MAXTIMEOUT;
|
||||
REASSIGN(curclass.motd, ftpd_strdup(_NAME_FTPLOGINMESG));
|
||||
REASSIGN(curclass.notify, NULL);
|
||||
curclass.portmin = 0;
|
||||
curclass.portmax = 0;
|
||||
curclass.rateget = 0;
|
||||
curclass.rateput = 0;
|
||||
curclass.timeout = DEFAULT_TIMEOUT;
|
||||
/* curclass.type is set elsewhere */
|
||||
curclass.umask = DEFAULT_UMASK;
|
||||
curclass.mmapsize = 0;
|
||||
curclass.readsize = 0;
|
||||
curclass.writesize = 0;
|
||||
curclass.sendbufsize = 0;
|
||||
curclass.sendlowat = 0;
|
||||
|
||||
CURCLASS_FLAGS_SET(checkportcmd);
|
||||
CURCLASS_FLAGS_CLR(denyquick);
|
||||
CURCLASS_FLAGS_CLR(hidesymlinks);
|
||||
CURCLASS_FLAGS_SET(modify);
|
||||
CURCLASS_FLAGS_SET(passive);
|
||||
CURCLASS_FLAGS_CLR(private);
|
||||
CURCLASS_FLAGS_CLR(sanenames);
|
||||
CURCLASS_FLAGS_SET(upload);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the configuration file, looking for the named class, and
|
||||
* define curclass to contain the appropriate settings.
|
||||
*/
|
||||
void
|
||||
parse_conf(const char *findclass)
|
||||
{
|
||||
FILE *f;
|
||||
char *buf, *p;
|
||||
size_t len;
|
||||
LLT llval;
|
||||
int none, match;
|
||||
char *endp, errbuf[100];
|
||||
char *class, *word, *arg, *template;
|
||||
const char *infile;
|
||||
size_t line;
|
||||
struct ftpconv *conv, *cnext;
|
||||
|
||||
init_curclass();
|
||||
REASSIGN(curclass.classname, ftpd_strdup(findclass));
|
||||
/* set more guest defaults */
|
||||
if (strcasecmp(findclass, "guest") == 0) {
|
||||
CURCLASS_FLAGS_CLR(modify);
|
||||
curclass.umask = 0707;
|
||||
}
|
||||
|
||||
infile = conffilename(_NAME_FTPDCONF);
|
||||
if ((f = fopen(infile, "r")) == NULL)
|
||||
return;
|
||||
|
||||
line = 0;
|
||||
template = NULL;
|
||||
for (;
|
||||
(buf = fparseln(f, &len, &line, NULL, FPARSELN_UNESCCOMM |
|
||||
FPARSELN_UNESCCONT | FPARSELN_UNESCESC)) != NULL;
|
||||
free(buf)) {
|
||||
none = match = 0;
|
||||
p = buf;
|
||||
if (len < 1)
|
||||
continue;
|
||||
if (p[len - 1] == '\n')
|
||||
p[--len] = '\0';
|
||||
if (EMPTYSTR(p))
|
||||
continue;
|
||||
|
||||
NEXTWORD(p, word);
|
||||
NEXTWORD(p, class);
|
||||
NEXTWORD(p, arg);
|
||||
if (EMPTYSTR(word) || EMPTYSTR(class))
|
||||
continue;
|
||||
if (strcasecmp(class, "none") == 0)
|
||||
none = 1;
|
||||
if (! (strcasecmp(class, findclass) == 0 ||
|
||||
(template != NULL && strcasecmp(class, template) == 0) ||
|
||||
none ||
|
||||
strcasecmp(class, "all") == 0) )
|
||||
continue;
|
||||
|
||||
#define CONF_FLAG(Field) \
|
||||
do { \
|
||||
if (none || \
|
||||
(!EMPTYSTR(arg) && strcasecmp(arg, "off") == 0)) \
|
||||
CURCLASS_FLAGS_CLR(Field); \
|
||||
else \
|
||||
CURCLASS_FLAGS_SET(Field); \
|
||||
} while (0)
|
||||
|
||||
#define CONF_STRING(Field) \
|
||||
do { \
|
||||
if (none || EMPTYSTR(arg)) \
|
||||
arg = NULL; \
|
||||
else \
|
||||
arg = ftpd_strdup(arg); \
|
||||
REASSIGN(curclass.Field, arg); \
|
||||
} while (0)
|
||||
|
||||
#define CONF_LL(Field,Arg,Min,Max) \
|
||||
do { \
|
||||
if (none || EMPTYSTR(Arg)) \
|
||||
goto nextline; \
|
||||
llval = strsuftollx(#Field, Arg, Min, Max, \
|
||||
errbuf, sizeof(errbuf)); \
|
||||
if (errbuf[0]) { \
|
||||
syslog(LOG_WARNING, "%s line %d: %s", \
|
||||
infile, (int)line, errbuf); \
|
||||
goto nextline; \
|
||||
} \
|
||||
curclass.Field = llval; \
|
||||
} while(0)
|
||||
|
||||
if (0) {
|
||||
/* no-op */
|
||||
|
||||
} else if ((strcasecmp(word, "advertise") == 0)
|
||||
|| (strcasecmp(word, "advertize") == 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) {
|
||||
CONF_STRING(chroot);
|
||||
|
||||
} else if (strcasecmp(word, "classtype") == 0) {
|
||||
if (!none && !EMPTYSTR(arg)) {
|
||||
if (strcasecmp(arg, "GUEST") == 0)
|
||||
curclass.type = CLASS_GUEST;
|
||||
else if (strcasecmp(arg, "CHROOT") == 0)
|
||||
curclass.type = CLASS_CHROOT;
|
||||
else if (strcasecmp(arg, "REAL") == 0)
|
||||
curclass.type = CLASS_REAL;
|
||||
else {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: unknown class type `%s'",
|
||||
infile, (int)line, arg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (strcasecmp(word, "conversion") == 0) {
|
||||
char *suffix, *types, *disable, *convcmd;
|
||||
|
||||
if (EMPTYSTR(arg)) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: %s requires a suffix",
|
||||
infile, (int)line, word);
|
||||
continue; /* need a suffix */
|
||||
}
|
||||
NEXTWORD(p, types);
|
||||
NEXTWORD(p, disable);
|
||||
convcmd = p;
|
||||
if (convcmd)
|
||||
convcmd += strspn(convcmd, " \t");
|
||||
suffix = ftpd_strdup(arg);
|
||||
if (none || EMPTYSTR(types) ||
|
||||
EMPTYSTR(disable) || EMPTYSTR(convcmd)) {
|
||||
types = NULL;
|
||||
disable = NULL;
|
||||
convcmd = NULL;
|
||||
} else {
|
||||
types = ftpd_strdup(types);
|
||||
disable = ftpd_strdup(disable);
|
||||
convcmd = ftpd_strdup(convcmd);
|
||||
}
|
||||
for (conv = curclass.conversions; conv != NULL;
|
||||
conv = conv->next) {
|
||||
if (strcmp(conv->suffix, suffix) == 0)
|
||||
break;
|
||||
}
|
||||
if (conv == NULL) {
|
||||
conv = (struct ftpconv *)
|
||||
calloc(1, sizeof(struct ftpconv));
|
||||
if (conv == NULL) {
|
||||
syslog(LOG_WARNING, "can't malloc");
|
||||
continue;
|
||||
}
|
||||
conv->next = NULL;
|
||||
for (cnext = curclass.conversions;
|
||||
cnext != NULL; cnext = cnext->next)
|
||||
if (cnext->next == NULL)
|
||||
break;
|
||||
if (cnext != NULL)
|
||||
cnext->next = conv;
|
||||
else
|
||||
curclass.conversions = conv;
|
||||
}
|
||||
REASSIGN(conv->suffix, suffix);
|
||||
REASSIGN(conv->types, types);
|
||||
REASSIGN(conv->disable, disable);
|
||||
REASSIGN(conv->command, convcmd);
|
||||
|
||||
} else if (strcasecmp(word, "denyquick") == 0) {
|
||||
CONF_FLAG(denyquick);
|
||||
|
||||
} else if (strcasecmp(word, "display") == 0) {
|
||||
CONF_STRING(display);
|
||||
|
||||
} else if (strcasecmp(word, "hidesymlinks") == 0) {
|
||||
CONF_FLAG(hidesymlinks);
|
||||
|
||||
} else if (strcasecmp(word, "homedir") == 0) {
|
||||
CONF_STRING(homedir);
|
||||
|
||||
} else if (strcasecmp(word, "limit") == 0) {
|
||||
curclass.limit = DEFAULT_LIMIT;
|
||||
REASSIGN(curclass.limitfile, NULL);
|
||||
CONF_LL(limit, arg, -1, LLTMAX);
|
||||
REASSIGN(curclass.limitfile,
|
||||
EMPTYSTR(p) ? NULL : ftpd_strdup(p));
|
||||
|
||||
} else if (strcasecmp(word, "maxfilesize") == 0) {
|
||||
curclass.maxfilesize = DEFAULT_MAXFILESIZE;
|
||||
CONF_LL(maxfilesize, arg, -1, LLTMAX);
|
||||
|
||||
} else if (strcasecmp(word, "maxtimeout") == 0) {
|
||||
curclass.maxtimeout = DEFAULT_MAXTIMEOUT;
|
||||
CONF_LL(maxtimeout, arg,
|
||||
MIN(30, curclass.timeout), LLTMAX);
|
||||
|
||||
} else if (strcasecmp(word, "mmapsize") == 0) {
|
||||
curclass.mmapsize = 0;
|
||||
CONF_LL(mmapsize, arg, 0, SSIZE_MAX);
|
||||
|
||||
} else if (strcasecmp(word, "readsize") == 0) {
|
||||
curclass.readsize = 0;
|
||||
CONF_LL(readsize, arg, 0, SSIZE_MAX);
|
||||
|
||||
} else if (strcasecmp(word, "writesize") == 0) {
|
||||
curclass.writesize = 0;
|
||||
CONF_LL(writesize, arg, 0, SSIZE_MAX);
|
||||
|
||||
} else if (strcasecmp(word, "recvbufsize") == 0) {
|
||||
curclass.recvbufsize = 0;
|
||||
CONF_LL(recvbufsize, arg, 0, INT_MAX);
|
||||
|
||||
} else if (strcasecmp(word, "sendbufsize") == 0) {
|
||||
curclass.sendbufsize = 0;
|
||||
CONF_LL(sendbufsize, arg, 0, INT_MAX);
|
||||
|
||||
} else if (strcasecmp(word, "sendlowat") == 0) {
|
||||
curclass.sendlowat = 0;
|
||||
CONF_LL(sendlowat, arg, 0, INT_MAX);
|
||||
|
||||
} else if (strcasecmp(word, "modify") == 0) {
|
||||
CONF_FLAG(modify);
|
||||
|
||||
} else if (strcasecmp(word, "motd") == 0) {
|
||||
CONF_STRING(motd);
|
||||
|
||||
} else if (strcasecmp(word, "notify") == 0) {
|
||||
CONF_STRING(notify);
|
||||
|
||||
} else if (strcasecmp(word, "passive") == 0) {
|
||||
CONF_FLAG(passive);
|
||||
|
||||
} else if (strcasecmp(word, "portrange") == 0) {
|
||||
long minport, maxport;
|
||||
|
||||
curclass.portmin = 0;
|
||||
curclass.portmax = 0;
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
if (EMPTYSTR(p)) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: missing maxport argument",
|
||||
infile, (int)line);
|
||||
continue;
|
||||
}
|
||||
minport = strsuftollx("minport", arg, IPPORT_RESERVED,
|
||||
IPPORT_ANONMAX, errbuf, sizeof(errbuf));
|
||||
if (errbuf[0]) {
|
||||
syslog(LOG_WARNING, "%s line %d: %s",
|
||||
infile, (int)line, errbuf);
|
||||
continue;
|
||||
}
|
||||
maxport = strsuftollx("maxport", p, IPPORT_RESERVED,
|
||||
IPPORT_ANONMAX, errbuf, sizeof(errbuf));
|
||||
if (errbuf[0]) {
|
||||
syslog(LOG_WARNING, "%s line %d: %s",
|
||||
infile, (int)line, errbuf);
|
||||
continue;
|
||||
}
|
||||
if (minport >= maxport) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: minport %ld >= maxport %ld",
|
||||
infile, (int)line, minport, maxport);
|
||||
continue;
|
||||
}
|
||||
curclass.portmin = (int)minport;
|
||||
curclass.portmax = (int)maxport;
|
||||
|
||||
} else if (strcasecmp(word, "private") == 0) {
|
||||
CONF_FLAG(private);
|
||||
|
||||
} else if (strcasecmp(word, "rateget") == 0) {
|
||||
curclass.maxrateget = curclass.rateget = 0;
|
||||
CONF_LL(rateget, arg, 0, LLTMAX);
|
||||
curclass.maxrateget = curclass.rateget;
|
||||
|
||||
} else if (strcasecmp(word, "rateput") == 0) {
|
||||
curclass.maxrateput = curclass.rateput = 0;
|
||||
CONF_LL(rateput, arg, 0, LLTMAX);
|
||||
curclass.maxrateput = curclass.rateput;
|
||||
|
||||
} else if (strcasecmp(word, "sanenames") == 0) {
|
||||
CONF_FLAG(sanenames);
|
||||
|
||||
} else if (strcasecmp(word, "timeout") == 0) {
|
||||
curclass.timeout = DEFAULT_TIMEOUT;
|
||||
CONF_LL(timeout, arg, 30, curclass.maxtimeout);
|
||||
|
||||
} else if (strcasecmp(word, "template") == 0) {
|
||||
if (none)
|
||||
continue;
|
||||
REASSIGN(template, EMPTYSTR(arg) ? NULL : ftpd_strdup(arg));
|
||||
|
||||
} else if (strcasecmp(word, "umask") == 0) {
|
||||
unsigned long fumask;
|
||||
|
||||
curclass.umask = DEFAULT_UMASK;
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
errno = 0;
|
||||
endp = NULL;
|
||||
fumask = strtoul(arg, &endp, 8);
|
||||
if (errno || *arg == '\0' || *endp != '\0' ||
|
||||
fumask > 0777) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: invalid umask %s",
|
||||
infile, (int)line, arg);
|
||||
continue;
|
||||
}
|
||||
curclass.umask = (mode_t)fumask;
|
||||
|
||||
} else if (strcasecmp(word, "upload") == 0) {
|
||||
CONF_FLAG(upload);
|
||||
if (! CURCLASS_FLAGS_ISSET(upload))
|
||||
CURCLASS_FLAGS_CLR(modify);
|
||||
|
||||
} else {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: unknown directive '%s'",
|
||||
infile, (int)line, word);
|
||||
continue;
|
||||
}
|
||||
nextline:
|
||||
;
|
||||
}
|
||||
REASSIGN(template, NULL);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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' + "-".
|
||||
* If code == -1, flush the internal cache of directory names and return.
|
||||
*/
|
||||
void
|
||||
show_chdir_messages(int code)
|
||||
{
|
||||
static StringList *slist = NULL;
|
||||
|
||||
struct stat st;
|
||||
struct tm *t;
|
||||
glob_t gl;
|
||||
time_t now, then;
|
||||
int age;
|
||||
char curwd[MAXPATHLEN];
|
||||
char *cp, **rlist;
|
||||
|
||||
if (code == -1) {
|
||||
if (slist != NULL)
|
||||
sl_free(slist, 1);
|
||||
slist = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (quietmessages)
|
||||
return;
|
||||
|
||||
/* Setup list for directory cache */
|
||||
if (slist == NULL)
|
||||
slist = sl_init();
|
||||
if (slist == NULL) {
|
||||
syslog(LOG_WARNING, "can't allocate memory for stringlist");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if this directory has already been visited */
|
||||
if (getcwd(curwd, sizeof(curwd) - 1) == NULL) {
|
||||
syslog(LOG_WARNING, "can't getcwd: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (sl_find(slist, curwd) != NULL)
|
||||
return;
|
||||
|
||||
cp = ftpd_strdup(curwd);
|
||||
if (sl_add(slist, cp) == -1)
|
||||
syslog(LOG_WARNING, "can't add `%s' to stringlist", cp);
|
||||
|
||||
/* First check for a display file */
|
||||
(void)display_file(curclass.display, code);
|
||||
|
||||
/* Now see if there are any notify files */
|
||||
if (EMPTYSTR(curclass.notify))
|
||||
return;
|
||||
|
||||
memset(&gl, 0, sizeof(gl));
|
||||
if (glob(curclass.notify, GLOB_BRACE|GLOB_LIMIT, NULL, &gl) != 0
|
||||
|| gl.gl_matchc == 0) {
|
||||
globfree(&gl);
|
||||
return;
|
||||
}
|
||||
time(&now);
|
||||
for (rlist = gl.gl_pathv; *rlist != NULL; rlist++) {
|
||||
if (stat(*rlist, &st) != 0)
|
||||
continue;
|
||||
if (!S_ISREG(st.st_mode))
|
||||
continue;
|
||||
then = st.st_mtime;
|
||||
if (code != 0) {
|
||||
reply(-code, "%s", "");
|
||||
code = 0;
|
||||
}
|
||||
reply(-code, "Please read the file %s", *rlist);
|
||||
t = localtime(&now);
|
||||
age = 365 * t->tm_year + t->tm_yday;
|
||||
t = localtime(&then);
|
||||
age -= 365 * t->tm_year + t->tm_yday;
|
||||
reply(-code, " it was last modified on %.24s - %d day%s ago",
|
||||
ctime(&then), age, PLURAL(age));
|
||||
}
|
||||
globfree(&gl);
|
||||
}
|
||||
|
||||
int
|
||||
display_file(const char *file, int code)
|
||||
{
|
||||
FILE *f;
|
||||
char *buf, *p;
|
||||
char curwd[MAXPATHLEN];
|
||||
size_t len;
|
||||
off_t lastnum;
|
||||
time_t now;
|
||||
|
||||
lastnum = 0;
|
||||
if (quietmessages)
|
||||
return (0);
|
||||
|
||||
if (EMPTYSTR(file))
|
||||
return(0);
|
||||
if ((f = fopen(file, "r")) == NULL)
|
||||
return (0);
|
||||
reply(-code, "%s", "");
|
||||
|
||||
for (;
|
||||
(buf = fparseln(f, &len, NULL, "\0\0\0", 0)) != NULL; free(buf)) {
|
||||
if (len > 0)
|
||||
if (buf[len - 1] == '\n')
|
||||
buf[--len] = '\0';
|
||||
cprintf(stdout, " ");
|
||||
|
||||
for (p = buf; *p; p++) {
|
||||
if (*p == '%') {
|
||||
p++;
|
||||
switch (*p) {
|
||||
|
||||
case 'c':
|
||||
cprintf(stdout, "%s",
|
||||
curclass.classname ?
|
||||
curclass.classname : "<unknown>");
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
if (getcwd(curwd, sizeof(curwd)-1)
|
||||
== NULL){
|
||||
syslog(LOG_WARNING,
|
||||
"can't getcwd: %s",
|
||||
strerror(errno));
|
||||
continue;
|
||||
}
|
||||
cprintf(stdout, "%s", curwd);
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
if (! EMPTYSTR(emailaddr))
|
||||
cprintf(stdout, "%s",
|
||||
emailaddr);
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
cprintf(stdout, "%s", hostname);
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
if (curclass.limit == -1) {
|
||||
cprintf(stdout, "unlimited");
|
||||
lastnum = 0;
|
||||
} else {
|
||||
cprintf(stdout, LLF,
|
||||
(LLT)curclass.limit);
|
||||
lastnum = curclass.limit;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
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));
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
cprintf(stdout, "%s",
|
||||
pw ? pw->pw_name : "<unknown>");
|
||||
break;
|
||||
|
||||
case '%':
|
||||
CPUTC('%', stdout);
|
||||
break;
|
||||
|
||||
}
|
||||
} else
|
||||
CPUTC(*p, stdout);
|
||||
}
|
||||
cprintf(stdout, "\r\n");
|
||||
}
|
||||
|
||||
(void)fflush(stdout);
|
||||
(void)fclose(f);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse src, expanding '%' escapes, into dst (which must be at least
|
||||
* MAXPATHLEN long).
|
||||
*/
|
||||
void
|
||||
format_path(char *dst, const char *src)
|
||||
{
|
||||
size_t len;
|
||||
const char *p;
|
||||
|
||||
dst[0] = '\0';
|
||||
len = 0;
|
||||
if (src == NULL)
|
||||
return;
|
||||
for (p = src; *p && len < MAXPATHLEN; p++) {
|
||||
if (*p == '%') {
|
||||
p++;
|
||||
switch (*p) {
|
||||
|
||||
case 'c':
|
||||
len += strlcpy(dst + len, curclass.classname,
|
||||
MAXPATHLEN - len);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
len += strlcpy(dst + len, pw->pw_dir,
|
||||
MAXPATHLEN - len);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
len += strlcpy(dst + len, pw->pw_name,
|
||||
MAXPATHLEN - len);
|
||||
break;
|
||||
|
||||
case '%':
|
||||
dst[len++] = '%';
|
||||
break;
|
||||
|
||||
}
|
||||
} else
|
||||
dst[len++] = *p;
|
||||
}
|
||||
if (len < MAXPATHLEN)
|
||||
dst[len] = '\0';
|
||||
dst[MAXPATHLEN - 1] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Find s2 at the end of s1. If found, return a string up to (but
|
||||
* not including) s2, otherwise returns NULL.
|
||||
*/
|
||||
static char *
|
||||
strend(const char *s1, char *s2)
|
||||
{
|
||||
static char buf[MAXPATHLEN];
|
||||
|
||||
char *start;
|
||||
size_t l1, l2;
|
||||
|
||||
l1 = strlen(s1);
|
||||
l2 = strlen(s2);
|
||||
|
||||
if (l2 >= l1 || l1 >= sizeof(buf))
|
||||
return(NULL);
|
||||
|
||||
strlcpy(buf, s1, sizeof(buf));
|
||||
start = buf + (l1 - l2);
|
||||
|
||||
if (strcmp(start, s2) == 0) {
|
||||
*start = '\0';
|
||||
return(buf);
|
||||
} else
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
filetypematch(char *types, int mode)
|
||||
{
|
||||
for ( ; types[0] != '\0'; types++)
|
||||
switch (*types) {
|
||||
case 'd':
|
||||
if (S_ISDIR(mode))
|
||||
return(1);
|
||||
break;
|
||||
case 'f':
|
||||
if (S_ISREG(mode))
|
||||
return(1);
|
||||
break;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for a conversion. If we succeed, return a pointer to the
|
||||
* command to execute for the conversion.
|
||||
*
|
||||
* The command is stored in a static array so there's no memory
|
||||
* leak problems, and not too much to change in ftpd.c. This
|
||||
* routine doesn't need to be re-entrant unless we start using a
|
||||
* multi-threaded ftpd, and that's not likely for a while...
|
||||
*/
|
||||
const char **
|
||||
do_conversion(const char *fname)
|
||||
{
|
||||
struct ftpconv *cp;
|
||||
struct stat st;
|
||||
int o_errno;
|
||||
char *base = NULL;
|
||||
char *cmd, *p, *lp;
|
||||
char **argv;
|
||||
StringList *sl;
|
||||
|
||||
o_errno = errno;
|
||||
sl = NULL;
|
||||
cmd = NULL;
|
||||
for (cp = curclass.conversions; cp != NULL; cp = cp->next) {
|
||||
if (cp->suffix == NULL) {
|
||||
syslog(LOG_WARNING,
|
||||
"cp->suffix==NULL in conv list; SHOULDN'T HAPPEN!");
|
||||
continue;
|
||||
}
|
||||
if ((base = strend(fname, cp->suffix)) == NULL)
|
||||
continue;
|
||||
if (cp->types == NULL || cp->disable == NULL ||
|
||||
cp->command == NULL)
|
||||
continue;
|
||||
/* Is it enabled? */
|
||||
if (strcmp(cp->disable, ".") != 0 &&
|
||||
stat(cp->disable, &st) == 0)
|
||||
continue;
|
||||
/* Does the base exist? */
|
||||
if (stat(base, &st) < 0)
|
||||
continue;
|
||||
/* Is the file type ok */
|
||||
if (!filetypematch(cp->types, st.st_mode))
|
||||
continue;
|
||||
break; /* "We have a winner!" */
|
||||
}
|
||||
|
||||
/* If we got through the list, no conversion */
|
||||
if (cp == NULL)
|
||||
goto cleanup_do_conv;
|
||||
|
||||
/* Split up command into an argv */
|
||||
if ((sl = sl_init()) == NULL)
|
||||
goto cleanup_do_conv;
|
||||
cmd = ftpd_strdup(cp->command);
|
||||
p = cmd;
|
||||
while (p) {
|
||||
NEXTWORD(p, lp);
|
||||
if (strcmp(lp, "%s") == 0)
|
||||
lp = base;
|
||||
if (sl_add(sl, ftpd_strdup(lp)) == -1)
|
||||
goto cleanup_do_conv;
|
||||
}
|
||||
|
||||
if (sl_add(sl, NULL) == -1)
|
||||
goto cleanup_do_conv;
|
||||
argv = sl->sl_str;
|
||||
free(cmd);
|
||||
free(sl);
|
||||
return (void *)(intptr_t)argv;
|
||||
|
||||
cleanup_do_conv:
|
||||
if (sl)
|
||||
sl_free(sl, 1);
|
||||
free(cmd);
|
||||
errno = o_errno;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Count the number of current connections, reading from
|
||||
* /var/run/ftpd.pids-<class>
|
||||
* Does a kill -0 on each pid in that file, and only counts
|
||||
* processes that exist (or frees the slot if it doesn't).
|
||||
* Adds getpid() to the first free slot. Truncates the file
|
||||
* if possible.
|
||||
*/
|
||||
void
|
||||
count_users(void)
|
||||
{
|
||||
char fn[MAXPATHLEN];
|
||||
int fd;
|
||||
size_t i, last, count;
|
||||
ssize_t scount;
|
||||
pid_t *pids, mypid;
|
||||
struct stat sb;
|
||||
struct flock fl;
|
||||
|
||||
(void)strlcpy(fn, _PATH_CLASSPIDS, sizeof(fn));
|
||||
(void)strlcat(fn, curclass.classname, sizeof(fn));
|
||||
pids = NULL;
|
||||
connections = 1;
|
||||
fl.l_start = 0;
|
||||
fl.l_len = 0;
|
||||
fl.l_pid = 0;
|
||||
fl.l_type = F_WRLCK;
|
||||
fl.l_whence = SEEK_SET;
|
||||
|
||||
if ((fd = open(fn, O_RDWR | O_CREAT, 0600)) == -1)
|
||||
return;
|
||||
if (fcntl(fd, F_SETLK, &fl) == -1)
|
||||
goto cleanup_count;
|
||||
if (fstat(fd, &sb) == -1)
|
||||
goto cleanup_count;
|
||||
if ((pids = malloc(sb.st_size + sizeof(pid_t))) == NULL)
|
||||
goto cleanup_count;
|
||||
/* XXX: implement a better read loop */
|
||||
scount = read(fd, pids, sb.st_size);
|
||||
if (scount == -1 || scount != sb.st_size || scount < 0)
|
||||
goto cleanup_count;
|
||||
count = (size_t)scount / sizeof(pid_t);
|
||||
mypid = getpid();
|
||||
last = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (pids[i] == 0)
|
||||
continue;
|
||||
if (kill(pids[i], 0) == -1 && errno != EPERM) {
|
||||
if (mypid != 0) {
|
||||
pids[i] = mypid;
|
||||
mypid = 0;
|
||||
last = i;
|
||||
}
|
||||
} else {
|
||||
connections++;
|
||||
last = i;
|
||||
}
|
||||
}
|
||||
if (mypid != 0) {
|
||||
if (pids[last] != 0)
|
||||
last++;
|
||||
pids[last] = mypid;
|
||||
}
|
||||
count = (last + 1) * sizeof(pid_t);
|
||||
if (lseek(fd, 0, SEEK_SET) == -1)
|
||||
goto cleanup_count;
|
||||
/* XXX: implement a better write loop */
|
||||
scount = write(fd, pids, count);
|
||||
if (scount == -1 || (size_t)scount != count)
|
||||
goto cleanup_count;
|
||||
(void)ftruncate(fd, count);
|
||||
|
||||
cleanup_count:
|
||||
fl.l_type = F_UNLCK;
|
||||
(void)fcntl(fd, F_SETLK, &fl);
|
||||
close(fd);
|
||||
REASSIGN(pids, NULL);
|
||||
}
|
380
libexec/ftpd/extern.h
Normal file
380
libexec/ftpd/extern.h
Normal file
|
@ -0,0 +1,380 @@
|
|||
/* $NetBSD: extern.h,v 1.62 2011/08/29 20:41:06 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)extern.h 8.2 (Berkeley) 4/4/94
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Luke Mewburn.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1997 and 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#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)
|
||||
# define LLTMIN LONG_MIN
|
||||
# define LLTMAX LONG_MAX
|
||||
#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)
|
||||
# define LLTMIN LLONG_MIN
|
||||
# define LLTMAX LLONG_MAX
|
||||
#endif
|
||||
|
||||
#define FTP_BUFLEN 512
|
||||
|
||||
void abor(void);
|
||||
void closedataconn(FILE *);
|
||||
char *conffilename(const char *);
|
||||
void count_users(void);
|
||||
void cprintf(FILE *, const char *, ...)
|
||||
__attribute__((__format__(__printf__, 2, 3)));
|
||||
void cwd(const char *);
|
||||
FILE *dataconn(const char *, off_t, const char *);
|
||||
void delete(const char *);
|
||||
int display_file(const char *, int);
|
||||
const char **do_conversion(const char *);
|
||||
__dead void dologout(int);
|
||||
__dead void fatal(const char *);
|
||||
void feat(void);
|
||||
void format_path(char *, const char *);
|
||||
int ftpd_pclose(FILE *);
|
||||
FILE *ftpd_popen(const char *[], const char *, int);
|
||||
int get_line(char *, int, FILE *);
|
||||
void init_curclass(void);
|
||||
void logxfer(const char *, off_t, const char *, const char *,
|
||||
const struct timeval *, const char *);
|
||||
struct tab *lookup(struct tab *, const char *);
|
||||
void makedir(const char *);
|
||||
void mlsd(const char *);
|
||||
void mlst(const char *);
|
||||
void opts(const char *);
|
||||
void parse_conf(const char *);
|
||||
void pass(const char *);
|
||||
void passive(void);
|
||||
int lpsvproto2af(int);
|
||||
int af2lpsvproto(int);
|
||||
int epsvproto2af(int);
|
||||
int af2epsvproto(int);
|
||||
void long_passive(const char *, int);
|
||||
int extended_port(const char *);
|
||||
void epsv_protounsupp(const char *);
|
||||
void perror_reply(int, const char *);
|
||||
void pwd(void);
|
||||
void removedir(const char *);
|
||||
void renamecmd(const char *, const char *);
|
||||
char *renamefrom(const char *);
|
||||
void reply(int, const char *, ...)
|
||||
__attribute__((__format__(__printf__, 2, 3)));
|
||||
void retrieve(const char *[], const char *);
|
||||
void send_file_list(const char *);
|
||||
void show_chdir_messages(int);
|
||||
void sizecmd(const char *);
|
||||
void statcmd(void);
|
||||
void statfilecmd(const char *);
|
||||
void statxfer(void);
|
||||
void store(const char *, const char *, int);
|
||||
void user(const char *);
|
||||
char *ftpd_strdup(const char *);
|
||||
void yyerror(const char *);
|
||||
|
||||
#ifdef SUPPORT_UTMP
|
||||
struct utmp;
|
||||
|
||||
void ftpd_initwtmp(void);
|
||||
void ftpd_logwtmp(const char *, const char *, const char *);
|
||||
void ftpd_login(const struct utmp *);
|
||||
int ftpd_logout(const char *);
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_UTMPX
|
||||
struct utmpx;
|
||||
struct sockinet;
|
||||
|
||||
void ftpd_initwtmpx(void);
|
||||
void ftpd_logwtmpx(const char *, const char *, const char *,
|
||||
struct sockinet *, int, int);
|
||||
void ftpd_loginx(const struct utmpx *);
|
||||
int ftpd_logoutx(const char *, int, int);
|
||||
#endif
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
# define HAVE_SETPROCTITLE 1
|
||||
# define HAVE_STRUCT_SOCKADDR_SA_LEN 1
|
||||
# define HAVE_SOCKADDR_SNPRINTF 1
|
||||
#endif
|
||||
|
||||
struct sockinet {
|
||||
union sockunion {
|
||||
struct sockaddr_in su_sin;
|
||||
#ifdef INET6
|
||||
struct sockaddr_in6 su_sin6;
|
||||
#endif
|
||||
} si_su;
|
||||
#if !defined(HAVE_STRUCT_SOCKADDR_SA_LEN)
|
||||
int si_len;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined(HAVE_STRUCT_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 {
|
||||
const char *name;
|
||||
short token;
|
||||
short state;
|
||||
short flags; /* 1 if command implemented, 2 if has options,
|
||||
4 if can occur OOB */
|
||||
const char *help;
|
||||
char *options;
|
||||
};
|
||||
|
||||
struct ftpconv {
|
||||
struct ftpconv *next;
|
||||
char *suffix; /* Suffix of requested name */
|
||||
char *types; /* Valid file types */
|
||||
char *disable; /* File to disable conversions */
|
||||
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_denyquick = 1<<1, /* Check ftpusers(5) before PASS */
|
||||
FLAG_hidesymlinks = 1<<2, /* For symbolic links, list the file
|
||||
or directory the link references
|
||||
rather than the link itself */
|
||||
FLAG_modify = 1<<3, /* Allow CHMOD, DELE, MKD, RMD, RNFR,
|
||||
UMASK */
|
||||
FLAG_passive = 1<<4, /* Allow PASV mode */
|
||||
FLAG_private = 1<<5, /* Don't publish class info in STAT */
|
||||
FLAG_sanenames = 1<<6, /* Restrict names of uploaded files */
|
||||
FLAG_upload = 1<<7, /* 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 {
|
||||
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 */
|
||||
char *display; /* File to display upon chdir */
|
||||
char *homedir; /* Directory to chdir(2) to at login */
|
||||
classflag_t flags; /* Flags; see classflag_t above */
|
||||
LLT limit; /* Max connections (-1 = unlimited) */
|
||||
char *limitfile; /* File to display if limit reached */
|
||||
LLT maxfilesize; /* Maximum file size of uploads */
|
||||
LLT maxrateget; /* Maximum get transfer rate throttle */
|
||||
LLT maxrateput; /* Maximum put transfer rate throttle */
|
||||
LLT maxtimeout; /* Maximum permitted timeout */
|
||||
char *motd; /* MotD file to display after login */
|
||||
char *notify; /* Files to notify about upon chdir */
|
||||
LLT portmin; /* Minumum port for passive mode */
|
||||
LLT portmax; /* Maximum port for passive mode */
|
||||
LLT rateget; /* Get (RETR) transfer rate throttle */
|
||||
LLT rateput; /* Put (STOR) transfer rate throttle */
|
||||
LLT timeout; /* Default timeout */
|
||||
class_ft type; /* Class type */
|
||||
mode_t umask; /* Umask to use */
|
||||
LLT mmapsize; /* mmap window size */
|
||||
LLT readsize; /* data read size */
|
||||
LLT writesize; /* data write size */
|
||||
LLT recvbufsize; /* SO_RCVBUF size */
|
||||
LLT sendbufsize; /* SO_SNDBUF size */
|
||||
LLT sendlowat; /* SO_SNDLOWAT size */
|
||||
};
|
||||
|
||||
extern void ftp_loop(void) __attribute__ ((noreturn));
|
||||
extern void ftp_handle_line(char *);
|
||||
|
||||
#ifndef GLOBAL
|
||||
#define GLOBAL extern
|
||||
#endif
|
||||
|
||||
|
||||
GLOBAL struct sockinet ctrl_addr;
|
||||
GLOBAL struct sockinet data_dest;
|
||||
GLOBAL struct sockinet data_source;
|
||||
GLOBAL struct sockinet his_addr;
|
||||
GLOBAL struct sockinet pasv_addr;
|
||||
GLOBAL int connections;
|
||||
GLOBAL struct ftpclass curclass;
|
||||
GLOBAL int ftpd_debug;
|
||||
GLOBAL char *emailaddr;
|
||||
GLOBAL int form;
|
||||
GLOBAL int gidcount; /* number of entries in gidlist[] */
|
||||
GLOBAL gid_t *gidlist;
|
||||
GLOBAL int hasyyerrored;
|
||||
GLOBAL char hostname[MAXHOSTNAMELEN+1];
|
||||
GLOBAL char homedir[MAXPATHLEN];
|
||||
#ifdef KERBEROS5
|
||||
GLOBAL krb5_context kcontext;
|
||||
#endif
|
||||
GLOBAL int logged_in;
|
||||
GLOBAL int logging;
|
||||
GLOBAL int pdata; /* for passive mode */
|
||||
#if defined(HAVE_SETPROCTITLE)
|
||||
GLOBAL char proctitle[BUFSIZ]; /* initial part of title */
|
||||
#endif
|
||||
GLOBAL struct passwd *pw;
|
||||
GLOBAL int quietmessages;
|
||||
GLOBAL char remotehost[MAXHOSTNAMELEN+1];
|
||||
GLOBAL char remoteloghost[2 * MAXHOSTNAMELEN+1];
|
||||
GLOBAL off_t restart_point;
|
||||
GLOBAL char tmpline[FTP_BUFLEN];
|
||||
GLOBAL int type;
|
||||
GLOBAL int usedefault; /* for data transfers */
|
||||
GLOBAL const char *version;
|
||||
GLOBAL int is_oob;
|
||||
|
||||
/* total file data bytes */
|
||||
GLOBAL off_t total_data_in, total_data_out, total_data;
|
||||
/* total number of data files */
|
||||
GLOBAL off_t total_files_in, total_files_out, total_files;
|
||||
/* total bytes */
|
||||
GLOBAL off_t total_bytes_in, total_bytes_out, total_bytes;
|
||||
/* total number of xfers */
|
||||
GLOBAL off_t total_xfers_in, total_xfers_out, total_xfers;
|
||||
|
||||
extern struct tab cmdtab[];
|
||||
|
||||
#define INTERNAL_LS "/bin/ls"
|
||||
|
||||
|
||||
#define CMD_IMPLEMENTED(x) ((x)->flags != 0)
|
||||
#define CMD_HAS_OPTIONS(x) ((x)->flags & 0x2)
|
||||
#define CMD_OOB(x) ((x)->flags & 0x4)
|
||||
|
||||
#define CPUTC(c, f) do { \
|
||||
putc(c, f); total_bytes++; total_bytes_out++; \
|
||||
} while (0);
|
||||
|
||||
#define CURCLASSTYPE curclass.type == CLASS_GUEST ? "GUEST" : \
|
||||
curclass.type == CLASS_CHROOT ? "CHROOT" : \
|
||||
curclass.type == CLASS_REAL ? "REAL" : \
|
||||
"<unknown>"
|
||||
|
||||
#define ISDOTDIR(x) (x[0] == '.' && x[1] == '\0')
|
||||
#define ISDOTDOTDIR(x) (x[0] == '.' && x[1] == '.' && x[2] == '\0')
|
||||
|
||||
#define EMPTYSTR(p) ((p) == NULL || *(p) == '\0')
|
||||
#define NEXTWORD(P, W) do { \
|
||||
(W) = strsep(&(P), " \t"); \
|
||||
} while ((W) != NULL && *(W) == '\0')
|
||||
#define PLURAL(s) ((s) == 1 ? "" : "s")
|
||||
#define REASSIGN(X,Y) do { if (X) free(X); (X)=(Y); } while (/*CONSTCOND*/0)
|
||||
|
||||
#ifndef IPPORT_ANONMAX
|
||||
# define IPPORT_ANONMAX 65535
|
||||
#endif
|
2578
libexec/ftpd/ftpcmd.c
Normal file
2578
libexec/ftpd/ftpcmd.c
Normal file
File diff suppressed because it is too large
Load diff
1875
libexec/ftpd/ftpcmd.y
Normal file
1875
libexec/ftpd/ftpcmd.y
Normal file
File diff suppressed because it is too large
Load diff
871
libexec/ftpd/ftpd.8
Normal file
871
libexec/ftpd/ftpd.8
Normal file
|
@ -0,0 +1,871 @@
|
|||
.\" $NetBSD: ftpd.8,v 1.85 2009/05/01 10:53:27 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1997-2008 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software contributed to The NetBSD Foundation
|
||||
.\" by Luke Mewburn.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" Copyright (c) 1985, 1988, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)ftpd.8 8.2 (Berkeley) 4/19/94
|
||||
.\"
|
||||
.Dd May 1, 2009
|
||||
.Dt FTPD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ftpd
|
||||
.Nd
|
||||
Internet File Transfer Protocol server
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl 46DdHlnQqrsUuWwX
|
||||
.Op Fl a Ar anondir
|
||||
.Op Fl C Ar user Ns Op @ Ns Ar host
|
||||
.Op Fl c Ar confdir
|
||||
.Op Fl e Ar emailaddr
|
||||
.Op Fl h Ar hostname
|
||||
.Op Fl L Ar xferlogfile
|
||||
.Op Fl P Ar dataport
|
||||
.Op Fl V Ar version
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is the Internet File Transfer Protocol server process.
|
||||
The server uses the
|
||||
.Tn TCP
|
||||
protocol and listens at the port specified in the
|
||||
.Dq ftp
|
||||
service specification; see
|
||||
.Xr services 5 .
|
||||
.Pp
|
||||
Available options:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl 4
|
||||
When
|
||||
.Fl D
|
||||
is specified, bind to IPv4 addresses only.
|
||||
.It Fl 6
|
||||
When
|
||||
.Fl D
|
||||
is specified, bind to IPv6 addresses only.
|
||||
.It Fl a Ar anondir
|
||||
Define
|
||||
.Ar anondir
|
||||
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 user Ns Op @ Ns Ar host
|
||||
Check whether
|
||||
.Ar user
|
||||
.Po
|
||||
as if connecting from
|
||||
.Ar host ,
|
||||
if provided
|
||||
.Pc
|
||||
would be granted access under
|
||||
the restrictions given in
|
||||
.Xr ftpusers 5 ,
|
||||
and exit without attempting a connection.
|
||||
.Nm
|
||||
exits with an exit code of 0 if access would be granted, or 1 otherwise.
|
||||
This can be useful for testing configurations.
|
||||
.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 D
|
||||
Run as daemon.
|
||||
.Nm
|
||||
will listen on the default FTP port for incoming connections
|
||||
and fork a child for each connection.
|
||||
This is lower overhead than starting
|
||||
.Nm
|
||||
from
|
||||
.Xr inetd 8
|
||||
and thus might be useful on busy servers to reduce load.
|
||||
.It Fl d
|
||||
Debugging information is written to the syslog using a facility of
|
||||
.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
|
||||
Equivalent to
|
||||
.Do
|
||||
-h
|
||||
`hostname`
|
||||
.Dc .
|
||||
.It Fl h Ar hostname
|
||||
Explicitly set the hostname to advertise as to
|
||||
.Ar hostname .
|
||||
The default is the hostname associated with the IP address that
|
||||
.Nm
|
||||
is listening on.
|
||||
This ability (with or without
|
||||
.Fl h ) ,
|
||||
in conjunction with
|
||||
.Fl c Ar confdir ,
|
||||
is useful when configuring
|
||||
.Sq virtual
|
||||
.Tn FTP
|
||||
servers, each listening on separate addresses as separate names.
|
||||
Refer to
|
||||
.Xr inetd.conf 5
|
||||
for more information on starting services to listen on specific IP addresses.
|
||||
.It Fl L Ar xferlogfile
|
||||
Log
|
||||
.Tn wu-ftpd
|
||||
style
|
||||
.Sq xferlog
|
||||
entries to
|
||||
.Ar xferlogfile .
|
||||
.It Fl l
|
||||
Each successful and failed
|
||||
.Tn FTP
|
||||
session is logged using syslog with a facility of
|
||||
.Dv LOG_FTP .
|
||||
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 n
|
||||
Don't attempt translation of IP addresses to hostnames.
|
||||
.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
|
||||
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 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 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
|
||||
than the (listening-port - 1) for
|
||||
.Sy PORT
|
||||
style commands, which is contrary to the
|
||||
.Cm RFC 959
|
||||
specification, but in practice very few clients rely upon this behaviour.
|
||||
See
|
||||
.Sx SECURITY CONSIDERATIONS
|
||||
below for more details.
|
||||
.It Fl s
|
||||
Require a secure authentication mechanism like Kerberos or S/Key to be used.
|
||||
.It Fl U
|
||||
Don't log each concurrent
|
||||
.Tn FTP
|
||||
session to
|
||||
.Pa /var/run/utmp .
|
||||
This is the default.
|
||||
.It Fl u
|
||||
Log each concurrent
|
||||
.Tn FTP
|
||||
session to
|
||||
.Pa /var/run/utmp ,
|
||||
making them visible to commands such as
|
||||
.Xr who 1 .
|
||||
.It Fl V Ar version
|
||||
Use
|
||||
.Ar version
|
||||
as the version to advertise in the login banner and in the output of
|
||||
.Sy STAT
|
||||
and
|
||||
.Sy SYST
|
||||
instead of the default version information.
|
||||
If
|
||||
.Ar version
|
||||
is empty or
|
||||
.Sq -
|
||||
then don't display any version information.
|
||||
.It Fl W
|
||||
Don't log each
|
||||
.Tn FTP
|
||||
session to
|
||||
.Pa /var/log/wtmp .
|
||||
.It Fl w
|
||||
Log each
|
||||
.Tn FTP
|
||||
session to
|
||||
.Pa /var/log/wtmp ,
|
||||
making them visible to commands such as
|
||||
.Xr last 1 .
|
||||
This is the default.
|
||||
.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 "sed -ne 's/^.*xferlog: //p' /var/log/xferlog \*[Gt] wuxferlog"
|
||||
.El
|
||||
.Pp
|
||||
The file
|
||||
.Pa /etc/nologin
|
||||
can be used to disable
|
||||
.Tn FTP
|
||||
access.
|
||||
If the file exists,
|
||||
.Nm
|
||||
displays it and exits.
|
||||
If the file
|
||||
.Pa /etc/ftpwelcome
|
||||
exists,
|
||||
.Nm
|
||||
prints it before issuing the
|
||||
.Dq ready
|
||||
message.
|
||||
If the file
|
||||
.Pa /etc/motd
|
||||
exists (under the chroot directory if applicable),
|
||||
.Nm
|
||||
prints it after a successful login.
|
||||
This may be changed with the
|
||||
.Xr ftpd.conf 5
|
||||
directive
|
||||
.Sy motd .
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
server currently supports the following
|
||||
.Tn FTP
|
||||
requests.
|
||||
The case of the requests is ignored.
|
||||
.Bl -column "Request" "Description" -offset indent
|
||||
.It Sy Request Ta Sy Description
|
||||
.It ABOR Ta "abort previous command"
|
||||
.It ACCT Ta "specify account (ignored)"
|
||||
.It ALLO Ta "allocate storage (vacuously)"
|
||||
.It APPE Ta "append to a file"
|
||||
.It CDUP Ta "change to parent of current working directory"
|
||||
.It CWD Ta "change working directory"
|
||||
.It DELE Ta "delete a file"
|
||||
.It EPSV Ta "prepare for server-to-server transfer"
|
||||
.It EPRT Ta "specify data connection port"
|
||||
.It FEAT Ta "list extra features that are not defined in" Cm "RFC 959"
|
||||
.It HELP Ta "give help information"
|
||||
.It LIST Ta "give list files in a directory" Pq Dq Li "ls -lA"
|
||||
.It LPSV Ta "prepare for server-to-server transfer"
|
||||
.It LPRT Ta "specify data connection port"
|
||||
.It MLSD Ta "list contents of directory in a machine-processable form"
|
||||
.It MLST Ta "show a pathname in a machine-processable form"
|
||||
.It MKD Ta "make a directory"
|
||||
.It MDTM Ta "show last modification time of file"
|
||||
.It MODE Ta "specify data transfer" Em mode
|
||||
.It NLST Ta "give name list of files in directory"
|
||||
.It NOOP Ta "do nothing"
|
||||
.It OPTS Ta "define persistent options for a given command"
|
||||
.It PASS Ta "specify password"
|
||||
.It PASV Ta "prepare for server-to-server transfer"
|
||||
.It PORT Ta "specify data connection port"
|
||||
.It PWD Ta "print the current working directory"
|
||||
.It QUIT Ta "terminate session"
|
||||
.It REST Ta "restart incomplete transfer"
|
||||
.It RETR Ta "retrieve a file"
|
||||
.It RMD Ta "remove a directory"
|
||||
.It RNFR Ta "specify rename-from file name"
|
||||
.It RNTO Ta "specify rename-to file name"
|
||||
.It SITE Ta "non-standard commands (see next section)"
|
||||
.It SIZE Ta "return size of file"
|
||||
.It STAT Ta "return status of server"
|
||||
.It STOR Ta "store a file"
|
||||
.It STOU Ta "store a file with a unique name"
|
||||
.It STRU Ta "specify data transfer" Em structure
|
||||
.It SYST Ta "show operating system type of server system"
|
||||
.It TYPE Ta "specify data transfer" Em type
|
||||
.It USER Ta "specify user name"
|
||||
.It XCUP Ta "change to parent of current working directory (deprecated)"
|
||||
.It XCWD Ta "change working directory (deprecated)"
|
||||
.It XMKD Ta "make a directory (deprecated)"
|
||||
.It XPWD Ta "print the current working directory (deprecated)"
|
||||
.It XRMD Ta "remove a directory (deprecated)"
|
||||
.El
|
||||
.Pp
|
||||
The following non-standard or
|
||||
.Ux
|
||||
specific commands are supported by the SITE request.
|
||||
.Pp
|
||||
.Bl -column Request Description -offset indent
|
||||
.It Sy Request Ta Sy Description
|
||||
.It CHMOD Ta "change mode of a file, e.g. ``SITE CHMOD 755 filename''"
|
||||
.It HELP Ta "give help information."
|
||||
.It IDLE Ta "set idle-timer, e.g. ``SITE IDLE 60''"
|
||||
.It RATEGET Ta "set maximum get rate throttle in bytes/second, e.g. ``SITE RATEGET 5k''"
|
||||
.It RATEPUT Ta "set maximum put rate throttle in bytes/second, e.g. ``SITE RATEPUT 5k''"
|
||||
.It UMASK Ta "change umask, e.g. ``SITE UMASK 002''"
|
||||
.El
|
||||
.Pp
|
||||
The following
|
||||
.Tn FTP
|
||||
requests (as specified in
|
||||
.Cm RFC 959
|
||||
and
|
||||
.Cm RFC 2228 )
|
||||
are recognized, but are not implemented:
|
||||
.Sy ACCT ,
|
||||
.Sy ADAT ,
|
||||
.Sy AUTH ,
|
||||
.Sy CCC ,
|
||||
.Sy CONF ,
|
||||
.Sy ENC ,
|
||||
.Sy MIC ,
|
||||
.Sy PBSZ ,
|
||||
.Sy PROT ,
|
||||
.Sy REIN ,
|
||||
and
|
||||
.Sy SMNT .
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
server will abort an active file transfer only when the
|
||||
.Sy ABOR
|
||||
command is preceded by a Telnet "Interrupt Process" (IP)
|
||||
signal and a Telnet "Synch" signal in the command Telnet stream,
|
||||
as described in Internet
|
||||
.Cm RFC 959 .
|
||||
If a
|
||||
.Sy STAT
|
||||
command is received during a data transfer, preceded by a Telnet IP
|
||||
and Synch, transfer status will be returned.
|
||||
.Pp
|
||||
.Nm
|
||||
interprets file names according to the
|
||||
.Dq globbing
|
||||
conventions used by
|
||||
.Xr csh 1 .
|
||||
This allows users to use the metacharacters
|
||||
.Dq Li \&*?[]{}~ .
|
||||
.Ss User authentication
|
||||
.Nm
|
||||
authenticates users according to five rules.
|
||||
.Pp
|
||||
.Bl -enum -offset indent
|
||||
.It
|
||||
The login name must be in the password data base,
|
||||
.Xr passwd 5 ,
|
||||
and not have a null password.
|
||||
In this case a password must be provided by the client before any
|
||||
file operations may be performed.
|
||||
If the user has an S/Key key, the response from a successful
|
||||
.Sy USER
|
||||
command will include an S/Key challenge.
|
||||
The client may choose to respond with a
|
||||
.Sy PASS
|
||||
command giving either
|
||||
a standard password or an S/Key one-time password.
|
||||
The server will automatically determine which type of password it
|
||||
has been given and attempt to authenticate accordingly.
|
||||
See
|
||||
.Xr skey 1
|
||||
for more information on S/Key authentication.
|
||||
S/Key is a Trademark of Bellcore.
|
||||
.It
|
||||
The login name must be allowed based on the information in
|
||||
.Xr ftpusers 5 .
|
||||
.It
|
||||
The user must have a standard shell returned by
|
||||
.Xr getusershell 3 .
|
||||
If the user's shell field in the password database is empty, the
|
||||
shell is assumed to be
|
||||
.Pa /bin/sh .
|
||||
As per
|
||||
.Xr shells 5 ,
|
||||
the user's shell must be listed with full path in
|
||||
.Pa /etc/shells .
|
||||
.It
|
||||
If directed by the file
|
||||
.Xr ftpchroot 5
|
||||
the session's root directory will be changed by
|
||||
.Xr chroot 2
|
||||
to the directory specified in the
|
||||
.Xr ftpd.conf 5
|
||||
.Sy chroot
|
||||
directive (if set),
|
||||
or to the home directory of the user.
|
||||
This facility may also be triggered by enabling the boolean
|
||||
.Sy ftp-chroot
|
||||
in
|
||||
.Xr login.conf 5 .
|
||||
However, the user must still supply a password.
|
||||
This feature is intended as a compromise between a fully anonymous account
|
||||
and a fully privileged account.
|
||||
The account should also be set up as for an anonymous account.
|
||||
.It
|
||||
If the user name is
|
||||
.Dq anonymous
|
||||
or
|
||||
.Dq ftp ,
|
||||
an
|
||||
anonymous
|
||||
.Tn FTP
|
||||
account must be present in the password
|
||||
file (user
|
||||
.Dq ftp ) .
|
||||
In this case the user is allowed
|
||||
to log in by specifying any password (by convention an email address for
|
||||
the user should be used as the password).
|
||||
.Pp
|
||||
The server performs a
|
||||
.Xr chroot 2
|
||||
to the directory specified in the
|
||||
.Xr ftpd.conf 5
|
||||
.Sy chroot
|
||||
directive (if set),
|
||||
the
|
||||
.Fl a Ar anondir
|
||||
directory (if set),
|
||||
or to the home directory of the
|
||||
.Dq ftp
|
||||
user.
|
||||
.Pp
|
||||
The server then performs a
|
||||
.Xr chdir 2
|
||||
to the directory specified in the
|
||||
.Xr ftpd.conf 5
|
||||
.Sy homedir
|
||||
directive (if set), otherwise to
|
||||
.Pa / .
|
||||
.Pp
|
||||
If other restrictions are required (such as disabling of certain
|
||||
commands and the setting of a specific umask), then appropriate
|
||||
entries in
|
||||
.Xr ftpd.conf 5
|
||||
are required.
|
||||
.Pp
|
||||
If the first character of the password supplied by an anonymous user
|
||||
is
|
||||
.Dq - ,
|
||||
then the verbose messages displayed at login and upon a
|
||||
.Sy CWD
|
||||
command are suppressed.
|
||||
.El
|
||||
.Ss Display file escape sequences
|
||||
When
|
||||
.Nm
|
||||
displays various files back to the client (such as
|
||||
.Pa /etc/ftpwelcome
|
||||
and
|
||||
.Pa /etc/motd ) ,
|
||||
various escape strings are replaced with information pertinent
|
||||
to the current connection.
|
||||
.Pp
|
||||
The supported escape strings are:
|
||||
.Bl -tag -width "Escape" -offset indent -compact
|
||||
.It Sy "Escape"
|
||||
.Sy Description
|
||||
.It "\&%c"
|
||||
Class name.
|
||||
.It "\&%C"
|
||||
Current working directory.
|
||||
.It "\&%E"
|
||||
Email address given with
|
||||
.Fl e .
|
||||
.It "\&%L"
|
||||
Local hostname.
|
||||
.It "\&%M"
|
||||
Maximum number of users for this class.
|
||||
Displays
|
||||
.Dq unlimited
|
||||
if there's no limit.
|
||||
.It "\&%N"
|
||||
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"
|
||||
User name.
|
||||
.It "\&%\&%"
|
||||
A
|
||||
.Dq \&%
|
||||
character.
|
||||
.El
|
||||
.Ss Setting up a restricted ftp subtree
|
||||
In order that system security is not breached, it is recommended
|
||||
that the
|
||||
subtrees for the
|
||||
.Dq ftp
|
||||
and
|
||||
.Dq chroot
|
||||
accounts be constructed with care, following these rules
|
||||
(replace
|
||||
.Dq ftp
|
||||
in the following directory names
|
||||
with the appropriate account name for
|
||||
.Sq chroot
|
||||
users):
|
||||
.Bl -tag -width "~ftp/incoming" -offset indent
|
||||
.It Pa ~ftp
|
||||
Make the home directory owned by
|
||||
.Dq root
|
||||
and unwritable by anyone.
|
||||
.It Pa ~ftp/bin
|
||||
Make this directory owned by
|
||||
.Dq root
|
||||
and unwritable by anyone (mode 555).
|
||||
Generally any conversion commands should be installed
|
||||
here (mode 111).
|
||||
.It Pa ~ftp/etc
|
||||
Make this directory owned by
|
||||
.Dq root
|
||||
and unwritable by anyone (mode 555).
|
||||
The files
|
||||
.Pa pwd.db
|
||||
(see
|
||||
.Xr passwd 5 )
|
||||
and
|
||||
.Pa group
|
||||
(see
|
||||
.Xr group 5 )
|
||||
must be present for the
|
||||
.Sy LIST
|
||||
command to be able to display owner and group names instead of numbers.
|
||||
The password field in
|
||||
.Xr passwd 5
|
||||
is not used, and should not contain real passwords.
|
||||
The file
|
||||
.Pa motd ,
|
||||
if present, will be printed after a successful login.
|
||||
These files should be mode 444.
|
||||
.It Pa ~ftp/pub
|
||||
This directory and the subdirectories beneath it should be owned
|
||||
by the users and groups responsible for placing files in them,
|
||||
and be writable only by them (mode 755 or 775).
|
||||
They should
|
||||
.Em not
|
||||
be owned or writable by ftp or its group.
|
||||
.It Pa ~ftp/incoming
|
||||
This directory is where anonymous users place files they upload.
|
||||
The owners should be the user
|
||||
.Dq ftp
|
||||
and an appropriate group.
|
||||
Members of this group will be the only users with access to these
|
||||
files after they have been uploaded; these should be people who
|
||||
know how to deal with them appropriately.
|
||||
If you wish anonymous
|
||||
.Tn FTP
|
||||
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
|
||||
The following
|
||||
.Xr ftpd.conf 5
|
||||
directives should be used:
|
||||
.Dl "modify guest off"
|
||||
.Dl "umask guest 0707"
|
||||
.Dl "upload guest on"
|
||||
.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
|
||||
the error messages generated by a conversion or
|
||||
.Sy LIST
|
||||
command.
|
||||
The owner should be the user
|
||||
.Dq ftp .
|
||||
The permissions should be 300.
|
||||
.Pp
|
||||
If you don't enable conversion commands, or don't want anonymous users
|
||||
uploading files here (see
|
||||
.Pa ~ftp/incoming
|
||||
above), then don't create this directory.
|
||||
However, error messages from conversion or
|
||||
.Sy LIST
|
||||
commands won't be returned to the user.
|
||||
(This is the traditional behaviour.)
|
||||
Note that the
|
||||
.Xr ftpd.conf 5
|
||||
directive
|
||||
.Sy upload
|
||||
can be used to prevent users uploading here.
|
||||
.El
|
||||
.Pp
|
||||
To set up "ftp-only" accounts that provide only
|
||||
.Tn FTP ,
|
||||
but no valid shell
|
||||
login, you can copy/link
|
||||
.Pa /sbin/nologin
|
||||
to
|
||||
.Pa /sbin/ftplogin ,
|
||||
and enter
|
||||
.Pa /sbin/ftplogin
|
||||
to
|
||||
.Pa /etc/shells
|
||||
to allow logging-in via
|
||||
.Tn FTP
|
||||
into the accounts, which must have
|
||||
.Pa /sbin/ftplogin
|
||||
as login shell.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/ftpwelcome -compact
|
||||
.It Pa /etc/ftpchroot
|
||||
List of normal users whose root directory should be changed via
|
||||
.Xr chroot 2 .
|
||||
.It Pa /etc/ftpd.conf
|
||||
Configure file conversions and other settings.
|
||||
.It Pa /etc/ftpusers
|
||||
List of unwelcome/restricted users.
|
||||
.It Pa /etc/ftpwelcome
|
||||
Welcome notice before login.
|
||||
.It Pa /etc/motd
|
||||
Welcome notice after login.
|
||||
.It Pa /etc/nologin
|
||||
If it exists, displayed and access is refused.
|
||||
.It Pa /var/run/ftpd.pids-CLASS
|
||||
State file of logged-in processes for the
|
||||
.Nm
|
||||
class
|
||||
.Sq CLASS .
|
||||
.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 ,
|
||||
.Xr skey 1 ,
|
||||
.Xr who 1 ,
|
||||
.Xr getusershell 3 ,
|
||||
.Xr ftpchroot 5 ,
|
||||
.Xr ftpd.conf 5 ,
|
||||
.Xr ftpusers 5 ,
|
||||
.Xr login.conf 5 ,
|
||||
.Xr syslogd 8
|
||||
.Sh STANDARDS
|
||||
.Nm
|
||||
recognizes all commands in
|
||||
.Cm RFC 959 ,
|
||||
follows the guidelines in
|
||||
.Cm RFC 1123 ,
|
||||
recognizes all commands in
|
||||
.Cm RFC 2228
|
||||
(although they are not supported yet),
|
||||
and supports the extensions from
|
||||
.Cm RFC 2389 ,
|
||||
.Cm RFC 2428 ,
|
||||
and
|
||||
.Cm RFC 3659 .
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command appeared in
|
||||
.Bx 4.2 .
|
||||
.Pp
|
||||
Various features such as the
|
||||
.Xr ftpd.conf 5
|
||||
functionality,
|
||||
.Cm RFC 2389 ,
|
||||
and
|
||||
.Cm RFC 3659
|
||||
support was implemented in
|
||||
.Nx 1.3
|
||||
and later releases by Luke Mewburn.
|
||||
.Sh BUGS
|
||||
The server must run as the super-user to create sockets with
|
||||
privileged port numbers (i.e, those less than
|
||||
.Dv IPPORT_RESERVED ,
|
||||
which is 1024).
|
||||
If
|
||||
.Nm
|
||||
is listening on a privileged port
|
||||
it maintains an effective user id of the logged in user, reverting
|
||||
to the super-user only when binding addresses to privileged sockets.
|
||||
The
|
||||
.Fl r
|
||||
option can be used to override this behaviour and force privileges to
|
||||
be permanently revoked; see
|
||||
.Sx SECURITY CONSIDERATIONS
|
||||
below for more details.
|
||||
.Pp
|
||||
.Nm
|
||||
may have trouble handling connections from scoped IPv6 addresses, or
|
||||
IPv4 mapped addresses
|
||||
.Po
|
||||
IPv4 connection on
|
||||
.Dv AF_INET6
|
||||
socket
|
||||
.Pc .
|
||||
For the latter case, running two daemons,
|
||||
one for IPv4 and one for IPv6, will avoid the problem.
|
||||
.Sh SECURITY CONSIDERATIONS
|
||||
.Cm RFC 959
|
||||
provides no restrictions on the
|
||||
.Sy PORT
|
||||
command, and this can lead to security problems, as
|
||||
.Nm
|
||||
can be fooled into connecting to any service on any host.
|
||||
With the
|
||||
.Dq checkportcmd
|
||||
feature of the
|
||||
.Xr ftpd.conf 5 ,
|
||||
.Sy PORT
|
||||
commands with different host addresses, or TCP ports lower than
|
||||
.Dv IPPORT_RESERVED
|
||||
will be rejected.
|
||||
This also prevents
|
||||
.Sq third-party proxy ftp
|
||||
from working.
|
||||
Use of this option is
|
||||
.Em strongly
|
||||
recommended, and enabled by default.
|
||||
.Pp
|
||||
By default
|
||||
.Nm
|
||||
uses a port that is one less than the port it is listening on to
|
||||
communicate back to the client for the
|
||||
.Sy EPRT ,
|
||||
.Sy LPRT ,
|
||||
and
|
||||
.Sy PORT
|
||||
commands, unless overridden with
|
||||
.Fl P Ar dataport .
|
||||
As the default port for
|
||||
.Nm
|
||||
(21) is a privileged port below
|
||||
.Dv IPPORT_RESERVED ,
|
||||
.Nm
|
||||
retains the ability to switch back to root privileges to bind these
|
||||
ports.
|
||||
In order to increase security by reducing the potential for a bug in
|
||||
.Nm
|
||||
providing a remote root compromise,
|
||||
.Nm
|
||||
will permanently drop root privileges if one of the following is true:
|
||||
.Bl -enum -offset indent
|
||||
.It
|
||||
.Nm
|
||||
is running on a port greater than
|
||||
.Dv IPPORT_RESERVED
|
||||
and the user has logged in as a
|
||||
.Sq guest
|
||||
or
|
||||
.Sq chroot
|
||||
user.
|
||||
.It
|
||||
.Nm
|
||||
was invoked with
|
||||
.Fl r .
|
||||
.El
|
||||
.Pp
|
||||
Don't create
|
||||
.Pa ~ftp/tmp
|
||||
if you don't want anonymous users to upload files there.
|
||||
That directory is only necessary if you want to display the error
|
||||
messages of conversion commands to the user.
|
||||
Note that if uploads are disabled with the
|
||||
.Xr ftpd.conf 5
|
||||
directive
|
||||
.Sy upload ,
|
||||
then this directory cannot be abused by the user in this way, so it
|
||||
should be safe to create.
|
||||
.Pp
|
||||
To avoid possible denial-of-service attacks,
|
||||
.Sy SIZE
|
||||
requests against files larger than 10240 bytes will be denied if
|
||||
the current transfer
|
||||
.Sy TYPE
|
||||
is
|
||||
.Sq Li A
|
||||
(ASCII).
|
4000
libexec/ftpd/ftpd.c
Normal file
4000
libexec/ftpd/ftpd.c
Normal file
File diff suppressed because it is too large
Load diff
738
libexec/ftpd/ftpd.conf.5
Normal file
738
libexec/ftpd/ftpd.conf.5
Normal file
|
@ -0,0 +1,738 @@
|
|||
.\" $NetBSD: ftpd.conf.5,v 1.37 2009/04/09 02:25:45 joerg Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1997-2008 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software contributed to The NetBSD Foundation
|
||||
.\" by Luke Mewburn.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd April 13, 2007
|
||||
.Dt FTPD.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ftpd.conf
|
||||
.Nd
|
||||
.Xr ftpd 8
|
||||
configuration file
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
file specifies various configuration options for
|
||||
.Xr ftpd 8
|
||||
that apply once a user has authenticated their connection.
|
||||
.Pp
|
||||
.Nm
|
||||
consists of a series of lines, each of which may contain a
|
||||
configuration directive, a comment, or a blank line.
|
||||
Directives that appear later in the file override settings by previous
|
||||
directives.
|
||||
This allows
|
||||
.Sq wildcard
|
||||
entries to define defaults, and then have class-specific overrides.
|
||||
.Pp
|
||||
A directive line has the format:
|
||||
.Dl command class [arguments]
|
||||
.Pp
|
||||
A
|
||||
.Dq \e
|
||||
is the escape character; it can be used to escape the meaning of the
|
||||
comment character, or if it is the last character on a line, extends
|
||||
a configuration directive across multiple lines.
|
||||
A
|
||||
.Dq #
|
||||
is the comment character, and all characters from it to the end of
|
||||
line are ignored (unless it is escaped with the escape character).
|
||||
.Pp
|
||||
Each authenticated user is a member of a
|
||||
.Em class ,
|
||||
which is determined by
|
||||
.Xr ftpusers 5 .
|
||||
.Em class
|
||||
is used to determine which
|
||||
.Nm
|
||||
entries apply to the user.
|
||||
The following special classes exist when parsing entries in
|
||||
.Nm :
|
||||
.Bl -tag -width "chroot" -compact -offset indent
|
||||
.It Sy all
|
||||
Matches any class.
|
||||
.It Sy none
|
||||
Matches no class.
|
||||
.El
|
||||
.Pp
|
||||
Each class has a type, which may be one of:
|
||||
.Bl -tag -width "CHROOT" -offset indent
|
||||
.It Sy GUEST
|
||||
Guests (as per the
|
||||
.Dq anonymous
|
||||
and
|
||||
.Dq ftp
|
||||
logins).
|
||||
A
|
||||
.Xr chroot 2
|
||||
is performed after login.
|
||||
.It Sy CHROOT
|
||||
.Xr chroot 2 Ns ed
|
||||
users (as per
|
||||
.Xr ftpchroot 5 ) .
|
||||
A
|
||||
.Xr chroot 2
|
||||
is performed after login.
|
||||
.It Sy REAL
|
||||
Normal users.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Xr ftpd 8
|
||||
.Sy STAT
|
||||
command will return the class settings for the current user as defined by
|
||||
.Nm ,
|
||||
unless the
|
||||
.Sy private
|
||||
directive is set for the class.
|
||||
.Pp
|
||||
Each configuration line may be one of:
|
||||
.Bl -tag -width 4n
|
||||
.It Sy advertize Ar class Op 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
|
||||
.Ar host
|
||||
not is specified, disable this.
|
||||
.It Sy checkportcmd Ar class Op Sy off
|
||||
Check the
|
||||
.Sy PORT
|
||||
command for validity.
|
||||
The
|
||||
.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
|
||||
.Dv IPPORT_RESERVED .
|
||||
It is
|
||||
.Em strongly
|
||||
encouraged that this option be used, especially for sites concerned
|
||||
with potential security problems with
|
||||
.Tn FTP
|
||||
bounce attacks.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Sy off
|
||||
is specified, disable this feature, otherwise enable it.
|
||||
.It Sy chroot Ar class Op Sy pathformat
|
||||
If
|
||||
.Ar pathformat
|
||||
is not specified or
|
||||
.Ar class
|
||||
is
|
||||
.Dq none ,
|
||||
use the default behavior (see below).
|
||||
Otherwise,
|
||||
.Ar pathformat
|
||||
is parsed to create a directory to create as the root directory with
|
||||
.Xr chroot 2
|
||||
into upon login.
|
||||
.Pp
|
||||
.Ar pathformat
|
||||
can contain the following escape strings:
|
||||
.Bl -tag -width "Escape" -offset indent -compact
|
||||
.It Sy "Escape"
|
||||
.Sy Description
|
||||
.It "\&%c"
|
||||
Class name.
|
||||
.It "\&%d"
|
||||
Home directory of user.
|
||||
.It "\&%u"
|
||||
User name.
|
||||
.It "\&%\&%"
|
||||
A
|
||||
.Dq \&%
|
||||
character.
|
||||
.El
|
||||
.Pp
|
||||
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 specified, 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
|
||||
to
|
||||
.Ar type
|
||||
(see above).
|
||||
.It Sy conversion Ar class Ar suffix Op Ar "type disable command"
|
||||
Define an automatic in-line file conversion.
|
||||
If a file to retrieve ends in
|
||||
.Ar suffix ,
|
||||
and a real file (sans
|
||||
.Ar suffix )
|
||||
exists, then the output of
|
||||
.Ar command
|
||||
is returned instead of the contents of the file.
|
||||
.Pp
|
||||
.Bl -tag -width "disable" -offset indent
|
||||
.It Ar suffix
|
||||
The suffix to initiate the conversion.
|
||||
.It Ar type
|
||||
A list of valid file types for the conversion.
|
||||
Valid types are:
|
||||
.Sq f
|
||||
(file), and
|
||||
.Sq d
|
||||
(directory).
|
||||
.It Ar disable
|
||||
The name of file that will prevent conversion if it exists.
|
||||
A file name of
|
||||
.Dq Pa \&.
|
||||
will prevent this disabling action
|
||||
(i.e., the conversion is always permitted.)
|
||||
.It Ar command
|
||||
The command to run for the conversion.
|
||||
The first word should be the full path name
|
||||
of the command, as
|
||||
.Xr execv 3
|
||||
is used to execute the command.
|
||||
All instances of the word
|
||||
.Dq %s
|
||||
in
|
||||
.Ar command
|
||||
are replaced with the requested file (sans
|
||||
.Ar suffix ) .
|
||||
.El
|
||||
.Pp
|
||||
Conversion directives specified later in the file override earlier
|
||||
conversions with the same suffix.
|
||||
.It Sy denyquick Ar class Op Sy off
|
||||
Enforce
|
||||
.Xr ftpusers 5
|
||||
rules after the
|
||||
.Sy USER
|
||||
command is received, rather than after the
|
||||
.Sy PASS
|
||||
command is received.
|
||||
Whilst enabling this feature may allow information leakage about
|
||||
available accounts (for example, if you allow some users of a
|
||||
.Sy REAL
|
||||
or
|
||||
.Sy CHROOT
|
||||
class but not others), it is useful in preventing a denied user
|
||||
(such as
|
||||
.Sq root )
|
||||
from entering their password across an insecure connection.
|
||||
This option is
|
||||
.Em strongly
|
||||
recommended for servers which run an anonymous-only service.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Sy off
|
||||
is specified, disable this feature, otherwise enable it.
|
||||
.It Sy display Ar class Op Ar file
|
||||
If
|
||||
.Ar file
|
||||
is not specified or
|
||||
.Ar class
|
||||
is
|
||||
.Dq none ,
|
||||
disable this.
|
||||
Otherwise, each time the user enters a new directory, check if
|
||||
.Ar file
|
||||
exists, and if so, display its contents to the user.
|
||||
Escape sequences are supported; refer to
|
||||
.Sx Display file escape sequences
|
||||
in
|
||||
.Xr ftpd 8
|
||||
for more information.
|
||||
.It Sy hidesymlinks Ar class Op Sy off
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Sy off
|
||||
is specified, disable this feature.
|
||||
Otherwise, the
|
||||
.Sy LIST
|
||||
command lists symbolic links as the file or directory the link
|
||||
references
|
||||
.Pq Dq Li "ls -LlA" .
|
||||
Servers which run an anonymous service may wish to enable this
|
||||
feature for
|
||||
.Sy GUEST
|
||||
users, so that symbolic links do not leak names in
|
||||
directories that are not searchable by
|
||||
.Sy GUEST
|
||||
users.
|
||||
.It Sy homedir Ar class Op Sy pathformat
|
||||
If
|
||||
.Ar pathformat
|
||||
is not specified or
|
||||
.Ar class
|
||||
is
|
||||
.Dq none ,
|
||||
use the default behavior (see below).
|
||||
Otherwise,
|
||||
.Ar pathformat
|
||||
is parsed to create a directory to change into upon login, and to use
|
||||
as the
|
||||
.Sq home
|
||||
directory of the user for tilde expansion in pathnames, etc.
|
||||
.Ar pathformat
|
||||
is parsed as per the
|
||||
.Sy chroot
|
||||
directive.
|
||||
.Pp
|
||||
The default home directory is the home directory of the user for
|
||||
.Sy REAL
|
||||
users, and
|
||||
.Pa /
|
||||
for
|
||||
.Sy GUEST
|
||||
and
|
||||
.Sy CHROOT
|
||||
users.
|
||||
.It Sy limit Ar class Op Ar count Op Ar file
|
||||
Limit the maximum number of concurrent connections for
|
||||
.Ar class
|
||||
to
|
||||
.Ar count ,
|
||||
with
|
||||
.Sq \-1
|
||||
meaning unlimited connections.
|
||||
If the limit is exceeded and
|
||||
.Ar file
|
||||
is specified, 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 Op Ar size
|
||||
Set the maximum size of an uploaded file to
|
||||
.Ar size ,
|
||||
with
|
||||
.Sq \-1
|
||||
meaning unlimited connections.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar size
|
||||
is not specified, disable this.
|
||||
.It Sy maxtimeout Ar class Op 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 .
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar time
|
||||
is not specified, use the default.
|
||||
.It Sy mmapsize Ar class Op Ar size
|
||||
Set the size of the sliding window to map a file using
|
||||
.Xr mmap 2 .
|
||||
If zero,
|
||||
.Xr ftpd 8
|
||||
will use
|
||||
.Xr read 2
|
||||
instead.
|
||||
The default is zero.
|
||||
This option affects only binary transfers.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar size
|
||||
is not specified, use the default.
|
||||
.It Sy modify Ar class Op Sy off
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Sy off
|
||||
is specified, disable the following commands:
|
||||
.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
|
||||
.Ar file
|
||||
is not specified or
|
||||
.Ar class
|
||||
is
|
||||
.Dq none ,
|
||||
disable this.
|
||||
Otherwise, use
|
||||
.Ar file
|
||||
as the message of the day file to display after login.
|
||||
Escape sequences are supported; refer to
|
||||
.Sx Display file escape sequences
|
||||
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
|
||||
is not specified or
|
||||
.Ar class
|
||||
is
|
||||
.Dq none ,
|
||||
disable this.
|
||||
Otherwise, each time the user enters a new directory,
|
||||
notify the user of any files matching
|
||||
.Ar fileglob .
|
||||
.It Sy passive Ar class Op Sy off
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Sy off
|
||||
is specified, prevent passive
|
||||
.Sy ( PASV ,
|
||||
.Sy LPSV ,
|
||||
and
|
||||
.Sy EPSV )
|
||||
connections.
|
||||
Otherwise, enable them.
|
||||
.It Sy portrange Ar class Op Ar min Ar max
|
||||
Set the range of port number which will be used for the passive data port.
|
||||
.Ar max
|
||||
must be greater than
|
||||
.Ar min ,
|
||||
and both numbers must be be between
|
||||
.Dv IPPORT_RESERVED
|
||||
(1024) and 65535.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or no arguments are specified, disable this.
|
||||
.It Sy private Ar class Op Sy off
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Sy off
|
||||
is specified, do not display class information in the output of the
|
||||
.Sy STAT
|
||||
command.
|
||||
Otherwise, display the information.
|
||||
.It Sy rateget Ar class Op Ar rate
|
||||
Set the maximum get
|
||||
.Pq Sy RETR
|
||||
transfer rate throttle for
|
||||
.Ar class
|
||||
to
|
||||
.Ar rate
|
||||
bytes per second.
|
||||
If
|
||||
.Ar rate
|
||||
is 0, the throttle is disabled.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar rate
|
||||
is not specified, disable this.
|
||||
.It Sy rateput Ar class Op Ar rate
|
||||
Set the maximum put
|
||||
.Pq Sy STOR
|
||||
transfer rate throttle for
|
||||
.Ar class
|
||||
to
|
||||
.Ar rate
|
||||
bytes per second.
|
||||
If
|
||||
.Ar rate
|
||||
is 0, the throttle is disabled.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar rate
|
||||
is not specified, disable this.
|
||||
.It Sy readsize Ar class Op Ar size
|
||||
Set the size of the read buffer to
|
||||
.Xr read 2
|
||||
a file.
|
||||
The default is the file system block size.
|
||||
This option affects only binary transfers.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar size
|
||||
is not specified, use the default.
|
||||
.It Sy recvbufsize Ar class Op Ar size
|
||||
Set the size of the socket receive buffer.
|
||||
The default is zero and the system default value will be used.
|
||||
This option affects only passive transfers.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar size
|
||||
is not specified, use the default.
|
||||
.It Sy sanenames Ar class Op Sy off
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Sy off
|
||||
is specified, 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 sendbufsize Ar class Op Ar size
|
||||
Set the size of the socket send buffer.
|
||||
The default is zero and the system default value will be used.
|
||||
This option affects only binary transfers.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar size
|
||||
is not specified, use the default.
|
||||
.It Sy sendlowat Ar class Op Ar size
|
||||
Set the low water mark of socket send buffer.
|
||||
The default is zero and system default value will be used.
|
||||
This option affects only for binary transfer.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar size
|
||||
is not specified, use the default.
|
||||
.It Sy template Ar class Op Ar refclass
|
||||
Define
|
||||
.Ar refclass
|
||||
as the
|
||||
.Sq template
|
||||
for
|
||||
.Ar class ;
|
||||
any reference to
|
||||
.Ar refclass
|
||||
in following directives will also apply to members of
|
||||
.Ar class .
|
||||
This is useful to define a template class so that other classes which are
|
||||
to share common attributes can be easily defined without unnecessary
|
||||
duplication.
|
||||
There can be only one template defined at a time.
|
||||
If
|
||||
.Ar refclass
|
||||
is not specified, disable the template for
|
||||
.Ar class .
|
||||
.It Sy timeout Ar class Op Ar time
|
||||
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 .
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar time
|
||||
is not specified, use the default.
|
||||
.It Sy umask Ar class Op Ar umaskval
|
||||
Set the umask to
|
||||
.Ar umaskval .
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar umaskval
|
||||
is not specified, set to the default of
|
||||
.Li 027 .
|
||||
.It Sy upload Ar class Op Sy off
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Sy off
|
||||
is specified, disable the following commands:
|
||||
.Sy APPE ,
|
||||
.Sy STOR ,
|
||||
and
|
||||
.Sy STOU ,
|
||||
as well as the modify commands:
|
||||
.Sy CHMOD ,
|
||||
.Sy DELE ,
|
||||
.Sy MKD ,
|
||||
.Sy RMD ,
|
||||
.Sy RNFR ,
|
||||
and
|
||||
.Sy UMASK .
|
||||
Otherwise, enable them.
|
||||
.It Sy writesize Ar class Op Ar size
|
||||
Limit the number of bytes to
|
||||
.Xr write 2
|
||||
at a time.
|
||||
The default is zero, which means all the data available as a result of
|
||||
.Xr mmap 2
|
||||
or
|
||||
.Xr read 2
|
||||
will be written at a time.
|
||||
This option affects only binary transfers.
|
||||
If
|
||||
.Ar class
|
||||
is
|
||||
.Dq none
|
||||
or
|
||||
.Ar size
|
||||
is not specified, use the default.
|
||||
.El
|
||||
.Ss Numeric argument suffix parsing
|
||||
Where command arguments are numeric, a decimal number is expected.
|
||||
Two or more numbers may be separated by an
|
||||
.Dq x
|
||||
to indicate a product.
|
||||
Each number may have one of the following optional suffixes:
|
||||
.Bl -tag -width 3n -offset indent -compact
|
||||
.It b
|
||||
Block; multiply by 512
|
||||
.It k
|
||||
Kibi; multiply by 1024 (1 KiB)
|
||||
.It m
|
||||
Mebi; multiply by 1048576 (1 MiB)
|
||||
.It g
|
||||
Gibi; multiply by 1073741824 (1 GiB)
|
||||
.It t
|
||||
Tebi; multiply by 1099511627776 (1 TiB)
|
||||
.It w
|
||||
Word; multiply by the number of bytes in an integer
|
||||
.El
|
||||
.Pp
|
||||
See
|
||||
.Xr strsuftoll 3
|
||||
for more information.
|
||||
.Sh DEFAULTS
|
||||
The following defaults are used:
|
||||
.Pp
|
||||
.Bd -literal -offset indent -compact
|
||||
checkportcmd all
|
||||
classtype chroot CHROOT
|
||||
classtype guest GUEST
|
||||
classtype real REAL
|
||||
display none
|
||||
limit all \-1 # unlimited connections
|
||||
maxtimeout all 7200 # 2 hours
|
||||
modify all
|
||||
motd all motd
|
||||
notify none
|
||||
passive all
|
||||
timeout all 900 # 15 minutes
|
||||
umask all 027
|
||||
upload all
|
||||
modify guest off
|
||||
umask guest 0707
|
||||
.Ed
|
||||
.Sh FILES
|
||||
.Bl -tag -width /usr/share/examples/ftpd/ftpd.conf -compact
|
||||
.It Pa /etc/ftpd.conf
|
||||
This file.
|
||||
.It Pa /usr/share/examples/ftpd/ftpd.conf
|
||||
A sample
|
||||
.Nm
|
||||
file.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr strsuftoll 3 ,
|
||||
.Xr ftpchroot 5 ,
|
||||
.Xr ftpusers 5 ,
|
||||
.Xr ftpd 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
functionality was implemented in
|
||||
.Nx 1.3
|
||||
and later releases by Luke Mewburn, based on work by Simon Burge.
|
179
libexec/ftpd/ftpusers.5
Normal file
179
libexec/ftpd/ftpusers.5
Normal file
|
@ -0,0 +1,179 @@
|
|||
.\" $NetBSD: ftpusers.5,v 1.17 2008/09/13 02:41:52 lukem Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1997-2008 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software contributed to The NetBSD Foundation
|
||||
.\" by Luke Mewburn.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd July 17, 2000
|
||||
.Dt FTPUSERS 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ftpusers ,
|
||||
.Nm ftpchroot
|
||||
.Nd
|
||||
.Xr ftpd 8
|
||||
access control file
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
file provides user access control for
|
||||
.Xr ftpd 8
|
||||
by defining which users may login.
|
||||
.Pp
|
||||
If the
|
||||
.Nm
|
||||
file does not exist, all users are denied access.
|
||||
.Pp
|
||||
A
|
||||
.Dq \e
|
||||
is the escape character; it can be used to escape the meaning of the
|
||||
comment character, or if it is the last character on a line, extends
|
||||
a configuration directive across multiple lines.
|
||||
A
|
||||
.Dq #
|
||||
is the comment character, and all characters from it to the end of
|
||||
line are ignored (unless it is escaped with the escape character).
|
||||
.Pp
|
||||
The syntax of each line is:
|
||||
.Dl userglob[:groupglob][@host] [directive [class]]
|
||||
.Pp
|
||||
These elements are:
|
||||
.Bl -tag -width "groupglob" -offset indent
|
||||
.It Sy userglob
|
||||
matched against the user name, using
|
||||
.Xr fnmatch 3
|
||||
glob matching
|
||||
(e.g,
|
||||
.Sq f* ) .
|
||||
.It Sy groupglob
|
||||
matched against all the groups that the user is a member of, using
|
||||
.Xr fnmatch 3
|
||||
glob matching
|
||||
(e.g,
|
||||
.Sq *src ) .
|
||||
.It Sy host
|
||||
either a CIDR address (refer to
|
||||
.Xr inet_net_pton 3 )
|
||||
to match against the remote address
|
||||
(e.g,
|
||||
.Sq 1.2.3.4/24 ) ,
|
||||
or an
|
||||
.Xr fnmatch 3
|
||||
glob to match against the remote hostname
|
||||
(e.g,
|
||||
.Sq *.NetBSD.org ) .
|
||||
.It Sy directive
|
||||
If
|
||||
.Dq allow
|
||||
or
|
||||
.Dq yes
|
||||
the user is allowed access.
|
||||
If
|
||||
.Dq deny
|
||||
or
|
||||
.Dq no ,
|
||||
or
|
||||
.Sy directive
|
||||
is not given, the user is denied access.
|
||||
.It Sy class
|
||||
defines the class to use in
|
||||
.Xr ftpd.conf 5 .
|
||||
.El
|
||||
.Pp
|
||||
If
|
||||
.Sy class
|
||||
is not given, it defaults to one of the following:
|
||||
.Bl -tag -width "chroot" -offset indent
|
||||
.It Sy chroot
|
||||
If there is a match in
|
||||
.Sx /etc/ftpchroot
|
||||
for the user.
|
||||
.It Sy guest
|
||||
If the user name is
|
||||
.Dq anonymous
|
||||
or
|
||||
.Sq ftp .
|
||||
.It Sy real
|
||||
If neither of the above is true.
|
||||
.El
|
||||
.Pp
|
||||
No further comparisons are attempted after the first successful match.
|
||||
If no match is found, the user is granted access.
|
||||
This syntax is backward-compatible with the old syntax.
|
||||
.Pp
|
||||
If a user requests a guest login, the
|
||||
.Xr ftpd 8
|
||||
server checks to see that
|
||||
both
|
||||
.Dq anonymous
|
||||
and
|
||||
.Dq ftp
|
||||
have access, so if you deny all users by default, you will need to add both
|
||||
.Dq "anonymous allow"
|
||||
and
|
||||
.Dq "ftp allow"
|
||||
to
|
||||
.Pa /etc/ftpusers
|
||||
in order to allow guest logins.
|
||||
.Ss /etc/ftpchroot
|
||||
The file
|
||||
.Pa /etc/ftpchroot
|
||||
is used to determine which users will have their session's root directory
|
||||
changed (using
|
||||
.Xr chroot 2 ) ,
|
||||
either to the directory specified in the
|
||||
.Xr ftpd.conf 5
|
||||
.Sy chroot
|
||||
directive (if set),
|
||||
or to the home directory of the user.
|
||||
If the file does not exist, the root directory change is not performed.
|
||||
.Pp
|
||||
The syntax is similar to
|
||||
.Nm ,
|
||||
except that the
|
||||
.Sy class
|
||||
argument is ignored.
|
||||
If there's a positive match, the session's root directory is changed.
|
||||
No further comparisons are attempted after the first successful match.
|
||||
This syntax is backward-compatible with the old syntax.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /usr/share/examples/ftpd/ftpusers -compact
|
||||
.It Pa /etc/ftpchroot
|
||||
List of normal users who should have their ftp session's root directory
|
||||
changed by using
|
||||
.Xr chroot 2 .
|
||||
.It Pa /etc/ftpusers
|
||||
This file.
|
||||
.It Pa /usr/share/examples/ftpd/ftpusers
|
||||
A sample
|
||||
.Nm
|
||||
file.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr fnmatch 3 ,
|
||||
.Xr inet_net_pton 3 ,
|
||||
.Xr ftpd.conf 5 ,
|
||||
.Xr ftpd 8
|
172
libexec/ftpd/logutmp.c
Normal file
172
libexec/ftpd/logutmp.c
Normal file
|
@ -0,0 +1,172 @@
|
|||
/* $NetBSD: logutmp.c,v 1.12 2011/09/16 16:13:17 plunky Exp $ */
|
||||
|
||||
/*
|
||||
* Portions Copyright (c) 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright (c) 1996, Jason Downs. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: logutmp.c,v 1.12 2011/09/16 16:13:17 plunky Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ttyent.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
#ifdef SUPPORT_UTMPX
|
||||
#include <utmpx.h>
|
||||
#endif
|
||||
#include <util.h>
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
#ifdef SUPPORT_UTMP
|
||||
typedef struct utmp UTMP;
|
||||
|
||||
static int fd = -1;
|
||||
static int topslot = -1;
|
||||
|
||||
/*
|
||||
* Special versions of login()/logout() which hold the utmp file open,
|
||||
* for use with ftpd.
|
||||
*/
|
||||
|
||||
void
|
||||
ftpd_login(const struct utmp *ut)
|
||||
{
|
||||
UTMP ubuf;
|
||||
|
||||
/*
|
||||
* First, loop through /etc/ttys, if needed, to initialize the
|
||||
* top of the tty slots, since ftpd has no tty.
|
||||
*/
|
||||
if (topslot < 0) {
|
||||
topslot = 0;
|
||||
while (getttyent() != NULL)
|
||||
topslot++;
|
||||
}
|
||||
if ((topslot < 0) || ((fd < 0)
|
||||
&& (fd = open(_PATH_UTMP, O_RDWR|O_CREAT, 0644)) < 0))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Now find a slot that's not in use...
|
||||
*/
|
||||
(void)lseek(fd, (off_t)(topslot * sizeof(UTMP)), SEEK_SET);
|
||||
|
||||
while (1) {
|
||||
if (read(fd, &ubuf, sizeof(UTMP)) == sizeof(UTMP)) {
|
||||
if (!ubuf.ut_name[0]) {
|
||||
(void)lseek(fd, -(off_t)sizeof(UTMP), SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
topslot++;
|
||||
} else {
|
||||
(void)lseek(fd, (off_t)(topslot * sizeof(UTMP)),
|
||||
SEEK_SET);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(void)write(fd, ut, sizeof(UTMP));
|
||||
}
|
||||
|
||||
int
|
||||
ftpd_logout(const char *line)
|
||||
{
|
||||
UTMP ut;
|
||||
int rval;
|
||||
|
||||
rval = 0;
|
||||
if (fd < 0)
|
||||
return(rval);
|
||||
|
||||
(void)lseek(fd, 0, SEEK_SET);
|
||||
|
||||
while (read(fd, &ut, sizeof(UTMP)) == sizeof(UTMP)) {
|
||||
if (!ut.ut_name[0]
|
||||
|| strncmp(ut.ut_line, line, UT_LINESIZE))
|
||||
continue;
|
||||
memset(ut.ut_name, 0, UT_NAMESIZE);
|
||||
memset(ut.ut_host, 0, UT_HOSTSIZE);
|
||||
(void)time(&ut.ut_time);
|
||||
(void)lseek(fd, -(off_t)sizeof(UTMP), SEEK_CUR);
|
||||
(void)write(fd, &ut, sizeof(UTMP));
|
||||
rval = 1;
|
||||
}
|
||||
return(rval);
|
||||
}
|
||||
#endif /* SUPPORT_UTMP */
|
||||
|
||||
#ifdef SUPPORT_UTMPX
|
||||
/*
|
||||
* special version of loginx which updates utmpx only.
|
||||
*/
|
||||
void
|
||||
ftpd_loginx(const struct utmpx *ut)
|
||||
{
|
||||
(void)pututxline(ut);
|
||||
}
|
||||
|
||||
int
|
||||
ftpd_logoutx(const char *line, int status, int mode)
|
||||
{
|
||||
return logoutx(line, status, mode);
|
||||
}
|
||||
#endif
|
145
libexec/ftpd/logwtmp.c
Normal file
145
libexec/ftpd/logwtmp.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
/* $NetBSD: logwtmp.c,v 1.25 2006/09/23 16:03:50 xtraeme Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)logwtmp.c 8.1 (Berkeley) 6/4/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: logwtmp.c,v 1.25 2006/09/23 16:03:50 xtraeme Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#ifdef SUPPORT_UTMP
|
||||
#include <utmp.h>
|
||||
#endif
|
||||
#ifdef SUPPORT_UTMPX
|
||||
#include <utmpx.h>
|
||||
#endif
|
||||
#include <util.h>
|
||||
|
||||
#ifdef KERBEROS5
|
||||
#include <krb5/krb5.h>
|
||||
#endif
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
#ifdef SUPPORT_UTMP
|
||||
static int fd = -1;
|
||||
|
||||
void
|
||||
ftpd_initwtmp(void)
|
||||
{
|
||||
const char *wf = _PATH_WTMP;
|
||||
if ((fd = open(wf, O_WRONLY|O_APPEND, 0)) == -1)
|
||||
syslog(LOG_ERR, "Cannot open `%s' (%m)", wf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Modified version of logwtmp that holds wtmp file open
|
||||
* after first call, for use with ftp (which may chroot
|
||||
* after login, but before logout).
|
||||
*/
|
||||
void
|
||||
ftpd_logwtmp(const char *line, const char *name, const char *host)
|
||||
{
|
||||
struct utmp ut;
|
||||
struct stat buf;
|
||||
|
||||
if (fd < 0)
|
||||
return;
|
||||
if (fstat(fd, &buf) == 0) {
|
||||
(void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
|
||||
(void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
|
||||
(void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
|
||||
(void)time(&ut.ut_time);
|
||||
if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
|
||||
sizeof(struct utmp))
|
||||
(void)ftruncate(fd, buf.st_size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_UTMPX
|
||||
static int fdx = -1;
|
||||
|
||||
void
|
||||
ftpd_initwtmpx(void)
|
||||
{
|
||||
const char *wf = _PATH_WTMPX;
|
||||
if ((fdx = open(wf, O_WRONLY|O_APPEND, 0)) == -1)
|
||||
syslog(LOG_ERR, "Cannot open `%s' (%m)", wf);
|
||||
}
|
||||
|
||||
void
|
||||
ftpd_logwtmpx(const char *line, const char *name, const char *host,
|
||||
struct sockinet *haddr, int status, int utx_type)
|
||||
{
|
||||
struct utmpx ut;
|
||||
struct stat buf;
|
||||
|
||||
if (fdx < 0)
|
||||
return;
|
||||
if (fstat(fdx, &buf) == 0) {
|
||||
(void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
|
||||
(void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
|
||||
(void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
|
||||
if (haddr)
|
||||
(void)memcpy(&ut.ut_ss, &haddr->si_su, haddr->su_len);
|
||||
else
|
||||
(void)memset(&ut.ut_ss, 0, sizeof(ut.ut_ss));
|
||||
ut.ut_type = utx_type;
|
||||
if (WIFEXITED(status))
|
||||
ut.ut_exit.e_exit = (uint16_t)WEXITSTATUS(status);
|
||||
if (WIFSIGNALED(status))
|
||||
ut.ut_exit.e_termination = (uint16_t)WTERMSIG(status);
|
||||
(void)gettimeofday(&ut.ut_tv, NULL);
|
||||
if(write(fdx, (char *)&ut, sizeof(struct utmpx)) !=
|
||||
sizeof(struct utmpx))
|
||||
(void)ftruncate(fdx, buf.st_size);
|
||||
}
|
||||
}
|
||||
#endif
|
48
libexec/ftpd/pathnames.h
Normal file
48
libexec/ftpd/pathnames.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/* $NetBSD: pathnames.h,v 1.12 2004/12/11 18:37:26 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
|
||||
*/
|
||||
|
||||
#include <paths.h>
|
||||
|
||||
#ifndef _DEFAULT_CONFDIR
|
||||
#define _DEFAULT_CONFDIR "/etc"
|
||||
#endif
|
||||
|
||||
#define _NAME_FTPCHROOT "ftpchroot"
|
||||
#define _NAME_FTPDCONF "ftpd.conf"
|
||||
#define _NAME_FTPLOGINMESG "motd"
|
||||
#define _NAME_FTPUSERS "ftpusers"
|
||||
#define _NAME_FTPWELCOME "ftpwelcome"
|
||||
|
||||
#define _PATH_CLASSPIDS "/var/run/ftpd.pids-"
|
||||
|
||||
#define TMPFILE "/tmp/ftpdXXXXXXX"
|
245
libexec/ftpd/popen.c
Normal file
245
libexec/ftpd/popen.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
/* $NetBSD: popen.c,v 1.37 2010/03/20 18:23:30 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999-2009 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Luke Mewburn.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software written by Ken Arnold and
|
||||
* published in UNIX Review, Vol. 6, No. 8.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: popen.c,v 1.37 2010/03/20 18:23:30 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <glob.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stringlist.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef KERBEROS5
|
||||
#include <krb5/krb5.h>
|
||||
#endif
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
#define INCR 100
|
||||
/*
|
||||
* Special version of popen which avoids call to shell. This ensures no-one
|
||||
* may create a pipe to a hidden program as a side effect of a list or dir
|
||||
* command.
|
||||
* If stderrfd != -1, then send stderr of a read command there,
|
||||
* otherwise close stderr.
|
||||
*/
|
||||
static int *pids;
|
||||
static int fds;
|
||||
|
||||
extern int ls_main(int, char *[]);
|
||||
|
||||
FILE *
|
||||
ftpd_popen(const char *argv[], const char *ptype, int stderrfd)
|
||||
{
|
||||
FILE *iop;
|
||||
int argc, pdes[2], pid;
|
||||
volatile int isls;
|
||||
char **pop;
|
||||
StringList *sl;
|
||||
|
||||
iop = NULL;
|
||||
isls = 0;
|
||||
if ((*ptype != 'r' && *ptype != 'w') || ptype[1])
|
||||
return (NULL);
|
||||
|
||||
if (!pids) {
|
||||
if ((fds = getdtablesize()) <= 0)
|
||||
return (NULL);
|
||||
if ((pids = (int *)malloc((unsigned int)(fds * sizeof(int)))) == NULL)
|
||||
return (NULL);
|
||||
memset(pids, 0, fds * sizeof(int));
|
||||
}
|
||||
if (pipe(pdes) < 0)
|
||||
return (NULL);
|
||||
|
||||
if ((sl = sl_init()) == NULL)
|
||||
goto pfree;
|
||||
|
||||
/* glob each piece */
|
||||
if (sl_add(sl, ftpd_strdup(argv[0])) == -1)
|
||||
goto pfree;
|
||||
for (argc = 1; argv[argc]; argc++) {
|
||||
glob_t gl;
|
||||
int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE|GLOB_LIMIT;
|
||||
|
||||
memset(&gl, 0, sizeof(gl));
|
||||
if (glob(argv[argc], flags, NULL, &gl)
|
||||
|| gl.gl_pathv == NULL) {
|
||||
if (sl_add(sl, ftpd_strdup(argv[argc])) == -1) {
|
||||
globfree(&gl);
|
||||
goto pfree;
|
||||
}
|
||||
} else {
|
||||
for (pop = gl.gl_pathv; *pop; pop++) {
|
||||
if (sl_add(sl, ftpd_strdup(*pop)) == -1) {
|
||||
globfree(&gl);
|
||||
goto pfree;
|
||||
}
|
||||
}
|
||||
}
|
||||
globfree(&gl);
|
||||
}
|
||||
if (sl_add(sl, NULL) == -1)
|
||||
goto pfree;
|
||||
|
||||
#ifndef NO_INTERNAL_LS
|
||||
isls = (strcmp(sl->sl_str[0], INTERNAL_LS) == 0);
|
||||
#endif
|
||||
|
||||
pid = isls ? fork() : vfork();
|
||||
switch (pid) {
|
||||
case -1: /* error */
|
||||
(void)close(pdes[0]);
|
||||
(void)close(pdes[1]);
|
||||
goto pfree;
|
||||
/* NOTREACHED */
|
||||
case 0: /* child */
|
||||
if (*ptype == 'r') {
|
||||
if (pdes[1] != STDOUT_FILENO) {
|
||||
dup2(pdes[1], STDOUT_FILENO);
|
||||
(void)close(pdes[1]);
|
||||
}
|
||||
if (stderrfd == -1)
|
||||
(void)close(STDERR_FILENO);
|
||||
else
|
||||
dup2(stderrfd, STDERR_FILENO);
|
||||
(void)close(pdes[0]);
|
||||
} else {
|
||||
if (pdes[0] != STDIN_FILENO) {
|
||||
dup2(pdes[0], STDIN_FILENO);
|
||||
(void)close(pdes[0]);
|
||||
}
|
||||
(void)close(pdes[1]);
|
||||
}
|
||||
#ifndef NO_INTERNAL_LS
|
||||
if (isls) { /* use internal ls */
|
||||
optreset = optind = optopt = 1;
|
||||
closelog();
|
||||
exit(ls_main(sl->sl_cur - 1, sl->sl_str));
|
||||
}
|
||||
#endif
|
||||
|
||||
execv(sl->sl_str[0], sl->sl_str);
|
||||
_exit(1);
|
||||
}
|
||||
/* parent; assume fdopen can't fail... */
|
||||
if (*ptype == 'r') {
|
||||
iop = fdopen(pdes[0], ptype);
|
||||
(void)close(pdes[1]);
|
||||
} else {
|
||||
iop = fdopen(pdes[1], ptype);
|
||||
(void)close(pdes[0]);
|
||||
}
|
||||
pids[fileno(iop)] = pid;
|
||||
|
||||
pfree:
|
||||
if (sl)
|
||||
sl_free(sl, 1);
|
||||
return (iop);
|
||||
}
|
||||
|
||||
int
|
||||
ftpd_pclose(FILE *iop)
|
||||
{
|
||||
int fdes, status;
|
||||
pid_t pid;
|
||||
sigset_t nsigset, osigset;
|
||||
|
||||
/*
|
||||
* pclose returns -1 if stream is not associated with a
|
||||
* `popened' command, or, if already `pclosed'.
|
||||
*/
|
||||
if (pids == 0 || pids[fdes = fileno(iop)] == 0)
|
||||
return (-1);
|
||||
(void)fclose(iop);
|
||||
sigemptyset(&nsigset);
|
||||
sigaddset(&nsigset, SIGINT);
|
||||
sigaddset(&nsigset, SIGQUIT);
|
||||
sigaddset(&nsigset, SIGHUP);
|
||||
sigprocmask(SIG_BLOCK, &nsigset, &osigset);
|
||||
while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR)
|
||||
continue;
|
||||
sigprocmask(SIG_SETMASK, &osigset, NULL);
|
||||
pids[fdes] = 0;
|
||||
if (pid < 0)
|
||||
return (pid);
|
||||
if (WIFEXITED(status))
|
||||
return (WEXITSTATUS(status));
|
||||
return (1);
|
||||
}
|
33
libexec/ftpd/version.h
Normal file
33
libexec/ftpd/version.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* $NetBSD: version.h,v 1.74 2010/03/21 20:27:26 lukem Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 1999-2009 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Luke Mewburn.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef FTPD_VERSION
|
||||
#define FTPD_VERSION "NetBSD-ftpd 20100320"
|
||||
#endif
|
|
@ -59,6 +59,7 @@
|
|||
2011/05/26 00:00:00,external/public-domain/xz
|
||||
2012/10/17 12:00:00,external/README
|
||||
2012/10/17 12:00:00,include
|
||||
2012/10/17 12:00:00,libexec/ftpd
|
||||
2012/10/17 12:00:00,libexec/ld.elf_so
|
||||
2012/10/17 12:00:00,libexec/Makefile
|
||||
2012/10/17 12:00:00,libexec/Makefile.inc
|
||||
|
|
Loading…
Reference in a new issue