import netbsd ftpd

Change-Id: Id7a3dbd40a6f37c55bcbb0d1456301f60626298f
This commit is contained in:
Ben Gras 2013-05-30 14:47:40 +00:00
parent eb1e5bf042
commit 62da011387
19 changed files with 13250 additions and 2 deletions

View file

@ -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

View file

@ -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

View file

@ -4,7 +4,7 @@
.include <bsd.own.mk>
SUBDIR= \
\
ftpd \
ld.elf_so
.if defined(__MINIX)

58
libexec/ftpd/Makefile Normal file
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

1875
libexec/ftpd/ftpcmd.y Normal file

File diff suppressed because it is too large Load diff

871
libexec/ftpd/ftpd.8 Normal file
View 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

File diff suppressed because it is too large Load diff

738
libexec/ftpd/ftpd.conf.5 Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View file

@ -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