/* Copyright (C) 1999 Beau Kuiper
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "ftpd.h"
#include "ftpcmd.h"
#include "reply.h"
extern FTPCMD mainftpcmd[];
/* This will print a NICE! error to the user */
void reporterror(FTPSTATE *peer, char *filename, int errorno)
{
ftp_write(peer, FALSE, 550, "'%s': %s", filename, strerror(errorno));
}
int readipstr(char *data, int *port, unsigned int *ip)
{
int a1,a2,a3,a4,a5,a6, result;
result = sscanf(data, "%d,%d,%d,%d,%d,%d",&a1, &a2, &a3, &a4, &a5, &a6);
if (result != 6)
return(FALSE);
*ip = (a1 << 24) | (a2 << 16) | (a3 << 8) | (a4);
*port = (a5 * 256) + a6;
return(TRUE);
}
int readeipstr(char *ip, unsigned int *outip)
{
int a1, a2, a3, a4, result;
result = sscanf(ip, "%d.%d.%d.%d", &a1, &a2, &a3, &a4);
if (result != 4)
return(FALSE);
*outip = (a1 << 24) | (a2 << 16) | (a3 << 8) | (a4);
return(TRUE);
}
int ftp_dele(FTPSTATE *peer, char *filename)
{
if (file_unlink(peer, filename) == 0)
ftp_write(peer, FALSE, 250, REPLY_DELETE(filename));
else
reporterror(peer, filename, errno);
return(FALSE);
}
int ftp_chmod(FTPSTATE *peer, char *filename, int mode)
{
if (file_chmod(peer, filename, mode) == 0)
ftp_write(peer, FALSE, 250, REPLY_CHMOD(filename, mode));
else
reporterror(peer, filename, errno);
return(FALSE);
}
int ftp_size(FTPSTATE *peer, char *filename)
{
int filefd;
off_t size = 0;
int asize;
struct stat statdata;
if (peer->binary)
{
filefd = file_stat(peer, filename, &statdata);
if (filefd == 0)
size = statdata.st_size;
}
else
{
char *rname;
size = 0;
filefd = file_readopen(peer, filename, &rname);
freewrapper(rname);
if (filefd > 0)
{
char *chin, buffer[BUFFERSIZE];
asize = read(filefd, buffer, BUFFERSIZE-1);
while (asize > 0)
{
buffer[asize] = 0;
size += asize;
chin = buffer;
while ((chin = strchr(chin, 10)) != NULL)
{
chin++;
size++;
}
asize = read(filefd, buffer, BUFFERSIZE-1);
}
close(filefd);
}
}
if (filefd >= 0)
ftp_write(peer, FALSE, 213, "%s", offt_tostr(size));
else
reporterror(peer, filename, errno);
return(FALSE);
}
int ftp_mdtm(FTPSTATE *peer, char *filename)
{
struct stat statdata;
if (file_stat(peer, filename, &statdata) == 0)
{
char timestr[20];
struct tm *resulttm = gmtime(&statdata.st_mtime);
strftime(timestr, 20, "%Y%m%d%H%M%S", resulttm);
ftp_write(peer, FALSE, 213, timestr);
}
else
reporterror(peer, filename, errno);
return(FALSE);
}
void setdumptokens(FTPSTATE *peer, TOKENSET *ts)
{
char *outstr;
time_t mytime = time(NULL);
outstr = ctime(&mytime);
outstr[strlen(outstr) - 1] = 0;
tokenset_settoken(ts, 'T', strdupwrapper(outstr));
tokenset_settoken(ts, 'U', strdupwrapper(peer->username));
if (peer->pwd)
tokenset_settoken(ts, 'C', strdupwrapper(dir_getvirtual(peer, peer->pwd)));
tokenset_settoken(ts, 'E', strdupwrapper(peer->vserver->email));
tokenset_settoken(ts, 'M', safe_snprintf("%d", peer->maxusers));
if (peer->loggedin)
tokenset_settoken(ts, 'N', safe_snprintf("%d", peer->usercount));
tokenset_settoken(ts, 'R', strdupwrapper(peer->hostname));
tokenset_settoken(ts, 'L', strdupwrapper(peer->vserver->vhostname));
tokenset_settoken(ts, 'f', safe_snprintf("%d", peer->downloadedfiles));
tokenset_settoken(ts, 'F', safe_snprintf("%d", peer->uploadedfiles));
tokenset_settoken(ts, 'b', safe_snprintf("%s", offt_tostr(peer->downloadedfilebytes)));
tokenset_settoken(ts, 'B', safe_snprintf("%s", offt_tostr(peer->uploadedfilebytes)));
tokenset_settoken(ts, 'I', safe_snprintf("%s", offt_tostr(peer->listdownloadedbytes)));
tokenset_settoken(ts, 'i', safe_snprintf("%d", peer->listconns));
tokenset_settoken(ts, 'D', safe_snprintf("%s", offt_tostr(peer->listdownloadedbytes + peer->downloadedfilebytes)));
tokenset_settoken(ts, 't', safe_snprintf("%s", offt_tostr(peer->listdownloadedbytes + peer->downloadedfilebytes + peer->uploadedfilebytes)));
tokenset_settoken(ts, 'c', safe_snprintf("%d", peer->listconns + peer->downloadedfiles + peer->uploadedfiles));
tokenset_settoken(ts, 'd', safe_snprintf("%d", peer->listconns + peer->downloadedfiles));
if (peer->ratioinfo)
ratio_settokens(peer->ratioinfo, ts);
tokenset_settoken(ts, 'v', strdupwrapper(peer->vserver->sectionname));
}
int ftp_dumper(FTPSTATE *peer, NEWFILE *infile, int number, char *fmessage, int dotokens, int endtokens)
{
TOKENSET *ts = NULL;
char *inp, *tfmessage;
int first;
if (dotokens)
if ((infile != NULL) || (endtokens))
{
ts = tokenset_new();
setdumptokens(peer, ts);
}
if (infile != NULL)
{
first = TRUE;
while ((inp = nfgetcs(infile, '\n')) != NULL)
{
if (inp[strlen(inp)-1] == '\n')
inp[strlen(inp)-1] = 0;
if (dotokens)
inp = tokenset_apply(ts, inp, FALSE);
if (first || config->altlongreplies)
{
ftp_write(peer, TRUE, 0, "%d-%s", number, inp);
first = FALSE;
}
else
ftp_write(peer, TRUE, 0, " %s", inp);
freewrapper(inp);
}
nfclose(infile);
}
if (endtokens)
{
tfmessage = tokenset_apply(ts, strdupwrapper(fmessage), FALSE);
ftp_write(peer, FALSE, number, "%s", tfmessage);
freewrapper(tfmessage);
}
else
ftp_write(peer, FALSE, number, "%s", fmessage);
if (ts)
tokenset_finish(ts);
return(FALSE);
}
int ftp_dumpstr(FTPSTATE *peer, char *dumpstr, int number, char *fmessage, int endtokens)
{
TOKENSET *ts = NULL;
char *oldinp = dumpstr;
char *inp = dumpstr;
char *datline, *tfmessage;
int first;
ts = tokenset_new();
setdumptokens(peer, ts);
first = TRUE;
while (oldinp != NULL)
{
inp = strchr(inp, '\n');
if (inp != NULL)
*inp = 0;
datline = strdupwrapper(oldinp);
if (inp != NULL)
{
*inp = '\n';
inp++;
}
oldinp = inp;
datline = tokenset_apply(ts, datline, FALSE);
if (first || config->altlongreplies)
{
ftp_write(peer, TRUE, 0, "%d-%s", number, datline);
first = FALSE;
}
else
ftp_write(peer, TRUE, 0, " %s", datline);
freewrapper(datline);
}
if (endtokens)
{
tfmessage = tokenset_apply(ts, strdupwrapper(fmessage), FALSE);
ftp_write(peer, FALSE, number, "%s", tfmessage);
freewrapper(tfmessage);
}
else
ftp_write(peer, FALSE, number, "%s", fmessage);
tokenset_finish(ts);
return(FALSE);
}
VSERVER *find_vserver_byname(char *name)
{
VSERVER *v = config->vservers;
while((v != NULL) && (strcasecmp(v->vhostname, name) != 0))
v = v->next;
return(v);
}
int host_isip(char *name)
{
while(((*name >= '0') && (*name <= '9')) || (*name == '.'))
name++;
return(*name == 0);
}
int ftp_host(FTPSTATE *peer, char *params)
{
VSERVER *v;
/* if there are no vservers, or hostname vservers are not defined,
return with not implemented */
if ((!config->vservers) || (!config->hostvservers))
return(ftp_write(peer, FALSE, 502, REPLY_NOHOSTS));
/* if a vserver has already been selected, return 530 */
if (peer->vserver != config->defaults)
return(ftp_write(peer, FALSE, 530, REPLY_HOSTSELECTED));
if (config->defaulthost && (host_isip(params)))
v = config->defaulthost;
else
v = find_vserver_byname(params);
if (!v)
return(ftp_write(peer, FALSE, 533, REPLY_HOSTNOTFOUND(params)));
switch(vserver_select(peer, v))
{
case 1:
return(ftp_write(peer, FALSE, 533, REPLY_HOSTMISCONF(params)));
case 2:
return(ftp_write(peer, FALSE, 533, REPLY_HOSTNOTFOUND(params)));
case 3:
ftp_write(peer, FALSE, 421, REPLY_HOSTTOOBUSY(params));
return(TRUE);
}
ftp_write(peer, FALSE, 202, REPLY_HOSTSEL(v->vhostname));
return(3);
}
int ftp_rnto(FTPSTATE *peer, char *filename)
{
char *badfile;
char *oldname;
if (!peer->renameoldname)
return(ftp_write(peer, FALSE, 503, REPLY_RENAMENOSOURCE));
oldname = dir_getvirtual(peer, peer->renameoldname);
if ((badfile = file_rename(peer, oldname, filename)) == NULL)
ftp_write(peer, FALSE, 250, REPLY_RENAME(oldname, filename));
else
reporterror(peer, badfile, errno);
freewrapper(peer->renameoldname);
peer->renameoldname = NULL;
return(FALSE);
}
int ftp_mkd(FTPSTATE *peer, char *filename)
{
if (file_mkdir(peer, filename) == 0)
{
char *newfile = file_expand(peer, filename);
ftp_write(peer, FALSE, 257, REPLY_MKDIR(dir_getvirtual(peer, newfile)));
freewrapper(newfile);
}
else
reporterror(peer, filename, errno);
return(FALSE);
}
int ftp_rmd(FTPSTATE *peer, char *filename)
{
if (file_rmdir(peer, filename) == 0)
ftp_write(peer, FALSE, 250, REPLY_RMDIR(filename));
else
reporterror(peer, filename, errno);
return(FALSE);
}
int ftp_cwddo(FTPSTATE *peer, char *newdir, int dump)
{
char *tmp = strdupwrapper(peer->pwd);
dir_combine(peer, &tmp, newdir);
if (!checkchdir(peer, tmp))
{
freewrapper(tmp);
reporterror(peer, newdir, errno);
return(FALSE);
}
chdir(tmp);
if (peer->realdir)
{
char *nt;
/* this relies on the side effect of checkchdir where
the server changes dir to check */
nt = (char *)dir_getreal(peer);
if (nt != NULL)
{
freewrapper(tmp);
tmp = nt;
}
}
{
NEWFILE *nfile = NULL;
char *outstr;
int ret = 257;
/* If we need to print a file, then open it */
/* Oh bugger, crap, and other things, I left a big
security hole here! :-(, now fixed */
if (dump)
ret = 250;
freewrapper(peer->pwd);
peer->pwd = tmp;
if ((dump) && (peer->cwddump) && (!peer->cwddumpdata))
{
if (peer->cwddump[0] == '/')
/* if it is an absolute file, don't worry
about permissions accessing file */
nfile = nfopen(peer->cwddump);
else
/* worry like hell and pass request via
both ACL's and file permissions! */
nfile = file_nfopen(peer, peer->cwddump);
}
outstr = safe_snprintf(REPLY_PWD(dir_getvirtual(peer, peer->pwd)));
if ((dump) && (peer->cwddumpdata))
ftp_dumpstr(peer, peer->cwddumpdata, ret, outstr, FALSE);
else
ftp_dumper(peer, nfile, ret, outstr, TRUE, FALSE);
freewrapper(outstr);
}
return(FALSE);
}
int ftp_cwd(FTPSTATE *peer, char *newdir)
{
return(ftp_cwddo(peer, newdir, TRUE));
}
int ftp_run(FTPSTATE *peer, INPUTLINE *cmd, char *token)
{
if ((cmd->command->ftpfunc) == NULL)
return(ftp_write(peer, FALSE, 500, REPLY_CMDNOTKNOWN(token)));
if (cmd->command->paramnum)
{
if (cmd->parameters == NULL)
return(ftp_write(peer, FALSE, 500, REPLY_NOPARAM(token)));
else if (cmd->parameters[0] == 0)
return(ftp_write(peer, FALSE, 500, REPLY_NOPARAM(token)));
}
if ((cmd->command->needslogin) && (peer->loggedin != TRUE))
return(ftp_write(peer, FALSE, 530, REPLY_NOLOGIN));
if ((!cmd->command->dataportok) && (peer->dport))
return(ftp_write(peer, FALSE, 520, REPLY_DATACONNINVALID(token)));
else
return(cmd->command->ftpfunc(peer, cmd->parameters));
}
int ftp_quit(FTPSTATE *peer, char *param)
{
if (peer->quitdump)
{
NEWFILE *nfile = nfopen(peer->quitdump);
ftp_dumper(peer, nfile, 221, REPLY_QUIT, TRUE, FALSE);
}
else if (peer->quitdumpdata)
ftp_dumpstr(peer, peer->quitdumpdata, 221, REPLY_QUIT, FALSE);
else
ftp_write(peer, FALSE, 221, REPLY_QUIT);
return(TRUE);
}
int ftp_user(FTPSTATE *peer, char *param)
{
if (peer->jailenabled)
return(ftp_write(peer, FALSE, 530, REPLY_JAILUSER));
if (peer->loginsleft == 0)
return(ftp_write(peer, FALSE, 530, REPLY_NOCREDITS));
if (peer->loggedin)
shinfo_delusergroup(peer->groupname);
shinfo_changeuser(param);
peer->loggedin = 0;
freewrapper(peer->username);
peer->username = strdupwrapper(param);
return(ftp_write(peer, FALSE, 331, REPLY_USER(peer->username)));
}
int ftp_host_compat(FTPSTATE *peer)
{
VSERVER *v;
char *name;
/* if there are no vservers, or hostname vservers are not defined,
return with not implemented */
if ((!config->vservers) || (!config->hostvservers))
return(1);
/* if a vserver has already been selected, return 530 */
if (peer->vserver != config->defaults)
return(1);
name = strchr(peer->username, '%');
if (!name)
v = config->defaulthost;
else
{
*name = 0;
name++;
if (config->defaulthost && (host_isip(name)))
v = config->defaulthost;
else
v = find_vserver_byname(name);
}
if (!v)
return(0);
switch(vserver_select(peer, v))
{
case 1:
case 2:
return(0);
case 3:
return(2);
}
return(1);
}
int ftp_pass(FTPSTATE *peer, char *param)
{
int result = FALSE;
int loginok, oldnice = peer->nicevalue;
int toomany = FALSE;
char *errmsg = NULL;
switch(ftp_host_compat(peer))
{
case 0:
return(ftp_write(peer, FALSE, 530, REPLY_LOGINFAIL(peer->username, "Bad password")));
case 2:
ftp_write(peer, FALSE, 421, REPLY_TOOMANYUSERS);
return(TRUE);
}
if (peer->loggedin)
return(ftp_write(peer, FALSE, 530, REPLY_ALREADYLOGGEDIN));
if (strcmp(peer->username, "<unknown>") == 0)
return(ftp_write(peer, FALSE, 503, REPLY_USEUSERFIRST));
loginok = (param != NULL);
if (loginok)
{
file_becomeroot(peer);
setgroups(0, NULL);
errmsg = setuseropts(peer, param);
loginok = (errmsg == NULL);
}
/* check some stuff, set basedir to real pathname */
if (loginok)
{
file_becomeuser(peer);
if (chdir(peer->basedir) == -1)
{
loginok = FALSE;
log_giveentry(MYLOG_INFO, NULL, safe_snprintf("rootdir(%s) for user '%s' is not accessable. Check rootdir and rootdir permissions", peer->basedir, peer->username));
}
else
{
char *curdir = getcwd2();
if (strcmp(curdir, peer->basedir) != 0)
{
log_giveentry(MYLOG_INFO, NULL, safe_snprintf("rootdir changed from '%s' to '%s', symbolic links resolved for user '%s'", peer->basedir, curdir, peer->username));
freewrapper(peer->basedir);
peer->basedir = curdir;
}
else
freewrapper(curdir);
}
file_becomeroot(peer);
}
if (loginok)
{
peer->usercount = toomany = shinfo_addusergroup(peer->groupname, peer->maxusers);
toomany = (toomany == -1);
if (toomany)
loginok = FALSE;
}
if (loginok)
{
char *outstr;
NEWFILE *nfile;
log_addentry(MYLOG_LOGIN, peer, "Login successful.");
outstr = safe_snprintf(REPLY_PASSOK(peer->username));
/* perform chroot if needed */
if (peer->chroot)
dochroot(peer);
if (nice(peer->nicevalue + (-oldnice)) == -1)
{
log_giveentry(MYLOG_INFO, NULL, safe_snprintf("nice(%d) gave error %s", peer->nicevalue + (-oldnice), strerror(errno)));
peer->nicevalue = oldnice;
}
if (config->rootmode)
setgroups(peer->supgids[0], peer->supgids + 1);
/* see if rootdir == "/", change to "" */
if (peer->basedir[1] == 0)
peer->basedir[0] = 0;
if ((peer->droproot) && (config->rootmode))
{
if (giveuproot(peer->uidt_asuid, peer->gidt_asgid))
log_addentry(MYLOG_INFO, peer, "Failed to set capabilities!");
peer->jailenabled = TRUE;
/* we are not root anymore and can never be root
again! */
config->rootmode = FALSE;
}
file_becomeuser(peer);
nfile = nfopen(peer->logindump);
peer->pwd = strdupwrapper(peer->basedir);
dir_combine(peer, &(peer->pwd), peer->homedir);
if (peer->logindumpdata)
result = ftp_dumpstr(peer, peer->logindumpdata, 230, outstr, FALSE);
else
result = ftp_dumper(peer, nfile, 230, outstr, TRUE, FALSE);
freewrapper(outstr);
}
else
{
peer->loggedin = FALSE;
log_addentry(MYLOG_LOGIN, peer, "Login failed");
peer->timeout = peer->vserver->timeout;
if (toomany)
{
NEWFILE *nfile = nfopen(peer->busydump);
logfullmessage(GROUPFULL, peer->remoteip);
if (peer->busydumpdata)
ftp_dumpstr(peer, peer->busydumpdata, 421, REPLY_TOOMANYUSERS, FALSE);
else
ftp_dumper(peer, nfile, 421, REPLY_TOOMANYUSERS, TRUE, FALSE);
}
else
{
usleep(peer->vserver->authwait);
if (errmsg == NULL)
errmsg = strdupwrapper("Bad password");
result = ftp_write(peer, FALSE, 530, REPLY_LOGINFAIL(peer->username, errmsg));
if (peer->loginsleft > 0)
peer->loginsleft--;
freewrapper(errmsg);
}
freewrapper(peer->username);
peer->username = strdupwrapper("<unknown>");
}
if (toomany)
return(TRUE); /* quit */
return(3); /* make sure timeout gets updated */
}
int ftp_rest(FTPSTATE *peer, char *param)
{
off_t newpos;
int res;
res = strto_offt(param, &newpos);
if ((res != 0) || (newpos < 0))
return(ftp_write(peer, FALSE, 501, REPLY_INVALIDREST));
else
{
peer->restartpos = newpos;
return(ftp_write(peer, FALSE, 350, REPLY_RESTOK(peer->restartpos)));
}
}
int ftp_syst(FTPSTATE *peer, char *param)
{
return(ftp_write(peer, FALSE, 215, "UNIX Type: L8"));
}
int ftp_port(FTPSTATE *peer, char *param)
{
if (peer->epsv_forced)
return(ftp_write(peer, FALSE, 500, REPLY_EPSVSET));
/* reset remoteport */
peer->remoteport = 0;
if (peer->passiveport)
{
select_delfd(peer->sel, peer->passiveport);
peer->passiveport = 0;
}
if (readipstr(param, &(peer->remoteport), &(peer->dataip)))
{
if ((peer->remoteport <= 1024) || (peer->remoteport >= 65536))
{
peer->remoteport = 0;
return(ftp_write(peer, FALSE, 500, REPLY_PORTBADPORT));
}
if ((peer->dataip != peer->remoteip) && (!peer->fxpallow))
{
peer->remoteport = 0;
peer->dataip = peer->remoteip;
return(ftp_write(peer, FALSE, 500, REPLY_PORTBADFXP));
}
return(ftp_write(peer, FALSE, 200, REPLY_PORTOK(
peer->dataip >> 24, peer->dataip >> 16 & 255, peer->dataip >> 8 & 255,
peer->dataip & 255, peer->remoteport)));
}
else
return(ftp_write(peer, FALSE, 501, REPLY_PORTBADPARM));
}
int ftp_eprt(FTPSTATE *peer, char *param)
{
char *ipstr;
int proto, tcpport;
unsigned int remote_ip;
if (peer->epsv_forced)
return(ftp_write(peer, FALSE, 500, REPLY_EPSVSET));
ipstr = mallocwrapper(strlen(param) + 1);
/* clear off old ports */
peer->remoteport = 0;
if (peer->passiveport)
{
select_delfd(peer->sel, peer->passiveport);
peer->passiveport = 0;
}
if (sscanf(param, "|%d|%[0-9.]|%d|", &proto, ipstr, &tcpport) != 3)
ftp_write(peer, FALSE, 500, REPLY_EPRTBADPARM);
else if (proto != FTP_IPV4)
ftp_write(peer, FALSE, 522, REPLY_BADPROTO);
else if (!readeipstr(ipstr, &(remote_ip)))
ftp_write(peer, FALSE, 500, REPLY_EPRTBADPARM);
else if (tcpport <= 1024)
ftp_write(peer, FALSE, 500, REPLY_EPRTBADPORT);
else if ((remote_ip != peer->remoteip) && (!peer->fxpallow))
ftp_write(peer, FALSE, 500, REPLY_EPRTBADFXP);
else
{
/* everything seems to be ok */
peer->remoteport = tcpport;
peer->dataip = remote_ip;
ftp_write(peer, FALSE, 200, REPLY_EPRTOK(
peer->dataip >> 24, peer->dataip >> 16 & 255, peer->dataip >> 8 & 255,
peer->dataip & 255, peer->remoteport));
}
freewrapper(ipstr);
return(FALSE);
}
int ftp_pwd(FTPSTATE *peer, char *param)
{
return(ftp_cwddo(peer, ".", FALSE));
}
int ftp_type(FTPSTATE *peer, char *param)
{
if ((param[0] & (255-32)) == 'A')
{
peer->binary = FALSE;
return(ftp_write(peer, FALSE, 200, REPLY_TYPEASCII));
}
else if ((param[0] & (255-32)) == 'I')
{
peer->binary = TRUE;
return(ftp_write(peer, FALSE, 200, REPLY_TYPEBINARY));
}
else
return(ftp_write(peer, FALSE, 504, REPLY_TYPEUNIMP));
}
int ftp_abor(FTPSTATE *peer, char *param)
{
/* abort any active or pending data port */
abortdatasocket(peer);
return(ftp_write(peer, FALSE, 226, REPLY_ABORT));
}
int ftp_pasv(FTPSTATE *peer, char *param)
{
unsigned int a1, a2, a3, a4, a5, a6;
if (peer->epsv_forced)
return(ftp_write(peer, FALSE, 500, REPLY_EPSVSET));
if (peer->passiveport != 0)
select_delfd(peer->sel, peer->passiveport);
peer->remoteport = 0;
peer->passiveport = listenparrelelport(peer->remotefd, &(peer->remoteport), &a1, 5);
if (peer->passiveport == -1)
{
peer->passiveport = 0;
reporterror(peer, "passive port", errno);
return(FALSE);
}
select_addfd(peer->sel, peer->passiveport);
a2 = ((a1 >> 8) & 255);
a3 = ((a1 >> 16) & 255);
a4 = ((a1 >> 24) & 255);
a1 = a1 & 255;
a5 = (peer->remoteport >> 8);
a6 = (peer->remoteport & 255);
return(ftp_write(peer, FALSE, 227, REPLY_PASV(a4, a3, a2, a1, a5, a6)));
}
int ftp_epsv(FTPSTATE *peer, char *param)
{
int proto, a1;
/* the all parameter means that only epsv can be used from now on */
if (peer->passiveport != 0)
select_delfd(peer->sel, peer->passiveport);
peer->remoteport = 0;
peer->passiveport = 0;
if (param)
{
if (strcasecmp(param, "ALL") == 0)
{
peer->epsv_forced = 1;
return(ftp_write(peer, FALSE, 200, REPLY_EPSVON));
}
else if (sscanf(param, "%d", &proto) == 1)
{
if (proto != FTP_IPV4)
return(ftp_write(peer, FALSE, 522, REPLY_BADPROTO));
}
else
return(ftp_write(peer, FALSE, 500, REPLY_EPSVERR));
}
peer->passiveport = listenparrelelport(peer->remotefd, &(peer->remoteport), &a1, 5);
if (peer->passiveport == -1)
{
peer->passiveport = 0;
reporterror(peer, "passive port", errno);
return(FALSE);
}
select_addfd(peer->sel, peer->passiveport);
return(ftp_write(peer, FALSE, 229, REPLY_EPSV(peer->remoteport)));
}
int ftp_list(FTPSTATE *peer, char *param)
{
char *p = param;
int done = FALSE;
int parm = 0;
while (!done)
{
if (p == NULL)
done = TRUE;
else if ((p[0] != '-') && (p[0] != ' ') && (p[0] != 0))
done = TRUE;
else
{
parm = parm | ftplist_parseflags(p + 1);
p = strchr(p, ' ');
if (p != NULL)
p++;
}
}
return(ftp_lister(peer, p, FALSE, parm));
}
int ftp_nlst(FTPSTATE *peer, char *param)
{
char *p = param;
int done = FALSE;
int parm = 0;
while (!done)
{
if (p == NULL)
done = TRUE;
else if ((p[0] != '-') && (p[0] != ' ') && (p[0] != 0))
done = TRUE;
else
{
parm = parm | ftplist_parseflags(p + 1);
p = strchr(p, ' ');
if (p != NULL)
p++;
}
}
return(ftp_lister(peer, p, TRUE, parm));
}
int ftp_cdup(FTPSTATE *peer, char *param)
{
return(ftp_cwd(peer, ".."));
}
int ftp_rnfr(FTPSTATE *peer, char *param)
{
freeifnotnull(peer->renameoldname);
peer->renameoldname = file_expand(peer, param);
return(ftp_write(peer, FALSE, 350, REPLY_RENAMESOURCE));
}
int ftp_noop(FTPSTATE *peer, char *param)
{
return(ftp_write(peer, FALSE, 200, REPLY_NOOP));
}
int ftp_rein(FTPSTATE *peer, char *param)
{
if (peer->jailenabled)
return(ftp_write(peer, FALSE, 530, REPLY_JAILUSER));
if (peer->loggedin)
shinfo_delusergroup(peer->groupname);
peer->loggedin = FALSE;
abortdatasocket(peer);
return(ftp_write(peer, FALSE, 220, "Reinitialize successful, enter username."));
}
int ftp_none(FTPSTATE *peer, char *param)
{
return(FALSE);
}
int ftp_help(FTPSTATE *peer, char *param)
{
return(ftp_dohelp(peer, mainftpcmd, param, peer->cmddisableset));
}
int ftp_dohelp(FTPSTATE *peer, FTPCMD *ftpcmds, char *command, int *disableset)
{
char outstr[128];
char cmd[10];
int result = FALSE;
int count2,count = 0;
if (command != NULL)
{
while(((strcasecmp(ftpcmds[count].command, command) != 0) &&
(ftpcmds[count].ftpfunc != NULL)) ||
(peer->loggedin ? disableset[count] : ftpcmds[count].needslogin))
count++;
if (ftpcmds[count].ftpfunc == NULL)
ftp_write(peer, FALSE, 502, REPLY_HELPUNKNOWN(command));
else
ftp_write(peer, FALSE, 214, "%-8s : %s", ftpcmds[count].command, ftpcmds[count].helpdesc);
return(FALSE);
}
ftp_write(peer, TRUE, 0, REPLY_HELPSTART);
while (ftpcmds[count].ftpfunc != NULL)
{
count2 = 0;
if (config->altlongreplies)
strcpy(outstr, "214-");
else
strcpy(outstr, " ");
/* now increment past disabled commands */
while((peer->loggedin ? disableset[count] : ftpcmds[count].needslogin))
count++;
while ((count2 < 7) && (ftpcmds[count].ftpfunc != NULL))
{
snprintf(cmd, 10, "%-9s", ftpcmds[count].command);
strcat(outstr, cmd);
count2++;
count++;
/* now increment past disabled commands */
while((peer->loggedin ? disableset[count] : ftpcmds[count].needslogin))
count++;
}
ftp_write(peer, TRUE, 0, outstr);
}
result = ftp_write(peer, FALSE, 214, REPLY_HELPEND(peer->vserver->email));
return(result);
}
int ftp_allo(FTPSTATE *peer, char *param)
{
return(ftp_write(peer, FALSE, 202, REPLY_ALLO));
}
int ftp_acct(FTPSTATE *peer, char *param)
{
return(ftp_write(peer, FALSE, 200, REPLY_ACCT));
}
int ftp_stru(FTPSTATE *peer, char *param)
{
if ((param[0] & (255-32)) == 'F')
return(ftp_write(peer, FALSE, 200, REPLY_STRUFILE));
else
return(ftp_write(peer, FALSE, 500, REPLY_STRUUNKNOWN));
}
syntax highlighted by Code2HTML, v. 0.9.1