major overhaul (just before netbsd 1.5 :-):
* implement draft-ietf-ftpext-mlst-10 commands, especially MLST and MLSD. we already supported SIZE and MDTM. add the appropriate FEAT output lines. * migrate a lot of the command code from ftpcmd.y and ftpd.c to cmds.c * make dataconn(), feat(), lookup(), opts() and sizecmd() public * modify struct tab so that it has a `flags' instead of `implemented' element, and remove the `hasopts' element. If flags == 1, the command is implemented. if flags == 2, the command is implemented and takes options * add macros ISDOTDIR(x) (is x ".") and ISDOTDOTDIR(x) (is x "..") * modify lreply() so that lreply(-2, ...) just outputs the given info without a prefix or trailing \r\n. this saves doing b = printf(); total_* += b; * enhance statcmd(). still needs work in the LPRT status stuff. * crank version
This commit is contained in:
parent
7c77443b0b
commit
a26448af43
|
@ -1,12 +1,13 @@
|
|||
# $NetBSD: Makefile,v 1.40 2000/03/05 06:12:19 lukem Exp $
|
||||
# $NetBSD: Makefile,v 1.41 2000/06/14 13:44:21 lukem Exp $
|
||||
# @(#)Makefile 8.2 (Berkeley) 4/4/94
|
||||
|
||||
SRCTOP= ../..
|
||||
.include <bsd.crypto.mk>
|
||||
|
||||
PROG= ftpd
|
||||
SRCS= conf.c ftpd.c ftpcmd.y logutmp.c logwtmp.c popen.c
|
||||
SRCS= cmds.c conf.c ftpd.c ftpcmd.y logutmp.c logwtmp.c popen.c
|
||||
CPPFLAGS+=-DHASSETPROCTITLE
|
||||
# CPPFLAGS+=-DDEBUG # XXX for lukem testing
|
||||
DPADD+= ${LIBCRYPT} ${LIBUTIL}
|
||||
LDADD+= -lcrypt -lutil
|
||||
MAN= ftpd.conf.5 ftpusers.5 ftpd.8
|
||||
|
|
|
@ -0,0 +1,779 @@
|
|||
/* $NetBSD: cmds.c,v 1.1 2000/06/14 13:44:22 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999-2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Luke Mewburn.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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.1 2000/06/14 13:44:22 lukem Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <arpa/ftp.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <tzfile.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
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 */
|
||||
int iscurdir; /* nonzero if name is the current dir */
|
||||
} factelem;
|
||||
|
||||
static void ack(const char *);
|
||||
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 void fact_unix_group(const char *, FILE *, factelem *);
|
||||
static void fact_unix_mode(const char *, FILE *, factelem *);
|
||||
static void fact_unix_owner(const char *, FILE *, factelem *);
|
||||
static int matchgroup(gid_t, gid_t *, int);
|
||||
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 },
|
||||
{ "Size", 1, fact_size },
|
||||
{ "Modify", 1, fact_modify },
|
||||
{ "Perm", 1, fact_perm },
|
||||
{ "Unique", 1, fact_unique },
|
||||
{ "UNIX.mode", 1, fact_unix_mode },
|
||||
{ "UNIX.owner", 0, fact_unix_owner },
|
||||
{ "UNIX.group", 0, fact_unix_group },
|
||||
/* "Create" */
|
||||
/* "Lang" */
|
||||
/* "Media-Type" */
|
||||
/* "CharSet" */
|
||||
{ NULL, NULL, },
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
cwd(const char *path)
|
||||
{
|
||||
|
||||
if (chdir(path) < 0)
|
||||
perror_reply(550, path);
|
||||
else {
|
||||
show_chdir_messages(250);
|
||||
ack("CWD");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
delete(const char *name)
|
||||
{
|
||||
char *p = NULL;
|
||||
|
||||
if (remove(name) < 0) {
|
||||
p = strerror(errno);
|
||||
perror_reply(550, name);
|
||||
} else
|
||||
ack("DELE");
|
||||
logcmd("delete", -1, name, NULL, NULL, p);
|
||||
}
|
||||
|
||||
void
|
||||
feat(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
lreply(211, "Features supported");
|
||||
lreply(-1, " MDTM");
|
||||
lreply(-2, " MLST ");
|
||||
for (i = 0; facttab[i].name; i++)
|
||||
lreply(-2, "%s%s;", facttab[i].name,
|
||||
facttab[i].enabled ? "*" : "");
|
||||
lreply(-1, "");
|
||||
lreply(-1, " REST STREAM");
|
||||
lreply(-1, " SIZE");
|
||||
lreply(-1, " TVFS");
|
||||
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.");
|
||||
logcmd("mkdir", -1, name, NULL, NULL, p);
|
||||
}
|
||||
|
||||
void
|
||||
mlsd(const char *path)
|
||||
{
|
||||
FILE *dout;
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
struct stat sb, pdirstat;
|
||||
char name[MAXPATHLEN];
|
||||
factelem f;
|
||||
|
||||
if (path == NULL)
|
||||
path = ".";
|
||||
if (stat(path, &pdirstat) == -1) {
|
||||
mlsdperror:
|
||||
perror_reply(550, path);
|
||||
return;
|
||||
}
|
||||
if (! S_ISDIR(pdirstat.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
goto mlsdperror;
|
||||
}
|
||||
#ifdef DEBUG /* send mlsd to ctrl connection not data connection */
|
||||
dout = stdout;
|
||||
lreply(250, "MLSD %s", path);
|
||||
#else
|
||||
dout = dataconn("MLSD", (off_t)-1, "w");
|
||||
if (dout == NULL)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if ((dirp = opendir(path)) == NULL)
|
||||
goto mlsdperror;
|
||||
f.stat = &sb;
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
snprintf(name, sizeof(name), "%s/%s", path, dp->d_name);
|
||||
/* printf("got >%s< >%s<\n", dp->d_name, name); */
|
||||
if (stat(name, &sb) == -1)
|
||||
continue;
|
||||
f.path = name;
|
||||
if (ISDOTDIR(dp->d_name)) { /* special case curdir: */
|
||||
f.display = path; /* set name to real name */
|
||||
f.iscurdir = 1; /* flag name is curdir */
|
||||
f.pdirstat = NULL; /* require stat of parent */
|
||||
} else {
|
||||
f.display = dp->d_name;
|
||||
f.iscurdir = 0;
|
||||
if (ISDOTDOTDIR(dp->d_name))
|
||||
f.pdirstat = NULL;
|
||||
else
|
||||
f.pdirstat = &pdirstat; /* cache parent stat */
|
||||
}
|
||||
mlsname(dout, &f);
|
||||
}
|
||||
(void)closedir(dirp);
|
||||
|
||||
#ifdef DEBUG
|
||||
reply(250, "End");
|
||||
#else
|
||||
if (ferror(dout) != 0)
|
||||
perror_reply(550, "Data connection");
|
||||
else
|
||||
reply(226, "MLSD complete.");
|
||||
(void) fclose(dout);
|
||||
total_xfers_out++;
|
||||
total_xfers++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
mlst(const char *path)
|
||||
{
|
||||
struct stat sb;
|
||||
factelem f;
|
||||
|
||||
if (path == NULL)
|
||||
path = ".";
|
||||
if (stat(path, &sb) == -1) {
|
||||
perror_reply(550, path);
|
||||
return;
|
||||
}
|
||||
lreply(250, "MLST %s", path);
|
||||
f.path = path;
|
||||
f.display = path;
|
||||
f.stat = &sb;
|
||||
f.pdirstat = NULL;
|
||||
f.iscurdir = 0;
|
||||
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(501, "%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 i, onedone;
|
||||
char *p;
|
||||
|
||||
for (i = 0; facttab[i].name; i++)
|
||||
facttab[i].enabled = 0;
|
||||
if (ep == NULL || *ep == '\0')
|
||||
goto displaymlstopts;
|
||||
|
||||
/* don't like spaces, and need trailing ; */
|
||||
if (strchr(ep, ' ') != NULL || ep[strlen(ep) - 1] != ';') {
|
||||
reply(501, "Invalid MLST options");
|
||||
return;
|
||||
}
|
||||
while ((p = strsep(&ep, ";")) != NULL) {
|
||||
for (i = 0; facttab[i].name; i++)
|
||||
if (strcasecmp(p, facttab[i].name) == 0) {
|
||||
facttab[i].enabled = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
displaymlstopts:
|
||||
lreply(-2, "200 MLST OPTS");
|
||||
for (i = onedone = 0; facttab[i].name; i++) {
|
||||
if (facttab[i].enabled) {
|
||||
lreply(-2, "%s%s;", onedone ? "" : " ",
|
||||
facttab[i].name);
|
||||
onedone++;
|
||||
}
|
||||
}
|
||||
lreply(-1, "");
|
||||
return;
|
||||
}
|
||||
|
||||
/* default cases */
|
||||
if (ep != NULL && *ep != '\0')
|
||||
REASSIGN(c->options, xstrdup(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)
|
||||
reply(550, "Can't get the current directory: %s.",
|
||||
strerror(errno));
|
||||
else
|
||||
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");
|
||||
logcmd("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 (xstrdup(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");
|
||||
logcmd("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, "%qu", (qufmt_t)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;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
while((c=getc(fin)) != EOF) {
|
||||
if (c == '\n') /* will get expanded to \r\n */
|
||||
count++;
|
||||
count++;
|
||||
}
|
||||
(void) fclose(fin);
|
||||
|
||||
reply(213, "%qd", (qdfmt_t)count);
|
||||
break; }
|
||||
default:
|
||||
reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
statfilecmd(const char *filename)
|
||||
{
|
||||
FILE *fin;
|
||||
int c;
|
||||
char *argv[] = { INTERNAL_LS, "-lgA", "", NULL };
|
||||
|
||||
argv[2] = (char *)filename;
|
||||
fin = ftpd_popen(argv, "r", STDOUT_FILENO);
|
||||
lreply(211, "status of %s:", filename);
|
||||
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;
|
||||
}
|
||||
(void) putchar('\r');
|
||||
total_bytes++;
|
||||
total_bytes_out++;
|
||||
}
|
||||
(void) putchar(c);
|
||||
total_bytes++;
|
||||
total_bytes_out++;
|
||||
}
|
||||
(void) ftpd_pclose(fin);
|
||||
reply(211, "End of Status");
|
||||
}
|
||||
|
||||
/* -- */
|
||||
|
||||
static void
|
||||
ack(const char *s)
|
||||
{
|
||||
|
||||
reply(250, "%s command successful.", s);
|
||||
}
|
||||
|
||||
static void
|
||||
fact_modify(const char *fact, FILE *fd, factelem *fe)
|
||||
{
|
||||
struct tm *t;
|
||||
|
||||
t = gmtime(&(fe->stat->st_mtime));
|
||||
fprintf(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, ngid;
|
||||
struct stat *pdir;
|
||||
gid_t gids[NGROUPS_MAX];
|
||||
|
||||
ngid = getgroups(sizeof(gids), gids);
|
||||
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, gids, ngid)) {
|
||||
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);
|
||||
}
|
||||
|
||||
fprintf(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.modify) {
|
||||
size_t len;
|
||||
char realdir[MAXPATHLEN], *p;
|
||||
struct stat dir;
|
||||
|
||||
len = strlcpy(realdir, fe->path, sizeof(realdir));
|
||||
/* printf("[path=%s]", fe->path); */
|
||||
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));
|
||||
}
|
||||
/* printf("[real=%s]", 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, gids, ngid))
|
||||
pdirwok = ((pdir->st_mode & S_IWGRP) != 0);
|
||||
else
|
||||
pdirwok = ((pdir->st_mode & S_IWOTH) != 0);
|
||||
}
|
||||
|
||||
/* printf("[euid=%d,r%d,w%d,x%d,pw%d]", geteuid(), rok, wok, xok, pdirwok);
|
||||
*/
|
||||
|
||||
/* 'a': can APPE to file */
|
||||
if (wok && curclass.upload && S_ISREG(fe->stat->st_mode))
|
||||
fputs("a", fd);
|
||||
|
||||
/* 'c': can create or append to files in directory */
|
||||
if (wok && curclass.modify && S_ISDIR(fe->stat->st_mode))
|
||||
fputs("c", fd);
|
||||
|
||||
/* 'd': can delete file or directory */
|
||||
if (pdirwok && curclass.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)
|
||||
fputs("d", fd);
|
||||
}
|
||||
|
||||
/* 'e': can enter directory */
|
||||
if (xok && S_ISDIR(fe->stat->st_mode))
|
||||
fputs("e", fd);
|
||||
|
||||
/* 'f': can rename file or directory */
|
||||
if (pdirwok && curclass.modify)
|
||||
fputs("f", fd);
|
||||
|
||||
/* 'l': can list directory */
|
||||
if (rok && xok && S_ISDIR(fe->stat->st_mode))
|
||||
fputs("l", fd);
|
||||
|
||||
/* 'm': can create directory */
|
||||
if (wok && curclass.modify && S_ISDIR(fe->stat->st_mode))
|
||||
fputs("m", fd);
|
||||
|
||||
/* 'p': can remove files in directory */
|
||||
if (wok && curclass.modify && S_ISDIR(fe->stat->st_mode))
|
||||
fputs("p", fd);
|
||||
|
||||
/* 'r': can RETR file */
|
||||
if (rok && S_ISREG(fe->stat->st_mode))
|
||||
fputs("r", fd);
|
||||
|
||||
/* 'w': can STOR file */
|
||||
if (wok && curclass.upload && S_ISREG(fe->stat->st_mode))
|
||||
fputs("w", fd);
|
||||
|
||||
fputc(';', fd);
|
||||
}
|
||||
|
||||
static void
|
||||
fact_size(const char *fact, FILE *fd, factelem *fe)
|
||||
{
|
||||
|
||||
if (S_ISREG(fe->stat->st_mode))
|
||||
fprintf(fd, "%s=%lld;", fact, (long long)fe->stat->st_size);
|
||||
}
|
||||
|
||||
static void
|
||||
fact_type(const char *fact, FILE *fd, factelem *fe)
|
||||
{
|
||||
|
||||
fprintf(fd, "%s=", fact);
|
||||
switch (fe->stat->st_mode & S_IFMT) {
|
||||
case S_IFDIR:
|
||||
if (fe->iscurdir || ISDOTDIR(fe->display))
|
||||
fputs("cdir", fd);
|
||||
else if (ISDOTDOTDIR(fe->display))
|
||||
fputs("pdir", fd);
|
||||
else
|
||||
fputs("dir", fd);
|
||||
break;
|
||||
case S_IFREG:
|
||||
fputs("file", fd);
|
||||
break;
|
||||
case S_IFIFO:
|
||||
fputs("OS.unix=fifo", fd);
|
||||
break;
|
||||
case S_IFLNK:
|
||||
fputs("OS.unix=slink", fd);
|
||||
break;
|
||||
case S_IFSOCK:
|
||||
fputs("OS.unix=socket", fd);
|
||||
break;
|
||||
case S_IFBLK:
|
||||
case S_IFCHR:
|
||||
fprintf(fd, "OS.unix=%s-%d/%d",
|
||||
S_ISBLK(fe->stat->st_mode) ? "blk" : "chr",
|
||||
major(fe->stat->st_rdev), minor(fe->stat->st_rdev));
|
||||
break;
|
||||
default:
|
||||
fprintf(fd, "OS.unix=UNKNOWN(0%o)", fe->stat->st_mode & S_IFMT);
|
||||
break;
|
||||
}
|
||||
fputc(';', fd);
|
||||
}
|
||||
|
||||
static void
|
||||
fact_unique(const char *fact, FILE *fd, factelem *fe)
|
||||
{
|
||||
|
||||
fprintf(fd, "%s=%04x%08x;", fact, fe->stat->st_dev, fe->stat->st_ino);
|
||||
}
|
||||
|
||||
static void
|
||||
fact_unix_mode(const char *fact, FILE *fd, factelem *fe)
|
||||
{
|
||||
|
||||
fprintf(fd, "%s=%03o;", fact, fe->stat->st_mode & ACCESSPERMS);
|
||||
}
|
||||
|
||||
static void
|
||||
fact_unix_owner(const char *fact, FILE *fd, factelem *fe)
|
||||
{
|
||||
|
||||
fprintf(fd, "%s=%d;", fact, (int)fe->stat->st_uid);
|
||||
}
|
||||
|
||||
static void
|
||||
fact_unix_group(const char *fact, FILE *fd, factelem *fe)
|
||||
{
|
||||
|
||||
fprintf(fd, "%s=%d;", fact, (int)fe->stat->st_gid);
|
||||
}
|
||||
|
||||
static int
|
||||
matchgroup(gid_t gid, gid_t *gidlist, int ngids)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ngids; i++)
|
||||
if (gid == gidlist[i])
|
||||
return(1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
mlsname(FILE *fp, factelem *fe)
|
||||
{
|
||||
int i;
|
||||
|
||||
fputs(" ", fp);
|
||||
for (i = 0; facttab[i].name; i++) {
|
||||
if (facttab[i].enabled)
|
||||
(facttab[i].display)(facttab[i].name, fp, fe);
|
||||
}
|
||||
fprintf(fp, " %s\r\n", fe->display);
|
||||
}
|
||||
|
||||
static void
|
||||
replydirname(const char *name, const char *message)
|
||||
{
|
||||
char npath[MAXPATHLEN];
|
||||
int i;
|
||||
|
||||
for (i = 0; *name != '\0' && i < sizeof(npath) - 1; i++, name++) {
|
||||
npath[i] = *name;
|
||||
if (*name == '"')
|
||||
npath[++i] = '"';
|
||||
}
|
||||
npath[i] = '\0';
|
||||
reply(257, "\"%s\" %s", npath, message);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: extern.h,v 1.26 2000/05/20 02:20:18 lukem Exp $ */
|
||||
/* $NetBSD: extern.h,v 1.27 2000/06/14 13:44:22 lukem Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992, 1993
|
||||
|
@ -105,10 +105,12 @@ char *conffilename(const char *);
|
|||
char **copyblk(char **);
|
||||
void count_users(void);
|
||||
void cwd(const char *);
|
||||
FILE *dataconn(const char *, off_t, const char *);
|
||||
void delete(const char *);
|
||||
char **do_conversion(const char *);
|
||||
void dologout(int);
|
||||
void fatal(const char *);
|
||||
void feat(void);
|
||||
int format_file(const char *, int);
|
||||
int ftpd_pclose(FILE *);
|
||||
FILE *ftpd_popen(char *[], const char *, int);
|
||||
|
@ -117,8 +119,12 @@ void init_curclass(void);
|
|||
void logcmd(const char *, off_t, const char *, const char *,
|
||||
const struct timeval *, const char *);
|
||||
void logwtmp(const char *, const char *, const char *);
|
||||
struct tab *lookup(struct tab *, const char *);
|
||||
void lreply(int, 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);
|
||||
|
@ -132,6 +138,7 @@ void reply(int, const char *, ...);
|
|||
void retrieve(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 store(const char *, const char *, int);
|
||||
|
@ -147,7 +154,16 @@ typedef enum {
|
|||
CLASS_GUEST,
|
||||
CLASS_CHROOT,
|
||||
CLASS_REAL
|
||||
} class_t;
|
||||
} class_ft;
|
||||
|
||||
struct tab {
|
||||
char *name;
|
||||
short token;
|
||||
short state;
|
||||
short flags; /* 1 if command implemented, 2 if has options */
|
||||
char *help;
|
||||
char *options;
|
||||
};
|
||||
|
||||
struct ftpconv {
|
||||
struct ftpconv *next;
|
||||
|
@ -177,7 +193,7 @@ struct ftpclass {
|
|||
int rateget; /* Get (RETR) transfer rate throttle */
|
||||
int rateput; /* Put (STOR) transfer rate throttle */
|
||||
unsigned int timeout; /* Default timeout */
|
||||
class_t type; /* Class type */
|
||||
class_ft type; /* Class type */
|
||||
mode_t umask; /* Umask to use */
|
||||
int upload; /* As per modify, but also allow
|
||||
APPE, STOR, STOU */
|
||||
|
@ -244,6 +260,21 @@ 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 == 2)
|
||||
|
||||
#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 { \
|
||||
|
@ -251,5 +282,3 @@ GLOBAL off_t total_xfers_in, total_xfers_out, total_xfers;
|
|||
} 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)
|
||||
|
||||
#define INTERNAL_LS "/bin/ls"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $NetBSD: ftpcmd.y,v 1.46 2000/05/20 02:20:18 lukem Exp $ */
|
||||
/* $NetBSD: ftpcmd.y,v 1.47 2000/06/14 13:44:23 lukem Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997-1999 The NetBSD Foundation, Inc.
|
||||
* Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
|
@ -83,7 +83,7 @@
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)ftpcmd.y 8.3 (Berkeley) 4/6/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: ftpcmd.y,v 1.46 2000/05/20 02:20:18 lukem Exp $");
|
||||
__RCSID("$NetBSD: ftpcmd.y,v 1.47 2000/06/14 13:44:23 lukem Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -150,7 +150,7 @@ char *fromname;
|
|||
|
||||
FEAT OPTS
|
||||
|
||||
SIZE MDTM
|
||||
SIZE MDTM MLST MLSD
|
||||
|
||||
LPRT LPSV EPRT EPSV
|
||||
|
||||
|
@ -952,11 +952,8 @@ cmd
|
|||
/* RFC 2389 */
|
||||
| FEAT CRLF
|
||||
{
|
||||
lreply(211, "Features supported");
|
||||
lreply(-1, " MDTM");
|
||||
lreply(-1, " REST STREAM");
|
||||
lreply(-1, " SIZE");
|
||||
reply(211, "End");
|
||||
|
||||
feat();
|
||||
}
|
||||
|
||||
| OPTS SP STRING CRLF
|
||||
|
@ -967,12 +964,9 @@ cmd
|
|||
}
|
||||
|
||||
|
||||
/* BSD extensions */
|
||||
/* extensions from draft-ietf-ftpext-mlst-10 */
|
||||
|
||||
/*
|
||||
* SIZE is not in RFC 959, but Postel has blessed it and
|
||||
* it will be in the updated RFC.
|
||||
*
|
||||
* Return size of file in a format suitable for
|
||||
* using with RESTART (we just count bytes).
|
||||
*/
|
||||
|
@ -985,9 +979,6 @@ cmd
|
|||
}
|
||||
|
||||
/*
|
||||
* MDTM is not in RFC 959, but Postel has blessed it and
|
||||
* it will be in the updated RFC.
|
||||
*
|
||||
* Return modification time of file as an ISO 3307
|
||||
* style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx
|
||||
* where xxx is the fractional second (of any precision,
|
||||
|
@ -1003,6 +994,7 @@ cmd
|
|||
reply(550, "%s: not a plain file.", $4);
|
||||
} else {
|
||||
struct tm *t;
|
||||
|
||||
t = gmtime(&stbuf.st_mtime);
|
||||
reply(213,
|
||||
"%04d%02d%02d%02d%02d%02d",
|
||||
|
@ -1015,6 +1007,32 @@ cmd
|
|||
free($4);
|
||||
}
|
||||
|
||||
| MLST check_login SP pathname CRLF
|
||||
{
|
||||
if ($2 && $4 != NULL)
|
||||
mlst($4);
|
||||
if ($4 != NULL)
|
||||
free($4);
|
||||
}
|
||||
|
||||
| MLST CRLF
|
||||
{
|
||||
mlst(NULL);
|
||||
}
|
||||
|
||||
| MLSD check_login SP pathname CRLF
|
||||
{
|
||||
if ($2 && $4 != NULL)
|
||||
mlsd($4);
|
||||
if ($4 != NULL)
|
||||
free($4);
|
||||
}
|
||||
|
||||
| MLSD CRLF
|
||||
{
|
||||
mlsd(NULL);
|
||||
}
|
||||
|
||||
| error CRLF
|
||||
{
|
||||
yyerrok;
|
||||
|
@ -1373,111 +1391,100 @@ check_upload
|
|||
#define NSTR 8 /* Number followed by a string */
|
||||
#define NOARGS 9 /* No arguments allowed */
|
||||
|
||||
struct tab {
|
||||
char *name;
|
||||
short token;
|
||||
short state;
|
||||
short implemented; /* 1 if command is implemented */
|
||||
short hasopts; /* 1 if command takes options */
|
||||
char *help;
|
||||
char *options;
|
||||
};
|
||||
|
||||
struct tab cmdtab[] = {
|
||||
/* From RFC 959, in order defined (5.3.1) */
|
||||
{ "USER", USER, STR1, 1, 0, "<sp> username" },
|
||||
{ "PASS", PASS, ZSTR1, 1, 0, "<sp> password" },
|
||||
{ "ACCT", ACCT, STR1, 0, 0, "(specify account)" },
|
||||
{ "CWD", CWD, OSTR, 1, 0, "[ <sp> directory-name ]" },
|
||||
{ "CDUP", CDUP, NOARGS, 1, 0, "(change to parent directory)" },
|
||||
{ "SMNT", SMNT, ARGS, 0, 0, "(structure mount)" },
|
||||
{ "QUIT", QUIT, NOARGS, 1, 0, "(terminate service)" },
|
||||
{ "REIN", REIN, NOARGS, 0, 0, "(reinitialize server state)" },
|
||||
{ "PORT", PORT, ARGS, 1, 0, "<sp> b0, b1, b2, b3, b4" },
|
||||
{ "LPRT", LPRT, ARGS, 1, 0, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." },
|
||||
{ "EPRT", EPRT, STR1, 1, 0, "<sp> |af|addr|port|" },
|
||||
{ "PASV", PASV, NOARGS, 1, 0, "(set server in passive mode)" },
|
||||
{ "LPSV", LPSV, ARGS, 1, 0, "(set server in passive mode)" },
|
||||
{ "EPSV", EPSV, ARGS, 1, 0, "[<sp> af|ALL]" },
|
||||
{ "TYPE", TYPE, ARGS, 1, 0, "<sp> [ A | E | I | L ]" },
|
||||
{ "STRU", STRU, ARGS, 1, 0, "(specify file structure)" },
|
||||
{ "MODE", MODE, ARGS, 1, 0, "(specify transfer mode)" },
|
||||
{ "RETR", RETR, STR1, 1, 0, "<sp> file-name" },
|
||||
{ "STOR", STOR, STR1, 1, 0, "<sp> file-name" },
|
||||
{ "STOU", STOU, STR1, 1, 0, "<sp> file-name" },
|
||||
{ "APPE", APPE, STR1, 1, 0, "<sp> file-name" },
|
||||
{ "ALLO", ALLO, ARGS, 1, 0, "allocate storage (vacuously)" },
|
||||
{ "REST", REST, ARGS, 1, 0, "<sp> offset (restart command)" },
|
||||
{ "RNFR", RNFR, STR1, 1, 0, "<sp> file-name" },
|
||||
{ "RNTO", RNTO, STR1, 1, 0, "<sp> file-name" },
|
||||
{ "ABOR", ABOR, NOARGS, 1, 0, "(abort operation)" },
|
||||
{ "DELE", DELE, STR1, 1, 0, "<sp> file-name" },
|
||||
{ "RMD", RMD, STR1, 1, 0, "<sp> path-name" },
|
||||
{ "MKD", MKD, STR1, 1, 0, "<sp> path-name" },
|
||||
{ "PWD", PWD, NOARGS, 1, 0, "(return current directory)" },
|
||||
{ "LIST", LIST, OSTR, 1, 0, "[ <sp> path-name ]" },
|
||||
{ "NLST", NLST, OSTR, 1, 0, "[ <sp> path-name ]" },
|
||||
{ "SITE", SITE, SITECMD, 1, 0, "site-cmd [ <sp> arguments ]" },
|
||||
{ "SYST", SYST, NOARGS, 1, 0, "(get type of operating system)" },
|
||||
{ "STAT", STAT, OSTR, 1, 0, "[ <sp> path-name ]" },
|
||||
{ "HELP", HELP, OSTR, 1, 0, "[ <sp> <string> ]" },
|
||||
{ "NOOP", NOOP, NOARGS, 1, 1, "" },
|
||||
{ "USER", USER, STR1, 1, "<sp> username" },
|
||||
{ "PASS", PASS, ZSTR1, 1, "<sp> password" },
|
||||
{ "ACCT", ACCT, STR1, 0, "(specify account)" },
|
||||
{ "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" },
|
||||
{ "CDUP", CDUP, NOARGS, 1, "(change to parent directory)" },
|
||||
{ "SMNT", SMNT, ARGS, 0, "(structure mount)" },
|
||||
{ "QUIT", QUIT, NOARGS, 1, "(terminate service)" },
|
||||
{ "REIN", REIN, NOARGS, 0, "(reinitialize server state)" },
|
||||
{ "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" },
|
||||
{ "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." },
|
||||
{ "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|" },
|
||||
{ "PASV", PASV, NOARGS, 1, "(set server in passive mode)" },
|
||||
{ "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" },
|
||||
{ "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]" },
|
||||
{ "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" },
|
||||
{ "STRU", STRU, ARGS, 1, "(specify file structure)" },
|
||||
{ "MODE", MODE, ARGS, 1, "(specify transfer mode)" },
|
||||
{ "RETR", RETR, STR1, 1, "<sp> file-name" },
|
||||
{ "STOR", STOR, STR1, 1, "<sp> file-name" },
|
||||
{ "STOU", STOU, STR1, 1, "<sp> file-name" },
|
||||
{ "APPE", APPE, STR1, 1, "<sp> file-name" },
|
||||
{ "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" },
|
||||
{ "REST", REST, ARGS, 1, "<sp> offset (restart command)" },
|
||||
{ "RNFR", RNFR, STR1, 1, "<sp> file-name" },
|
||||
{ "RNTO", RNTO, STR1, 1, "<sp> file-name" },
|
||||
{ "ABOR", ABOR, NOARGS, 1, "(abort operation)" },
|
||||
{ "DELE", DELE, STR1, 1, "<sp> file-name" },
|
||||
{ "RMD", RMD, STR1, 1, "<sp> path-name" },
|
||||
{ "MKD", MKD, STR1, 1, "<sp> path-name" },
|
||||
{ "PWD", PWD, NOARGS, 1, "(return current directory)" },
|
||||
{ "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" },
|
||||
{ "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" },
|
||||
{ "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" },
|
||||
{ "SYST", SYST, NOARGS, 1, "(get type of operating system)" },
|
||||
{ "STAT", STAT, OSTR, 1, "[ <sp> path-name ]" },
|
||||
{ "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" },
|
||||
{ "NOOP", NOOP, NOARGS, 2, "" },
|
||||
|
||||
/* From RFC 2228, in order defined */
|
||||
{ "AUTH", AUTH, STR1, 1, 0, "<sp> mechanism-name" },
|
||||
{ "ADAT", ADAT, STR1, 1, 0, "<sp> base-64-data" },
|
||||
{ "PROT", PROT, STR1, 1, 0, "<sp> prot-code" },
|
||||
{ "PBSZ", PBSZ, ARGS, 1, 0, "<sp> decimal-integer" },
|
||||
{ "CCC", CCC, NOARGS, 1, 0, "(Disable data protection)" },
|
||||
{ "MIC", MIC, STR1, 1, 0, "<sp> base64data" },
|
||||
{ "CONF", CONF, STR1, 1, 0, "<sp> base64data" },
|
||||
{ "ENC", ENC, STR1, 1, 0, "<sp> base64data" },
|
||||
{ "AUTH", AUTH, STR1, 1, "<sp> mechanism-name" },
|
||||
{ "ADAT", ADAT, STR1, 1, "<sp> base-64-data" },
|
||||
{ "PROT", PROT, STR1, 1, "<sp> prot-code" },
|
||||
{ "PBSZ", PBSZ, ARGS, 1, "<sp> decimal-integer" },
|
||||
{ "CCC", CCC, NOARGS, 1, "(Disable data protection)" },
|
||||
{ "MIC", MIC, STR1, 1, "<sp> base64data" },
|
||||
{ "CONF", CONF, STR1, 1, "<sp> base64data" },
|
||||
{ "ENC", ENC, STR1, 1, "<sp> base64data" },
|
||||
|
||||
/* From RFC 2389, in order defined */
|
||||
{ "FEAT", FEAT, NOARGS, 1, 0, "(display extended features)" },
|
||||
{ "OPTS", OPTS, STR1, 1, 0, "<sp> command [ <sp> options ]" },
|
||||
{ "FEAT", FEAT, NOARGS, 1, "(display extended features)" },
|
||||
{ "OPTS", OPTS, STR1, 1, "<sp> command [ <sp> options ]" },
|
||||
|
||||
/* Non standardized extensions */
|
||||
{ "SIZE", SIZE, OSTR, 1, 0, "<sp> path-name" },
|
||||
{ "MDTM", MDTM, OSTR, 1, 0, "<sp> path-name" },
|
||||
/* from draft-ietf-ftpext-mlst-10 */
|
||||
{ "MDTM", MDTM, OSTR, 1, "<sp> path-name" },
|
||||
{ "SIZE", SIZE, OSTR, 1, "<sp> path-name" },
|
||||
{ "MLST", MLST, OSTR, 2, "[ <sp> path-name ]" },
|
||||
{ "MLSD", MLSD, OSTR, 1, "[ <sp> directory-name ]" },
|
||||
|
||||
/* obsolete commands */
|
||||
{ "MAIL", MAIL, OSTR, 0, 0, "(mail to user)" },
|
||||
{ "MLFL", MLFL, OSTR, 0, 0, "(mail file)" },
|
||||
{ "MRCP", MRCP, STR1, 0, 0, "(mail recipient)" },
|
||||
{ "MRSQ", MRSQ, OSTR, 0, 0, "(mail recipient scheme question)" },
|
||||
{ "MSAM", MSAM, OSTR, 0, 0, "(mail send to terminal and mailbox)" },
|
||||
{ "MSND", MSND, OSTR, 0, 0, "(mail send to terminal)" },
|
||||
{ "MSOM", MSOM, OSTR, 0, 0, "(mail send to terminal or mailbox)" },
|
||||
{ "XCUP", CDUP, NOARGS, 1, 0, "(change to parent directory)" },
|
||||
{ "XCWD", CWD, OSTR, 1, 0, "[ <sp> directory-name ]" },
|
||||
{ "XMKD", MKD, STR1, 1, 0, "<sp> path-name" },
|
||||
{ "XPWD", PWD, NOARGS, 1, 0, "(return current directory)" },
|
||||
{ "XRMD", RMD, STR1, 1, 0, "<sp> path-name" },
|
||||
{ "MAIL", MAIL, OSTR, 0, "(mail to user)" },
|
||||
{ "MLFL", MLFL, OSTR, 0, "(mail file)" },
|
||||
{ "MRCP", MRCP, STR1, 0, "(mail recipient)" },
|
||||
{ "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" },
|
||||
{ "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" },
|
||||
{ "MSND", MSND, OSTR, 0, "(mail send to terminal)" },
|
||||
{ "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" },
|
||||
{ "XCUP", CDUP, NOARGS, 1, "(change to parent directory)" },
|
||||
{ "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" },
|
||||
{ "XMKD", MKD, STR1, 1, "<sp> path-name" },
|
||||
{ "XPWD", PWD, NOARGS, 1, "(return current directory)" },
|
||||
{ "XRMD", RMD, STR1, 1, "<sp> path-name" },
|
||||
|
||||
{ NULL, 0, 0, 0, 0, 0 }
|
||||
{ NULL, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
struct tab sitetab[] = {
|
||||
{ "CHMOD", CHMOD, NSTR, 1, 0, "<sp> mode <sp> file-name" },
|
||||
{ "HELP", HELP, OSTR, 1, 0, "[ <sp> <string> ]" },
|
||||
{ "IDLE", IDLE, ARGS, 1, 0, "[ <sp> maximum-idle-time ]" },
|
||||
{ "RATEGET", RATEGET, OSTR, 1,0,"[ <sp> get-throttle-rate ]" },
|
||||
{ "RATEPUT", RATEPUT, OSTR, 1,0,"[ <sp> put-throttle-rate ]" },
|
||||
{ "UMASK", UMASK, ARGS, 1, 0, "[ <sp> umask ]" },
|
||||
{ NULL, 0, 0, 0, 0, 0 }
|
||||
{ "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" },
|
||||
{ "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" },
|
||||
{ "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" },
|
||||
{ "RATEGET", RATEGET,OSTR, 1, "[ <sp> get-throttle-rate ]" },
|
||||
{ "RATEPUT", RATEPUT,OSTR, 1, "[ <sp> put-throttle-rate ]" },
|
||||
{ "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" },
|
||||
{ NULL, 0, 0, 0, NULL }
|
||||
};
|
||||
|
||||
static void help(struct tab *, const char *);
|
||||
static struct tab *lookup(struct tab *, const char *);
|
||||
static void opts(const char *);
|
||||
static void sizecmd(char *);
|
||||
static void help(struct tab *, const char *);
|
||||
static void toolong(int);
|
||||
static int yylex(void);
|
||||
|
||||
extern int epsvall;
|
||||
|
||||
static struct tab *
|
||||
struct tab *
|
||||
lookup(struct tab *p, const char *cmd)
|
||||
{
|
||||
|
||||
|
@ -1630,7 +1637,7 @@ yylex(void)
|
|||
p = lookup(cmdtab, cbuf);
|
||||
cbuf[cpos] = c;
|
||||
if (p != NULL) {
|
||||
if (p->implemented == 0) {
|
||||
if (! CMD_IMPLEMENTED(p)) {
|
||||
reply(502, "%s command not implemented.",
|
||||
p->name);
|
||||
hasyyerrored = 1;
|
||||
|
@ -1655,7 +1662,7 @@ yylex(void)
|
|||
p = lookup(sitetab, cp);
|
||||
cbuf[cpos] = c;
|
||||
if (p != NULL) {
|
||||
if (p->implemented == 0) {
|
||||
if (!CMD_IMPLEMENTED(p)) {
|
||||
reply(502, "SITE %s command not implemented.",
|
||||
p->name);
|
||||
hasyyerrored = 1;
|
||||
|
@ -1846,7 +1853,6 @@ help(struct tab *ctab, const char *s)
|
|||
{
|
||||
struct tab *c;
|
||||
int width, NCMDS;
|
||||
off_t b;
|
||||
char *type;
|
||||
|
||||
if (ctab == sitetab)
|
||||
|
@ -1874,22 +1880,18 @@ help(struct tab *ctab, const char *s)
|
|||
columns = 1;
|
||||
lines = (NCMDS + columns - 1) / columns;
|
||||
for (i = 0; i < lines; i++) {
|
||||
b = printf(" ");
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
lreply(-2, " ");
|
||||
for (j = 0; j < columns; j++) {
|
||||
c = ctab + j * lines + i;
|
||||
b = printf("%s", c->name);
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
lreply(-2, "%s", c->name);
|
||||
w = strlen(c->name);
|
||||
if (! c->implemented) {
|
||||
if (! CMD_IMPLEMENTED(c)) {
|
||||
putchar('-');
|
||||
total_bytes++;
|
||||
total_bytes_out++;
|
||||
w++;
|
||||
}
|
||||
if (c->hasopts) {
|
||||
if (CMD_HAS_OPTIONS(c)) {
|
||||
putchar('+');
|
||||
total_bytes++;
|
||||
total_bytes_out++;
|
||||
|
@ -1904,9 +1906,7 @@ help(struct tab *ctab, const char *s)
|
|||
w++;
|
||||
}
|
||||
}
|
||||
b = printf("\r\n");
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
lreply(-2, "\r\n");
|
||||
}
|
||||
(void) fflush(stdout);
|
||||
reply(214, "Direct comments to ftp-bugs@%s.", hostname);
|
||||
|
@ -1917,83 +1917,9 @@ help(struct tab *ctab, const char *s)
|
|||
reply(502, "Unknown command %s.", s);
|
||||
return;
|
||||
}
|
||||
if (c->implemented)
|
||||
if (CMD_IMPLEMENTED(c))
|
||||
reply(214, "Syntax: %s%s %s", type, c->name, c->help);
|
||||
else
|
||||
reply(214, "%s%-*s\t%s; not implemented.", type, width,
|
||||
c->name, c->help);
|
||||
}
|
||||
|
||||
static void
|
||||
sizecmd(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, "%qu", (qufmt_t)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;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
while((c=getc(fin)) != EOF) {
|
||||
if (c == '\n') /* will get expanded to \r\n */
|
||||
count++;
|
||||
count++;
|
||||
}
|
||||
(void) fclose(fin);
|
||||
|
||||
reply(213, "%qd", (qdfmt_t)count);
|
||||
break; }
|
||||
default:
|
||||
reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
|
||||
}
|
||||
}
|
||||
|
||||
static 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 (c->implemented == 0) {
|
||||
reply(502, "%s command not implemented.", c->name);
|
||||
return;
|
||||
}
|
||||
if (c->hasopts == 0) {
|
||||
reply(501, "%s command does not support persistent options.",
|
||||
c->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ep != NULL && *ep != '\0')
|
||||
REASSIGN(c->options, xstrdup(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);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: ftpd.8,v 1.51 2000/05/16 00:59:12 itojun Exp $
|
||||
.\" $NetBSD: ftpd.8,v 1.52 2000/06/14 13:44:24 lukem Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
|
@ -67,7 +67,7 @@
|
|||
.\"
|
||||
.\" @(#)ftpd.8 8.2 (Berkeley) 4/19/94
|
||||
.\"
|
||||
.Dd January 13, 2000
|
||||
.Dd June 14, 2000
|
||||
.Dt FTPD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -543,7 +543,10 @@ recognizes all commands in
|
|||
.Cm RFC 2228
|
||||
(although they are not supported yet),
|
||||
and supports the extensions from
|
||||
.Cm RFC 2389.
|
||||
.Cm RFC 2389 ,
|
||||
.Cm RFC 2428
|
||||
and
|
||||
.Cm draft-ietf-ftpext-mlst-10 .
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ftpd.c,v 1.92 2000/06/02 14:47:19 explorer Exp $ */
|
||||
/* $NetBSD: ftpd.c,v 1.93 2000/06/14 13:44:24 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
|
||||
|
@ -109,7 +109,7 @@ __COPYRIGHT(
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: ftpd.c,v 1.92 2000/06/02 14:47:19 explorer Exp $");
|
||||
__RCSID("$NetBSD: ftpd.c,v 1.93 2000/06/14 13:44:24 lukem Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -144,6 +144,7 @@ __RCSID("$NetBSD: ftpd.c,v 1.92 2000/06/02 14:47:19 explorer Exp $");
|
|||
#include <pwd.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -165,8 +166,6 @@ __RCSID("$NetBSD: ftpd.c,v 1.92 2000/06/02 14:47:19 explorer Exp $");
|
|||
#include "pathnames.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
int data;
|
||||
jmp_buf urgcatch;
|
||||
struct passwd *pw;
|
||||
|
@ -204,16 +203,9 @@ int epsvall = 0;
|
|||
int swaitmax = SWAITMAX;
|
||||
int swaitint = SWAITINT;
|
||||
|
||||
#define CURCLASSTYPE curclass.type == CLASS_GUEST ? "GUEST" : \
|
||||
curclass.type == CLASS_CHROOT ? "CHROOT" : \
|
||||
curclass.type == CLASS_REAL ? "REAL" : \
|
||||
"<unknown>"
|
||||
|
||||
static void ack(const char *);
|
||||
static int bind_pasv_addr(void);
|
||||
static int checkuser(const char *, const char *, int, int, char **);
|
||||
static int checkaccess(const char *);
|
||||
static FILE *dataconn(const char *, off_t, const char *);
|
||||
static void dolog(struct sockaddr *);
|
||||
static void end_login(void);
|
||||
static FILE *getdatasock(const char *);
|
||||
|
@ -221,7 +213,6 @@ static char *gunique(const char *);
|
|||
static void lostconn(int);
|
||||
static void myoob(int);
|
||||
static int receive_data(FILE *, FILE *);
|
||||
static void replydirname(const char *, const char *);
|
||||
static int send_data(FILE *, FILE *, off_t, int);
|
||||
static struct passwd *sgetpwnam(const char *);
|
||||
|
||||
|
@ -487,9 +478,9 @@ sgetpwnam(const char *name)
|
|||
return (&save);
|
||||
}
|
||||
|
||||
static int login_attempts; /* number of failed login attempts */
|
||||
static int askpasswd; /* had user command, ask for passwd */
|
||||
static char curname[10]; /* current USER name */
|
||||
static int login_attempts; /* number of failed login attempts */
|
||||
static int askpasswd; /* had user command, ask for passwd */
|
||||
static char curname[10]; /* current USER name */
|
||||
|
||||
/*
|
||||
* USER command.
|
||||
|
@ -1259,7 +1250,7 @@ getdatasock(const char *mode)
|
|||
return (NULL);
|
||||
}
|
||||
|
||||
static FILE *
|
||||
FILE *
|
||||
dataconn(const char *name, off_t size, const char *mode)
|
||||
{
|
||||
char sizebuf[32];
|
||||
|
@ -1647,41 +1638,6 @@ receive_data(FILE *instr, FILE *outstr)
|
|||
return (rval);
|
||||
}
|
||||
|
||||
void
|
||||
statfilecmd(const char *filename)
|
||||
{
|
||||
FILE *fin;
|
||||
int c;
|
||||
char *argv[] = { INTERNAL_LS, "-lgA", "", NULL };
|
||||
|
||||
argv[2] = (char *)filename;
|
||||
fin = ftpd_popen(argv, "r", STDOUT_FILENO);
|
||||
lreply(211, "status of %s:", filename);
|
||||
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;
|
||||
}
|
||||
(void) putchar('\r');
|
||||
total_bytes++;
|
||||
total_bytes_out++;
|
||||
}
|
||||
(void) putchar(c);
|
||||
total_bytes++;
|
||||
total_bytes_out++;
|
||||
}
|
||||
(void) ftpd_pclose(fin);
|
||||
reply(211, "End of Status");
|
||||
}
|
||||
|
||||
void
|
||||
statcmd(void)
|
||||
{
|
||||
|
@ -1689,7 +1645,7 @@ statcmd(void)
|
|||
static char ntop_buf[INET6_ADDRSTRLEN];
|
||||
u_char *a, *p;
|
||||
int ispassive, af;
|
||||
off_t b, otbi, otbo, otb;
|
||||
off_t otbi, otbo, otb;
|
||||
|
||||
a = p = (u_char *)NULL;
|
||||
|
||||
|
@ -1712,69 +1668,49 @@ statcmd(void)
|
|||
lreply(0, "Waiting for password");
|
||||
else
|
||||
lreply(0, "Waiting for user name");
|
||||
b = printf(" TYPE: %s", typenames[type]);
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
if (type == TYPE_A || type == TYPE_E) {
|
||||
b = printf(", FORM: %s", formnames[form]);
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
}
|
||||
lreply(-2, " TYPE: %s", typenames[type]);
|
||||
if (type == TYPE_A || type == TYPE_E)
|
||||
lreply(-2, ", FORM: %s", formnames[form]);
|
||||
if (type == TYPE_L) {
|
||||
#if NBBY == 8
|
||||
b = printf(" %d", NBBY);
|
||||
lreply(-2, " %d", NBBY);
|
||||
#else
|
||||
/* XXX: `bytesize' needs to be defined in this case */
|
||||
b = printf(" %d", bytesize);
|
||||
lreply(-2, " %d", bytesize);
|
||||
#endif
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
}
|
||||
b = printf("; STRUcture: %s; transfer MODE: %s\r\n",
|
||||
lreply(-1, "; STRUcture: %s; transfer MODE: %s",
|
||||
strunames[stru], modenames[mode]);
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
ispassive = 0;
|
||||
if (data != -1) {
|
||||
lreply(0, "Data connection open");
|
||||
su = NULL;
|
||||
} else if (pdata != -1) {
|
||||
b = printf(" in Passive mode");
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
lreply(0, "in Passive mode");
|
||||
su = (union sockunion *)&pasv_addr;
|
||||
ispassive = 1;
|
||||
goto printaddr;
|
||||
} else if (usedefault == 0) {
|
||||
if (epsvall) {
|
||||
b = printf("211- EPSV only mode (EPSV ALL )\r\n");
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
lreply(0, "EPSV only mode (EPSV ALL)");
|
||||
goto epsvonly;
|
||||
}
|
||||
b = printf("211- %s",
|
||||
(data_dest.su_family == AF_INET) ? "PORT" : "LPRT");
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
su = (union sockunion *)&data_dest;
|
||||
printaddr:
|
||||
/* PASV/PORT */
|
||||
/* PASV/PORT */
|
||||
if (su->su_family == AF_INET) {
|
||||
if (ispassive)
|
||||
b = printf("211- PASV ");
|
||||
else
|
||||
b = printf("211- PORT ");
|
||||
a = (u_char *) &su->su_sin.sin_addr;
|
||||
p = (u_char *) &su->su_sin.sin_port;
|
||||
#define UC(b) (((int) b) & 0xff)
|
||||
b += printf("(%d,%d,%d,%d,%d,%d)\r\n",
|
||||
lreply(0, "%s (%d,%d,%d,%d,%d,%d)",
|
||||
ispassive ? "PASV" : "PORT" ,
|
||||
UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
|
||||
UC(p[0]), UC(p[1]));
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
}
|
||||
|
||||
/* LPSV/LPRT */
|
||||
/* XXXLUKEM this code doesn't look right; speak to itojun */
|
||||
|
||||
/* LPSV/LPRT */
|
||||
{
|
||||
int alen, af, i;
|
||||
|
||||
|
@ -1797,16 +1733,11 @@ statcmd(void)
|
|||
break;
|
||||
}
|
||||
if (af) {
|
||||
if (ispassive)
|
||||
b = printf("211- LPSV ");
|
||||
else
|
||||
b = printf("211- LPRT ");
|
||||
printf("(%d,%d", af, alen);
|
||||
lreply(-2, " %s (%d,%d",
|
||||
ispassive ? "LPSV" : "LPRT", af, alen);
|
||||
for (i = 0; i < alen; i++)
|
||||
b += printf("%d,", UC(a[alen]));
|
||||
b += printf("%d,%d,%d)\r\n", 2, UC(p[0]), UC(p[1]));
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
lreply(-2, "%d,", UC(a[alen]));
|
||||
lreply(-1, "%d,%d,%d)", 2, UC(p[0]), UC(p[1]));
|
||||
#undef UC
|
||||
}
|
||||
}
|
||||
|
@ -1826,16 +1757,11 @@ statcmd(void)
|
|||
}
|
||||
if (af) {
|
||||
if (getnameinfo((struct sockaddr *)su, su->su_len,
|
||||
ntop_buf, sizeof(ntop_buf), NULL, 0,
|
||||
ntop_buf, sizeof(ntop_buf), NULL, 0,
|
||||
NI_NUMERICHOST) == 0) {
|
||||
if (ispassive)
|
||||
b = printf("211 - EPSV ");
|
||||
else
|
||||
b = printf("211 - EPRT ");
|
||||
b += printf("(|%d|%s|%d|)\r\n",
|
||||
af, ntop_buf, ntohs(su->su_port));
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
lreply(0, "%s (|%d|%s|%d|)",
|
||||
ispassive ? "EPSV" : "EPRT",
|
||||
af, ntop_buf, ntohs(su->su_port));
|
||||
}
|
||||
}
|
||||
} else
|
||||
|
@ -1932,6 +1858,11 @@ fatal(const char *s)
|
|||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* reply() --
|
||||
* display the final line of a reply, with a trailing CRLF
|
||||
* i.e, n + " " + fmt + CRLF
|
||||
*/
|
||||
void
|
||||
reply(int n, const char *fmt, ...)
|
||||
{
|
||||
|
@ -1952,6 +1883,14 @@ reply(int n, const char *fmt, ...)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* lreply() --
|
||||
* depending on the value of n, display a line with a trailing CRLF:
|
||||
* n == -2 freeform text, but no trailing CRLF
|
||||
* n == -1 freeform text
|
||||
* n == 0 prefix the message with 4 spaces
|
||||
* n > 0 prefix the message with n + "-"
|
||||
*/
|
||||
void
|
||||
lreply(int n, const char *fmt, ...)
|
||||
{
|
||||
|
@ -1964,133 +1903,25 @@ lreply(int n, const char *fmt, ...)
|
|||
case 0:
|
||||
b += printf(" ");
|
||||
case -1:
|
||||
case -2:
|
||||
break;
|
||||
default:
|
||||
b += printf("%d-", n);
|
||||
break;
|
||||
}
|
||||
b += vprintf(fmt, ap);
|
||||
b += printf("\r\n");
|
||||
if (n != -2)
|
||||
b += printf("\r\n");
|
||||
total_bytes += b;
|
||||
total_bytes_out += b;
|
||||
(void)fflush(stdout);
|
||||
if (debug) {
|
||||
if (n != -2)
|
||||
(void)fflush(stdout);
|
||||
if (debug && n >= 0) {
|
||||
syslog(LOG_DEBUG, "<--- %d- ", n);
|
||||
vsyslog(LOG_DEBUG, fmt, ap);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ack(const char *s)
|
||||
{
|
||||
|
||||
reply(250, "%s command successful.", s);
|
||||
}
|
||||
|
||||
void
|
||||
delete(const char *name)
|
||||
{
|
||||
char *p = NULL;
|
||||
|
||||
if (remove(name) < 0) {
|
||||
p = strerror(errno);
|
||||
perror_reply(550, name);
|
||||
} else
|
||||
ack("DELE");
|
||||
logcmd("delete", -1, name, NULL, NULL, p);
|
||||
}
|
||||
|
||||
void
|
||||
cwd(const char *path)
|
||||
{
|
||||
|
||||
if (chdir(path) < 0)
|
||||
perror_reply(550, path);
|
||||
else {
|
||||
show_chdir_messages(250);
|
||||
ack("CWD");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
replydirname(const char *name, const char *message)
|
||||
{
|
||||
char npath[MAXPATHLEN];
|
||||
int i;
|
||||
|
||||
for (i = 0; *name != '\0' && i < sizeof(npath) - 1; i++, name++) {
|
||||
npath[i] = *name;
|
||||
if (*name == '"')
|
||||
npath[++i] = '"';
|
||||
}
|
||||
npath[i] = '\0';
|
||||
reply(257, "\"%s\" %s", npath, message);
|
||||
}
|
||||
|
||||
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.");
|
||||
logcmd("mkdir", -1, name, NULL, NULL, p);
|
||||
}
|
||||
|
||||
void
|
||||
removedir(const char *name)
|
||||
{
|
||||
char *p = NULL;
|
||||
|
||||
if (rmdir(name) < 0) {
|
||||
p = strerror(errno);
|
||||
perror_reply(550, name);
|
||||
} else
|
||||
ack("RMD");
|
||||
logcmd("rmdir", -1, name, NULL, NULL, p);
|
||||
}
|
||||
|
||||
void
|
||||
pwd(void)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
if (getcwd(path, sizeof(path) - 1) == NULL)
|
||||
reply(550, "Can't get the current directory: %s.",
|
||||
strerror(errno));
|
||||
else
|
||||
replydirname(path, "is the current directory.");
|
||||
}
|
||||
|
||||
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 (xstrdup(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");
|
||||
logcmd("rename", -1, from, to, NULL, p);
|
||||
}
|
||||
|
||||
static void
|
||||
dolog(struct sockaddr *who)
|
||||
{
|
||||
|
@ -2497,10 +2328,7 @@ send_file_list(const char *whichf)
|
|||
while ((dir = readdir(dirp)) != NULL) {
|
||||
char nbuf[MAXPATHLEN];
|
||||
|
||||
if (dir->d_name[0] == '.' && dir->d_namlen == 1)
|
||||
continue;
|
||||
if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
|
||||
dir->d_namlen == 2)
|
||||
if (ISDOTDIR(dir->d_name) || ISDOTDOTDIR(dir->d_name))
|
||||
continue;
|
||||
|
||||
(void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname,
|
||||
|
@ -2579,7 +2407,6 @@ conffilename(const char *s)
|
|||
* if elapsed != NULL, append "in xxx.yyy seconds"
|
||||
* if error != NULL, append ": " + error
|
||||
*/
|
||||
|
||||
void
|
||||
logcmd(const char *command, off_t bytes, const char *file1, const char *file2,
|
||||
const struct timeval *elapsed, const char *error)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: version.h,v 1.10 2000/05/20 23:34:55 lukem Exp $ */
|
||||
/* $NetBSD: version.h,v 1.11 2000/06/14 13:44:25 lukem Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
|
@ -36,5 +36,5 @@
|
|||
*/
|
||||
|
||||
#ifndef FTPD_VERSION
|
||||
#define FTPD_VERSION "NetBSD-ftpd 20000521"
|
||||
#define FTPD_VERSION "NetBSD-ftpd 20000614"
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue